View Javadoc
1   /*
2    * Copyright (C) 2015, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.gitrepo;
11  
12  import java.io.File;
13  import java.io.FileInputStream;
14  import java.io.FileOutputStream;
15  import java.io.IOException;
16  import java.nio.channels.FileChannel;
17  import java.util.ArrayList;
18  import java.util.Arrays;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Set;
24  
25  import org.eclipse.jgit.lib.Repository;
26  
27  /**
28   * The representation of a repo sub project.
29   *
30   * @see <a href="https://code.google.com/p/git-repo/">git-repo project page</a>
31   * @since 4.0
32   */
33  public class RepoProject implements Comparable<RepoProject> {
34  	private final String name;
35  	private final String path;
36  	private final String revision;
37  	private final String remote;
38  	private final Set<String> groups;
39  	private final List<CopyFile> copyfiles;
40  	private final List<LinkFile> linkfiles;
41  	private String recommendShallow;
42  	private String url;
43  	private String defaultRevision;
44  
45  	/**
46  	 * The representation of a reference file configuration.
47  	 *
48  	 * @since 4.8
49  	 */
50  	public static class ReferenceFile {
51  		final Repository repo;
52  		final String path;
53  		final String src;
54  		final String dest;
55  
56  		/**
57  		 * @param repo
58  		 *            the super project.
59  		 * @param path
60  		 *            the path of the project containing this copyfile config.
61  		 * @param src
62  		 *            the source path relative to the sub repo.
63  		 * @param dest
64  		 *            the destination path relative to the super project.
65  		 */
66  		public ReferenceFile(Repository repo, String path, String src, String dest) {
67  			this.repo = repo;
68  			this.path = path;
69  			this.src = src;
70  			this.dest = dest;
71  		}
72  	}
73  
74  	/**
75  	 * The representation of a copy file configuration.
76  	 */
77  	public static class CopyFile extends ReferenceFile {
78  		/**
79  		 * @param repo
80  		 *            the super project.
81  		 * @param path
82  		 *            the path of the project containing this copyfile config.
83  		 * @param src
84  		 *            the source path relative to the sub repo.
85  		 * @param dest
86  		 *            the destination path relative to the super project.
87  		 */
88  		public CopyFile(Repository repo, String path, String src, String dest) {
89  			super(repo, path, src, dest);
90  		}
91  
92  		/**
93  		 * Do the copy file action.
94  		 *
95  		 * @throws IOException
96  		 */
97  		public void copy() throws IOException {
98  			File srcFile = new File(repo.getWorkTree(),
99  					path + "/" + src); //$NON-NLS-1$
100 			File destFile = new File(repo.getWorkTree(), dest);
101 			try (FileInputStream input = new FileInputStream(srcFile);
102 					FileOutputStream output = new FileOutputStream(destFile)) {
103 				FileChannel channel = input.getChannel();
104 				output.getChannel().transferFrom(channel, 0, channel.size());
105 			}
106 			destFile.setExecutable(srcFile.canExecute());
107 		}
108 	}
109 
110 	/**
111 	 * The representation of a link file configuration.
112 	 *
113 	 * @since 4.8
114 	 */
115 	public static class LinkFile extends ReferenceFile {
116 		/**
117 		 * @param repo
118 		 *            the super project.
119 		 * @param path
120 		 *            the path of the project containing this linkfile config.
121 		 * @param src
122 		 *            the source path relative to the sub repo.
123 		 * @param dest
124 		 *            the destination path relative to the super project.
125 		 */
126 		public LinkFile(Repository repo, String path, String src, String dest) {
127 			super(repo, path, src, dest);
128 		}
129 	}
130 
131 	/**
132 	 * Constructor for RepoProject
133 	 *
134 	 * @param name
135 	 *            the relative path to the {@code remote}
136 	 * @param path
137 	 *            the relative path to the super project
138 	 * @param revision
139 	 *            a SHA-1 or branch name or tag name
140 	 * @param remote
141 	 *            name of the remote definition
142 	 * @param groups
143 	 *            set of groups
144 	 * @param recommendShallow
145 	 *            recommendation for shallowness
146 	 * @since 4.4
147 	 */
148 	public RepoProject(String name, String path, String revision,
149 			String remote, Set<String> groups,
150 			String recommendShallow) {
151 		if (name == null) {
152 			throw new NullPointerException();
153 		}
154 		this.name = name;
155 		if (path != null)
156 			this.path = path;
157 		else
158 			this.path = name;
159 		this.revision = revision;
160 		this.remote = remote;
161 		this.groups = groups;
162 		this.recommendShallow = recommendShallow;
163 		copyfiles = new ArrayList<>();
164 		linkfiles = new ArrayList<>();
165 	}
166 
167 	/**
168 	 * Constructor for RepoProject
169 	 *
170 	 * @param name
171 	 *            the relative path to the {@code remote}
172 	 * @param path
173 	 *            the relative path to the super project
174 	 * @param revision
175 	 *            a SHA-1 or branch name or tag name
176 	 * @param remote
177 	 *            name of the remote definition
178 	 * @param groupsParam
179 	 *            comma separated group list
180 	 */
181 	public RepoProject(String name, String path, String revision,
182 			String remote, String groupsParam) {
183 		this(name, path, revision, remote, new HashSet<String>(), null);
184 		if (groupsParam != null && groupsParam.length() > 0)
185 			this.setGroups(groupsParam);
186 	}
187 
188 	/**
189 	 * Set the url of the sub repo.
190 	 *
191 	 * @param url
192 	 *            project url
193 	 * @return this for chaining.
194 	 */
195 	public RepoProject setUrl(String url) {
196 		this.url = url;
197 		return this;
198 	}
199 
200 	/**
201 	 * Set the url of the sub repo.
202 	 *
203 	 * @param groupsParam
204 	 *            comma separated group list
205 	 * @return this for chaining.
206 	 * @since 4.4
207 	 */
208 	public RepoProject setGroups(String groupsParam) {
209 		this.groups.clear();
210 		this.groups.addAll(Arrays.asList(groupsParam.split(","))); //$NON-NLS-1$
211 		return this;
212 	}
213 
214 	/**
215 	 * Set the default revision for the sub repo.
216 	 *
217 	 * @param defaultRevision
218 	 *            the name of the default revision
219 	 * @return this for chaining.
220 	 */
221 	public RepoProject setDefaultRevision(String defaultRevision) {
222 		this.defaultRevision = defaultRevision;
223 		return this;
224 	}
225 
226 	/**
227 	 * Get the name (relative path to the {@code remote}) of this sub repo.
228 	 *
229 	 * @return {@code name}
230 	 */
231 	public String getName() {
232 		return name;
233 	}
234 
235 	/**
236 	 * Get the path (relative path to the super project) of this sub repo.
237 	 *
238 	 * @return {@code path}
239 	 */
240 	public String getPath() {
241 		return path;
242 	}
243 
244 	/**
245 	 * Get the revision of the sub repo.
246 	 *
247 	 * @return {@code revision} if set, or {@code defaultRevision}.
248 	 */
249 	public String getRevision() {
250 		return revision == null ? defaultRevision : revision;
251 	}
252 
253 	/**
254 	 * Getter for the copyfile configurations.
255 	 *
256 	 * @return Immutable copy of {@code copyfiles}
257 	 */
258 	public List<CopyFile> getCopyFiles() {
259 		return Collections.unmodifiableList(copyfiles);
260 	}
261 
262 	/**
263 	 * Getter for the linkfile configurations.
264 	 *
265 	 * @return Immutable copy of {@code linkfiles}
266 	 * @since 4.8
267 	 */
268 	public List<LinkFile> getLinkFiles() {
269 		return Collections.unmodifiableList(linkfiles);
270 	}
271 
272 	/**
273 	 * Get the url of the sub repo.
274 	 *
275 	 * @return {@code url}
276 	 */
277 	public String getUrl() {
278 		return url;
279 	}
280 
281 	/**
282 	 * Get the name of the remote definition of the sub repo.
283 	 *
284 	 * @return {@code remote}
285 	 */
286 	public String getRemote() {
287 		return remote;
288 	}
289 
290 	/**
291 	 * Test whether this sub repo belongs to a specified group.
292 	 *
293 	 * @param group
294 	 *            a group
295 	 * @return true if {@code group} is present.
296 	 */
297 	public boolean inGroup(String group) {
298 		return groups.contains(group);
299 	}
300 
301 	/**
302 	 * Return the set of groups.
303 	 *
304 	 * @return a Set of groups.
305 	 * @since 4.4
306 	 */
307 	public Set<String> getGroups() {
308 		return groups;
309 	}
310 
311 	/**
312 	 * Return the recommendation for shallowness.
313 	 *
314 	 * @return the String of "clone-depth"
315 	 * @since 4.4
316 	 */
317 	public String getRecommendShallow() {
318 		return recommendShallow;
319 	}
320 
321 	/**
322 	 * Sets the recommendation for shallowness.
323 	 *
324 	 * @param recommendShallow
325 	 *            recommendation for shallowness
326 	 * @since 4.4
327 	 */
328 	public void setRecommendShallow(String recommendShallow) {
329 		this.recommendShallow = recommendShallow;
330 	}
331 
332 	/**
333 	 * Add a copy file configuration.
334 	 *
335 	 * @param copyfile a {@link org.eclipse.jgit.gitrepo.RepoProject.CopyFile} object.
336 	 */
337 	public void addCopyFile(CopyFile copyfile) {
338 		copyfiles.add(copyfile);
339 	}
340 
341 	/**
342 	 * Add a bunch of copyfile configurations.
343 	 *
344 	 * @param copyFiles
345 	 *            a collection of
346 	 *            {@link org.eclipse.jgit.gitrepo.RepoProject.CopyFile} objects
347 	 */
348 	public void addCopyFiles(Collection<CopyFile> copyFiles) {
349 		this.copyfiles.addAll(copyFiles);
350 	}
351 
352 	/**
353 	 * Clear all the copyfiles.
354 	 *
355 	 * @since 4.2
356 	 */
357 	public void clearCopyFiles() {
358 		this.copyfiles.clear();
359 	}
360 
361 	/**
362 	 * Add a link file configuration.
363 	 *
364 	 * @param linkfile a {@link org.eclipse.jgit.gitrepo.RepoProject.LinkFile} object.
365 	 * @since 4.8
366 	 */
367 	public void addLinkFile(LinkFile linkfile) {
368 		linkfiles.add(linkfile);
369 	}
370 
371 	/**
372 	 * Add a bunch of linkfile configurations.
373 	 *
374 	 * @param linkFiles
375 	 *            a collection of {@link LinkFile}s
376 	 * @since 4.8
377 	 */
378 	public void addLinkFiles(Collection<LinkFile> linkFiles) {
379 		this.linkfiles.addAll(linkFiles);
380 	}
381 
382 	/**
383 	 * Clear all the linkfiles.
384 	 *
385 	 * @since 4.8
386 	 */
387 	public void clearLinkFiles() {
388 		this.linkfiles.clear();
389 	}
390 
391 	private String getPathWithSlash() {
392 		if (path.endsWith("/")) { //$NON-NLS-1$
393 			return path;
394 		}
395 		return path + "/"; //$NON-NLS-1$
396 	}
397 
398 	/**
399 	 * Check if this sub repo is the ancestor of given sub repo.
400 	 *
401 	 * @param that
402 	 *            non null
403 	 * @return true if this sub repo is the ancestor of given sub repo.
404 	 */
405 	public boolean isAncestorOf(RepoProject that) {
406 		return isAncestorOf(that.getPathWithSlash());
407 	}
408 
409 	/**
410 	 * Check if this sub repo is an ancestor of the given path.
411 	 *
412 	 * @param thatPath
413 	 *            path to be checked to see if it is within this repository
414 	 * @return true if this sub repo is an ancestor of the given path.
415 	 * @since 4.2
416 	 */
417 	public boolean isAncestorOf(String thatPath) {
418 		return thatPath.startsWith(getPathWithSlash());
419 	}
420 
421 	/** {@inheritDoc} */
422 	@Override
423 	public boolean equals(Object o) {
424 		if (o instanceof RepoProject) {
425 			RepoProject that = (RepoProject) o;
426 			return this.getPathWithSlash().equals(that.getPathWithSlash());
427 		}
428 		return false;
429 	}
430 
431 	/** {@inheritDoc} */
432 	@Override
433 	public int hashCode() {
434 		return this.getPathWithSlash().hashCode();
435 	}
436 
437 	/** {@inheritDoc} */
438 	@Override
439 	public int compareTo(RepoProject that) {
440 		return this.getPathWithSlash().compareTo(that.getPathWithSlash());
441 	}
442 }
443