summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandSymlinkTest.java162
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java16
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java37
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java31
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java89
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java94
9 files changed, 396 insertions, 41 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandSymlinkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandSymlinkTest.java
new file mode 100644
index 0000000000..12f4dcc0c7
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandSymlinkTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.gitrepo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FS;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RepoCommandSymlinkTest extends RepositoryTestCase {
+ @Before
+ public void beforeMethod() {
+ // If this assumption fails the tests are skipped. When running on a
+ // filesystem not supporting symlinks I don't want this tests
+ org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ }
+
+ private Repository defaultDb;
+
+ private String rootUri;
+ private String defaultUri;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ defaultDb = createWorkRepository();
+ try (Git git = new Git(defaultDb)) {
+ JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "hello world");
+ git.add().addFilepattern("hello.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ addRepoToClose(defaultDb);
+ }
+
+ defaultUri = defaultDb.getDirectory().toURI().toString();
+ int root = defaultUri.lastIndexOf("/",
+ defaultUri.lastIndexOf("/.git") - 1)
+ + 1;
+ rootUri = defaultUri.substring(0, root)
+ + "manifest";
+ defaultUri = defaultUri.substring(root);
+ }
+
+ @Test
+ public void testLinkFileBare() throws Exception {
+ try (
+ Repository remoteDb = createBareRepository();
+ Repository tempDb = createWorkRepository()) {
+ StringBuilder xmlContent = new StringBuilder();
+ xmlContent
+ .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+ .append("<manifest>")
+ .append("<remote name=\"remote1\" fetch=\".\" />")
+ .append("<default revision=\"master\" remote=\"remote1\" />")
+ .append("<project path=\"foo\" name=\"").append(defaultUri)
+ .append("\" revision=\"master\" >")
+ .append("<linkfile src=\"hello.txt\" dest=\"LinkedHello\" />")
+ .append("<linkfile src=\"hello.txt\" dest=\"foo/LinkedHello\" />")
+ .append("<linkfile src=\"hello.txt\" dest=\"subdir/LinkedHello\" />")
+ .append("</project>")
+ .append("<project path=\"bar/baz\" name=\"")
+ .append(defaultUri).append("\" revision=\"master\" >")
+ .append("<linkfile src=\"hello.txt\" dest=\"bar/foo/LinkedHello\" />")
+ .append("</project>").append("</manifest>");
+ JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
+ xmlContent.toString());
+ RepoCommand command = new RepoCommand(remoteDb);
+ command.setPath(
+ tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
+ .setURI(rootUri).call();
+ // Clone it
+ File directory = createTempDirectory("testCopyFileBare");
+ Repository localDb = Git.cloneRepository().setDirectory(directory)
+ .setURI(remoteDb.getDirectory().toURI().toString()).call()
+ .getRepository();
+
+ // The LinkedHello symlink should exist.
+ File linkedhello = new File(localDb.getWorkTree(), "LinkedHello");
+ assertTrue("The LinkedHello file should exist",
+ localDb.getFS().exists(linkedhello));
+ assertTrue("The LinkedHello file should be a symlink",
+ localDb.getFS().isSymLink(linkedhello));
+ assertEquals("foo/hello.txt",
+ localDb.getFS().readSymLink(linkedhello));
+
+ // The foo/LinkedHello file should be skipped.
+ File linkedfoohello = new File(localDb.getWorkTree(), "foo/LinkedHello");
+ assertFalse("The foo/LinkedHello file should be skipped",
+ localDb.getFS().exists(linkedfoohello));
+
+ // The subdir/LinkedHello file should use a relative ../
+ File linkedsubdirhello = new File(localDb.getWorkTree(),
+ "subdir/LinkedHello");
+ assertTrue("The subdir/LinkedHello file should exist",
+ localDb.getFS().exists(linkedsubdirhello));
+ assertTrue("The subdir/LinkedHello file should be a symlink",
+ localDb.getFS().isSymLink(linkedsubdirhello));
+ assertEquals("../foo/hello.txt",
+ localDb.getFS().readSymLink(linkedsubdirhello));
+
+ // The bar/foo/LinkedHello file should use a single relative ../
+ File linkedbarfoohello = new File(localDb.getWorkTree(),
+ "bar/foo/LinkedHello");
+ assertTrue("The bar/foo/LinkedHello file should exist",
+ localDb.getFS().exists(linkedbarfoohello));
+ assertTrue("The bar/foo/LinkedHello file should be a symlink",
+ localDb.getFS().isSymLink(linkedbarfoohello));
+ assertEquals("../baz/hello.txt",
+ localDb.getFS().readSymLink(linkedbarfoohello));
+
+ localDb.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java
index 109d0e6ee3..c0f4965668 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilsTest.java
@@ -465,12 +465,12 @@ public class FileUtilsTest {
@Test
public void testRelativize_doc() {
- // This is the javadoc example
+ // This is the example from the javadoc
String base = toOSPathString("c:\\Users\\jdoe\\eclipse\\git\\project");
String other = toOSPathString("c:\\Users\\jdoe\\eclipse\\git\\another_project\\pom.xml");
String expected = toOSPathString("..\\another_project\\pom.xml");
- String actual = FileUtils.relativize(base, other);
+ String actual = FileUtils.relativizeNativePath(base, other);
assertEquals(expected, actual);
}
@@ -483,13 +483,13 @@ public class FileUtilsTest {
String expectedCaseSensitive = toOSPathString("..\\..\\Git\\test\\d\\f.txt");
if (systemReader.isWindows()) {
- String actual = FileUtils.relativize(base, other);
+ String actual = FileUtils.relativizeNativePath(base, other);
assertEquals(expectedCaseInsensitive, actual);
} else if (systemReader.isMacOS()) {
- String actual = FileUtils.relativize(base, other);
+ String actual = FileUtils.relativizeNativePath(base, other);
assertEquals(expectedCaseInsensitive, actual);
} else {
- String actual = FileUtils.relativize(base, other);
+ String actual = FileUtils.relativizeNativePath(base, other);
assertEquals(expectedCaseSensitive, actual);
}
}
@@ -501,7 +501,7 @@ public class FileUtilsTest {
// 'file.java' is treated as a folder
String expected = toOSPathString("../../project");
- String actual = FileUtils.relativize(base, other);
+ String actual = FileUtils.relativizeNativePath(base, other);
assertEquals(expected, actual);
}
@@ -511,7 +511,7 @@ public class FileUtilsTest {
String other = toOSPathString("file:/home/eclipse/runtime-New_configuration/project_1");
String expected = "";
- String actual = FileUtils.relativize(base, other);
+ String actual = FileUtils.relativizeNativePath(base, other);
assertEquals(expected, actual);
}
@@ -521,7 +521,7 @@ public class FileUtilsTest {
String other = toOSPathString("/home/eclipse 3.4/runtime New_configuration/project_1/file");
String expected = "file";
- String actual = FileUtils.relativize(base, other);
+ String actual = FileUtils.relativizeNativePath(base, other);
assertEquals(expected, actual);
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index da076dcb7f..225cb53718 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -431,6 +431,7 @@ noHEADExistsAndNoExplicitStartingRevisionWasSpecified=No HEAD exists and no expl
noHMACsupport=No {0} support: {1}
noMergeBase=No merge base could be determined. Reason={0}. {1}
noMergeHeadSpecified=No merge head specified
+nonBareLinkFilesNotSupported=Link files are not supported with nonbare repos
noSuchRef=no such ref
notABoolean=Not a boolean: {0}
notABundle=not a bundle
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
index 94c8e437c3..ddc6addbc3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -60,6 +60,8 @@ import java.util.Set;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.gitrepo.RepoProject.CopyFile;
+import org.eclipse.jgit.gitrepo.RepoProject.LinkFile;
+import org.eclipse.jgit.gitrepo.RepoProject.ReferenceFile;
import org.eclipse.jgit.gitrepo.internal.RepoText;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Repository;
@@ -209,6 +211,15 @@ public class ManifestParser extends DefaultHandler {
currentProject.getPath(),
attributes.getValue("src"), //$NON-NLS-1$
attributes.getValue("dest"))); //$NON-NLS-1$
+ } else if ("linkfile".equals(qName)) { //$NON-NLS-1$
+ if (currentProject == null) {
+ throw new SAXException(RepoText.get().invalidManifest);
+ }
+ currentProject.addLinkFile(new LinkFile(
+ rootRepo,
+ currentProject.getPath(),
+ attributes.getValue("src"), //$NON-NLS-1$
+ attributes.getValue("dest"))); //$NON-NLS-1$
} else if ("include".equals(qName)) { //$NON-NLS-1$
String name = attributes.getValue("name"); //$NON-NLS-1$
if (includedReader != null) {
@@ -359,19 +370,25 @@ public class ManifestParser extends DefaultHandler {
else
last = p;
}
- removeNestedCopyfiles();
+ removeNestedCopyAndLinkfiles();
}
- /** Remove copyfiles that sit in a subdirectory of any other project. */
- void removeNestedCopyfiles() {
+ private void removeNestedCopyAndLinkfiles() {
for (RepoProject proj : filteredProjects) {
List<CopyFile> copyfiles = new ArrayList<>(proj.getCopyFiles());
proj.clearCopyFiles();
for (CopyFile copyfile : copyfiles) {
- if (!isNestedCopyfile(copyfile)) {
+ if (!isNestedReferencefile(copyfile)) {
proj.addCopyFile(copyfile);
}
}
+ List<LinkFile> linkfiles = new ArrayList<>(proj.getLinkFiles());
+ proj.clearLinkFiles();
+ for (LinkFile linkfile : linkfiles) {
+ if (!isNestedReferencefile(linkfile)) {
+ proj.addLinkFile(linkfile);
+ }
+ }
}
}
@@ -393,18 +410,18 @@ public class ManifestParser extends DefaultHandler {
return false;
}
- private boolean isNestedCopyfile(CopyFile copyfile) {
- if (copyfile.dest.indexOf('/') == -1) {
- // If the copyfile is at root level then it won't be nested.
+ private boolean isNestedReferencefile(ReferenceFile referencefile) {
+ if (referencefile.dest.indexOf('/') == -1) {
+ // If the referencefile is at root level then it won't be nested.
return false;
}
for (RepoProject proj : filteredProjects) {
- if (proj.getPath().compareTo(copyfile.dest) > 0) {
+ if (proj.getPath().compareTo(referencefile.dest) > 0) {
// Early return as remaining projects can't be ancestor of this
- // copyfile config (filteredProjects is sorted).
+ // referencefile config (filteredProjects is sorted).
return false;
}
- if (proj.isAncestorOf(copyfile.dest)) {
+ if (proj.isAncestorOf(referencefile.dest)) {
return true;
}
}
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 8f5f15e8d8..6669c9cfb7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -49,6 +49,7 @@ 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;
@@ -69,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;
@@ -506,6 +508,7 @@ public class RepoCommand extends GitCommand<RevCommit> {
proj.getPath(),
proj.getRevision(),
proj.getCopyFiles(),
+ proj.getLinkFiles(),
proj.getGroups(),
proj.getRecommendShallow());
}
@@ -593,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();
@@ -667,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)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
index 700cf11070..00cd38d69e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -70,14 +70,17 @@ public class RepoProject implements Comparable<RepoProject> {
private final String remote;
private final Set<String> groups;
private final List<CopyFile> copyfiles;
+ private final List<LinkFile> linkfiles;
private String recommendShallow;
private String url;
private String defaultRevision;
/**
- * The representation of a copy file configuration.
+ * The representation of a reference file configuration.
+ *
+ * @since 4.8
*/
- public static class CopyFile {
+ public static class ReferenceFile {
final Repository repo;
final String path;
final String src;
@@ -93,12 +96,31 @@ public class RepoProject implements Comparable<RepoProject> {
* @param dest
* the destination path relative to the super project.
*/
- public CopyFile(Repository repo, String path, String src, String dest) {
+ public ReferenceFile(Repository repo, String path, String src, String dest) {
this.repo = repo;
this.path = path;
this.src = src;
this.dest = dest;
}
+ }
+
+ /**
+ * The representation of a copy file configuration.
+ */
+ public static class CopyFile extends ReferenceFile {
+ /**
+ * @param repo
+ * the super project.
+ * @param path
+ * the path of the project containing this copyfile config.
+ * @param src
+ * the source path relative to the sub repo.
+ * @param dest
+ * the destination path relative to the super project.
+ */
+ public CopyFile(Repository repo, String path, String src, String dest) {
+ super(repo, path, src, dest);
+ }
/**
* Do the copy file action.
@@ -126,6 +148,27 @@ public class RepoProject implements Comparable<RepoProject> {
}
/**
+ * The representation of a link file configuration.
+ *
+ * @since 4.8
+ */
+ public static class LinkFile extends ReferenceFile {
+ /**
+ * @param repo
+ * the super project.
+ * @param path
+ * the path of the project containing this linkfile config.
+ * @param src
+ * the source path relative to the sub repo.
+ * @param dest
+ * the destination path relative to the super project.
+ */
+ public LinkFile(Repository repo, String path, String src, String dest) {
+ super(repo, path, src, dest);
+ }
+ }
+
+ /**
* @param name
* the relative path to the {@code remote}
* @param path
@@ -156,6 +199,7 @@ public class RepoProject implements Comparable<RepoProject> {
this.groups = groups;
this.recommendShallow = recommendShallow;
copyfiles = new ArrayList<>();
+ linkfiles = new ArrayList<>();
}
/**
@@ -250,6 +294,16 @@ public class RepoProject implements Comparable<RepoProject> {
}
/**
+ * Getter for the linkfile configurations.
+ *
+ * @return Immutable copy of {@code linkfiles}
+ * @since 4.8
+ */
+ public List<LinkFile> getLinkFiles() {
+ return Collections.unmodifiableList(linkfiles);
+ }
+
+ /**
* Get the url of the sub repo.
*
* @return {@code url}
@@ -335,6 +389,35 @@ public class RepoProject implements Comparable<RepoProject> {
this.copyfiles.clear();
}
+ /**
+ * Add a link file configuration.
+ *
+ * @param linkfile
+ * @since 4.8
+ */
+ public void addLinkFile(LinkFile linkfile) {
+ linkfiles.add(linkfile);
+ }
+
+ /**
+ * Add a bunch of linkfile configurations.
+ *
+ * @param linkFiles
+ * @since 4.8
+ */
+ public void addLinkFiles(Collection<LinkFile> linkFiles) {
+ this.linkfiles.addAll(linkFiles);
+ }
+
+ /**
+ * Clear all the linkfiles.
+ *
+ * @since 4.8
+ */
+ public void clearLinkFiles() {
+ this.linkfiles.clear();
+ }
+
private String getPathWithSlash() {
if (path.endsWith("/")) //$NON-NLS-1$
return path;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 0e52fccaaa..b2c59a357b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -490,6 +490,7 @@ public class JGitText extends TranslationBundle {
/***/ public String noHMACsupport;
/***/ public String noMergeBase;
/***/ public String noMergeHeadSpecified;
+ /***/ public String nonBareLinkFilesNotSupported;
/***/ public String noSuchRef;
/***/ public String notABoolean;
/***/ public String notABundle;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index 68b71309b1..229355c50a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -777,7 +777,7 @@ public abstract class FS {
}
/**
- * See {@link FileUtils#relativize(String, String)}.
+ * See {@link FileUtils#relativizePath(String, String, String, boolean)}.
*
* @param base
* The path against which <code>other</code> should be
@@ -786,11 +786,11 @@ public abstract class FS {
* The path that will be made relative to <code>base</code>.
* @return A relative path that, when resolved against <code>base</code>,
* will yield the original <code>other</code>.
- * @see FileUtils#relativize(String, String)
+ * @see FileUtils#relativizePath(String, String, String, boolean)
* @since 3.7
*/
public String relativize(String base, String other) {
- return FileUtils.relativize(base, other);
+ return FileUtils.relativizePath(base, other, File.separator, this.isCaseSensitive());
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index 1f20e9700d..76dbb8756e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -468,10 +468,71 @@ public class FileUtils {
throw new IOException(JGitText.get().cannotCreateTempDir);
}
+
+ /**
+ * @deprecated Use the more-clearly-named
+ * {@link FileUtils#relativizeNativePath(String, String)}
+ * instead, or directly call
+ * {@link FileUtils#relativizePath(String, String, String, boolean)}
+ *
+ * Expresses <code>other</code> as a relative file path from
+ * <code>base</code>. File-separator and case sensitivity are
+ * based on the current file system.
+ *
+ * See also
+ * {@link FileUtils#relativizePath(String, String, String, boolean)}.
+ *
+ * @param base
+ * Base path
+ * @param other
+ * Destination path
+ * @return Relative path from <code>base</code> to <code>other</code>
+ * @since 3.7
+ */
+ @Deprecated
+ public static String relativize(String base, String other) {
+ return relativizeNativePath(base, other);
+ }
+
+ /**
+ * Expresses <code>other</code> as a relative file path from <code>base</code>.
+ * File-separator and case sensitivity are based on the current file system.
+ *
+ * See also {@link FileUtils#relativizePath(String, String, String, boolean)}.
+ *
+ * @param base
+ * Base path
+ * @param other
+ * Destination path
+ * @return Relative path from <code>base</code> to <code>other</code>
+ * @since 4.8
+ */
+ public static String relativizeNativePath(String base, String other) {
+ return FS.DETECTED.relativize(base, other);
+ }
+
+ /**
+ * Expresses <code>other</code> as a relative file path from <code>base</code>.
+ * File-separator and case sensitivity are based on Git's internal representation of files (which matches Unix).
+ *
+ * See also {@link FileUtils#relativizePath(String, String, String, boolean)}.
+ *
+ * @param base
+ * Base path
+ * @param other
+ * Destination path
+ * @return Relative path from <code>base</code> to <code>other</code>
+ * @since 4.8
+ */
+ public static String relativizeGitPath(String base, String other) {
+ return relativizePath(base, other, "/", false); //$NON-NLS-1$
+ }
+
+
/**
- * This will try and make a given path relative to another.
+ * Expresses <code>other</code> as a relative file path from <code>base</code>
* <p>
- * For example, if this is called with the two following paths :
+ * For example, if called with the two following paths :
*
* <pre>
* <code>base = "c:\\Users\\jdoe\\eclipse\\git\\project"</code>
@@ -480,9 +541,7 @@ public class FileUtils {
*
* This will return "..\\another_project\\pom.xml".
* </p>
- * <p>
- * This method uses {@link File#separator} to split the paths into segments.
- * </p>
+ *
* <p>
* <b>Note</b> that this will return the empty String if <code>base</code>
* and <code>other</code> are equal.
@@ -494,29 +553,32 @@ public class FileUtils {
* folder and not a file.
* @param other
* The path that will be made relative to <code>base</code>.
+ * @param dirSeparator
+ * A string that separates components of the path. In practice, this is "/" or "\\".
+ * @param caseSensitive
+ * Whether to consider differently-cased directory names as distinct
* @return A relative path that, when resolved against <code>base</code>,
* will yield the original <code>other</code>.
- * @since 3.7
+ * @since 4.8
*/
- public static String relativize(String base, String other) {
+ public static String relativizePath(String base, String other, String dirSeparator, boolean caseSensitive) {
if (base.equals(other))
return ""; //$NON-NLS-1$
- final boolean ignoreCase = !FS.DETECTED.isCaseSensitive();
- final String[] baseSegments = base.split(Pattern.quote(File.separator));
+ final String[] baseSegments = base.split(Pattern.quote(dirSeparator));
final String[] otherSegments = other.split(Pattern
- .quote(File.separator));
+ .quote(dirSeparator));
int commonPrefix = 0;
while (commonPrefix < baseSegments.length
&& commonPrefix < otherSegments.length) {
- if (ignoreCase
+ if (caseSensitive
&& baseSegments[commonPrefix]
- .equalsIgnoreCase(otherSegments[commonPrefix]))
+ .equals(otherSegments[commonPrefix]))
commonPrefix++;
- else if (!ignoreCase
+ else if (!caseSensitive
&& baseSegments[commonPrefix]
- .equals(otherSegments[commonPrefix]))
+ .equalsIgnoreCase(otherSegments[commonPrefix]))
commonPrefix++;
else
break;
@@ -524,11 +586,11 @@ public class FileUtils {
final StringBuilder builder = new StringBuilder();
for (int i = commonPrefix; i < baseSegments.length; i++)
- builder.append("..").append(File.separator); //$NON-NLS-1$
+ builder.append("..").append(dirSeparator); //$NON-NLS-1$
for (int i = commonPrefix; i < otherSegments.length; i++) {
builder.append(otherSegments[i]);
if (i < otherSegments.length - 1)
- builder.append(File.separator);
+ builder.append(dirSeparator);
}
return builder.toString();
}