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