diff options
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java | 141 |
1 files changed, 133 insertions, 8 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java index e105dc063b..1de8a0be2e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -49,11 +49,14 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.UnsupportedOperationException; +import java.net.URI; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.StringJoiner; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.Git; @@ -67,6 +70,7 @@ import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.gitrepo.ManifestParser.IncludedFileReader; import org.eclipse.jgit.gitrepo.RepoProject.CopyFile; +import org.eclipse.jgit.gitrepo.RepoProject.LinkFile; import org.eclipse.jgit.gitrepo.internal.RepoText; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.CommitBuilder; @@ -106,7 +110,8 @@ import org.eclipse.jgit.util.FileUtils; */ public class RepoCommand extends GitCommand<RevCommit> { private String manifestPath; - private String uri; + private String baseUri; + private URI targetUri; private String groupsParam; private String branch; private String targetBranch = Constants.HEAD; @@ -274,7 +279,25 @@ public class RepoCommand extends GitCommand<RevCommit> { * @return this command */ public RepoCommand setURI(String uri) { - this.uri = uri; + this.baseUri = uri; + return this; + } + + /** + * Set the URI of the superproject (this repository), so the .gitmodules + * file can specify the submodule URLs relative to the superproject. + * + * @param uri + * the URI of the repository holding the superproject. + * @return this command + * @since 4.8 + */ + public RepoCommand setTargetURI(String uri) { + // The repo name is interpreted as a directory, for example + // Gerrit (http://gerrit.googlesource.com/gerrit) has a + // .gitmodules referencing ../plugins/hooks, which is + // on http://gerrit.googlesource.com/plugins/hooks, + this.targetUri = URI.create(uri + "/"); //$NON-NLS-1$ return this; } @@ -452,9 +475,8 @@ public class RepoCommand extends GitCommand<RevCommit> { public RevCommit call() throws GitAPIException { try { checkCallable(); - if (uri == null || uri.length() == 0) { - throw new IllegalArgumentException( - JGitText.get().uriNotConfigured); + if (baseUri == null) { + baseUri = ""; //$NON-NLS-1$ } if (inputStream == null) { if (manifestPath == null || manifestPath.length() == 0) @@ -478,7 +500,7 @@ public class RepoCommand extends GitCommand<RevCommit> { git = new Git(repo); ManifestParser parser = new ManifestParser( - includedReader, manifestPath, branch, uri, groupsParam, repo); + includedReader, manifestPath, branch, baseUri, groupsParam, repo); try { parser.read(inputStream); for (RepoProject proj : parser.getFilteredProjects()) { @@ -486,6 +508,7 @@ public class RepoCommand extends GitCommand<RevCommit> { proj.getPath(), proj.getRevision(), proj.getCopyFiles(), + proj.getLinkFiles(), proj.getGroups(), proj.getRecommendShallow()); } @@ -550,8 +573,13 @@ public class RepoCommand extends GitCommand<RevCommit> { rec.append("\n"); //$NON-NLS-1$ attributes.append(rec.toString()); } + + URI submodUrl = URI.create(nameUri); + if (targetUri != null) { + submodUrl = relativize(targetUri, submodUrl); + } cfg.setString("submodule", path, "path", path); //$NON-NLS-1$ //$NON-NLS-2$ - cfg.setString("submodule", path, "url", nameUri); //$NON-NLS-1$ //$NON-NLS-2$ + cfg.setString("submodule", path, "url", submodUrl.toString()); //$NON-NLS-1$ //$NON-NLS-2$ // create gitlink DirCacheEntry dcEntry = new DirCacheEntry(path); @@ -568,6 +596,25 @@ public class RepoCommand extends GitCommand<RevCommit> { dcEntry.setFileMode(FileMode.REGULAR_FILE); builder.add(dcEntry); } + for (LinkFile linkfile : proj.getLinkFiles()) { + String link; + if (linkfile.dest.contains("/")) { //$NON-NLS-1$ + link = FileUtils.relativizeGitPath( + linkfile.dest.substring(0, + linkfile.dest.lastIndexOf('/')), + proj.getPath() + "/" + linkfile.src); //$NON-NLS-1$ + } else { + link = proj.getPath() + "/" + linkfile.src; //$NON-NLS-1$ + } + + objectId = inserter.insert(Constants.OBJ_BLOB, + link.getBytes( + Constants.CHARACTER_ENCODING)); + dcEntry = new DirCacheEntry(linkfile.dest); + dcEntry.setObjectId(objectId); + dcEntry.setFileMode(FileMode.SYMLINK); + builder.add(dcEntry); + } } String content = cfg.toText(); @@ -642,13 +689,20 @@ public class RepoCommand extends GitCommand<RevCommit> { } private void addSubmodule(String url, String path, String revision, - List<CopyFile> copyfiles, Set<String> groups, String recommendShallow) + List<CopyFile> copyfiles, List<LinkFile> linkfiles, + Set<String> groups, String recommendShallow) throws GitAPIException, IOException { if (repo.isBare()) { RepoProject proj = new RepoProject(url, path, revision, null, groups, recommendShallow); proj.addCopyFiles(copyfiles); + proj.addLinkFiles(linkfiles); bareProjects.add(proj); } else { + if (!linkfiles.isEmpty()) { + throw new UnsupportedOperationException( + JGitText.get().nonBareLinkFilesNotSupported); + } + SubmoduleAddCommand add = git .submoduleAdd() .setPath(path) @@ -672,6 +726,77 @@ public class RepoCommand extends GitCommand<RevCommit> { } } + /* + * Assume we are document "a/b/index.html", what should we put in a href to get to "a/" ? + * Returns the child if either base or child is not a bare path. This provides a missing feature in + * java.net.URI (see http://bugs.java.com/view_bug.do?bug_id=6226081). + */ + private static final String SLASH = "/"; //$NON-NLS-1$ + static URI relativize(URI current, URI target) { + + // We only handle bare paths for now. + if (!target.toString().equals(target.getPath())) { + return target; + } + if (!current.toString().equals(current.getPath())) { + return target; + } + + String cur = current.normalize().getPath(); + String dest = target.normalize().getPath(); + + // TODO(hanwen): maybe (absolute, relative) should throw an exception. + if (cur.startsWith(SLASH) != dest.startsWith(SLASH)) { + return target; + } + + while (cur.startsWith(SLASH)) { + cur = cur.substring(1); + } + while (dest.startsWith(SLASH)) { + dest = dest.substring(1); + } + + if (cur.indexOf('/') == -1 || dest.indexOf('/') == -1) { + // Avoid having to special-casing in the next two ifs. + String prefix = "prefix/"; //$NON-NLS-1$ + cur = prefix + cur; + dest = prefix + dest; + } + + if (!cur.endsWith(SLASH)) { + // The current file doesn't matter. + int lastSlash = cur.lastIndexOf('/'); + cur = cur.substring(0, lastSlash); + } + String destFile = ""; //$NON-NLS-1$ + if (!dest.endsWith(SLASH)) { + // We always have to provide the destination file. + int lastSlash = dest.lastIndexOf('/'); + destFile = dest.substring(lastSlash + 1, dest.length()); + dest = dest.substring(0, dest.lastIndexOf('/')); + } + + String[] cs = cur.split(SLASH); + String[] ds = dest.split(SLASH); + + int common = 0; + while (common < cs.length && common < ds.length && cs[common].equals(ds[common])) { + common++; + } + + StringJoiner j = new StringJoiner(SLASH); + for (int i = common; i < cs.length; i++) { + j.add(".."); //$NON-NLS-1$ + } + for (int i = common; i < ds.length; i++) { + j.add(ds[i]); + } + + j.add(destFile); + return URI.create(j.toString()); + } + private static String findRef(String ref, Repository repo) throws IOException { if (!ObjectId.isId(ref)) { |