summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.pgm
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.pgm')
-rw-r--r--org.eclipse.jgit.pgm/BUCK70
-rw-r--r--org.eclipse.jgit.pgm/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin1
-rw-r--r--org.eclipse.jgit.pgm/pom.xml11
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties8
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java130
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java7
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java21
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java15
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java131
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java9
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java3
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java2
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java10
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java8
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java6
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java83
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java145
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java15
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java163
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java52
21 files changed, 778 insertions, 114 deletions
diff --git a/org.eclipse.jgit.pgm/BUCK b/org.eclipse.jgit.pgm/BUCK
new file mode 100644
index 0000000000..edcf2fc28f
--- /dev/null
+++ b/org.eclipse.jgit.pgm/BUCK
@@ -0,0 +1,70 @@
+include_defs('//tools/git.defs')
+
+java_library(
+ name = 'pgm',
+ srcs = glob(['src/**']),
+ resources = glob(['resources/**']),
+ deps = [
+ ':services',
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.archive:jgit-archive',
+ '//org.eclipse.jgit.http.apache:http-apache',
+ '//org.eclipse.jgit.ui:ui',
+ '//lib:args4j',
+ ],
+ visibility = ['PUBLIC'],
+)
+
+prebuilt_jar(
+ name = 'services',
+ binary_jar = ':services__jar',
+)
+
+genrule(
+ name = 'services__jar',
+ cmd = 'cd $SRCDIR ; zip -qr $OUT .',
+ srcs = glob(['META-INF/services/*']),
+ out = 'services.jar',
+)
+
+genrule(
+ name = 'jgit',
+ cmd = ''.join([
+ 'mkdir $TMP/META-INF &&',
+ 'cp $(location :binary_manifest) $TMP/META-INF/MANIFEST.MF &&',
+ 'cp $(location :jgit_jar) $TMP/jgit.jar &&',
+ 'cd $TMP && zip $TMP/jgit.jar META-INF/MANIFEST.MF &&',
+ 'cat $SRCDIR/jgit.sh $TMP/jgit.jar >$OUT &&',
+ 'chmod a+x $OUT',
+ ]),
+ srcs = ['jgit.sh'],
+ out = 'jgit',
+ visibility = ['PUBLIC'],
+)
+
+java_binary(
+ name = 'jgit_jar',
+ deps = [
+ ':pgm',
+ '//lib:slf4j-simple',
+ '//lib:tukaani-xz',
+ ],
+ blacklist = [
+ 'META-INF/DEPENDENCIES',
+ 'META-INF/maven/.*',
+ ],
+)
+
+genrule(
+ name = 'binary_manifest',
+ cmd = ';'.join(['echo "%s: %s" >>$OUT' % e for e in [
+ ('Manifest-Version', '1.0'),
+ ('Main-Class', 'org.eclipse.jgit.pgm.Main'),
+ ('Bundle-Version', git_version()),
+ ('Implementation-Title', 'JGit Command Line Interface'),
+ ('Implementation-Vendor', 'Eclipse.org - JGit'),
+ ('Implementation-Vendor-URL', 'http://www.eclipse.org/jgit/'),
+ ('Implementation-Vendor-Id', 'org.eclipse.jgit'),
+ ]] + ['echo >>$OUT']),
+ out = 'MANIFEST.MF',
+)
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index 567fd05750..9dc6aea16f 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -21,6 +21,7 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)",
org.eclipse.jgit.gitrepo;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.2.0,4.3.0)",
org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
org.eclipse.jgit.merge;version="4.2.0",
org.eclipse.jgit.nls;version="[4.2.0,4.3.0)",
@@ -31,6 +32,7 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)",
org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)",
org.eclipse.jgit.storage.pack;version="[4.2.0,4.3.0)",
org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.2.0,4.3.0)",
org.eclipse.jgit.transport.resolver;version="[4.2.0,4.3.0)",
org.eclipse.jgit.treewalk;version="[4.2.0,4.3.0)",
org.eclipse.jgit.treewalk.filter;version="[4.2.0,4.3.0)",
diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
index c13f63e80f..6aa20041b5 100644
--- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
+++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -41,6 +41,7 @@ org.eclipse.jgit.pgm.debug.DiffAlgorithms
org.eclipse.jgit.pgm.debug.MakeCacheTree
org.eclipse.jgit.pgm.debug.ReadDirCache
org.eclipse.jgit.pgm.debug.RebuildCommitGraph
+org.eclipse.jgit.pgm.debug.RebuildRefTree
org.eclipse.jgit.pgm.debug.ShowCacheTree
org.eclipse.jgit.pgm.debug.ShowCommands
org.eclipse.jgit.pgm.debug.ShowDirCache
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index ca2ead2925..2642491321 100644
--- a/org.eclipse.jgit.pgm/pom.xml
+++ b/org.eclipse.jgit.pgm/pom.xml
@@ -95,6 +95,17 @@
</dependency>
<dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit.http.apache</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-version}</version>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index 335336da28..b4b1261b37 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -20,6 +20,7 @@ branchAlreadyExists=A branch named ''{0}'' already exists.
branchCreatedFrom=branch: Created from {0}
branchDetachedHEAD=detached HEAD
branchIsNotAnAncestorOfYourCurrentHEAD=The branch ''{0}'' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run ''jgit branch -D {0}''.
+branchNameRequired=branch name required
branchNotFound=branch ''{0}'' not found.
cacheTreePathInfo="{0}": {1} entries, {2} children
cannotBeRenamed={0} cannot be renamed
@@ -89,7 +90,9 @@ metaVar_author=AUTHOR
metaVar_base=base
metaVar_blameL=START,END
metaVar_blameReverse=START..END
+metaVar_branchAndStartPoint=branch [start-name]
metaVar_branchName=branch
+metaVar_branchNames=branch ...
metaVar_bucket=BUCKET
metaVar_command=command
metaVar_commandDetail=DETAIL
@@ -109,6 +112,7 @@ metaVar_message=message
metaVar_n=n
metaVar_name=name
metaVar_object=object
+metaVar_oldNewBranchNames=[oldbranch] newbranch
metaVar_op=OP
metaVar_pass=PASS
metaVar_path=path
@@ -125,6 +129,7 @@ metaVar_treeish=tree-ish
metaVar_uriish=uri-ish
metaVar_url=URL
metaVar_user=USER
+metaVar_values=value ...
metaVar_version=VERSION
mostCommonlyUsedCommandsAre=The most commonly used commands are:
needApprovalToDestroyCurrentRepository=Need approval to destroy current repository
@@ -223,6 +228,7 @@ usage_MergeBase=Find as good common ancestors as possible for a merge
usage_MergesTwoDevelopmentHistories=Merges two development histories
usage_ReadDirCache= Read the DirCache 100 times
usage_RebuildCommitGraph=Recreate a repository from another one's commit graph
+usage_RebuildRefTree=Copy references into a RefTree
usage_Remote=Manage set of tracked repositories
usage_RepositoryToReadFrom=Repository to read from
usage_RepositoryToReceiveInto=Repository to receive into
@@ -337,6 +343,7 @@ usage_recordChangesToRepository=Record changes to the repository
usage_recurseIntoSubtrees=recurse into subtrees
usage_renameLimit=limit size of rename matrix
usage_reset=Reset current HEAD to the specified state
+usage_resetReference=Reset to given reference name
usage_resetHard=Resets the index and working tree
usage_resetSoft=Resets without touching the index file nor the working tree
usage_resetMixed=Resets the index but not the working tree
@@ -353,6 +360,7 @@ usage_tags=fetch all tags
usage_notags=do not fetch tags
usage_tagMessage=tag message
usage_untrackedFilesMode=show untracked files
+usage_updateRef=reference to update
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream
usage_checkoutBranchAfterClone=checkout named branch instead of remotes's HEAD
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
index 65aa24f356..045f3571e5 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
@@ -45,7 +45,6 @@ package org.eclipse.jgit.pgm;
import java.io.IOException;
import java.text.MessageFormat;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
@@ -65,15 +64,18 @@ import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText;
-import org.eclipse.jgit.pgm.opt.CmdLineParser;
+import org.eclipse.jgit.pgm.opt.OptionWithValuesListHandler;
import org.eclipse.jgit.revwalk.RevWalk;
import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.ExampleMode;
import org.kohsuke.args4j.Option;
@Command(common = true, usage = "usage_listCreateOrDeleteBranches")
class Branch extends TextBuiltin {
+ private String otherBranch;
+ private boolean createForce;
+ private boolean rename;
+
@Option(name = "--remote", aliases = { "-r" }, usage = "usage_actOnRemoteTrackingBranches")
private boolean remote = false;
@@ -83,23 +85,69 @@ class Branch extends TextBuiltin {
@Option(name = "--contains", metaVar = "metaVar_commitish", usage = "usage_printOnlyBranchesThatContainTheCommit")
private String containsCommitish;
- @Option(name = "--delete", aliases = { "-d" }, usage = "usage_deleteFullyMergedBranch")
- private boolean delete = false;
+ private List<String> delete;
- @Option(name = "--delete-force", aliases = { "-D" }, usage = "usage_deleteBranchEvenIfNotMerged")
- private boolean deleteForce = false;
+ @Option(name = "--delete", aliases = {
+ "-d" }, metaVar = "metaVar_branchNames", usage = "usage_deleteFullyMergedBranch", handler = OptionWithValuesListHandler.class)
+ public void delete(List<String> names) {
+ if (names.isEmpty()) {
+ throw die(CLIText.get().branchNameRequired);
+ }
+ delete = names;
+ }
- @Option(name = "--create-force", aliases = { "-f" }, usage = "usage_forceCreateBranchEvenExists")
- private boolean createForce = false;
+ private List<String> deleteForce;
- @Option(name = "-m", usage = "usage_moveRenameABranch")
- private boolean rename = false;
+ @Option(name = "--delete-force", aliases = {
+ "-D" }, metaVar = "metaVar_branchNames", usage = "usage_deleteBranchEvenIfNotMerged", handler = OptionWithValuesListHandler.class)
+ public void deleteForce(List<String> names) {
+ if (names.isEmpty()) {
+ throw die(CLIText.get().branchNameRequired);
+ }
+ deleteForce = names;
+ }
+
+ @Option(name = "--create-force", aliases = {
+ "-f" }, metaVar = "metaVar_branchAndStartPoint", usage = "usage_forceCreateBranchEvenExists", handler = OptionWithValuesListHandler.class)
+ public void createForce(List<String> branchAndStartPoint) {
+ createForce = true;
+ if (branchAndStartPoint.isEmpty()) {
+ throw die(CLIText.get().branchNameRequired);
+ }
+ if (branchAndStartPoint.size() > 2) {
+ throw die(CLIText.get().tooManyRefsGiven);
+ }
+ if (branchAndStartPoint.size() == 1) {
+ branch = branchAndStartPoint.get(0);
+ } else {
+ branch = branchAndStartPoint.get(0);
+ otherBranch = branchAndStartPoint.get(1);
+ }
+ }
+
+ @Option(name = "--move", aliases = {
+ "-m" }, metaVar = "metaVar_oldNewBranchNames", usage = "usage_moveRenameABranch", handler = OptionWithValuesListHandler.class)
+ public void moveRename(List<String> currentAndNew) {
+ rename = true;
+ if (currentAndNew.isEmpty()) {
+ throw die(CLIText.get().branchNameRequired);
+ }
+ if (currentAndNew.size() > 2) {
+ throw die(CLIText.get().tooManyRefsGiven);
+ }
+ if (currentAndNew.size() == 1) {
+ branch = currentAndNew.get(0);
+ } else {
+ branch = currentAndNew.get(0);
+ otherBranch = currentAndNew.get(1);
+ }
+ }
@Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beVerbose")
private boolean verbose = false;
- @Argument
- private List<String> branches = new ArrayList<String>();
+ @Argument(metaVar = "metaVar_name")
+ private String branch;
private final Map<String, Ref> printRefs = new LinkedHashMap<String, Ref>();
@@ -110,30 +158,33 @@ class Branch extends TextBuiltin {
@Override
protected void run() throws Exception {
- if (delete || deleteForce)
- delete(deleteForce);
- else {
- if (branches.size() > 2)
- throw die(CLIText.get().tooManyRefsGiven + new CmdLineParser(this).printExample(ExampleMode.ALL));
-
+ if (delete != null || deleteForce != null) {
+ if (delete != null) {
+ delete(delete, false);
+ }
+ if (deleteForce != null) {
+ delete(deleteForce, true);
+ }
+ } else {
if (rename) {
String src, dst;
- if (branches.size() == 1) {
+ if (otherBranch == null) {
final Ref head = db.getRef(Constants.HEAD);
- if (head != null && head.isSymbolic())
+ if (head != null && head.isSymbolic()) {
src = head.getLeaf().getName();
- else
+ } else {
throw die(CLIText.get().cannotRenameDetachedHEAD);
- dst = branches.get(0);
+ }
+ dst = branch;
} else {
- src = branches.get(0);
+ src = branch;
final Ref old = db.getRef(src);
if (old == null)
throw die(MessageFormat.format(CLIText.get().doesNotExist, src));
if (!old.getName().startsWith(Constants.R_HEADS))
throw die(MessageFormat.format(CLIText.get().notABranch, src));
src = old.getName();
- dst = branches.get(1);
+ dst = otherBranch;
}
if (!dst.startsWith(Constants.R_HEADS))
@@ -145,13 +196,14 @@ class Branch extends TextBuiltin {
if (r.rename() != Result.RENAMED)
throw die(MessageFormat.format(CLIText.get().cannotBeRenamed, src));
- } else if (branches.size() > 0) {
- String newHead = branches.get(0);
+ } else if (createForce || branch != null) {
+ String newHead = branch;
String startBranch;
- if (branches.size() == 2)
- startBranch = branches.get(1);
- else
+ if (createForce) {
+ startBranch = otherBranch;
+ } else {
startBranch = Constants.HEAD;
+ }
Ref startRef = db.getRef(startBranch);
ObjectId startAt = db.resolve(startBranch + "^0"); //$NON-NLS-1$
if (startRef != null) {
@@ -164,22 +216,27 @@ class Branch extends TextBuiltin {
}
startBranch = Repository.shortenRefName(startBranch);
String newRefName = newHead;
- if (!newRefName.startsWith(Constants.R_HEADS))
+ if (!newRefName.startsWith(Constants.R_HEADS)) {
newRefName = Constants.R_HEADS + newRefName;
- if (!Repository.isValidRefName(newRefName))
+ }
+ if (!Repository.isValidRefName(newRefName)) {
throw die(MessageFormat.format(CLIText.get().notAValidRefName, newRefName));
- if (!createForce && db.resolve(newRefName) != null)
+ }
+ if (!createForce && db.resolve(newRefName) != null) {
throw die(MessageFormat.format(CLIText.get().branchAlreadyExists, newHead));
+ }
RefUpdate updateRef = db.updateRef(newRefName);
updateRef.setNewObjectId(startAt);
updateRef.setForceUpdate(createForce);
updateRef.setRefLogMessage(MessageFormat.format(CLIText.get().branchCreatedFrom, startBranch), false);
Result update = updateRef.update();
- if (update == Result.REJECTED)
+ if (update == Result.REJECTED) {
throw die(MessageFormat.format(CLIText.get().couldNotCreateBranch, newHead, update.toString()));
+ }
} else {
- if (verbose)
+ if (verbose) {
rw = new RevWalk(db);
+ }
list();
}
}
@@ -249,7 +306,8 @@ class Branch extends TextBuiltin {
outw.println();
}
- private void delete(boolean force) throws IOException {
+ private void delete(List<String> branches, boolean force)
+ throws IOException {
String current = db.getBranch();
ObjectId head = db.resolve(Constants.HEAD);
for (String branch : branches) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
index 45794629ec..94517dbf2f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
@@ -60,7 +60,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
-import org.kohsuke.args4j.spi.StopOptionHandler;
+import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
@Command(common = true, usage = "usage_checkout")
class Checkout extends TextBuiltin {
@@ -74,11 +74,10 @@ class Checkout extends TextBuiltin {
@Option(name = "--orphan", usage = "usage_orphan")
private boolean orphan = false;
- @Argument(required = true, index = 0, metaVar = "metaVar_name", usage = "usage_checkout")
+ @Argument(required = false, index = 0, metaVar = "metaVar_name", usage = "usage_checkout")
private String name;
- @Argument(index = 1)
- @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class)
+ @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class)
private List<String> paths = new ArrayList<String>();
@Override
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
index cd6953cb05..04078287fb 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
@@ -50,6 +50,7 @@ import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.SystemReader;
@@ -70,6 +71,9 @@ class Clone extends AbstractFetchCommand {
@Option(name = "--bare", usage = "usage_bareClone")
private boolean isBare;
+ @Option(name = "--quiet", usage = "usage_quiet")
+ private Boolean quiet;
+
@Argument(index = 0, required = true, metaVar = "metaVar_uriish")
private String sourceUri;
@@ -109,10 +113,16 @@ class Clone extends AbstractFetchCommand {
command.setGitDir(gitdir == null ? null : new File(gitdir));
command.setDirectory(localNameF);
- outw.println(MessageFormat.format(CLIText.get().cloningInto, localName));
+ boolean msgs = quiet == null || !quiet.booleanValue();
+ if (msgs) {
+ command.setProgressMonitor(new TextProgressMonitor(errw));
+ outw.println(MessageFormat.format(
+ CLIText.get().cloningInto, localName));
+ outw.flush();
+ }
try {
db = command.call().getRepository();
- if (db.resolve(Constants.HEAD) == null)
+ if (msgs && db.resolve(Constants.HEAD) == null)
outw.println(CLIText.get().clonedEmptyRepository);
} catch (InvalidRemoteException e) {
throw die(MessageFormat.format(CLIText.get().doesNotExist,
@@ -121,8 +131,9 @@ class Clone extends AbstractFetchCommand {
if (db != null)
db.close();
}
-
- outw.println();
- outw.flush();
+ if (msgs) {
+ outw.println();
+ outw.flush();
+ }
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
index f07df1a4b5..a25f1e9305 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
@@ -86,6 +86,21 @@ public class Die extends RuntimeException {
* @since 3.4
*/
public Die(boolean aborted) {
+ this(aborted, null);
+ }
+
+ /**
+ * Construct a new exception reflecting the fact that the command execution
+ * has been aborted before running.
+ *
+ * @param aborted
+ * boolean indicating the fact the execution has been aborted
+ * @param cause
+ * can be null
+ * @since 4.2
+ */
+ public Die(boolean aborted, final Throwable cause) {
+ super(cause != null ? cause.getMessage() : null, cause);
this.aborted = aborted;
}
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 ceb0d6b2fe..d701f22c38 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
@@ -62,6 +62,8 @@ import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.pgm.opt.CmdLineParser;
import org.eclipse.jgit.pgm.opt.SubcommandHandler;
+import org.eclipse.jgit.transport.HttpTransport;
+import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory;
import org.eclipse.jgit.util.CachedAuthenticator;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
@@ -88,13 +90,23 @@ public class Main {
@Argument(index = 1, metaVar = "metaVar_arg")
private List<String> arguments = new ArrayList<String>();
+ PrintWriter writer;
+
+ /**
+ *
+ */
+ public Main() {
+ HttpTransport.setConnectionFactory(new HttpClientConnectionFactory());
+ }
+
/**
* Execute the command line.
*
* @param argv
* arguments.
+ * @throws Exception
*/
- public static void main(final String[] argv) {
+ public static void main(final String[] argv) throws Exception {
new Main().run(argv);
}
@@ -113,8 +125,10 @@ public class Main {
*
* @param argv
* arguments.
+ * @throws Exception
*/
- protected void run(final String[] argv) {
+ protected void run(final String[] argv) throws Exception {
+ writer = createErrorWriter();
try {
if (!installConsole()) {
AwtAuthenticator.install();
@@ -123,12 +137,14 @@ public class Main {
configureHttpProxy();
execute(argv);
} catch (Die err) {
- if (err.isAborted())
- System.exit(1);
- System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage()));
- if (showStackTrace)
- err.printStackTrace();
- System.exit(128);
+ if (err.isAborted()) {
+ exit(1, err);
+ }
+ writer.println(CLIText.fatalError(err.getMessage()));
+ if (showStackTrace) {
+ err.printStackTrace(writer);
+ }
+ exit(128, err);
} catch (Exception err) {
// Try to detect errno == EPIPE and exit normally if that happens
// There may be issues with operating system versions and locale,
@@ -136,46 +152,54 @@ public class Main {
// under other circumstances.
if (err.getClass() == IOException.class) {
// Linux, OS X
- if (err.getMessage().equals("Broken pipe")) //$NON-NLS-1$
- System.exit(0);
+ if (err.getMessage().equals("Broken pipe")) { //$NON-NLS-1$
+ exit(0, err);
+ }
// Windows
- if (err.getMessage().equals("The pipe is being closed")) //$NON-NLS-1$
- System.exit(0);
+ if (err.getMessage().equals("The pipe is being closed")) { //$NON-NLS-1$
+ exit(0, err);
+ }
}
if (!showStackTrace && err.getCause() != null
- && err instanceof TransportException)
- System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getCause().getMessage()));
+ && err instanceof TransportException) {
+ writer.println(CLIText.fatalError(err.getCause().getMessage()));
+ }
if (err.getClass().getName().startsWith("org.eclipse.jgit.errors.")) { //$NON-NLS-1$
- System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage()));
- if (showStackTrace)
+ writer.println(CLIText.fatalError(err.getMessage()));
+ if (showStackTrace) {
err.printStackTrace();
- System.exit(128);
+ }
+ exit(128, err);
}
err.printStackTrace();
- System.exit(1);
+ exit(1, err);
}
if (System.out.checkError()) {
- System.err.println(CLIText.get().unknownIoErrorStdout);
- System.exit(1);
+ writer.println(CLIText.get().unknownIoErrorStdout);
+ exit(1, null);
}
- if (System.err.checkError()) {
+ if (writer.checkError()) {
// No idea how to present an error here, most likely disk full or
// broken pipe
- System.exit(1);
+ exit(1, null);
}
}
+ PrintWriter createErrorWriter() {
+ return new PrintWriter(System.err);
+ }
+
private void execute(final String[] argv) throws Exception {
- final CmdLineParser clp = new CmdLineParser(this);
- PrintWriter writer = new PrintWriter(System.err);
+ final CmdLineParser clp = new SubcommandLineParser(this);
+
try {
clp.parseArgument(argv);
} catch (CmdLineException err) {
if (argv.length > 0 && !help && !version) {
- writer.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage()));
+ writer.println(CLIText.fatalError(err.getMessage()));
writer.flush();
- System.exit(1);
+ exit(1, err);
}
}
@@ -191,22 +215,24 @@ public class Main {
writer.println(CLIText.get().mostCommonlyUsedCommandsAre);
final CommandRef[] common = CommandCatalog.common();
int width = 0;
- for (final CommandRef c : common)
+ for (final CommandRef c : common) {
width = Math.max(width, c.getName().length());
+ }
width += 2;
for (final CommandRef c : common) {
writer.print(' ');
writer.print(c.getName());
- for (int i = c.getName().length(); i < width; i++)
+ for (int i = c.getName().length(); i < width; i++) {
writer.print(' ');
+ }
writer.print(CLIText.get().resourceBundle().getString(c.getUsage()));
writer.println();
}
writer.println();
}
writer.flush();
- System.exit(1);
+ exit(1, null);
}
if (version) {
@@ -215,21 +241,39 @@ public class Main {
}
final TextBuiltin cmd = subcommand;
- if (cmd.requiresRepository())
- cmd.init(openGitDir(gitdir), null);
- else
- cmd.init(null, gitdir);
+ init(cmd);
try {
cmd.execute(arguments.toArray(new String[arguments.size()]));
} finally {
- if (cmd.outw != null)
+ if (cmd.outw != null) {
cmd.outw.flush();
- if (cmd.errw != null)
+ }
+ if (cmd.errw != null) {
cmd.errw.flush();
+ }
+ }
+ }
+
+ void init(final TextBuiltin cmd) throws IOException {
+ if (cmd.requiresRepository()) {
+ cmd.init(openGitDir(gitdir), null);
+ } else {
+ cmd.init(null, gitdir);
}
}
/**
+ * @param status
+ * @param t
+ * can be {@code null}
+ * @throws Exception
+ */
+ void exit(int status, Exception t) throws Exception {
+ writer.flush();
+ System.exit(status);
+ }
+
+ /**
* Evaluate the {@code --git-dir} option and open the repository.
*
* @param aGitdir
@@ -278,7 +322,7 @@ public class Main {
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException, ClassNotFoundException {
try {
- Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$
+ Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$
} catch (InvocationTargetException e) {
if (e.getCause() instanceof RuntimeException)
throw (RuntimeException) e.getCause();
@@ -332,4 +376,19 @@ public class Main {
}
}
}
+
+ /**
+ * Parser for subcommands which doesn't stop parsing on help options and so
+ * proceeds all specified options
+ */
+ static class SubcommandLineParser extends CmdLineParser {
+ public SubcommandLineParser(Object bean) {
+ super(bean);
+ }
+
+ @Override
+ protected boolean containsHelp(String... args) {
+ return false;
+ }
+ }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index cd65af9549..e739b58ae7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -148,9 +148,12 @@ class Merge extends TextBuiltin {
break;
case FAST_FORWARD:
ObjectId oldHeadId = oldHead.getObjectId();
- outw.println(MessageFormat.format(CLIText.get().updating, oldHeadId
- .abbreviate(7).name(), result.getNewHead().abbreviate(7)
- .name()));
+ if (oldHeadId != null) {
+ String oldId = oldHeadId.abbreviate(7).name();
+ String newId = result.getNewHead().abbreviate(7).name();
+ outw.println(MessageFormat.format(CLIText.get().updating, oldId,
+ newId));
+ }
outw.println(result.getMergeStatus().toString());
break;
case CHECKOUT_CONFLICT:
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
index 70868e920e..24916bd1c2 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
@@ -144,7 +144,7 @@ class Remote extends TextBuiltin {
}
@Override
- public void printUsageAndExit(final String message, final CmdLineParser clp)
+ public void printUsage(final String message, final CmdLineParser clp)
throws IOException {
errw.println(message);
errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$
@@ -160,7 +160,6 @@ class Remote extends TextBuiltin {
errw.println();
errw.flush();
- throw die(true);
}
private void print(List<RemoteConfig> remotes) throws IOException {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
index db88008e10..ea59527fed 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
@@ -55,7 +55,7 @@ class Repo extends TextBuiltin {
@Option(name = "--groups", aliases = { "-g" }, usage = "usage_groups")
private String groups = "default"; //$NON-NLS-1$
- @Argument(required = true, usage = "usage_pathToXml")
+ @Argument(required = true, metaVar = "metaVar_path", usage = "usage_pathToXml")
private String path;
@Option(name = "--record-remote-branch", usage = "usage_branches")
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
index 4d3af4b560..9cee37b791 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
@@ -51,7 +51,7 @@ import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
-import org.kohsuke.args4j.spi.StopOptionHandler;
+import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
@Command(common = true, usage = "usage_reset")
class Reset extends TextBuiltin {
@@ -65,12 +65,12 @@ class Reset extends TextBuiltin {
@Option(name = "--hard", usage = "usage_resetHard")
private boolean hard = false;
- @Argument(required = true, index = 0, metaVar = "metaVar_name", usage = "usage_reset")
+ @Argument(required = false, index = 0, metaVar = "metaVar_commitish", usage = "usage_resetReference")
private String commit;
- @Argument(index = 1)
- @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class)
- private List<String> paths = new ArrayList<String>();
+ @Argument(required = false, index = 1, metaVar = "metaVar_paths")
+ @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class)
+ private List<String> paths = new ArrayList<>();
@Override
protected void run() throws Exception {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
index e32fc9cab4..c5ecb8496e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
@@ -75,7 +75,13 @@ class RevParse extends TextBuiltin {
if (all) {
Map<String, Ref> allRefs = db.getRefDatabase().getRefs(ALL);
for (final Ref r : allRefs.values()) {
- outw.println(r.getObjectId().name());
+ ObjectId objectId = r.getObjectId();
+ // getRefs skips dangling symrefs, so objectId should never be
+ // null.
+ if (objectId == null) {
+ throw new NullPointerException();
+ }
+ outw.println(objectId.name());
}
} else {
if (verify && commits.size() > 1) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
index be82d070f7..6a6322131a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
@@ -59,8 +59,9 @@ import org.eclipse.jgit.lib.IndexDiff.StageState;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText;
+import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
-
+import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
import org.eclipse.jgit.pgm.opt.UntrackedFilesHandler;
/**
@@ -83,7 +84,8 @@ class Status extends TextBuiltin {
@Option(name = "--untracked-files", aliases = { "-u", "-uno", "-uall" }, usage = "usage_untrackedFilesMode", handler = UntrackedFilesHandler.class)
protected String untrackedFilesMode = "all"; // default value //$NON-NLS-1$
- @Option(name = "--", metaVar = "metaVar_path", multiValued = true)
+ @Argument(required = false, index = 0, metaVar = "metaVar_paths")
+ @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class)
protected List<String> filterPaths;
@Override
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
index 56cfc7e8ef..0dc549c7d7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
@@ -212,17 +212,20 @@ public abstract class TextBuiltin {
*/
protected void parseArguments(final String[] args) throws IOException {
final CmdLineParser clp = new CmdLineParser(this);
+ help = containsHelp(args);
try {
clp.parseArgument(args);
} catch (CmdLineException err) {
- if (!help) {
- this.errw.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage()));
- throw die(true);
+ this.errw.println(CLIText.fatalError(err.getMessage()));
+ if (help) {
+ printUsage("", clp); //$NON-NLS-1$
}
+ throw die(true, err);
}
if (help) {
- printUsageAndExit(clp);
+ printUsage("", clp); //$NON-NLS-1$
+ throw new TerminatedByHelpException();
}
argWalk = clp.getRevWalkGently();
@@ -246,6 +249,20 @@ public abstract class TextBuiltin {
* @throws IOException
*/
public void printUsageAndExit(final String message, final CmdLineParser clp) throws IOException {
+ printUsage(message, clp);
+ throw die(true);
+ }
+
+ /**
+ * @param message
+ * non null
+ * @param clp
+ * parser used to print options
+ * @throws IOException
+ * @since 4.2
+ */
+ protected void printUsage(final String message, final CmdLineParser clp)
+ throws IOException {
errw.println(message);
errw.print("jgit "); //$NON-NLS-1$
errw.print(commandName);
@@ -257,12 +274,19 @@ public abstract class TextBuiltin {
errw.println();
errw.flush();
- throw die(true);
}
/**
- * @return the resource bundle that will be passed to args4j for purpose
- * of string localization
+ * @return error writer, typically this is standard error.
+ * @since 4.2
+ */
+ public ThrowingPrintWriter getErrorWriter() {
+ return errw;
+ }
+
+ /**
+ * @return the resource bundle that will be passed to args4j for purpose of
+ * string localization
*/
protected ResourceBundle getResourceBundle() {
return CLIText.get().resourceBundle();
@@ -324,6 +348,19 @@ public abstract class TextBuiltin {
return new Die(aborted);
}
+ /**
+ * @param aborted
+ * boolean indicating that the execution has been aborted before
+ * running
+ * @param cause
+ * why the command has failed.
+ * @return a runtime exception the caller is expected to throw
+ * @since 4.2
+ */
+ protected static Die die(boolean aborted, final Throwable cause) {
+ return new Die(aborted, cause);
+ }
+
String abbreviateRef(String dst, boolean abbreviateRemote) {
if (dst.startsWith(R_HEADS))
dst = dst.substring(R_HEADS.length());
@@ -333,4 +370,36 @@ public abstract class TextBuiltin {
dst = dst.substring(R_REMOTES.length());
return dst;
}
+
+ /**
+ * @param args
+ * non null
+ * @return true if the given array contains help option
+ * @since 4.2
+ */
+ public static boolean containsHelp(String[] args) {
+ for (String str : args) {
+ if (str.equals("-h") || str.equals("--help")) { //$NON-NLS-1$ //$NON-NLS-2$
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Exception thrown by {@link TextBuiltin} if it proceeds 'help' option
+ *
+ * @since 4.2
+ */
+ public static class TerminatedByHelpException extends Die {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Default constructor
+ */
+ public TerminatedByHelpException() {
+ super(true);
+ }
+
+ }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java
new file mode 100644
index 0000000000..78ca1a7128
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015, 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.pgm.debug;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.internal.storage.reftree.RefTree;
+import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.pgm.Command;
+import org.eclipse.jgit.pgm.TextBuiltin;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+@Command(usage = "usage_RebuildRefTree")
+class RebuildRefTree extends TextBuiltin {
+ private String txnNamespace;
+ private String txnCommitted;
+
+ @Override
+ protected void run() throws Exception {
+ try (ObjectReader reader = db.newObjectReader();
+ RevWalk rw = new RevWalk(reader);
+ ObjectInserter inserter = db.newObjectInserter()) {
+ RefDatabase refDb = db.getRefDatabase();
+ if (refDb instanceof RefTreeDatabase) {
+ RefTreeDatabase d = (RefTreeDatabase) refDb;
+ refDb = d.getBootstrap();
+ txnNamespace = d.getTxnNamespace();
+ txnCommitted = d.getTxnCommitted();
+ } else {
+ RefTreeDatabase d = new RefTreeDatabase(db, refDb);
+ txnNamespace = d.getTxnNamespace();
+ txnCommitted = d.getTxnCommitted();
+ }
+
+ errw.format("Rebuilding %s from %s", //$NON-NLS-1$
+ txnCommitted, refDb.getClass().getSimpleName());
+ errw.println();
+ errw.flush();
+
+ CommitBuilder b = new CommitBuilder();
+ Ref ref = refDb.exactRef(txnCommitted);
+ RefUpdate update = refDb.newUpdate(txnCommitted, true);
+ ObjectId oldTreeId;
+
+ if (ref != null && ref.getObjectId() != null) {
+ ObjectId oldId = ref.getObjectId();
+ update.setExpectedOldObjectId(oldId);
+ b.setParentId(oldId);
+ oldTreeId = rw.parseCommit(oldId).getTree();
+ } else {
+ update.setExpectedOldObjectId(ObjectId.zeroId());
+ oldTreeId = ObjectId.zeroId();
+ }
+
+ RefTree tree = rebuild(refDb.getRefs(RefDatabase.ALL));
+ b.setTreeId(tree.writeTree(inserter));
+ b.setAuthor(new PersonIdent(db));
+ b.setCommitter(b.getAuthor());
+ if (b.getTreeId().equals(oldTreeId)) {
+ return;
+ }
+
+ update.setNewObjectId(inserter.insert(b));
+ inserter.flush();
+
+ RefUpdate.Result result = update.update(rw);
+ switch (result) {
+ case NEW:
+ case FAST_FORWARD:
+ break;
+ default:
+ throw die(String.format("%s: %s", update.getName(), result)); //$NON-NLS-1$
+ }
+ }
+ }
+
+ private RefTree rebuild(Map<String, Ref> refMap) {
+ RefTree tree = RefTree.newEmptyTree();
+ List<org.eclipse.jgit.internal.storage.reftree.Command> cmds
+ = new ArrayList<>();
+
+ for (Ref r : refMap.values()) {
+ if (r.getName().equals(txnCommitted)
+ || r.getName().startsWith(txnNamespace)) {
+ continue;
+ }
+ cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
+ null,
+ db.peel(r)));
+ }
+ tree.apply(cmds);
+ return tree;
+ }
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
index f5d581ad01..2812137266 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
@@ -74,6 +74,19 @@ public class CLIText extends TranslationBundle {
return MessageFormat.format(get().lineFormat, line);
}
+ /**
+ * Format the given argument as fatal error using the format defined by
+ * {@link #fatalError} ("fatal: " by default).
+ *
+ * @param message
+ * the message to format
+ * @return the formatted line
+ * @since 4.2
+ */
+ public static String fatalError(String message) {
+ return MessageFormat.format(get().fatalError, message);
+ }
+
// @formatter:off
/***/ public String alreadyOnBranch;
/***/ public String alreadyUpToDate;
@@ -85,6 +98,7 @@ public class CLIText extends TranslationBundle {
/***/ public String branchCreatedFrom;
/***/ public String branchDetachedHEAD;
/***/ public String branchIsNotAnAncestorOfYourCurrentHEAD;
+ /***/ public String branchNameRequired;
/***/ public String branchNotFound;
/***/ public String cacheTreePathInfo;
/***/ public String configFileNotFound;
@@ -184,6 +198,7 @@ public class CLIText extends TranslationBundle {
/***/ public String metaVar_uriish;
/***/ public String metaVar_url;
/***/ public String metaVar_user;
+ /***/ public String metaVar_values;
/***/ public String metaVar_version;
/***/ public String mostCommonlyUsedCommandsAre;
/***/ public String needApprovalToDestroyCurrentRepository;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
index 3f77aa6687..b531ba65a4 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
@@ -43,19 +43,18 @@
package org.eclipse.jgit.pgm.opt;
+import java.io.IOException;
+import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ResourceBundle;
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.IllegalAnnotationError;
-import org.kohsuke.args4j.NamedOptionDef;
-import org.kohsuke.args4j.Option;
-import org.kohsuke.args4j.OptionDef;
-import org.kohsuke.args4j.spi.OptionHandler;
-import org.kohsuke.args4j.spi.Setter;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.pgm.Die;
import org.eclipse.jgit.pgm.TextBuiltin;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -63,6 +62,15 @@ import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.IllegalAnnotationError;
+import org.kohsuke.args4j.NamedOptionDef;
+import org.kohsuke.args4j.Option;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
+import org.kohsuke.args4j.spi.Setter;
/**
* Extended command line parser which handles --foo=value arguments.
@@ -80,12 +88,17 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
registerHandler(RefSpec.class, RefSpecHandler.class);
registerHandler(RevCommit.class, RevCommitHandler.class);
registerHandler(RevTree.class, RevTreeHandler.class);
+ registerHandler(List.class, OptionWithValuesListHandler.class);
}
private final Repository db;
private RevWalk walk;
+ private boolean seenHelp;
+
+ private TextBuiltin cmd;
+
/**
* Creates a new command line owner that parses arguments/options and set
* them into the given object.
@@ -117,8 +130,12 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
*/
public CmdLineParser(final Object bean, Repository repo) {
super(bean);
- if (repo == null && bean instanceof TextBuiltin)
- repo = ((TextBuiltin) bean).getRepository();
+ if (bean instanceof TextBuiltin) {
+ cmd = (TextBuiltin) bean;
+ }
+ if (repo == null && cmd != null) {
+ repo = cmd.getRepository();
+ }
this.db = repo;
}
@@ -143,9 +160,75 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
}
tmp.add(str);
+
+ if (containsHelp(args)) {
+ // suppress exceptions on required parameters if help is present
+ seenHelp = true;
+ // stop argument parsing here
+ break;
+ }
+ }
+ List<OptionHandler> backup = null;
+ if (seenHelp) {
+ backup = unsetRequiredOptions();
}
- super.parseArgument(tmp.toArray(new String[tmp.size()]));
+ try {
+ super.parseArgument(tmp.toArray(new String[tmp.size()]));
+ } catch (Die e) {
+ if (!seenHelp) {
+ throw e;
+ }
+ printToErrorWriter(CLIText.fatalError(e.getMessage()));
+ } finally {
+ // reset "required" options to defaults for correct command printout
+ if (backup != null && !backup.isEmpty()) {
+ restoreRequiredOptions(backup);
+ }
+ seenHelp = false;
+ }
+ }
+
+ private void printToErrorWriter(String error) {
+ if (cmd == null) {
+ System.err.println(error);
+ } else {
+ try {
+ cmd.getErrorWriter().println(error);
+ } catch (IOException e1) {
+ System.err.println(error);
+ }
+ }
+ }
+
+ private List<OptionHandler> unsetRequiredOptions() {
+ List<OptionHandler> options = getOptions();
+ List<OptionHandler> backup = new ArrayList<>(options);
+ for (Iterator<OptionHandler> iterator = options.iterator(); iterator
+ .hasNext();) {
+ OptionHandler handler = iterator.next();
+ if (handler.option instanceof NamedOptionDef
+ && handler.option.required()) {
+ iterator.remove();
+ }
+ }
+ return backup;
+ }
+
+ private void restoreRequiredOptions(List<OptionHandler> backup) {
+ List<OptionHandler> options = getOptions();
+ options.clear();
+ options.addAll(backup);
+ }
+
+ /**
+ * @param args
+ * non null
+ * @return true if the given array contains help option
+ * @since 4.2
+ */
+ protected boolean containsHelp(final String... args) {
+ return TextBuiltin.containsHelp(args);
}
/**
@@ -181,7 +264,7 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
return walk;
}
- static class MyOptionDef extends OptionDef {
+ class MyOptionDef extends OptionDef {
public MyOptionDef(OptionDef o) {
super(o.usage(), o.metaVar(), o.required(), o.handler(), o
@@ -201,6 +284,11 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
return metaVar();
}
}
+
+ @Override
+ public boolean required() {
+ return seenHelp ? false : super.required();
+ }
}
@Override
@@ -211,4 +299,55 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
return super.createOptionHandler(new MyOptionDef(o), setter);
}
+
+ @SuppressWarnings("unchecked")
+ private List<OptionHandler> getOptions() {
+ List<OptionHandler> options = null;
+ try {
+ Field field = org.kohsuke.args4j.CmdLineParser.class
+ .getDeclaredField("options"); //$NON-NLS-1$
+ field.setAccessible(true);
+ options = (List<OptionHandler>) field.get(this);
+ } catch (NoSuchFieldException | SecurityException
+ | IllegalArgumentException | IllegalAccessException e) {
+ // ignore
+ }
+ if (options == null) {
+ return Collections.emptyList();
+ }
+ return options;
+ }
+
+ @Override
+ public void printSingleLineUsage(Writer w, ResourceBundle rb) {
+ List<OptionHandler> options = getOptions();
+ if (options.isEmpty()) {
+ super.printSingleLineUsage(w, rb);
+ return;
+ }
+ List<OptionHandler> backup = new ArrayList<>(options);
+ boolean changed = sortRestOfArgumentsHandlerToTheEnd(options);
+ try {
+ super.printSingleLineUsage(w, rb);
+ } finally {
+ if (changed) {
+ options.clear();
+ options.addAll(backup);
+ }
+ }
+ }
+
+ private boolean sortRestOfArgumentsHandlerToTheEnd(
+ List<OptionHandler> options) {
+ for (int i = 0; i < options.size(); i++) {
+ OptionHandler handler = options.get(i);
+ if (handler instanceof RestOfArgumentsHandler
+ || handler instanceof PathTreeFilterHandler) {
+ options.remove(i);
+ options.add(handler);
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java
new file mode 100644
index 0000000000..3de7a81091
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java
@@ -0,0 +1,52 @@
+package org.eclipse.jgit.pgm.opt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
+
+/**
+ * Handler which allows to parse option with few values
+ *
+ * @since 4.2
+ */
+public class OptionWithValuesListHandler extends OptionHandler<List<?>> {
+
+ /**
+ * @param parser
+ * @param option
+ * @param setter
+ */
+ public OptionWithValuesListHandler(CmdLineParser parser,
+ OptionDef option, Setter<List<?>> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ public int parseArguments(Parameters params) throws CmdLineException {
+ final List<String> list = new ArrayList<>();
+ for (int idx = 0; idx < params.size(); idx++) {
+ final String p;
+ try {
+ p = params.getParameter(idx);
+ } catch (CmdLineException cle) {
+ break;
+ }
+ list.add(p);
+ }
+ setter.addValue(list);
+ return list.size();
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return CLIText.get().metaVar_values;
+ }
+
+}