1 /*
2 * Copyright (C) 2015, Google Inc.
3 * and other copyright owners as documented in the project's IP log.
4 *
5 * This program and the accompanying materials are made available
6 * under the terms of the Eclipse Distribution License v1.0 which
7 * accompanies this distribution, is reproduced below, and is
8 * available at http://www.eclipse.org/org/documents/edl-v10.php
9 *
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials provided
22 * with the distribution.
23 *
24 * - Neither the name of the Eclipse Foundation, Inc. nor the
25 * names of its contributors may be used to endorse or promote
26 * products derived from this software without specific prior
27 * written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43 package org.eclipse.jgit.gitrepo;
44
45 import java.io.File;
46 import java.io.FileInputStream;
47 import java.io.FileOutputStream;
48 import java.io.IOException;
49 import java.nio.channels.FileChannel;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Set;
57
58 import org.eclipse.jgit.lib.Repository;
59
60 /**
61 * The representation of a repo sub project.
62 *
63 * @see <a href="https://code.google.com/p/git-repo/">git-repo project page</a>
64 * @since 4.0
65 */
66 public class RepoProject implements Comparable<RepoProject> {
67 private final String name;
68 private final String path;
69 private final String revision;
70 private final String remote;
71 private final Set<String> groups;
72 private final List<CopyFile> copyfiles;
73 private String recommendShallow;
74 private String url;
75 private String defaultRevision;
76
77 /**
78 * The representation of a copy file configuration.
79 */
80 public static class CopyFile {
81 final Repository repo;
82 final String path;
83 final String src;
84 final String dest;
85
86 /**
87 * @param repo
88 * the super project.
89 * @param path
90 * the path of the project containing this copyfile config.
91 * @param src
92 * the source path relative to the sub repo.
93 * @param dest
94 * the destination path relative to the super project.
95 */
96 public CopyFile(Repository repo, String path, String src, String dest) {
97 this.repo = repo;
98 this.path = path;
99 this.src = src;
100 this.dest = dest;
101 }
102
103 /**
104 * Do the copy file action.
105 *
106 * @throws IOException
107 */
108 public void copy() throws IOException {
109 File srcFile = new File(repo.getWorkTree(),
110 path + "/" + src); //$NON-NLS-1$
111 File destFile = new File(repo.getWorkTree(), dest);
112 FileInputStream input = new FileInputStream(srcFile);
113 try {
114 FileOutputStream output = new FileOutputStream(destFile);
115 try {
116 FileChannel channel = input.getChannel();
117 output.getChannel().transferFrom(
118 channel, 0, channel.size());
119 } finally {
120 output.close();
121 }
122 } finally {
123 input.close();
124 }
125 }
126 }
127
128 /**
129 * @param name
130 * the relative path to the {@code remote}
131 * @param path
132 * the relative path to the super project
133 * @param revision
134 * a SHA-1 or branch name or tag name
135 * @param remote
136 * name of the remote definition
137 * @param groups
138 * set of groups
139 * @param recommendShallow
140 * recommendation for shallowness
141 * @since 4.4
142 */
143 public RepoProject(String name, String path, String revision,
144 String remote, Set<String> groups,
145 String recommendShallow) {
146 if (name == null) {
147 throw new NullPointerException();
148 }
149 this.name = name;
150 if (path != null)
151 this.path = path;
152 else
153 this.path = name;
154 this.revision = revision;
155 this.remote = remote;
156 this.groups = groups;
157 this.recommendShallow = recommendShallow;
158 copyfiles = new ArrayList<CopyFile>();
159 }
160
161 /**
162 * @param name
163 * the relative path to the {@code remote}
164 * @param path
165 * the relative path to the super project
166 * @param revision
167 * a SHA-1 or branch name or tag name
168 * @param remote
169 * name of the remote definition
170 * @param groups
171 * comma separated group list
172 */
173 public RepoProject(String name, String path, String revision,
174 String remote, String groups) {
175 this(name, path, revision, remote, new HashSet<String>(), null);
176 if (groups != null && groups.length() > 0)
177 this.setGroups(groups);
178 }
179
180 /**
181 * Set the url of the sub repo.
182 *
183 * @param url
184 * @return this for chaining.
185 */
186 public RepoProject setUrl(String url) {
187 this.url = url;
188 return this;
189 }
190
191 /**
192 * Set the url of the sub repo.
193 *
194 * @param groups
195 * comma separated group list
196 * @return this for chaining.
197 * @since 4.4
198 */
199 public RepoProject setGroups(String groups) {
200 this.groups.clear();
201 this.groups.addAll(Arrays.asList(groups.split(","))); //$NON-NLS-1$
202 return this;
203 }
204
205 /**
206 * Set the default revision for the sub repo.
207 *
208 * @param defaultRevision
209 * @return this for chaining.
210 */
211 public RepoProject setDefaultRevision(String defaultRevision) {
212 this.defaultRevision = defaultRevision;
213 return this;
214 }
215
216 /**
217 * Get the name (relative path to the {@code remote}) of this sub repo.
218 *
219 * @return {@code name}
220 */
221 public String getName() {
222 return name;
223 }
224
225 /**
226 * Get the path (relative path to the super project) of this sub repo.
227 *
228 * @return {@code path}
229 */
230 public String getPath() {
231 return path;
232 }
233
234 /**
235 * Get the revision of the sub repo.
236 *
237 * @return {@code revision} if set, or {@code defaultRevision}.
238 */
239 public String getRevision() {
240 return revision == null ? defaultRevision : revision;
241 }
242
243 /**
244 * Getter for the copyfile configurations.
245 *
246 * @return Immutable copy of {@code copyfiles}
247 */
248 public List<CopyFile> getCopyFiles() {
249 return Collections.unmodifiableList(copyfiles);
250 }
251
252 /**
253 * Get the url of the sub repo.
254 *
255 * @return {@code url}
256 */
257 public String getUrl() {
258 return url;
259 }
260
261 /**
262 * Get the name of the remote definition of the sub repo.
263 *
264 * @return {@code remote}
265 */
266 public String getRemote() {
267 return remote;
268 }
269
270 /**
271 * Test whether this sub repo belongs to a specified group.
272 *
273 * @param group
274 * @return true if {@code group} is present.
275 */
276 public boolean inGroup(String group) {
277 return groups.contains(group);
278 }
279
280 /**
281 * Return the set of groups.
282 *
283 * @return a Set of groups.
284 * @since 4.4
285 */
286 public Set<String> getGroups() {
287 return groups;
288 }
289
290 /**
291 * Return the recommendation for shallowness.
292 *
293 * @return the String of "clone-depth"
294 * @since 4.4
295 */
296 public String getRecommendShallow() {
297 return recommendShallow;
298 }
299
300 /**
301 * Sets the recommendation for shallowness.
302 *
303 * @param recommendShallow
304 * recommendation for shallowness
305 * @since 4.4
306 */
307 public void setRecommendShallow(String recommendShallow) {
308 this.recommendShallow = recommendShallow;
309 }
310
311 /**
312 * Add a copy file configuration.
313 *
314 * @param copyfile
315 */
316 public void addCopyFile(CopyFile copyfile) {
317 copyfiles.add(copyfile);
318 }
319
320 /**
321 * Add a bunch of copyfile configurations.
322 *
323 * @param copyFiles
324 */
325 public void addCopyFiles(Collection<CopyFile> copyFiles) {
326 this.copyfiles.addAll(copyFiles);
327 }
328
329 /**
330 * Clear all the copyfiles.
331 *
332 * @since 4.2
333 */
334 public void clearCopyFiles() {
335 this.copyfiles.clear();
336 }
337
338 private String getPathWithSlash() {
339 if (path.endsWith("/")) //$NON-NLS-1$
340 return path;
341 else
342 return path + "/"; //$NON-NLS-1$
343 }
344
345 /**
346 * Check if this sub repo is the ancestor of given sub repo.
347 *
348 * @param that
349 * non null
350 * @return true if this sub repo is the ancestor of given sub repo.
351 */
352 public boolean isAncestorOf(RepoProject that) {
353 return isAncestorOf(that.getPathWithSlash());
354 }
355
356 /**
357 * Check if this sub repo is an ancestor of the given path.
358 *
359 * @param thatPath
360 * path to be checked to see if it is within this repository
361 * @return true if this sub repo is an ancestor of the given path.
362 * @since 4.2
363 */
364 public boolean isAncestorOf(String thatPath) {
365 return thatPath.startsWith(getPathWithSlash());
366 }
367
368 @Override
369 public boolean equals(Object o) {
370 if (o instanceof RepoProject) {
371 RepoProject that = (RepoProject) o;
372 return this.getPathWithSlash().equals(that.getPathWithSlash());
373 }
374 return false;
375 }
376
377 @Override
378 public int hashCode() {
379 return this.getPathWithSlash().hashCode();
380 }
381
382 @Override
383 public int compareTo(RepoProject that) {
384 return this.getPathWithSlash().compareTo(that.getPathWithSlash());
385 }
386 }
387