diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java index b0da55a43..2da210d7e 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java @@ -51,20 +51,15 @@ import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.eclipse.jgit.awtui.AwtAuthenticator; import org.eclipse.jgit.awtui.AwtSshSessionFactory; import org.eclipse.jgit.errors.TransportException; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.FileRepository; +import org.eclipse.jgit.lib.RepositoryBuilder; import org.eclipse.jgit.pgm.opt.CmdLineParser; import org.eclipse.jgit.pgm.opt.SubcommandHandler; import org.eclipse.jgit.util.CachedAuthenticator; -import org.eclipse.jgit.util.SystemReader; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.ExampleMode; @@ -168,51 +163,17 @@ private void execute(final String[] argv) throws Exception { final TextBuiltin cmd = subcommand; if (cmd.requiresRepository()) { - if (gitdir == null) { - String gitDirEnv = SystemReader.getInstance().getenv(Constants.GIT_DIR_KEY); - if (gitDirEnv != null) - gitdir = new File(gitDirEnv); - } - if (gitdir == null) - gitdir = findGitDir(); - - File gitworktree; - String gitWorkTreeEnv = SystemReader.getInstance().getenv(Constants.GIT_WORK_TREE_KEY); - if (gitWorkTreeEnv != null) - gitworktree = new File(gitWorkTreeEnv); - else - gitworktree = null; - - File indexfile; - String indexFileEnv = SystemReader.getInstance().getenv(Constants.GIT_INDEX_KEY); - if (indexFileEnv != null) - indexfile = new File(indexFileEnv); - else - indexfile = null; - - File objectdir; - String objectDirEnv = SystemReader.getInstance().getenv(Constants.GIT_OBJECT_DIRECTORY_KEY); - if (objectDirEnv != null) - objectdir = new File(objectDirEnv); - else - objectdir = null; - - File[] altobjectdirs; - String altObjectDirEnv = SystemReader.getInstance().getenv(Constants.GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY); - if (altObjectDirEnv != null) { - String[] parserdAltObjectDirEnv = altObjectDirEnv.split(File.pathSeparator); - altobjectdirs = new File[parserdAltObjectDirEnv.length]; - for (int i = 0; i < parserdAltObjectDirEnv.length; i++) - altobjectdirs[i] = new File(parserdAltObjectDirEnv[i]); - } else - altobjectdirs = null; - - if (gitdir == null || !gitdir.isDirectory()) { + RepositoryBuilder frb = new RepositoryBuilder() // + .setGitDir(gitdir) // + .readEnvironment() // + .findGitDir(); + if (frb.getGitDir() == null) { writer.println(CLIText.get().cantFindGitDirectory); writer.flush(); System.exit(1); } - cmd.init(new FileRepository(gitdir, gitworktree, objectdir, altobjectdirs, indexfile), gitdir); + + cmd.init(frb.build(), null); } else { cmd.init(null, gitdir); } @@ -224,27 +185,6 @@ private void execute(final String[] argv) throws Exception { } } - private static File findGitDir() { - Set ceilingDirectories = new HashSet(); - String ceilingDirectoriesVar = SystemReader.getInstance().getenv( - Constants.GIT_CEILING_DIRECTORIES_KEY); - if (ceilingDirectoriesVar != null) { - ceilingDirectories.addAll(Arrays.asList(ceilingDirectoriesVar - .split(File.pathSeparator))); - } - File current = new File("").getAbsoluteFile(); - while (current != null) { - final File gitDir = new File(current, Constants.DOT_GIT); - if (gitDir.isDirectory()) - return gitDir; - current = current.getParentFile(); - if (current != null - && ceilingDirectories.contains(current.getPath())) - break; - } - return null; - } - private static boolean installConsole() { try { install("org.eclipse.jgit.console.ConsoleAuthenticator"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositorySetupWorkDirTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositorySetupWorkDirTest.java index 070713d7b..187d3ae9d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositorySetupWorkDirTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositorySetupWorkDirTest.java @@ -47,6 +47,7 @@ import java.io.File; import java.io.IOException; +import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; /** @@ -78,7 +79,7 @@ public void testWorkdirIsParentDir_CreateRepositoryFromDotGitGitDir() public void testNotBare_CreateRepositoryFromWorkDirOnly() throws Exception { File workdir = getFile("workdir", "repo"); - Repository repo = new FileRepository(null, workdir); + FileRepository repo = new FileRepositoryBuilder().setWorkTree(workdir).build(); assertFalse(repo.isBare()); assertWorkdirPath(repo, "workdir", "repo"); assertGitdirPath(repo, "workdir", "repo", Constants.DOT_GIT); @@ -87,7 +88,7 @@ public void testNotBare_CreateRepositoryFromWorkDirOnly() throws Exception { public void testWorkdirIsDotGit_CreateRepositoryFromWorkDirOnly() throws Exception { File workdir = getFile("workdir", "repo"); - Repository repo = new FileRepository(null, workdir); + FileRepository repo = new FileRepositoryBuilder().setWorkTree(workdir).build(); assertGitdirPath(repo, "workdir", "repo", Constants.DOT_GIT); } @@ -96,7 +97,7 @@ public void testNotBare_CreateRepositoryFromGitDirOnlyWithWorktreeConfig() File gitDir = getFile("workdir", "repoWithConfig"); File workTree = getFile("workdir", "treeRoot"); setWorkTree(gitDir, workTree); - Repository repo = new FileRepository(gitDir, null); + FileRepository repo = new FileRepositoryBuilder().setGitDir(gitDir).build(); assertFalse(repo.isBare()); assertWorkdirPath(repo, "workdir", "treeRoot"); assertGitdirPath(repo, "workdir", "repoWithConfig"); @@ -106,7 +107,7 @@ public void testBare_CreateRepositoryFromGitDirOnlyWithBareConfigTrue() throws Exception { File gitDir = getFile("workdir", "repoWithConfig"); setBare(gitDir, true); - Repository repo = new FileRepository(gitDir, null); + FileRepository repo = new FileRepositoryBuilder().setGitDir(gitDir).build(); assertTrue(repo.isBare()); } @@ -114,7 +115,7 @@ public void testWorkdirIsParent_CreateRepositoryFromGitDirOnlyWithBareConfigFals throws Exception { File gitDir = getFile("workdir", "repoWithBareConfigTrue", "child"); setBare(gitDir, false); - Repository repo = new FileRepository(gitDir, null); + FileRepository repo = new FileRepositoryBuilder().setGitDir(gitDir).build(); assertWorkdirPath(repo, "workdir", "repoWithBareConfigTrue"); } @@ -122,21 +123,12 @@ public void testNotBare_CreateRepositoryFromGitDirOnlyWithBareConfigFalse() throws Exception { File gitDir = getFile("workdir", "repoWithBareConfigFalse", "child"); setBare(gitDir, false); - Repository repo = new FileRepository(gitDir, null); + FileRepository repo = new FileRepositoryBuilder().setGitDir(gitDir).build(); assertFalse(repo.isBare()); assertWorkdirPath(repo, "workdir", "repoWithBareConfigFalse"); assertGitdirPath(repo, "workdir", "repoWithBareConfigFalse", "child"); } - public void testNotBare_MakeBareUnbareBySetWorkdir() throws Exception { - File gitDir = getFile("gitDir"); - Repository repo = new FileRepository(gitDir); - repo.setWorkDir(getFile("workingDir")); - assertFalse(repo.isBare()); - assertWorkdirPath(repo, "workingDir"); - assertGitdirPath(repo, "gitDir"); - } - public void testExceptionThrown_BareRepoGetWorkDir() throws Exception { File gitDir = getFile("workdir"); try { @@ -176,20 +168,28 @@ private File getFile(String... pathComponents) { return result; } - private void setBare(File gitDir, boolean bare) throws IOException { - FileRepository repo = new FileRepository(gitDir, null); - repo.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + private void setBare(File gitDir, boolean bare) throws IOException, + ConfigInvalidException { + FileBasedConfig cfg = configFor(gitDir); + cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_BARE, bare); - repo.getConfig().save(); + cfg.save(); } - private void setWorkTree(File gitDir, File workTree) throws IOException { - FileRepository repo = new FileRepository(gitDir, null); - repo.getConfig() - .setString(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_WORKTREE, - workTree.getAbsolutePath()); - repo.getConfig().save(); + private void setWorkTree(File gitDir, File workTree) throws IOException, + ConfigInvalidException { + String path = workTree.getAbsolutePath(); + FileBasedConfig cfg = configFor(gitDir); + cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_WORKTREE, path); + cfg.save(); + } + + private FileBasedConfig configFor(File gitDir) throws IOException, + ConfigInvalidException { + FileBasedConfig cfg = new FileBasedConfig(new File(gitDir, "config")); + cfg.load(); + return cfg; } private void assertGitdirPath(Repository repo, String... expected) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0003_Basic.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0003_Basic.java index c770d605d..8dd5ae2bd 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0003_Basic.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0003_Basic.java @@ -80,7 +80,7 @@ public void test001_Initalize() { public void test000_openRepoBadArgs() throws IOException { try { - new FileRepository(null, null); + new FileRepositoryBuilder().build(); fail("Must pass either GIT_DIR or GIT_WORK_TREE"); } catch (IllegalArgumentException e) { assertEquals( @@ -102,7 +102,7 @@ public void test000_openrepo_default_gitDirSet() throws IOException { repo1initial.close(); File theDir = new File(repo1Parent, Constants.DOT_GIT); - Repository r = new FileRepository(theDir, null); + FileRepository r = new FileRepositoryBuilder().setGitDir(theDir).build(); assertEqualsPath(theDir, r.getDirectory()); assertEqualsPath(repo1Parent, r.getWorkDir()); assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); @@ -122,7 +122,8 @@ public void test000_openrepo_default_gitDirAndWorkTreeSet() throws IOException { repo1initial.close(); File theDir = new File(repo1Parent, Constants.DOT_GIT); - Repository r = new FileRepository(theDir, repo1Parent.getParentFile()); + FileRepository r = new FileRepositoryBuilder().setGitDir(theDir) + .setWorkTree(repo1Parent.getParentFile()).build(); assertEqualsPath(theDir, r.getDirectory()); assertEqualsPath(repo1Parent.getParentFile(), r.getWorkDir()); assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); @@ -142,7 +143,7 @@ public void test000_openrepo_default_workDirSet() throws IOException { repo1initial.close(); File theDir = new File(repo1Parent, Constants.DOT_GIT); - Repository r = new FileRepository(null, repo1Parent); + FileRepository r = new FileRepositoryBuilder().setWorkTree(repo1Parent).build(); assertEqualsPath(theDir, r.getDirectory()); assertEqualsPath(repo1Parent, r.getWorkDir()); assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); @@ -167,7 +168,7 @@ public void test000_openrepo_default_absolute_workdirconfig() repo1initial.close(); File theDir = new File(repo1Parent, Constants.DOT_GIT); - Repository r = new FileRepository(theDir, null); + FileRepository r = new FileRepositoryBuilder().setGitDir(theDir).build(); assertEqualsPath(theDir, r.getDirectory()); assertEqualsPath(workdir, r.getWorkDir()); assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); @@ -192,7 +193,7 @@ public void test000_openrepo_default_relative_workdirconfig() repo1initial.close(); File theDir = new File(repo1Parent, Constants.DOT_GIT); - Repository r = new FileRepository(theDir, null); + FileRepository r = new FileRepositoryBuilder().setGitDir(theDir).build(); assertEqualsPath(theDir, r.getDirectory()); assertEqualsPath(workdir, r.getWorkDir()); assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); @@ -210,14 +211,17 @@ public void test000_openrepo_alternate_index_file_and_objdirs() File repo1Parent = new File(trash.getParentFile(), "r1"); File indexFile = new File(trash, "idx"); File objDir = new File(trash, "../obj"); - File[] altObjDirs = new File[] { db.getObjectsDirectory() }; + File altObjDir = db.getObjectsDirectory(); Repository repo1initial = new FileRepository(new File(repo1Parent, Constants.DOT_GIT)); repo1initial.create(); repo1initial.close(); File theDir = new File(repo1Parent, Constants.DOT_GIT); - Repository r = new FileRepository(theDir, null, objDir, altObjDirs, - indexFile); + FileRepository r = new FileRepositoryBuilder() // + .setGitDir(theDir).setObjectDirectory(objDir) // + .addAlternateObjectDirectory(altObjDir) // + .setIndexFile(indexFile) // + .build(); assertEqualsPath(theDir, r.getDirectory()); assertEqualsPath(theDir.getParentFile(), r.getWorkDir()); assertEqualsPath(indexFile, r.getIndexFile()); diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties index 91b67daf8..f6e4ea5b4 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties @@ -298,6 +298,7 @@ remoteDoesNotSupportSmartHTTPPush=remote does not support smart HTTP push remoteHungUpUnexpectedly=remote hung up unexpectedly remoteNameCantBeNull=Remote name can't be null. repositoryAlreadyExists=Repository already exists: {0} +repositoryConfigFileInvalid=Repository config file {0} invalid {1} repositoryNotFound=repository not found: {0} requiredHashFunctionNotAvailable=Required hash function {0} not available. resolvingDeltas=Resolving deltas diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java index 0c64b9edd..377e9c119 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java @@ -357,6 +357,7 @@ public static JGitText get() { /***/ public String remoteHungUpUnexpectedly; /***/ public String remoteNameCantBeNull; /***/ public String repositoryAlreadyExists; + /***/ public String repositoryConfigFileInvalid; /***/ public String repositoryNotFound; /***/ public String requiredHashFunctionNotAvailable; /***/ public String resolvingDeltas; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java new file mode 100644 index 000000000..f5dd7eec7 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java @@ -0,0 +1,613 @@ +package org.eclipse.jgit.lib; + +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BARE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WORKTREE; +import static org.eclipse.jgit.lib.Constants.DOT_GIT; +import static org.eclipse.jgit.lib.Constants.GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY; +import static org.eclipse.jgit.lib.Constants.GIT_CEILING_DIRECTORIES_KEY; +import static org.eclipse.jgit.lib.Constants.GIT_DIR_KEY; +import static org.eclipse.jgit.lib.Constants.GIT_INDEX_KEY; +import static org.eclipse.jgit.lib.Constants.GIT_OBJECT_DIRECTORY_KEY; +import static org.eclipse.jgit.lib.Constants.GIT_WORK_TREE_KEY; + +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.jgit.JGitText; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.lib.RepositoryCache.FileKey; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.SystemReader; + +/** + * Base builder to customize repository construction. + *

+ * Repository implementations may subclass this builder in order to add custom + * repository detection methods. + * + * @param + * type of the repository builder. + * @param + * type of the repository that is constructed. + * @see RepositoryBuilder + * @see FileRepositoryBuilder + */ +public class BaseRepositoryBuilder { + private FS fs; + + private File gitDir; + + private File objectDirectory; + + private List alternateObjectDirectories; + + private File indexFile; + + private File workTree; + + /** Directories limiting the search for a Git repository. */ + private List ceilingDirectories; + + /** True only if the caller wants to force bare behavior. */ + private boolean bare; + + /** Configuration file of target repository, lazily loaded if required. */ + private Config config; + + /** + * Set the file system abstraction needed by this repository. + * + * @param fs + * the abstraction. + * @return {@code this} (for chaining calls). + */ + public B setFS(FS fs) { + this.fs = fs; + return self(); + } + + /** @return the file system abstraction, or null if not set. */ + public FS getFS() { + return fs; + } + + /** + * Set the Git directory storing the repository metadata. + *

+ * The meta directory stores the objects, references, and meta files like + * {@code MERGE_HEAD}, or the index file. If {@code null} the path is + * assumed to be {@code workTree/.git}. + * + * @param gitDir + * {@code GIT_DIR}, the repository meta directory. + * @return {@code this} (for chaining calls). + */ + public B setGitDir(File gitDir) { + this.gitDir = gitDir; + this.config = null; + return self(); + } + + /** @return the meta data directory; null if not set. */ + public File getGitDir() { + return gitDir; + } + + /** + * Set the directory storing the repository's objects. + * + * @param objectDirectory + * {@code GIT_OBJECT_DIRECTORY}, the directory where the + * repository's object files are stored. + * @return {@code this} (for chaining calls). + */ + public B setObjectDirectory(File objectDirectory) { + this.objectDirectory = objectDirectory; + return self(); + } + + /** @return the object directory; null if not set. */ + public File getObjectDirectory() { + return objectDirectory; + } + + /** + * Add an alternate object directory to the search list. + *

+ * This setting handles one alternate directory at a time, and is provided + * to support {@code GIT_ALTERNATE_OBJECT_DIRECTORIES}. + * + * @param other + * another objects directory to search after the standard one. + * @return {@code this} (for chaining calls). + */ + public B addAlternateObjectDirectory(File other) { + if (other != null) { + if (alternateObjectDirectories == null) + alternateObjectDirectories = new LinkedList(); + alternateObjectDirectories.add(other); + } + return self(); + } + + /** + * Add alternate object directories to the search list. + *

+ * This setting handles several alternate directories at once, and is + * provided to support {@code GIT_ALTERNATE_OBJECT_DIRECTORIES}. + * + * @param inList + * other object directories to search after the standard one. The + * collection's contents is copied to an internal list. + * @return {@code this} (for chaining calls). + */ + public B addAlternateObjectDirectories(Collection inList) { + if (inList != null) { + for (File path : inList) + addAlternateObjectDirectory(path); + } + return self(); + } + + /** + * Add alternate object directories to the search list. + *

+ * This setting handles several alternate directories at once, and is + * provided to support {@code GIT_ALTERNATE_OBJECT_DIRECTORIES}. + * + * @param inList + * other object directories to search after the standard one. The + * array's contents is copied to an internal list. + * @return {@code this} (for chaining calls). + */ + public B addAlternateObjectDirectories(File[] inList) { + if (inList != null) { + for (File path : inList) + addAlternateObjectDirectory(path); + } + return self(); + } + + /** @return ordered array of alternate directories; null if non were set. */ + public File[] getAlternateObjectDirectories() { + final List alts = alternateObjectDirectories; + if (alts == null) + return null; + return alts.toArray(new File[alts.size()]); + } + + /** + * Force the repository to be treated as bare (have no working directory). + *

+ * If bare the working directory aspects of the repository won't be + * configured, and will not be accessible. + * + * @return {@code this} (for chaining calls). + */ + public B setBare() { + setIndexFile(null); + setWorkTree(null); + bare = true; + return self(); + } + + /** @return true if this repository was forced bare by {@link #setBare()}. */ + public boolean isBare() { + return bare; + } + + /** + * Set the top level directory of the working files. + * + * @param workTree + * {@code GIT_WORK_TREE}, the working directory of the checkout. + * @return {@code this} (for chaining calls). + */ + public B setWorkTree(File workTree) { + this.workTree = workTree; + return self(); + } + + /** @return the work tree directory, or null if not set. */ + public File getWorkTree() { + return workTree; + } + + /** + * Set the local index file that is caching checked out file status. + *

+ * The location of the index file tracking the status information for each + * checked out file in {@code workTree}. This may be null to assume the + * default {@code gitDiir/index}. + * + * @param indexFile + * {@code GIT_INDEX_FILE}, the index file location. + * @return {@code this} (for chaining calls). + */ + public B setIndexFile(File indexFile) { + this.indexFile = indexFile; + return self(); + } + + /** @return the index file location, or null if not set. */ + public File getIndexFile() { + return indexFile; + } + + /** + * Read standard Git environment variables and configure from those. + *

+ * This method tries to read the standard Git environment variables, such as + * {@code GIT_DIR} and {@code GIT_WORK_TREE} to configure this builder + * instance. If an environment variable is set, it overrides the value + * already set in this builder. + * + * @return {@code this} (for chaining calls). + */ + public B readEnvironment() { + return readEnvironment(SystemReader.getInstance()); + } + + /** + * Read standard Git environment variables and configure from those. + *

+ * This method tries to read the standard Git environment variables, such as + * {@code GIT_DIR} and {@code GIT_WORK_TREE} to configure this builder + * instance. If a property is already set in the builder, the environment + * variable is not used. + * + * @param sr + * the SystemReader abstraction to access the environment. + * @return {@code this} (for chaining calls). + */ + public B readEnvironment(SystemReader sr) { + if (getGitDir() == null) { + String val = sr.getenv(GIT_DIR_KEY); + if (val != null) + setGitDir(new File(val)); + } + + if (getObjectDirectory() == null) { + String val = sr.getenv(GIT_OBJECT_DIRECTORY_KEY); + if (val != null) + setObjectDirectory(new File(val)); + } + + if (getAlternateObjectDirectories() == null) { + String val = sr.getenv(GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY); + if (val != null) { + for (String path : val.split(File.pathSeparator)) + addAlternateObjectDirectory(new File(path)); + } + } + + if (getWorkTree() == null) { + String val = sr.getenv(GIT_WORK_TREE_KEY); + if (val != null) + setWorkTree(new File(val)); + } + + if (getIndexFile() == null) { + String val = sr.getenv(GIT_INDEX_KEY); + if (val != null) + setIndexFile(new File(val)); + } + + if (ceilingDirectories == null) { + String val = sr.getenv(GIT_CEILING_DIRECTORIES_KEY); + if (val != null) { + for (String path : val.split(File.pathSeparator)) + addCeilingDirectory(new File(path)); + } + } + + return self(); + } + + /** + * Add a ceiling directory to the search limit list. + *

+ * This setting handles one ceiling directory at a time, and is provided to + * support {@code GIT_CEILING_DIRECTORIES}. + * + * @param root + * a path to stop searching at; its parent will not be searched. + * @return {@code this} (for chaining calls). + */ + public B addCeilingDirectory(File root) { + if (root != null) { + if (ceilingDirectories == null) + ceilingDirectories = new LinkedList(); + ceilingDirectories.add(root); + } + return self(); + } + + /** + * Add ceiling directories to the search list. + *

+ * This setting handles several ceiling directories at once, and is provided + * to support {@code GIT_CEILING_DIRECTORIES}. + * + * @param inList + * directory paths to stop searching at. The collection's + * contents is copied to an internal list. + * @return {@code this} (for chaining calls). + */ + public B addCeilingDirectories(Collection inList) { + if (inList != null) { + for (File path : inList) + addCeilingDirectory(path); + } + return self(); + } + + /** + * Add ceiling directories to the search list. + *

+ * This setting handles several ceiling directories at once, and is provided + * to support {@code GIT_CEILING_DIRECTORIES}. + * + * @param inList + * directory paths to stop searching at. The array's contents is + * copied to an internal list. + * @return {@code this} (for chaining calls). + */ + public B addCeilingDirectories(File[] inList) { + if (inList != null) { + for (File path : inList) + addCeilingDirectory(path); + } + return self(); + } + + /** + * Configure {@code GIT_DIR} by searching up the file system. + *

+ * Starts from the current working directory of the JVM and scans up through + * the directory tree until a Git repository is found. Success can be + * determined by checking for {@code getGitDir() != null}. + *

+ * The search can be limited to specific spaces of the local filesystem by + * {@link #addCeilingDirectory(File)}, or inheriting the list through a + * prior call to {@link #readEnvironment()}. + * + * @return {@code this} (for chaining calls). + */ + public B findGitDir() { + if (getGitDir() == null) + findGitDir(new File("").getAbsoluteFile()); + return self(); + } + + /** + * Configure {@code GIT_DIR} by searching up the file system. + *

+ * Starts from the supplied directory path and scans up through the parent + * directory tree until a Git repository is found. Success can be determined + * by checking for {@code getGitDir() != null}. + *

+ * The search can be limited to specific spaces of the local filesystem by + * {@link #addCeilingDirectory(File)}, or inheriting the list through a + * prior call to {@link #readEnvironment()}. + * + * @param current + * directory to begin searching in. + * @return {@code this} (for chaining calls). + */ + public B findGitDir(File current) { + if (getGitDir() == null) { + FS tryFS = safeFS(); + while (current != null) { + File dir = new File(current, DOT_GIT); + if (FileKey.isGitRepository(dir, tryFS)) { + setGitDir(dir); + break; + } + + current = current.getParentFile(); + if (current != null && ceilingDirectories.contains(current)) + break; + } + } + return self(); + } + + /** + * Guess and populate all parameters not already defined. + *

+ * If an option was not set, the setup method will try to default the option + * based on other options. If insufficient information is available, an + * exception is thrown to the caller. + * + * @return {@code this} + * @throws IllegalArgumentException + * insufficient parameters were set, or some parameters are + * incompatible with one another. + * @throws IOException + * the repository could not be accessed to configure the rest of + * the builder's parameters. + */ + public B setup() throws IllegalArgumentException, IOException { + requireGitDirOrWorkTree(); + setupGitDir(); + setupWorkTree(); + setupInternals(); + return self(); + } + + /** + * Create a repository matching the configuration in this builder. + *

+ * If an option was not set, the build method will try to default the option + * based on other options. If insufficient information is available, an + * exception is thrown to the caller. + * + * @return a repository matching this configuration. + * @throws IllegalArgumentException + * insufficient parameters were set. + * @throws IOException + * the repository could not be accessed to configure the rest of + * the builder's parameters. + */ + @SuppressWarnings("unchecked") + public R build() throws IOException { + return (R) new FileRepository(setup()); + } + + /** Require either {@code gitDir} or {@code workTree} to be set. */ + protected void requireGitDirOrWorkTree() { + if (getGitDir() == null && getWorkTree() == null) + throw new IllegalArgumentException( + JGitText.get().eitherGIT_DIRorGIT_WORK_TREEmustBePassed); + } + + /** + * Perform standard gitDir initialization. + * + * @throws IOException + * the repository could not be accessed + */ + protected void setupGitDir() throws IOException { + // No gitDir? Try to assume its under the workTree. + // + if (getGitDir() == null && getWorkTree() != null) + setGitDir(new File(getWorkTree(), DOT_GIT)); + } + + /** + * Perform standard work-tree initialization. + *

+ * This is a method typically invoked inside of {@link #setup()}, near the + * end after the repository has been identified and its configuration is + * available for inspection. + * + * @throws IOException + * the repository configuration could not be read. + */ + protected void setupWorkTree() throws IOException { + if (getFS() == null) + setFS(FS.DETECTED); + + // If we aren't bare, we should have a work tree. + // + if (!isBare() && getWorkTree() == null) + setWorkTree(guessWorkTreeOrFail()); + + if (!isBare()) { + // If after guessing we're still not bare, we must have + // a metadata directory to hold the repository. Assume + // its at the work tree. + // + if (getGitDir() == null) + setGitDir(getWorkTree().getParentFile()); + if (getIndexFile() == null) + setIndexFile(new File(getGitDir(), "index")); + } + } + + /** + * Configure the internal implementation details of the repository. + * + * @throws IOException + * the repository could not be accessed + */ + protected void setupInternals() throws IOException { + if (getObjectDirectory() == null && getGitDir() != null) + setObjectDirectory(safeFS().resolve(getGitDir(), "objects")); + } + + /** + * Get the cached repository configuration, loading if not yet available. + * + * @return the configuration of the repository. + * @throws IOException + * the configuration is not available, or is badly formed. + */ + protected Config getConfig() throws IOException { + if (config == null) + config = loadConfig(); + return config; + } + + /** + * Parse and load the repository specific configuration. + *

+ * The default implementation reads {@code gitDir/config}, or returns an + * empty configuration if gitDir was not set. + * + * @return the repository's configuration. + * @throws IOException + * the configuration is not available. + */ + protected Config loadConfig() throws IOException { + if (getGitDir() != null) { + // We only want the repository's configuration file, and not + // the user file, as these parameters must be unique to this + // repository and not inherited from other files. + // + File path = safeFS().resolve(getGitDir(), "config"); + FileBasedConfig cfg = new FileBasedConfig(path); + try { + cfg.load(); + } catch (ConfigInvalidException err) { + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().repositoryConfigFileInvalid, path + .getAbsolutePath(), err.getMessage())); + } + return cfg; + } else { + return new Config(); + } + } + + private File guessWorkTreeOrFail() throws IOException { + final Config cfg = getConfig(); + + // If set, core.worktree wins. + // + String path = cfg.getString(CONFIG_CORE_SECTION, null, + CONFIG_KEY_WORKTREE); + if (path != null) + return safeFS().resolve(getGitDir(), path); + + // If core.bare is set, honor its value. Assume workTree is + // the parent directory of the repository. + // + if (cfg.getString(CONFIG_CORE_SECTION, null, CONFIG_KEY_BARE) != null) { + if (cfg.getBoolean(CONFIG_CORE_SECTION, CONFIG_KEY_BARE, true)) { + setBare(); + return null; + } + return getGitDir().getParentFile(); + } + + if (getGitDir().getName().equals(DOT_GIT)) { + // No value for the "bare" flag, but gitDir is named ".git", + // use the parent of the directory + // + return getGitDir().getParentFile(); + } + + // We have to assume we are bare. + // + setBare(); + return null; + } + + /** @return the configured FS, or {@link FS#DETECTED}. */ + protected FS safeFS() { + return getFS() != null ? getFS() : FS.DETECTED; + } + + /** @return {@code this} */ + @SuppressWarnings("unchecked") + protected final B self() { + return (B) this; + } +} \ No newline at end of file diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileRepository.java index 86ae5fada..f45ffdf14 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileRepository.java @@ -56,7 +56,6 @@ import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.FileObjectDatabase.AlternateHandle; import org.eclipse.jgit.lib.FileObjectDatabase.AlternateRepository; -import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.SystemReader; /** @@ -95,176 +94,41 @@ public class FileRepository extends Repository { /** * Construct a representation of a Git repository. - * + *

* The work tree, object directory, alternate object directories and index * file locations are deduced from the given git directory and the default - * rules. + * rules by running {@link FileRepositoryBuilder}. This constructor is the + * same as saying: * - * @param d + *

+	 * new FileRepositoryBuilder().setGitDir(gitDir).build()
+	 * 
+ * + * @param gitDir * GIT_DIR (the location of the repository metadata). * @throws IOException * the repository appears to already exist but cannot be * accessed. + * @see FileRepositoryBuilder */ - public FileRepository(final File d) throws IOException { - this(d, null, null, null, null); // go figure it out + public FileRepository(final File gitDir) throws IOException { + this(new FileRepositoryBuilder().setGitDir(gitDir).setup()); } - /** - * Construct a representation of a Git repository. - * - * The work tree, object directory, alternate object directories and index - * file locations are deduced from the given git directory and the default - * rules. - * - * @param d - * GIT_DIR (the location of the repository metadata). May be - * null work workTree is set - * @param workTree - * GIT_WORK_TREE (the root of the checkout). May be null for - * default value. - * @throws IOException - * the repository appears to already exist but cannot be - * accessed. - */ - public FileRepository(final File d, final File workTree) throws IOException { - this(d, workTree, null, null, null); // go figure it out - } + FileRepository(final BaseRepositoryBuilder options) throws IOException { + super(options); - /** - * Construct a representation of a Git repository using the given parameters - * possibly overriding default conventions. - * - * @param d - * GIT_DIR (the location of the repository metadata). May be null - * for default value in which case it depends on GIT_WORK_TREE. - * @param workTree - * GIT_WORK_TREE (the root of the checkout). May be null for - * default value if GIT_DIR is provided. - * @param objectDir - * GIT_OBJECT_DIRECTORY (where objects and are stored). May be - * null for default value. Relative names ares resolved against - * GIT_WORK_TREE. - * @param alternateObjectDir - * GIT_ALTERNATE_OBJECT_DIRECTORIES (where more objects are read - * from). May be null for default value. Relative names ares - * resolved against GIT_WORK_TREE. - * @param indexFile - * GIT_INDEX_FILE (the location of the index file). May be null - * for default value. Relative names ares resolved against - * GIT_WORK_TREE. - * @throws IOException - * the repository appears to already exist but cannot be - * accessed. - */ - public FileRepository(final File d, final File workTree, final File objectDir, - final File[] alternateObjectDir, final File indexFile) throws IOException { - this(d, workTree, objectDir, alternateObjectDir, indexFile, FS.DETECTED); - } - - /** - * Construct a representation of a Git repository using the given parameters - * possibly overriding default conventions. - * - * @param d - * GIT_DIR (the location of the repository metadata). May be null - * for default value in which case it depends on GIT_WORK_TREE. - * @param workTree - * GIT_WORK_TREE (the root of the checkout). May be null for - * default value if GIT_DIR is provided. - * @param objectDir - * GIT_OBJECT_DIRECTORY (where objects and are stored). May be - * null for default value. Relative names ares resolved against - * GIT_WORK_TREE. - * @param alternateObjectDir - * GIT_ALTERNATE_OBJECT_DIRECTORIES (where more objects are read - * from). May be null for default value. Relative names ares - * resolved against GIT_WORK_TREE. - * @param indexFile - * GIT_INDEX_FILE (the location of the index file). May be null - * for default value. Relative names ares resolved against - * GIT_WORK_TREE. - * @param fs - * the file system abstraction which will be necessary to - * perform certain file system operations. - * @throws IOException - * the repository appears to already exist but cannot be - * accessed. - */ - public FileRepository(final File d, final File workTree, final File objectDir, - final File[] alternateObjectDir, final File indexFile, FS fs) - throws IOException { - - if (workTree != null) { - workDir = workTree; - if (d == null) - gitDir = new File(workTree, Constants.DOT_GIT); - else - gitDir = d; - } else { - if (d != null) - gitDir = d; - else - throw new IllegalArgumentException( - JGitText.get().eitherGIT_DIRorGIT_WORK_TREEmustBePassed); - } - - this.fs = fs; - - userConfig = SystemReader.getInstance().openUserConfig(fs); - repoConfig = new FileBasedConfig(userConfig, fs.resolve(gitDir, "config")); + userConfig = SystemReader.getInstance().openUserConfig(getFS()); + repoConfig = new FileBasedConfig(userConfig, getFS().resolve(getDirectory(), "config")); loadUserConfig(); loadRepoConfig(); - if (workDir == null) { - // if the working directory was not provided explicitly, - // we need to decide if this is a "bare" repository or not - // first, we check the working tree configuration - String workTreeConfig = getConfig().getString( - ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_WORKTREE); - if (workTreeConfig != null) { - // the working tree configuration wins - workDir = fs.resolve(d, workTreeConfig); - } else if (getConfig().getString( - ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_BARE) != null) { - // we have asserted that a value for the "bare" flag was set - if (!getConfig().getBoolean(ConfigConstants.CONFIG_CORE_SECTION, - ConfigConstants.CONFIG_KEY_BARE, true)) - // the "bare" flag is false -> use the parent of the - // meta data directory - workDir = gitDir.getParentFile(); - else - // the "bare" flag is true - workDir = null; - } else if (Constants.DOT_GIT.equals(gitDir.getName())) { - // no value for the "bare" flag, but the meta data directory - // is named ".git" -> use the parent of the meta data directory - workDir = gitDir.getParentFile(); - } else { - workDir = null; - } - } - refs = new RefDirectory(this); - if (objectDir != null) { - objectDatabase = new ObjectDirectory(repoConfig, // - fs.resolve(objectDir, ""), // - alternateObjectDir, // - fs); - } else { - objectDatabase = new ObjectDirectory(repoConfig, // - fs.resolve(gitDir, "objects"), // - alternateObjectDir, // - fs); - } - - if (indexFile != null) - this.indexFile = indexFile; - else - this.indexFile = new File(gitDir, "index"); + objectDatabase = new ObjectDirectory(repoConfig, // + options.getObjectDirectory(), // + options.getAlternateObjectDirectories(), // + getFS()); if (objectDatabase.exists()) { final String repositoryFormatVersion = getConfig().getString( @@ -314,13 +178,13 @@ public void create(boolean bare) throws IOException { final FileBasedConfig cfg = getConfig(); if (cfg.getFile().exists()) { throw new IllegalStateException(MessageFormat.format( - JGitText.get().repositoryAlreadyExists, gitDir)); + JGitText.get().repositoryAlreadyExists, getDirectory())); } - gitDir.mkdirs(); + getDirectory().mkdirs(); refs.create(); objectDatabase.create(); - new File(gitDir, "branches").mkdir(); + new File(getDirectory(), "branches").mkdir(); RefUpdate head = updateRef(Constants.HEAD); head.disableRefLog(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileRepositoryBuilder.java new file mode 100644 index 000000000..c0220d979 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileRepositoryBuilder.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010, 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.lib; + +import java.io.File; +import java.io.IOException; + +/** + * Constructs a {@link FileRepository}. + *

+ * Applications must set one of {@link #setGitDir(File)} or + * {@link #setWorkTree(File)}, or use {@link #readEnvironment()} or + * {@link #findGitDir()} in order to configure the minimum property set + * necessary to open a repository. + *

+ * Single repository applications trying to be compatible with other Git + * implementations are encouraged to use a model such as: + * + *

+ * new FileRepositoryBuilder() //
+ * 		.setGitDir(gitDirArgument) // --git-dir if supplied, no-op if null
+ * 		.readEnviroment() // scan environment GIT_* variables
+ * 		.findGitDir() // scan up the file system tree
+ * 		.build()
+ * 
+ */ +public class FileRepositoryBuilder extends + BaseRepositoryBuilder { + /** + * Create a repository matching the configuration in this builder. + *

+ * If an option was not set, the build method will try to default the option + * based on other options. If insufficient information is available, an + * exception is thrown to the caller. + * + * @return a repository matching this configuration. + * @throws IllegalArgumentException + * insufficient parameters were set. + * @throws IOException + * the repository could not be accessed to configure the rest of + * the builder's parameters. + */ + @Override + public FileRepository build() throws IOException { + return new FileRepository(setup()); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index 09411a453..939d923a7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -85,10 +85,10 @@ public abstract class Repository { private final AtomicInteger useCnt = new AtomicInteger(1); /** Metadata directory holding the repository's critical files. */ - protected File gitDir; + private final File gitDir; /** File abstraction used to resolve paths. */ - protected FS fs; + private final FS fs; private GitIndex index; @@ -96,14 +96,22 @@ public abstract class Repository { static private final List allListeners = new Vector(); // thread safe /** If not bare, the top level directory of the working files. */ - protected File workDir; + private final File workDir; /** If not bare, the index file caching the working file states. */ - protected File indexFile; + private final File indexFile; - /** Initialize a new repository instance. */ - protected Repository() { - // Empty constructor, defined protected to require subclassing. + /** + * Initialize a new repository instance. + * + * @param options + * options to configure the repository. + */ + protected Repository(final BaseRepositoryBuilder options) { + gitDir = options.getGitDir(); + fs = options.getFS(); + workDir = options.getWorkTree(); + indexFile = options.getIndexFile(); } /** @@ -1018,16 +1026,6 @@ public File getWorkDir() throws IllegalStateException { return workDir; } - /** - * Override default workdir - * - * @param workTree - * the work tree directory - */ - public void setWorkDir(File workTree) { - this.workDir = workTree; - } - /** * Register a {@link RepositoryListener} which will be notified * when ref changes are detected. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilder.java new file mode 100644 index 000000000..4b0e1f690 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilder.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010, 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.lib; + +import java.io.File; + +/** + * Base class to support constructing a {@link Repository}. + *

+ * Applications must set one of {@link #setGitDir(File)} or + * {@link #setWorkTree(File)}, or use {@link #readEnvironment()} or + * {@link #findGitDir()} in order to configure the minimum property set + * necessary to open a repository. + *

+ * Single repository applications trying to be compatible with other Git + * implementations are encouraged to use a model such as: + * + *

+ * new RepositoryBuilder() //
+ * 		.setGitDir(gitDirArgument) // --git-dir if supplied, no-op if null
+ * 		.readEnviroment() // scan environment GIT_* variables
+ * 		.findGitDir() // scan up the file system tree
+ * 		.build()
+ * 
+ * + * @see FileRepositoryBuilder + */ +public class RepositoryBuilder extends + BaseRepositoryBuilder { + // Empty implementation, everything is inherited. +}