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 final List<LinkFile> linkfiles;
74 private String recommendShallow;
75 private String url;
76 private String defaultRevision;
77
78 /**
79 * The representation of a reference file configuration.
80 *
81 * @since 4.8
82 */
83 public static class ReferenceFile {
84 final Repository repo;
85 final String path;
86 final String src;
87 final String dest;
88
89 /**
90 * @param repo
91 * the super project.
92 * @param path
93 * the path of the project containing this copyfile config.
94 * @param src
95 * the source path relative to the sub repo.
96 * @param dest
97 * the destination path relative to the super project.
98 */
99 public ReferenceFile(Repository repo, String path, String src, String dest) {
100 this.repo = repo;
101 this.path = path;
102 this.src = src;
103 this.dest = dest;
104 }
105 }
106
107 /**
108 * The representation of a copy file configuration.
109 */
110 public static class CopyFile extends ReferenceFile {
111 /**
112 * @param repo
113 * the super project.
114 * @param path
115 * the path of the project containing this copyfile config.
116 * @param src
117 * the source path relative to the sub repo.
118 * @param dest
119 * the destination path relative to the super project.
120 */
121 public CopyFile(Repository repo, String path, String src, String dest) {
122 super(repo, path, src, dest);
123 }
124
125 /**
126 * Do the copy file action.
127 *
128 * @throws IOException
129 */
130 public void copy() throws IOException {
131 File srcFile = new File(repo.getWorkTree(),
132 path + "/" + src); //$NON-NLS-1$
133 File destFile = new File(repo.getWorkTree(), dest);
134 FileInputStream input = new FileInputStream(srcFile);
135 try {
136 FileOutputStream output = new FileOutputStream(destFile);
137 try {
138 FileChannel channel = input.getChannel();
139 output.getChannel().transferFrom(
140 channel, 0, channel.size());
141 } finally {
142 output.close();
143 }
144 } finally {
145 input.close();
146 }
147 }
148 }
149
150 /**
151 * The representation of a link file configuration.
152 *
153 * @since 4.8
154 */
155 public static class LinkFile extends ReferenceFile {
156 /**
157 * @param repo
158 * the super project.
159 * @param path
160 * the path of the project containing this linkfile config.
161 * @param src
162 * the source path relative to the sub repo.
163 * @param dest
164 * the destination path relative to the super project.
165 */
166 public LinkFile(Repository repo, String path, String src, String dest) {
167 super(repo, path, src, dest);
168 }
169 }
170
171 /**
172 * Constructor for RepoProject
173 *
174 * @param name
175 * the relative path to the {@code remote}
176 * @param path
177 * the relative path to the super project
178 * @param revision
179 * a SHA-1 or branch name or tag name
180 * @param remote
181 * name of the remote definition
182 * @param groups
183 * set of groups
184 * @param recommendShallow
185 * recommendation for shallowness
186 * @since 4.4
187 */
188 public RepoProject(String name, String path, String revision,
189 String remote, Set<String> groups,
190 String recommendShallow) {
191 if (name == null) {
192 throw new NullPointerException();
193 }
194 this.name = name;
195 if (path != null)
196 this.path = path;
197 else
198 this.path = name;
199 this.revision = revision;
200 this.remote = remote;
201 this.groups = groups;
202 this.recommendShallow = recommendShallow;
203 copyfiles = new ArrayList<>();
204 linkfiles = new ArrayList<>();
205 }
206
207 /**
208 * Constructor for RepoProject
209 *
210 * @param name
211 * the relative path to the {@code remote}
212 * @param path
213 * the relative path to the super project
214 * @param revision
215 * a SHA-1 or branch name or tag name
216 * @param remote
217 * name of the remote definition
218 * @param groupsParam
219 * comma separated group list
220 */
221 public RepoProject(String name, String path, String revision,
222 String remote, String groupsParam) {
223 this(name, path, revision, remote, new HashSet<String>(), null);
224 if (groupsParam != null && groupsParam.length() > 0)
225 this.setGroups(groupsParam);
226 }
227
228 /**
229 * Set the url of the sub repo.
230 *
231 * @param url
232 * project url
233 * @return this for chaining.
234 */
235 public RepoProject setUrl(String url) {
236 this.url = url;
237 return this;
238 }
239
240 /**
241 * Set the url of the sub repo.
242 *
243 * @param groupsParam
244 * comma separated group list
245 * @return this for chaining.
246 * @since 4.4
247 */
248 public RepoProject setGroups(String groupsParam) {
249 this.groups.clear();
250 this.groups.addAll(Arrays.asList(groupsParam.split(","))); //$NON-NLS-1$
251 return this;
252 }
253
254 /**
255 * Set the default revision for the sub repo.
256 *
257 * @param defaultRevision
258 * the name of the default revision
259 * @return this for chaining.
260 */
261 public RepoProject setDefaultRevision(String defaultRevision) {
262 this.defaultRevision = defaultRevision;
263 return this;
264 }
265
266 /**
267 * Get the name (relative path to the {@code remote}) of this sub repo.
268 *
269 * @return {@code name}
270 */
271 public String getName() {
272 return name;
273 }
274
275 /**
276 * Get the path (relative path to the super project) of this sub repo.
277 *
278 * @return {@code path}
279 */
280 public String getPath() {
281 return path;
282 }
283
284 /**
285 * Get the revision of the sub repo.
286 *
287 * @return {@code revision} if set, or {@code defaultRevision}.
288 */
289 public String getRevision() {
290 return revision == null ? defaultRevision : revision;
291 }
292
293 /**
294 * Getter for the copyfile configurations.
295 *
296 * @return Immutable copy of {@code copyfiles}
297 */
298 public List<CopyFile> getCopyFiles() {
299 return Collections.unmodifiableList(copyfiles);
300 }
301
302 /**
303 * Getter for the linkfile configurations.
304 *
305 * @return Immutable copy of {@code linkfiles}
306 * @since 4.8
307 */
308 public List<LinkFile> getLinkFiles() {
309 return Collections.unmodifiableList(linkfiles);
310 }
311
312 /**
313 * Get the url of the sub repo.
314 *
315 * @return {@code url}
316 */
317 public String getUrl() {
318 return url;
319 }
320
321 /**
322 * Get the name of the remote definition of the sub repo.
323 *
324 * @return {@code remote}
325 */
326 public String getRemote() {
327 return remote;
328 }
329
330 /**
331 * Test whether this sub repo belongs to a specified group.
332 *
333 * @param group
334 * a group
335 * @return true if {@code group} is present.
336 */
337 public boolean inGroup(String group) {
338 return groups.contains(group);
339 }
340
341 /**
342 * Return the set of groups.
343 *
344 * @return a Set of groups.
345 * @since 4.4
346 */
347 public Set<String> getGroups() {
348 return groups;
349 }
350
351 /**
352 * Return the recommendation for shallowness.
353 *
354 * @return the String of "clone-depth"
355 * @since 4.4
356 */
357 public String getRecommendShallow() {
358 return recommendShallow;
359 }
360
361 /**
362 * Sets the recommendation for shallowness.
363 *
364 * @param recommendShallow
365 * recommendation for shallowness
366 * @since 4.4
367 */
368 public void setRecommendShallow(String recommendShallow) {
369 this.recommendShallow = recommendShallow;
370 }
371
372 /**
373 * Add a copy file configuration.
374 *
375 * @param copyfile a {@link org.eclipse.jgit.gitrepo.RepoProject.CopyFile} object.
376 */
377 public void addCopyFile(CopyFile copyfile) {
378 copyfiles.add(copyfile);
379 }
380
381 /**
382 * Add a bunch of copyfile configurations.
383 *
384 * @param copyFiles
385 * a collection of
386 * {@link org.eclipse.jgit.gitrepo.RepoProject.CopyFile} objects
387 */
388 public void addCopyFiles(Collection<CopyFile> copyFiles) {
389 this.copyfiles.addAll(copyFiles);
390 }
391
392 /**
393 * Clear all the copyfiles.
394 *
395 * @since 4.2
396 */
397 public void clearCopyFiles() {
398 this.copyfiles.clear();
399 }
400
401 /**
402 * Add a link file configuration.
403 *
404 * @param linkfile a {@link org.eclipse.jgit.gitrepo.RepoProject.LinkFile} object.
405 * @since 4.8
406 */
407 public void addLinkFile(LinkFile linkfile) {
408 linkfiles.add(linkfile);
409 }
410
411 /**
412 * Add a bunch of linkfile configurations.
413 *
414 * @param linkFiles
415 * a collection of {@link LinkFile}s
416 * @since 4.8
417 */
418 public void addLinkFiles(Collection<LinkFile> linkFiles) {
419 this.linkfiles.addAll(linkFiles);
420 }
421
422 /**
423 * Clear all the linkfiles.
424 *
425 * @since 4.8
426 */
427 public void clearLinkFiles() {
428 this.linkfiles.clear();
429 }
430
431 private String getPathWithSlash() {
432 if (path.endsWith("/")) //$NON-NLS-1$
433 return path;
434 else
435 return path + "/"; //$NON-NLS-1$
436 }
437
438 /**
439 * Check if this sub repo is the ancestor of given sub repo.
440 *
441 * @param that
442 * non null
443 * @return true if this sub repo is the ancestor of given sub repo.
444 */
445 public boolean isAncestorOf(RepoProject that) {
446 return isAncestorOf(that.getPathWithSlash());
447 }
448
449 /**
450 * Check if this sub repo is an ancestor of the given path.
451 *
452 * @param thatPath
453 * path to be checked to see if it is within this repository
454 * @return true if this sub repo is an ancestor of the given path.
455 * @since 4.2
456 */
457 public boolean isAncestorOf(String thatPath) {
458 return thatPath.startsWith(getPathWithSlash());
459 }
460
461 /** {@inheritDoc} */
462 @Override
463 public boolean equals(Object o) {
464 if (o instanceof RepoProject) {
465 RepoProject that = (RepoProject) o;
466 return this.getPathWithSlash().equals(that.getPathWithSlash());
467 }
468 return false;
469 }
470
471 /** {@inheritDoc} */
472 @Override
473 public int hashCode() {
474 return this.getPathWithSlash().hashCode();
475 }
476
477 /** {@inheritDoc} */
478 @Override
479 public int compareTo(RepoProject that) {
480 return this.getPathWithSlash().compareTo(that.getPathWithSlash());
481 }
482 }
483