diff options
Diffstat (limited to 'org.eclipse.jgit.pgm/src')
87 files changed, 6269 insertions, 3871 deletions
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java index bdaccb0657..201fa3d22d 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleAuthenticator.java @@ -1,45 +1,12 @@ /* * Copyright (C) 2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.console; @@ -49,9 +16,8 @@ import java.net.Authenticator; import java.net.PasswordAuthentication; import java.text.MessageFormat; -import org.eclipse.jgit.util.CachedAuthenticator; - import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.util.CachedAuthenticator; /** * Basic network prompt for username/password when using the console. @@ -59,7 +25,9 @@ import org.eclipse.jgit.pgm.internal.CLIText; * @since 4.0 */ public class ConsoleAuthenticator extends CachedAuthenticator { - /** Install this authenticator implementation into the JVM. */ + /** + * Install this authenticator implementation into the JVM. + */ public static void install() { final ConsoleAuthenticator c = new ConsoleAuthenticator(); if (c.cons == null) diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java index e805add814..5bdfc7bb51 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java @@ -1,46 +1,13 @@ /* * Copyright (C) 2010, Google Inc. * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.console; @@ -48,21 +15,22 @@ package org.eclipse.jgit.console; import java.io.Console; import org.eclipse.jgit.errors.UnsupportedCredentialItem; +import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.transport.ChainingCredentialsProvider; import org.eclipse.jgit.transport.CredentialItem; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.NetRCCredentialsProvider; import org.eclipse.jgit.transport.URIish; -import org.eclipse.jgit.pgm.internal.CLIText; - /** * Interacts with the user during authentication by using the text console. * * @since 4.0 */ public class ConsoleCredentialsProvider extends CredentialsProvider { - /** Install this implementation as the default. */ + /** + * Install this implementation as the default. + */ public static void install() { final ConsoleCredentialsProvider c = new ConsoleCredentialsProvider(); if (c.cons == null) @@ -132,18 +100,15 @@ public class ConsoleCredentialsProvider extends CredentialsProvider { if (v != null) { item.setValue(new String(v)); return true; - } else { - return false; - } - } else { - String v = cons.readLine("%s: ", item.getPromptText()); //$NON-NLS-1$ - if (v != null) { - item.setValue(v); - return true; - } else { - return false; } + return false; + } + String v = cons.readLine("%s: ", item.getPromptText()); //$NON-NLS-1$ + if (v != null) { + item.setValue(v); + return true; } + return false; } private boolean get(CredentialItem.CharArrayType item) { @@ -152,18 +117,15 @@ public class ConsoleCredentialsProvider extends CredentialsProvider { if (v != null) { item.setValueNoCopy(v); return true; - } else { - return false; - } - } else { - String v = cons.readLine("%s: ", item.getPromptText()); //$NON-NLS-1$ - if (v != null) { - item.setValueNoCopy(v.toCharArray()); - return true; - } else { - return false; } + return false; } + String v = cons.readLine("%s: ", item.getPromptText()); //$NON-NLS-1$ + if (v != null) { + item.setValueNoCopy(v.toCharArray()); + return true; + } + return false; } private boolean get(CredentialItem.InformationalMessage item) { @@ -178,8 +140,7 @@ public class ConsoleCredentialsProvider extends CredentialsProvider { if (r != null) { item.setValue(CLIText.get().answerYes.equalsIgnoreCase(r)); return true; - } else { - return false; } + return false; } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java index fde0a78bf6..4440e26f6d 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java @@ -3,52 +3,17 @@ * Copyright (C) 2008-2010, Google Inc. * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; -import static java.lang.Character.valueOf; - import java.io.IOException; import java.text.MessageFormat; @@ -66,10 +31,18 @@ abstract class AbstractFetchCommand extends TextBuiltin { @Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beMoreVerbose") private boolean verbose; - protected void showFetchResult(final FetchResult r) throws IOException { + /** + * Show fetch result. + * + * @param r + * a {@link org.eclipse.jgit.transport.FetchResult} object. + * @throws java.io.IOException + * if any. + */ + protected void showFetchResult(FetchResult r) throws IOException { try (ObjectReader reader = db.newObjectReader()) { boolean shownURI = false; - for (final TrackingRefUpdate u : r.getTrackingRefUpdates()) { + for (TrackingRefUpdate u : r.getTrackingRefUpdates()) { if (!verbose && u.getResult() == RefUpdate.Result.NO_CHANGE) continue; @@ -84,12 +57,15 @@ abstract class AbstractFetchCommand extends TextBuiltin { shownURI = true; } - outw.format(" %c %-17s %-10s -> %s", valueOf(type), longType, //$NON-NLS-1$ - src, dst); + outw.format(" %c %-17s %-10s -> %s", Character.valueOf(type), //$NON-NLS-1$ + longType, src, dst); outw.println(); } } showRemoteMessages(errw, r.getMessages()); + for (FetchResult submoduleResult : r.submoduleResults().values()) { + showFetchResult(submoduleResult); + } } static void showRemoteMessages(ThrowingPrintWriter writer, String pkt) throws IOException { @@ -129,20 +105,20 @@ abstract class AbstractFetchCommand extends TextBuiltin { final TrackingRefUpdate u) { final RefUpdate.Result r = u.getResult(); if (r == RefUpdate.Result.LOCK_FAILURE) - return "[lock fail]"; + return "[lock fail]"; //$NON-NLS-1$ if (r == RefUpdate.Result.IO_FAILURE) - return "[i/o error]"; + return "[i/o error]"; //$NON-NLS-1$ if (r == RefUpdate.Result.REJECTED) - return "[rejected]"; + return "[rejected]"; //$NON-NLS-1$ if (ObjectId.zeroId().equals(u.getNewObjectId())) - return "[deleted]"; + return "[deleted]"; //$NON-NLS-1$ if (r == RefUpdate.Result.NEW) { if (u.getRemoteName().startsWith(Constants.R_HEADS)) - return "[new branch]"; + return "[new branch]"; //$NON-NLS-1$ else if (u.getLocalName().startsWith(Constants.R_TAGS)) - return "[new tag]"; - return "[new]"; + return "[new tag]"; //$NON-NLS-1$ + return "[new]"; //$NON-NLS-1$ } if (r == RefUpdate.Result.FORCED) { @@ -158,7 +134,7 @@ abstract class AbstractFetchCommand extends TextBuiltin { } if (r == RefUpdate.Result.NO_CHANGE) - return "[up to date]"; + return "[up to date]"; //$NON-NLS-1$ return "[" + r.name() + "]"; //$NON-NLS-1$//$NON-NLS-2$ } @@ -170,7 +146,7 @@ abstract class AbstractFetchCommand extends TextBuiltin { } } - private static char shortTypeOf(final RefUpdate.Result r) { + private static char shortTypeOf(RefUpdate.Result r) { if (r == RefUpdate.Result.LOCK_FAILURE) return '!'; if (r == RefUpdate.Result.IO_FAILURE) diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java index 12aac77e9d..dc9d77df35 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2010, 2025 Sasa Zivkov <sasa.zivkov@sap.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -48,24 +15,53 @@ import java.util.List; import org.eclipse.jgit.api.AddCommand; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.pgm.internal.CLIText; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_addFileContentsToTheIndex") class Add extends TextBuiltin { + @Option(name = "--renormalize", usage = "usage_addRenormalize") + private boolean renormalize = false; + @Option(name = "--update", aliases = { "-u" }, usage = "usage_onlyMatchAgainstAlreadyTrackedFiles") private boolean update = false; - @Argument(required = true, metaVar = "metaVar_filepattern", usage = "usage_filesToAddContentFrom") - private List<String> filepatterns = new ArrayList<String>(); + @Option(name = "--all", aliases = { "-A", + "--no-ignore-removal" }, usage = "usage_addStageDeletions") + private Boolean all; + + @Option(name = "--no-all", aliases = { + "--ignore-removal" }, usage = "usage_addDontStageDeletions") + private void noAll(@SuppressWarnings("unused") boolean ignored) { + all = Boolean.FALSE; + } + + @Argument(metaVar = "metaVar_filepattern", usage = "usage_filesToAddContentFrom") + private List<String> filepatterns = new ArrayList<>(); @Override protected void run() throws Exception { - AddCommand addCmd = new Git(db).add(); - addCmd.setUpdate(update); - for (String p : filepatterns) - addCmd.addFilepattern(p); - addCmd.call(); + try (Git git = new Git(db)) { + if (renormalize) { + update = true; + } + if (update && all != null) { + throw die(CLIText.get().addIncompatibleOptions); + } + AddCommand addCmd = git.add(); + addCmd.setUpdate(update).setRenormalize(renormalize); + if (all != null) { + addCmd.setAll(all.booleanValue()); + } + for (String p : filepatterns) { + addCmd.addFilepattern(p); + } + addCmd.call(); + } catch (GitAPIException e) { + throw die(e.getMessage(), e); + } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java index e0a9244a8f..24a75a86e8 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AmazonS3Client.java @@ -1,51 +1,16 @@ /* * Copyright (C) 2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; -import static java.lang.Integer.valueOf; - import java.io.EOFException; import java.io.File; import java.io.FileInputStream; @@ -84,11 +49,14 @@ class AmazonS3Client extends TextBuiltin { protected void run() throws Exception { final AmazonS3 s3 = new AmazonS3(properties()); - if ("get".equals(op)) { //$NON-NLS-1$ + if (op == null) { + throw die(MessageFormat.format(CLIText.get().unsupportedOperation, op)); + } + switch (op) { + case "get": //$NON-NLS-1$ final URLConnection c = s3.get(bucket, key); int len = c.getContentLength(); - final InputStream in = c.getInputStream(); - try { + try (InputStream in = c.getInputStream()) { outw.flush(); final byte[] tmp = new byte[2048]; while (len > 0) { @@ -96,44 +64,41 @@ class AmazonS3Client extends TextBuiltin { if (n < 0) throw new EOFException(MessageFormat.format( CLIText.get().expectedNumberOfbytes, - valueOf(len))); + Integer.valueOf(len))); outs.write(tmp, 0, n); len -= n; } outs.flush(); - } finally { - in.close(); } - - } else if ("ls".equals(op) || "list".equals(op)) { //$NON-NLS-1$//$NON-NLS-2$ - for (final String k : s3.list(bucket, key)) + break; + case "ls": //$NON-NLS-1$ + case "list": //$NON-NLS-1$ + for (String k : s3.list(bucket, key)) outw.println(k); - - } else if ("rm".equals(op) || "delete".equals(op)) { //$NON-NLS-1$ //$NON-NLS-2$ + break; + case "rm": //$NON-NLS-1$ + case "delete": //$NON-NLS-1$ s3.delete(bucket, key); - - } else if ("put".equals(op)) { //$NON-NLS-1$ - final OutputStream os = s3.beginPut(bucket, key, null, null); - final byte[] tmp = new byte[2048]; - int n; - while ((n = ins.read(tmp)) > 0) - os.write(tmp, 0, n); - os.close(); - - } else { + break; + case "put": //$NON-NLS-1$ + try (OutputStream os = s3.beginPut(bucket, key, null, null)) { + final byte[] tmp = new byte[2048]; + int n; + while ((n = ins.read(tmp)) > 0) + os.write(tmp, 0, n); + } + break; + default: throw die(MessageFormat.format(CLIText.get().unsupportedOperation, op)); } } private Properties properties() { try { - final InputStream in = new FileInputStream(propertyFile); - try { + try (InputStream in = new FileInputStream(propertyFile)) { final Properties p = new Properties(); p.load(in); return p; - } finally { - in.close(); } } catch (FileNotFoundException e) { throw die(MessageFormat.format(CLIText.get().noSuchFile, propertyFile), e); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java index 80bb9ec9df..f98f8cb728 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2012 Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2012 Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -52,7 +19,6 @@ import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.archive.ArchiveFormats; import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.pgm.TextBuiltin; import org.eclipse.jgit.pgm.internal.CLIText; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @@ -87,8 +53,8 @@ class Archive extends TextBuiltin { else stream = outs; - try { - ArchiveCommand cmd = new Git(db).archive() + try (Git git = new Git(db)) { + ArchiveCommand cmd = git.archive() .setTree(tree) .setFormat(format) .setPrefix(prefix) @@ -96,11 +62,11 @@ class Archive extends TextBuiltin { if (output != null) cmd.setFilename(output); cmd.call(); - } catch (GitAPIException e) { - throw die(e.getMessage()); - } + } catch (GitAPIException e) { + throw die(e.getMessage(), e); + } } catch (FileNotFoundException e) { - throw die(e.getMessage()); + throw die(e.getMessage(), e); } finally { if (output != null && stream != null) stream.close(); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java index 0f541715ab..285fe2a96a 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java @@ -2,70 +2,37 @@ * Copyright (C) 2011, Google Inc. * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com> * Copyright (C) 2009, Johannes E. Schindelin - * Copyright (C) 2009, Johannes Schindelin <johannes.schindelin@gmx.de> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2009, Johannes Schindelin <johannes.schindelin@gmx.de> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; -import static java.lang.Integer.valueOf; -import static java.lang.Long.valueOf; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH; -import java.io.File; import java.io.IOException; import java.text.MessageFormat; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; +import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.blame.BlameGenerator; import org.eclipse.jgit.blame.BlameResult; import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.diff.RawTextComparator; -import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.pgm.internal.CLIText; @@ -114,7 +81,7 @@ class Blame extends TextBuiltin { private String rangeString; @Option(name = "--reverse", metaVar = "metaVar_blameReverse", usage = "usage_blameReverse") - private List<RevCommit> reverseRange = new ArrayList<RevCommit>(2); + private List<RevCommit> reverseRange = new ArrayList<>(2); @Argument(index = 0, required = false, metaVar = "metaVar_revision") private String revision; @@ -122,11 +89,9 @@ class Blame extends TextBuiltin { @Argument(index = 1, required = false, metaVar = "metaVar_file") private String file; - private ObjectReader reader; + private final Map<RevCommit, String> abbreviatedCommits = new HashMap<>(); - private final Map<RevCommit, String> abbreviatedCommits = new HashMap<RevCommit, String>(); - - private SimpleDateFormat dateFmt; + private DateTimeFormatter dateFmt; private int begin; @@ -134,64 +99,74 @@ class Blame extends TextBuiltin { private BlameResult blame; + /** Used to get a current time stamp for lines without commit. */ + private final PersonIdent dummyDate = new PersonIdent("", ""); //$NON-NLS-1$ //$NON-NLS-2$ + @Override - protected void run() throws Exception { + protected void run() { if (file == null) { - if (revision == null) + if (revision == null) { throw die(CLIText.get().fileIsRequired); + } file = revision; revision = null; } boolean autoAbbrev = abbrev == 0; - if (abbrev == 0) - abbrev = db.getConfig().getInt("core", "abbrev", 7); //$NON-NLS-1$ //$NON-NLS-2$ - if (!showBlankBoundary) + if (abbrev == 0) { + abbrev = db.getConfig().getInt("core", "abbrev", //$NON-NLS-1$ //$NON-NLS-2$ + OBJECT_ID_ABBREV_STRING_LENGTH); + } + if (!showBlankBoundary) { root = db.getConfig().getBoolean("blame", "blankboundary", false); //$NON-NLS-1$ //$NON-NLS-2$ - if (!root) + } + if (!root) { root = db.getConfig().getBoolean("blame", "showroot", false); //$NON-NLS-1$ //$NON-NLS-2$ + } - if (showRawTimestamp) - dateFmt = new SimpleDateFormat("ZZZZ"); //$NON-NLS-1$ - else - dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZZZ"); //$NON-NLS-1$ + if (showRawTimestamp) { + dateFmt = DateTimeFormatter.ofPattern("ZZ"); //$NON-NLS-1$ + } else { + dateFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss ZZ"); //$NON-NLS-1$ + } - reader = db.newObjectReader(); - try (BlameGenerator generator = new BlameGenerator(db, file)) { + try (ObjectReader reader = db.newObjectReader(); + BlameGenerator generator = new BlameGenerator(db, file)) { RevFlag scanned = generator.newFlag("SCANNED"); //$NON-NLS-1$ generator.setTextComparator(comparator); if (!reverseRange.isEmpty()) { RevCommit rangeStart = null; - List<RevCommit> rangeEnd = new ArrayList<RevCommit>(2); + List<RevCommit> rangeEnd = new ArrayList<>(2); for (RevCommit c : reverseRange) { - if (c.has(RevFlag.UNINTERESTING)) + if (c.has(RevFlag.UNINTERESTING)) { rangeStart = c; - else + } else { rangeEnd.add(c); + } } generator.reverse(rangeStart, rangeEnd); } else if (revision != null) { - generator.push(null, db.resolve(revision + "^{commit}")); //$NON-NLS-1$ - } else { - generator.push(null, db.resolve(Constants.HEAD)); - if (!db.isBare()) { - DirCache dc = db.readDirCache(); - int entry = dc.findEntry(file); - if (0 <= entry) - generator.push(null, dc.getEntry(entry).getObjectId()); - - File inTree = new File(db.getWorkTree(), file); - if (db.getFS().isFile(inTree)) - generator.push(null, new RawText(inTree)); + ObjectId rev = db.resolve(revision + "^{commit}"); //$NON-NLS-1$ + if (rev == null) { + throw die(MessageFormat.format(CLIText.get().noSuchRef, + revision)); } + generator.push(null, rev); + } else { + generator.prepareHead(); } blame = BlameResult.create(generator); + if (blame == null) { + throw die(MessageFormat.format(CLIText.get().noSuchPathInRef, + file, revision != null ? revision : Constants.HEAD)); + } begin = 0; end = blame.getResultContents().size(); - if (rangeString != null) + if (rangeString != null) { parseLineRangeOption(); + } blame.computeRange(begin, end); int authorWidth = 8; @@ -202,28 +177,36 @@ class Blame extends TextBuiltin { RevCommit c = blame.getSourceCommit(line); if (c != null && !c.has(scanned)) { c.add(scanned); - if (autoAbbrev) - abbrev = Math.max(abbrev, uniqueAbbrevLen(c)); + if (autoAbbrev) { + abbrev = Math.max(abbrev, uniqueAbbrevLen(reader, c)); + } + authorWidth = Math.max(authorWidth, author(line).length()); + dateWidth = Math.max(dateWidth, date(line).length()); + pathWidth = Math.max(pathWidth, path(line).length()); + } else if (c == null) { authorWidth = Math.max(authorWidth, author(line).length()); dateWidth = Math.max(dateWidth, date(line).length()); pathWidth = Math.max(pathWidth, path(line).length()); } - while (line + 1 < end && blame.getSourceCommit(line + 1) == c) + while (line + 1 < end + && sameCommit(blame.getSourceCommit(line + 1), c)) { line++; + } maxSourceLine = Math.max(maxSourceLine, blame.getSourceLine(line)); } - String pathFmt = MessageFormat.format(" %{0}s", valueOf(pathWidth)); //$NON-NLS-1$ + String pathFmt = MessageFormat.format(" %{0}s", //$NON-NLS-1$ + Integer.valueOf(pathWidth)); String numFmt = MessageFormat.format(" %{0}d", //$NON-NLS-1$ - valueOf(1 + (int) Math.log10(maxSourceLine + 1))); + Integer.valueOf(1 + (int) Math.log10(maxSourceLine + 1))); String lineFmt = MessageFormat.format(" %{0}d) ", //$NON-NLS-1$ - valueOf(1 + (int) Math.log10(end + 1))); + Integer.valueOf(1 + (int) Math.log10(end + 1))); String authorFmt = MessageFormat.format(" (%-{0}s %{1}s", //$NON-NLS-1$ - valueOf(authorWidth), valueOf(dateWidth)); + Integer.valueOf(authorWidth), Integer.valueOf(dateWidth)); for (int line = begin; line < end;) { RevCommit c = blame.getSourceCommit(line); - String commit = abbreviate(c); + String commit = abbreviate(reader, c); String author = null; String date = null; if (!noAuthor) { @@ -232,25 +215,39 @@ class Blame extends TextBuiltin { } do { outw.print(commit); - if (showSourcePath) + if (showSourcePath) { outw.format(pathFmt, path(line)); - if (showSourceLine) - outw.format(numFmt, valueOf(blame.getSourceLine(line) + 1)); - if (!noAuthor) + } + if (showSourceLine) { + outw.format(numFmt, + Integer.valueOf(blame.getSourceLine(line) + 1)); + } + if (!noAuthor) { outw.format(authorFmt, author, date); - outw.format(lineFmt, valueOf(line + 1)); + } + outw.format(lineFmt, Integer.valueOf(line + 1)); outw.flush(); blame.getResultContents().writeLine(outs, line); outs.flush(); outw.print('\n'); - } while (++line < end && blame.getSourceCommit(line) == c); + } while (++line < end + && sameCommit(blame.getSourceCommit(line), c)); } - } finally { - reader.close(); + } catch (NoWorkTreeException | NoHeadException | IOException e) { + throw die(e.getMessage(), e); } } - private int uniqueAbbrevLen(RevCommit commit) throws IOException { + @SuppressWarnings("ReferenceEquality") + private static boolean sameCommit(RevCommit a, RevCommit b) { + // Reference comparison is intentional; BlameGenerator uses a single + // RevWalk which caches the RevCommit objects, and if a given commit + // is cached the RevWalk returns the same instance. + return a == b; + } + + private int uniqueAbbrevLen(ObjectReader reader, RevCommit commit) + throws IOException { return reader.abbreviate(commit, abbrev).length(); } @@ -280,14 +277,14 @@ class Blame extends TextBuiltin { } } - if (beginStr.equals("")) //$NON-NLS-1$ + if (beginStr.isEmpty()) begin = 0; else if (beginStr.startsWith("/")) //$NON-NLS-1$ begin = findLine(0, beginStr); else begin = Math.max(0, Integer.parseInt(beginStr) - 1); - if (endStr.equals("")) //$NON-NLS-1$ + if (endStr.isEmpty()) end = blame.getResultContents().size(); else if (endStr.startsWith("/")) //$NON-NLS-1$ end = findLine(begin, endStr); @@ -329,48 +326,62 @@ class Blame extends TextBuiltin { } private String date(int line) { - if (blame.getSourceCommit(line) == null) - return ""; //$NON-NLS-1$ - - PersonIdent author = blame.getSourceAuthor(line); + PersonIdent author; + if (blame.getSourceCommit(line) == null) { + author = dummyDate; + } else { + author = blame.getSourceAuthor(line); + } if (author == null) return ""; //$NON-NLS-1$ - dateFmt.setTimeZone(author.getTimeZone()); - if (!showRawTimestamp) - return dateFmt.format(author.getWhen()); + if (!showRawTimestamp) { + return dateFmt.withZone(author.getZoneId()) + .format(author.getWhenAsInstant()); + } return String.format("%d %s", //$NON-NLS-1$ - valueOf(author.getWhen().getTime() / 1000L), - dateFmt.format(author.getWhen())); + Long.valueOf(author.getWhenAsInstant().getEpochSecond()), + dateFmt.withZone(author.getZoneId()) + .format(author.getWhenAsInstant())); } - private String abbreviate(RevCommit commit) throws IOException { + private String abbreviate(ObjectReader reader, RevCommit commit) + throws IOException { String r = abbreviatedCommits.get(commit); if (r != null) return r; - if (showBlankBoundary && commit.getParentCount() == 0) - commit = null; - if (commit == null) { - int len = showLongRevision ? OBJECT_ID_STRING_LENGTH : (abbrev + 1); - StringBuilder b = new StringBuilder(len); - for (int i = 0; i < len; i++) - b.append(' '); - r = b.toString(); - - } else if (!root && commit.getParentCount() == 0) { - if (showLongRevision) - r = "^" + commit.name().substring(0, OBJECT_ID_STRING_LENGTH - 1); //$NON-NLS-1$ - else - r = "^" + reader.abbreviate(commit, abbrev).name(); //$NON-NLS-1$ + if (showLongRevision) { + r = ObjectId.zeroId().name(); + } else { + r = ObjectId.zeroId().abbreviate(abbrev + 1).name(); + } } else { - if (showLongRevision) - r = commit.name(); - else - r = reader.abbreviate(commit, abbrev + 1).name(); + if (showBlankBoundary && commit.getParentCount() == 0) + commit = null; + + if (commit == null) { + int len = showLongRevision ? OBJECT_ID_STRING_LENGTH + : (abbrev + 1); + StringBuilder b = new StringBuilder(len); + for (int i = 0; i < len; i++) + b.append(' '); + r = b.toString(); + + } else if (!root && commit.getParentCount() == 0) { + if (showLongRevision) + r = "^" + commit.name().substring(0, //$NON-NLS-1$ + OBJECT_ID_STRING_LENGTH - 1); + else + r = "^" + reader.abbreviate(commit, abbrev).name(); //$NON-NLS-1$ + } else { + if (showLongRevision) + r = commit.name(); + else + r = reader.abbreviate(commit, abbrev + 1).name(); + } } - abbreviatedCommits.put(commit, r); return r; } 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 72e37158cd..e680394a79 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 @@ -1,51 +1,17 @@ /* - * Copyright (C) 2007-2008, Charles O'Farrell <charleso@charleso.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2007-2008, Charles O'Farrell <charleso@charleso.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ 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; @@ -55,6 +21,7 @@ import java.util.Map.Entry; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ListBranchCommand; import org.eclipse.jgit.api.ListBranchCommand.ListMode; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; @@ -65,15 +32,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,25 +53,95 @@ 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; + + /** + * Delete branches + * + * @param names + * a {@link java.util.List} of branch names. + */ + @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; + } + + private List<String> deleteForce; - @Option(name = "--delete-force", aliases = { "-D" }, usage = "usage_deleteBranchEvenIfNotMerged") - private boolean deleteForce = false; + /** + * Forcefully delete branches + * + * @param names + * a {@link java.util.List} of branch names. + */ + @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" }, usage = "usage_forceCreateBranchEvenExists") - private boolean createForce = false; + /** + * Forcefully create a list of branches + * + * @param branchAndStartPoint + * a branch name and a start point + */ + @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 = "-m", usage = "usage_moveRenameABranch") - private boolean rename = false; + /** + * Move or rename a branch + * + * @param currentAndNew + * the current and the new branch name + */ + @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>(); + private final Map<String, Ref> printRefs = new LinkedHashMap<>(); /** Only set for verbose branch listing at-the-moment */ private RevWalk rw; @@ -109,126 +149,150 @@ class Branch extends TextBuiltin { private int maxNameLength; @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)); - + protected void run() { + try { + if (delete != null || deleteForce != null) { + if (delete != null) { + delete(delete, false); + } + if (deleteForce != null) { + delete(deleteForce, true); + } + return; + } if (rename) { String src, dst; - if (branches.size() == 1) { - final Ref head = db.getRef(Constants.HEAD); - if (head != null && head.isSymbolic()) + if (otherBranch == null) { + final Ref head = db.exactRef(Constants.HEAD); + 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); - final Ref old = db.getRef(src); - if (old == null) + src = branch; + final Ref old = db.findRef(src); + if (old == null) { throw die(MessageFormat.format(CLIText.get().doesNotExist, src)); - if (!old.getName().startsWith(Constants.R_HEADS)) + } + 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)) + if (!dst.startsWith(Constants.R_HEADS)) { dst = Constants.R_HEADS + dst; - if (!Repository.isValidRefName(dst)) + } + if (!Repository.isValidRefName(dst)) { throw die(MessageFormat.format(CLIText.get().notAValidRefName, dst)); + } RefRename r = db.renameRef(src, dst); - if (r.rename() != Result.RENAMED) + 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); + } + Ref startRef = db.findRef(startBranch); ObjectId startAt = db.resolve(startBranch + "^0"); //$NON-NLS-1$ - if (startRef != null) + if (startRef != null) { startBranch = startRef.getName(); - else + } else if (startAt != null) { startBranch = startAt.name(); + } else { + throw die(MessageFormat.format( + CLIText.get().notAValidCommitName, startBranch)); + } 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(); } + } catch (IOException | GitAPIException e) { + throw die(e.getMessage(), e); } } - private void list() throws Exception { - Ref head = db.getRef(Constants.HEAD); + private void list() throws IOException, GitAPIException { + Ref head = db.exactRef(Constants.HEAD); // This can happen if HEAD is stillborn if (head != null) { String current = head.getLeaf().getName(); - ListBranchCommand command = new Git(db).branchList(); - if (all) - command.setListMode(ListMode.ALL); - else if (remote) - command.setListMode(ListMode.REMOTE); - - if (containsCommitish != null) - command.setContains(containsCommitish); - - List<Ref> refs = command.call(); - for (Ref ref : refs) { - if (ref.getName().equals(Constants.HEAD)) - addRef("(no branch)", head); //$NON-NLS-1$ - } + try (Git git = new Git(db)) { + ListBranchCommand command = git.branchList(); + if (all) + command.setListMode(ListMode.ALL); + else if (remote) + command.setListMode(ListMode.REMOTE); + + if (containsCommitish != null) + command.setContains(containsCommitish); + + List<Ref> refs = command.call(); + for (Ref ref : refs) { + if (ref.getName().equals(Constants.HEAD)) + addRef("(no branch)", head); //$NON-NLS-1$ + } - addRefs(refs, Constants.R_HEADS); - addRefs(refs, Constants.R_REMOTES); + addRefs(refs, Constants.R_HEADS); + addRefs(refs, Constants.R_REMOTES); - try (ObjectReader reader = db.newObjectReader()) { - for (final Entry<String, Ref> e : printRefs.entrySet()) { - final Ref ref = e.getValue(); - printHead(reader, e.getKey(), - current.equals(ref.getName()), ref); + try (ObjectReader reader = db.newObjectReader()) { + for (Entry<String, Ref> e : printRefs.entrySet()) { + final Ref ref = e.getValue(); + printHead(reader, e.getKey(), + current.equals(ref.getName()), ref); + } } } } } - private void addRefs(final Collection<Ref> refs, final String prefix) { - for (final Ref ref : RefComparator.sort(refs)) { + private void addRefs(Collection<Ref> refs, String prefix) { + for (Ref ref : RefComparator.sort(refs)) { final String name = ref.getName(); if (name.startsWith(prefix)) addRef(name.substring(name.indexOf('/', 5) + 1), ref); } } - private void addRef(final String name, final Ref ref) { + private void addRef(String name, Ref ref) { printRefs.put(name, ref); maxNameLength = Math.max(maxNameLength, name.length()); } private void printHead(final ObjectReader reader, final String ref, - final boolean isCurrent, final Ref refObj) throws Exception { + final boolean isCurrent, final Ref refObj) throws IOException { outw.print(isCurrent ? '*' : ' '); outw.print(' '); outw.print(ref); @@ -243,27 +307,28 @@ 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) { - if (current.equals(branch)) { - throw die(MessageFormat.format(CLIText.get().cannotDeleteTheBranchWhichYouAreCurrentlyOn, branch)); + for (String b : branches) { + if (b.equals(current)) { + throw die(MessageFormat.format(CLIText.get().cannotDeleteTheBranchWhichYouAreCurrentlyOn, b)); } RefUpdate update = db.updateRef((remote ? Constants.R_REMOTES : Constants.R_HEADS) - + branch); + + b); update.setNewObjectId(head); update.setForceUpdate(force || remote); Result result = update.delete(); if (result == Result.REJECTED) { - throw die(MessageFormat.format(CLIText.get().branchIsNotAnAncestorOfYourCurrentHEAD, branch)); + throw die(MessageFormat.format(CLIText.get().branchIsNotAnAncestorOfYourCurrentHEAD, b)); } else if (result == Result.NEW) - throw die(MessageFormat.format(CLIText.get().branchNotFound, branch)); + throw die(MessageFormat.format(CLIText.get().branchNotFound, b)); if (remote) - outw.println(MessageFormat.format(CLIText.get().deletedRemoteBranch, branch)); + outw.println(MessageFormat.format(CLIText.get().deletedRemoteBranch, b)); else if (verbose) - outw.println(MessageFormat.format(CLIText.get().deletedBranch, branch)); + outw.println(MessageFormat.format(CLIText.get().deletedBranch, b)); } } } 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 56d4fcff02..7a218ec926 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 @@ -1,45 +1,12 @@ /* * Copyright (C) 2010, 2012 Chris Aniszczyk <caniszczyk@gmail.com> - * Copyright (C) 2013, Obeo - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2013, Obeo and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -51,16 +18,18 @@ import java.util.List; import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.CheckoutConflictException; +import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.TextProgressMonitor; 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 { @@ -68,18 +37,20 @@ class Checkout extends TextBuiltin { @Option(name = "-b", usage = "usage_createBranchAndCheckout") private boolean createBranch = false; + @Option(name = "-B", usage = "usage_forcedSwitchBranch") + private boolean forceSwitchBranch = false; + @Option(name = "--force", aliases = { "-f" }, usage = "usage_forceCheckout") - private boolean force = false; + private boolean forced = false; @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) - private List<String> paths = new ArrayList<String>(); + @Option(name = "--", metaVar = "metaVar_paths", handler = RestOfArgumentsHandler.class) + private List<String> paths = new ArrayList<>(); @Override protected void run() throws Exception { @@ -89,47 +60,67 @@ class Checkout extends TextBuiltin { throw die(CLIText.get().onBranchToBeBorn); } - CheckoutCommand command = new Git(db).checkout(); - if (paths.size() > 0) { - command.setStartPoint(name); - for (String path : paths) - command.addPath(path); - } else { - command.setCreateBranch(createBranch); - command.setName(name); - command.setForce(force); - command.setOrphan(orphan); - } - try { - String oldBranch = db.getBranch(); - Ref ref = command.call(); - if (ref == null) - return; - if (Repository.shortenRefName(ref.getName()).equals(oldBranch)) { - outw.println(MessageFormat.format( - CLIText.get().alreadyOnBranch, - name)); - return; + try (Git git = new Git(db)) { + CheckoutCommand command = git.checkout() + .setProgressMonitor(new TextProgressMonitor(errw)); + if (!paths.isEmpty()) { + command.setStartPoint(name); + if (paths.size() == 1 && paths.get(0).equals(".")) { //$NON-NLS-1$ + command.setAllPaths(true); + } else { + command.addPaths(paths); + } + } else { + command.setCreateBranch(createBranch); + command.setName(name); + command.setForceRefUpdate(forceSwitchBranch); + command.setForced(forced); + command.setOrphan(orphan); + } + try { + String oldBranch = db.getBranch(); + Ref ref = command.call(); + if (ref == null) + return; + if (Repository.shortenRefName(ref.getName()).equals(oldBranch)) { + outw.println(MessageFormat.format( + CLIText.get().alreadyOnBranch, + name)); + return; + } + if (createBranch || orphan) + outw.println(MessageFormat.format( + CLIText.get().switchedToNewBranch, name)); + else + outw.println(MessageFormat.format( + CLIText.get().switchedToBranch, + Repository.shortenRefName(ref.getName()))); + } catch (InvalidRefNameException e){ + if (name == null){ + throw die(MessageFormat + .format("a valid ref is expected",e)); + } else { + throw die(MessageFormat + .format(CLIText.get().notAValidRefName, name, e)); + } + } + catch (RefNotFoundException e) { + throw die(MessageFormat + .format(CLIText.get().pathspecDidNotMatch, name), e); + } catch (RefAlreadyExistsException e) { + throw die(MessageFormat + .format(CLIText.get().branchAlreadyExists, name), e); + } catch (CheckoutConflictException e) { + StringBuilder builder = new StringBuilder(); + builder.append(CLIText.get().checkoutConflict); + builder.append(System.lineSeparator()); + for (String path : e.getConflictingPaths()) { + builder.append(MessageFormat.format( + CLIText.get().checkoutConflictPathLine, path)); + builder.append(System.lineSeparator()); + } + throw die(builder.toString(), e); } - if (createBranch || orphan) - outw.println(MessageFormat.format( - CLIText.get().switchedToNewBranch, name)); - else - outw.println(MessageFormat.format( - CLIText.get().switchedToBranch, - Repository.shortenRefName(ref.getName()))); - } catch (RefNotFoundException e) { - outw.println(MessageFormat.format( - CLIText.get().pathspecDidNotMatch, - name)); - } catch (RefAlreadyExistsException e) { - throw die(MessageFormat.format(CLIText.get().branchAlreadyExists, - name)); - } catch (CheckoutConflictException e) { - outw.println(CLIText.get().checkoutConflict); - for (String path : e.getConflictingPaths()) - outw.println(MessageFormat.format( - CLIText.get().checkoutConflictPathLine, path)); } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java new file mode 100644 index 0000000000..348f2e7dbb --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clean.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016, Ned Twigg <ned.twigg@diffplug.com> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Set; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.kohsuke.args4j.Option; + +@Command(common = true, usage = "usage_Clean") +class Clean extends TextBuiltin { + @Option(name = "-d", usage = "usage_removeUntrackedDirectories") + private boolean dirs = false; + + @Option(name = "--force", aliases = { + "-f" }, usage = "usage_forceClean") + private boolean force = false; + + @Option(name = "--dryRun", aliases = { "-n" }) + private boolean dryRun = false; + + @Override + protected void run() { + try (Git git = new Git(db)) { + boolean requireForce = git.getRepository().getConfig() + .getBoolean("clean", "requireForce", true); //$NON-NLS-1$ //$NON-NLS-2$ + if (requireForce && !(force || dryRun)) { + throw die(CLIText.fatalError(CLIText.get().cleanRequireForce)); + } + // Note that CleanCommand's setForce(true) will delete + // .git folders. In the cgit cli, this behavior + // requires setting "-f" twice, not sure how to do + // this with args4j, so this feature is unimplemented + // for now. + Set<String> removedFiles = git.clean().setCleanDirectories(dirs) + .setDryRun(dryRun).call(); + for (String removedFile : removedFiles) { + outw.println(MessageFormat.format(CLIText.get().removing, + removedFile)); + } + } catch (NoWorkTreeException | GitAPIException | IOException e) { + throw die(e.getMessage(), e); + } + } +} 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..1efba55f05 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 @@ -1,55 +1,30 @@ /* - * Copyright (C) 2008-2010, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008-2010, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; import java.io.File; +import java.io.IOException; import java.text.MessageFormat; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import org.eclipse.jgit.api.CloneCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.InvalidRemoteException; +import org.eclipse.jgit.api.errors.TransportException; +import org.eclipse.jgit.lib.AnyObjectId; 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; @@ -57,7 +32,7 @@ import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_cloneRepositoryIntoNewDir") -class Clone extends AbstractFetchCommand { +class Clone extends AbstractFetchCommand implements CloneCommand.Callback { @Option(name = "--origin", aliases = { "-o" }, metaVar = "metaVar_remoteName", usage = "usage_useNameInsteadOfOriginToTrackUpstream") private String remoteName = Constants.DEFAULT_REMOTE_NAME; @@ -70,6 +45,27 @@ class Clone extends AbstractFetchCommand { @Option(name = "--bare", usage = "usage_bareClone") private boolean isBare; + @Option(name = "--mirror", usage = "usage_mirrorClone") + private boolean isMirror; + + @Option(name = "--quiet", usage = "usage_quiet") + private Boolean quiet; + + @Option(name = "--depth", metaVar = "metaVar_depth", usage = "usage_depth") + private Integer depth = null; + + @Option(name = "--shallow-since", metaVar = "metaVar_shallowSince", usage = "usage_shallowSince") + private Instant shallowSince = null; + + @Option(name = "--shallow-exclude", metaVar = "metaVar_shallowExclude", usage = "usage_shallowExclude") + private List<String> shallowExcludes = new ArrayList<>(); + + @Option(name = "--recurse-submodules", usage = "usage_recurseSubmodules") + private boolean cloneSubmodules; + + @Option(name = "--timeout", metaVar = "metaVar_seconds", usage = "usage_abortConnectionIfNoActivity") + int timeout = -1; + @Argument(index = 0, required = true, metaVar = "metaVar_uriish") private String sourceUri; @@ -91,11 +87,14 @@ class Clone extends AbstractFetchCommand { if (localName == null) { try { localName = uri.getHumanishName(); + if (isBare || isMirror) { + localName = localName + Constants.DOT_GIT_EXT; + } localNameF = new File(SystemReader.getInstance().getProperty( Constants.OS_USER_DIR), localName); } catch (IllegalArgumentException e) { throw die(MessageFormat.format( - CLIText.get().cannotGuessLocalNameFrom, sourceUri)); + CLIText.get().cannotGuessLocalNameFrom, sourceUri), e); } } else localNameF = new File(localName); @@ -105,24 +104,80 @@ class Clone extends AbstractFetchCommand { CloneCommand command = Git.cloneRepository(); command.setURI(sourceUri).setRemote(remoteName).setBare(isBare) - .setNoCheckout(noCheckout).setBranch(branch); + .setMirror(isMirror).setNoCheckout(noCheckout).setBranch(branch) + .setCloneSubmodules(cloneSubmodules).setTimeout(timeout); + + if (depth != null) { + command.setDepth(depth.intValue()); + } + if (shallowSince != null) { + command.setShallowSince(shallowSince); + } + for (String shallowExclude : shallowExcludes) { + command.addShallowExclude(shallowExclude); + } 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)) + .setCallback(this); + 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 (TransportException e) { + throw die(e.getMessage(), e); } catch (InvalidRemoteException e) { throw die(MessageFormat.format(CLIText.get().doesNotExist, - sourceUri)); + sourceUri), e); } finally { if (db != null) db.close(); } + if (msgs) { + outw.println(); + outw.flush(); + } + } + + @Override + public void initializedSubmodules(Collection<String> submodules) { + try { + for (String submodule : submodules) { + outw.println(MessageFormat + .format(CLIText.get().submoduleRegistered, submodule)); + } + outw.flush(); + } catch (IOException e) { + // ignore + } + } - outw.println(); - outw.flush(); + @Override + public void cloningSubmodule(String path) { + try { + outw.println(MessageFormat.format( + CLIText.get().cloningInto, path)); + outw.flush(); + } catch (IOException e) { + // ignore + } + } + + @Override + public void checkingOut(AnyObjectId commit, String path) { + try { + outw.println(MessageFormat.format(CLIText.get().checkingOut, + path, commit.getName())); + outw.flush(); + } catch (IOException e) { + // ignore + } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Command.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Command.java index 0562416a85..52d5782bdd 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Command.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Command.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -50,7 +17,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * Annotation to document a {@link TextBuiltin}. + * Annotation to document a {@link org.eclipse.jgit.pgm.TextBuiltin}. * <p> * This is an optional annotation for TextBuiltin subclasses and it carries * documentation forward into the runtime system describing what the command is @@ -60,6 +27,8 @@ import java.lang.annotation.Target; @Target( { TYPE }) public @interface Command { /** + * Get the command name + * * @return name the command is invoked as from the command line. If the * (default) empty string is supplied the name will be generated * from the class name. @@ -67,11 +36,15 @@ public @interface Command { public String name() default ""; /** + * Get command description + * * @return one line description of the command's feature set. */ public String usage() default ""; /** + * If this command is considered to be commonly used + * * @return true if this command is considered to be commonly used. */ public boolean common() default false; diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java index 2673cc887d..2a9f7acdb9 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandCatalog.java @@ -1,68 +1,36 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import static java.nio.charset.StandardCharsets.UTF_8; + import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Comparator; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; -import java.util.Vector; /** * List of all commands known by jgit's command line tools. * <p> - * Commands are implementations of {@link TextBuiltin}, with an optional - * {@link Command} class annotation to insert additional documentation or - * override the default command name (which is guessed from the class name). + * Commands are implementations of {@link org.eclipse.jgit.pgm.TextBuiltin}, + * with an optional {@link org.eclipse.jgit.pgm.Command} class annotation to + * insert additional documentation or override the default command name (which + * is guessed from the class name). * <p> * Commands may be registered by adding them to a services file in the same JAR * (or classes directory) as the command implementation. The service file name @@ -85,11 +53,13 @@ public class CommandCatalog { * was derived from the DashLowerCaseForm class name. * @return the command instance; null if no command exists by that name. */ - public static CommandRef get(final String name) { + public static CommandRef get(String name) { return INSTANCE.commands.get(name); } /** + * Get all commands sorted by their name + * * @return all known commands, sorted by command name. */ public static CommandRef[] all() { @@ -97,23 +67,22 @@ public class CommandCatalog { } /** + * Get all common commands sorted by their name + * * @return all common commands, sorted by command name. */ public static CommandRef[] common() { - final ArrayList<CommandRef> common = new ArrayList<CommandRef>(); - for (final CommandRef c : INSTANCE.commands.values()) + final ArrayList<CommandRef> common = new ArrayList<>(); + for (CommandRef c : INSTANCE.commands.values()) if (c.isCommon()) common.add(c); return toSortedArray(common); } - private static CommandRef[] toSortedArray(final Collection<CommandRef> c) { - final CommandRef[] r = c.toArray(new CommandRef[c.size()]); - Arrays.sort(r, new Comparator<CommandRef>() { - public int compare(final CommandRef o1, final CommandRef o2) { - return o1.getName().compareTo(o2.getName()); - } - }); + private static CommandRef[] toSortedArray(Collection<CommandRef> c) { + final CommandRef[] r = c.toArray(new CommandRef[0]); + Arrays.sort(r, (CommandRef o1, CommandRef o2) -> o1.getName() + .compareTo(o2.getName())); return r; } @@ -123,7 +92,7 @@ public class CommandCatalog { private CommandCatalog() { ldr = Thread.currentThread().getContextClassLoader(); - commands = new HashMap<String, CommandRef>(); + commands = new HashMap<>(); final Enumeration<URL> catalogs = catalogs(); while (catalogs.hasMoreElements()) @@ -135,50 +104,30 @@ public class CommandCatalog { final String pfx = "META-INF/services/"; //$NON-NLS-1$ return ldr.getResources(pfx + TextBuiltin.class.getName()); } catch (IOException err) { - return new Vector<URL>().elements(); + return Collections.emptyEnumeration(); } } - private void scan(final URL cUrl) { - final BufferedReader cIn; - try { - final InputStream in = cUrl.openStream(); - cIn = new BufferedReader(new InputStreamReader(in, "UTF-8")); //$NON-NLS-1$ - } catch (IOException err) { - // If we cannot read from the service list, go to the next. - // - return; - } - - try { + private void scan(URL cUrl) { + try (BufferedReader cIn = new BufferedReader( + new InputStreamReader(cUrl.openStream(), UTF_8))) { String line; while ((line = cIn.readLine()) != null) { if (line.length() > 0 && !line.startsWith("#")) //$NON-NLS-1$ load(line); } - } catch (IOException err) { - // If we failed during a read, ignore the error. - // - } finally { - try { - cIn.close(); - } catch (IOException e) { - // Ignore the close error; we are only reading. - } + } catch (IOException e) { + // Ignore errors } } - private void load(final String cn) { + private void load(String cn) { final Class<? extends TextBuiltin> clazz; try { clazz = Class.forName(cn, false, ldr).asSubclass(TextBuiltin.class); - } catch (ClassNotFoundException notBuiltin) { + } catch (ClassNotFoundException | ClassCastException notBuiltin) { // Doesn't exist, even though the service entry is present. - // - return; - } catch (ClassCastException notBuiltin) { // Isn't really a builtin, even though its listed as such. - // return; } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandRef.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandRef.java index 52225150a5..fb5a8fffc1 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandRef.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CommandRef.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -50,7 +17,8 @@ import java.text.MessageFormat; import org.eclipse.jgit.pgm.internal.CLIText; /** - * Description of a command (a {@link TextBuiltin} subclass. + * Description of a command (a {@link org.eclipse.jgit.pgm.TextBuiltin} + * subclass). * <p> * These descriptions are lightweight compared to creating a command instance * and are therefore suitable for catalogs of "known" commands without linking @@ -65,29 +33,29 @@ public class CommandRef { boolean common; - CommandRef(final Class<? extends TextBuiltin> clazz) { + CommandRef(Class<? extends TextBuiltin> clazz) { this(clazz, guessName(clazz)); } - CommandRef(final Class<? extends TextBuiltin> clazz, final Command cmd) { + CommandRef(Class<? extends TextBuiltin> clazz, Command cmd) { this(clazz, cmd.name().length() > 0 ? cmd.name() : guessName(clazz)); usage = cmd.usage(); common = cmd.common(); } - private CommandRef(final Class<? extends TextBuiltin> clazz, final String cn) { + private CommandRef(Class<? extends TextBuiltin> clazz, String cn) { impl = clazz; name = cn; usage = ""; //$NON-NLS-1$ } - private static String guessName(final Class<? extends TextBuiltin> clazz) { + private static String guessName(Class<? extends TextBuiltin> clazz) { final StringBuilder s = new StringBuilder(); if (clazz.getName().startsWith("org.eclipse.jgit.pgm.debug.")) //$NON-NLS-1$ s.append("debug-"); //$NON-NLS-1$ boolean lastWasDash = true; - for (final char c : clazz.getSimpleName().toCharArray()) { + for (char c : clazz.getSimpleName().toCharArray()) { if (Character.isUpperCase(c)) { if (!lastWasDash) s.append('-'); @@ -102,6 +70,8 @@ public class CommandRef { } /** + * Get the <code>name</code>. + * * @return name the command is invoked as from the command line. */ public String getName() { @@ -109,6 +79,8 @@ public class CommandRef { } /** + * Get <code>usage</code>. + * * @return one line description of the command's feature set. */ public String getUsage() { @@ -116,6 +88,8 @@ public class CommandRef { } /** + * Is this command commonly used + * * @return true if this command is considered to be commonly used. */ public boolean isCommon() { @@ -123,6 +97,8 @@ public class CommandRef { } /** + * Get implementation class name + * * @return name of the Java class which implements this command. */ public String getImplementationClassName() { @@ -130,6 +106,8 @@ public class CommandRef { } /** + * Get implementation class loader + * * @return loader for {@link #getImplementationClassName()}. */ public ClassLoader getImplementationClassLoader() { @@ -137,32 +115,37 @@ public class CommandRef { } /** + * Create an instance of the command implementation + * * @return a new instance of the command implementation. */ public TextBuiltin create() { final Constructor<? extends TextBuiltin> c; try { c = impl.getDeclaredConstructor(); - } catch (SecurityException e) { - throw new RuntimeException(MessageFormat.format(CLIText.get().cannotCreateCommand, getName(), e)); - } catch (NoSuchMethodException e) { - throw new RuntimeException(MessageFormat.format(CLIText.get().cannotCreateCommand, getName(), e)); + } catch (SecurityException | NoSuchMethodException e) { + throw new RuntimeException(MessageFormat + .format(CLIText.get().cannotCreateCommand, getName(), e)); } c.setAccessible(true); final TextBuiltin r; try { r = c.newInstance(); - } catch (InstantiationException e) { - throw new RuntimeException(MessageFormat.format(CLIText.get().cannotCreateCommand, getName(), e)); - } catch (IllegalAccessException e) { - throw new RuntimeException(MessageFormat.format(CLIText.get().cannotCreateCommand, getName(), e)); - } catch (IllegalArgumentException e) { - throw new RuntimeException(MessageFormat.format(CLIText.get().cannotCreateCommand, getName(), e)); - } catch (InvocationTargetException e) { - throw new RuntimeException(MessageFormat.format(CLIText.get().cannotCreateCommand, getName(), e)); + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException(MessageFormat + .format(CLIText.get().cannotCreateCommand, getName(), e)); } r.setCommandName(getName()); return r; } + + @SuppressWarnings("nls") + @Override + public String toString() { + return "CommandRef [impl=" + impl + ", name=" + name + ", usage=" + + CLIText.get().resourceBundle().getString(usage) + ", common=" + + common + "]"; + } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java index 14c449a6b3..8df028d2e2 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java @@ -37,18 +37,18 @@ */ package org.eclipse.jgit.pgm; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.eclipse.jgit.api.CommitCommand; import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; -import org.eclipse.jgit.api.errors.NoHeadException; -import org.eclipse.jgit.api.errors.NoMessageException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.opt.GpgSignHandler; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.util.RawParseUtils; import org.kohsuke.args4j.Argument; @@ -74,43 +74,72 @@ class Commit extends TextBuiltin { @Option(name = "--amend", usage = "usage_CommitAmend") private boolean amend; + @Option(name = "--gpg-sign", aliases = { "-S" }, forbids = { + "--no-gpg-sign" }, handler = GpgSignHandler.class) + private String gpgSigningKey; + + @Option(name = "--no-gpg-sign", forbids = { "--gpg-sign" }) + private boolean noGpgSign; + @Argument(metaVar = "metaVar_commitPaths", usage = "usage_CommitPaths") - private List<String> paths = new ArrayList<String>(); + private List<String> paths = new ArrayList<>(); @Override - protected void run() throws NoHeadException, NoMessageException, - ConcurrentRefUpdateException, JGitInternalException, Exception { - CommitCommand commitCmd = new Git(db).commit(); - if (author != null) - commitCmd.setAuthor(RawParseUtils.parsePersonIdent(author)); - if (message != null) - commitCmd.setMessage(message); - if (only && paths.isEmpty()) - throw die(CLIText.get().pathsRequired); - if (only && all) - throw die(CLIText.get().onlyOneOfIncludeOnlyAllInteractiveCanBeUsed); - if (!paths.isEmpty()) - for (String p : paths) - commitCmd.setOnly(p); - commitCmd.setAmend(amend); - commitCmd.setAll(all); - Ref head = db.getRef(Constants.HEAD); - RevCommit commit; - try { - commit = commitCmd.call(); - } catch (JGitInternalException e) { - throw die(e.getMessage()); - } + protected void run() { + try (Git git = new Git(db)) { + CommitCommand commitCmd = git.commit(); + if (author != null) { + commitCmd.setAuthor(RawParseUtils.parsePersonIdent(author)); + } + if (message != null) { + commitCmd.setMessage(message); + } + if (noGpgSign) { + commitCmd.setSign(Boolean.FALSE); + } else if (gpgSigningKey != null) { + commitCmd.setSign(Boolean.TRUE); + if (!gpgSigningKey.equals(GpgSignHandler.DEFAULT)) { + commitCmd.setSigningKey(gpgSigningKey); + } + } + if (only && paths.isEmpty()) { + throw die(CLIText.get().pathsRequired); + } + if (only && all) { + throw die(CLIText.get().onlyOneCommitOptionAllowed); + } + if (!paths.isEmpty()) { + for (String p : paths) { + commitCmd.setOnly(p); + } + } + commitCmd.setAmend(amend); + commitCmd.setAll(all); + Ref head = db.exactRef(Constants.HEAD); + if (head == null) { + throw die(CLIText.get().onBranchToBeBorn); + } + RevCommit commit; + try { + commit = commitCmd.call(); + } catch (JGitInternalException | GitAPIException e) { + throw die(e.getMessage(), e); + } - String branchName; - if (!head.isSymbolic()) - branchName = CLIText.get().branchDetachedHEAD; - else { - branchName = head.getTarget().getName(); - if (branchName.startsWith(Constants.R_HEADS)) - branchName = branchName.substring(Constants.R_HEADS.length()); + String branchName; + if (!head.isSymbolic()) { + branchName = CLIText.get().branchDetachedHEAD; + } else { + branchName = head.getTarget().getName(); + if (branchName.startsWith(Constants.R_HEADS)) { + branchName = branchName + .substring(Constants.R_HEADS.length()); + } + } + outw.println('[' + branchName + ' ' + commit.name() + "] " //$NON-NLS-1$ + + commit.getShortMessage()); + } catch (IOException e) { + throw die(e.getMessage(), e); } - outw.println("[" + branchName + " " + commit.name() + "] " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - + commit.getShortMessage()); } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java index 8569e9278e..f5de7045d0 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java @@ -42,9 +42,9 @@ import java.io.IOException; import java.util.Set; import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.errors.NotSupportedException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.StringUtils; @@ -69,12 +69,15 @@ class Config extends TextBuiltin { private File configFile; @Override - protected void run() throws Exception { - if (list) + protected void run() { + if (!list) { + throw die(CLIText.get().configOnlyListOptionSupported); + } + try { list(); - else - throw new NotSupportedException( - "only --list option is currently supported"); + } catch (IOException | ConfigInvalidException e) { + throw die(e.getMessage(), e); + } } private void list() throws IOException, ConfigInvalidException { @@ -91,7 +94,7 @@ class Config extends TextBuiltin { if (global || isListAll()) list(SystemReader.getInstance().openUserConfig(null, fs)); if (local || isListAll()) - list(new FileBasedConfig(fs.resolve(getRepository().getDirectory(), + list(new FileBasedConfig(fs.resolve(getRepository().getCommonDirectory(), Constants.CONFIG), fs)); } @@ -122,4 +125,4 @@ class Config extends TextBuiltin { } } } -}
\ No newline at end of file +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ConvertRefStorage.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ConvertRefStorage.java new file mode 100644 index 0000000000..06e37da841 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ConvertRefStorage.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019, Google LLC and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import org.eclipse.jgit.internal.storage.file.FileRepository; +import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.ExplicitBooleanOptionHandler; + +@Command(common = true, usage = "usage_convertRefStorage") +class ConvertRefStorage extends TextBuiltin { + + @Option(name = "--format", usage = "usage_convertRefStorageFormat") + private String format = "reftable"; //$NON-NLS-1$ + + @Option(name = "--backup", handler = ExplicitBooleanOptionHandler.class, aliases = { + "-b" }, usage = "usage_convertRefStorageBackup") + private boolean backup = true; + + @Option(name = "--reflogs", handler = ExplicitBooleanOptionHandler.class, aliases = { + "-r" }, usage = "usage_convertRefStorageRefLogs") + private boolean writeLogs = true; + + @Override + protected void run() throws Exception { + ((FileRepository) db).convertRefStorage(format, writeLogs, backup); + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java index 04182d6dbe..ec201a55ef 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java @@ -1,55 +1,25 @@ /* - * Copyright (C) 2008-2009, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008-2009, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; import java.io.File; +import java.io.IOException; import java.net.InetSocketAddress; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.storage.file.WindowCacheConfig; @@ -58,6 +28,7 @@ import org.eclipse.jgit.transport.DaemonClient; import org.eclipse.jgit.transport.DaemonService; import org.eclipse.jgit.transport.resolver.FileResolver; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.SystemReader; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @@ -75,23 +46,23 @@ class Daemon extends TextBuiltin { @Option(name = "--timeout", metaVar = "metaVar_seconds", usage = "usage_abortConnectionIfNoActivity") int timeout = -1; - @Option(name = "--enable", metaVar = "metaVar_service", usage = "usage_enableTheServiceInAllRepositories", multiValued = true) - final List<String> enable = new ArrayList<String>(); + @Option(name = "--enable", metaVar = "metaVar_service", usage = "usage_enableTheServiceInAllRepositories") + List<String> enable = new ArrayList<>(); - @Option(name = "--disable", metaVar = "metaVar_service", usage = "usage_disableTheServiceInAllRepositories", multiValued = true) - final List<String> disable = new ArrayList<String>(); + @Option(name = "--disable", metaVar = "metaVar_service", usage = "usage_disableTheServiceInAllRepositories") + List<String> disable = new ArrayList<>(); - @Option(name = "--allow-override", metaVar = "metaVar_service", usage = "usage_configureTheServiceInDaemonServicename", multiValued = true) - final List<String> canOverride = new ArrayList<String>(); + @Option(name = "--allow-override", metaVar = "metaVar_service", usage = "usage_configureTheServiceInDaemonServicename") + List<String> canOverride = new ArrayList<>(); - @Option(name = "--forbid-override", metaVar = "metaVar_service", usage = "usage_configureTheServiceInDaemonServicename", multiValued = true) - final List<String> forbidOverride = new ArrayList<String>(); + @Option(name = "--forbid-override", metaVar = "metaVar_service", usage = "usage_configureTheServiceInDaemonServicename") + List<String> forbidOverride = new ArrayList<>(); @Option(name = "--export-all", usage = "usage_exportWithoutGitDaemonExportOk") boolean exportAll; @Argument(required = true, metaVar = "metaVar_directory", usage = "usage_directoriesToExport") - final List<File> directory = new ArrayList<File>(); + List<File> directory = new ArrayList<>(); @Override protected boolean requiresRepository() { @@ -101,19 +72,20 @@ class Daemon extends TextBuiltin { @Override protected void run() throws Exception { PackConfig packConfig = new PackConfig(); - - if (configFile != null) { + StoredConfig cfg; + if (configFile == null) { + cfg = getUserConfig(); + } else { if (!configFile.exists()) { throw die(MessageFormat.format( CLIText.get().configFileNotFound, // configFile.getAbsolutePath())); } - - FileBasedConfig cfg = new FileBasedConfig(configFile, FS.DETECTED); + cfg = new FileBasedConfig(configFile, FS.DETECTED); + } cfg.load(); new WindowCacheConfig().fromConfig(cfg).install(); packConfig.fromConfig(cfg); - } int threads = packConfig.getThreads(); if (threads <= 0) @@ -121,8 +93,8 @@ class Daemon extends TextBuiltin { if (1 < threads) packConfig.setExecutor(Executors.newFixedThreadPool(threads)); - final FileResolver<DaemonClient> resolver = new FileResolver<DaemonClient>(); - for (final File f : directory) { + final FileResolver<DaemonClient> resolver = new FileResolver<>(); + for (File f : directory) { outw.println(MessageFormat.format(CLIText.get().exporting, f.getAbsolutePath())); resolver.exportDirectory(f); } @@ -137,20 +109,29 @@ class Daemon extends TextBuiltin { if (0 <= timeout) d.setTimeout(timeout); - for (final String n : enable) + for (String n : enable) service(d, n).setEnabled(true); - for (final String n : disable) + for (String n : disable) service(d, n).setEnabled(false); - for (final String n : canOverride) + for (String n : canOverride) service(d, n).setOverridable(true); - for (final String n : forbidOverride) + for (String n : forbidOverride) service(d, n).setOverridable(false); - d.start(); outw.println(MessageFormat.format(CLIText.get().listeningOn, d.getAddress())); } + private StoredConfig getUserConfig() throws IOException { + StoredConfig userConfig = null; + try { + userConfig = SystemReader.getInstance().getUserConfig(); + } catch (ConfigInvalidException e) { + throw die(e.getMessage()); + } + return userConfig; + } + private static DaemonService service( final org.eclipse.jgit.transport.Daemon d, final String n) { @@ -159,4 +140,4 @@ class Daemon extends TextBuiltin { throw die(MessageFormat.format(CLIText.get().serviceNotSupported, n)); return svc; } -}
\ No newline at end of file +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java index 901e5604ae..2633336e12 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java @@ -1,50 +1,23 @@ /* - * Copyright (C) 2013, Matthias Sohn <matthias.sohn@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2013, Matthias Sohn <matthias.sohn@sap.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + import org.eclipse.jgit.api.DescribeCommand; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.RefNotFoundException; +import org.eclipse.jgit.errors.InvalidPatternException; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.pgm.internal.CLIText; import org.kohsuke.args4j.Argument; @@ -59,22 +32,53 @@ class Describe extends TextBuiltin { @Option(name = "--long", usage = "usage_LongFormat") private boolean longDesc; + @Option(name = "--all", usage = "usage_UseTags") + private boolean useAll; + + @Option(name = "--tags", usage = "usage_UseTags") + private boolean useTags; + + @Option(name = "--always", usage = "usage_AlwaysFallback") + private boolean always; + + @Option(name = "--match", usage = "usage_Match", metaVar = "metaVar_pattern") + private List<String> patterns = new ArrayList<>(); + + @Option(name = "--exclude", usage = "usage_Exclude", metaVar = "metaVar_pattern") + private List<String> excludes = new ArrayList<>(); + + @Option(name = "--abbrev", usage = "usage_Abbrev") + private Integer abbrev; + @Override - protected void run() throws Exception { - DescribeCommand cmd = new Git(db).describe(); - if (tree != null) - cmd.setTarget(tree); - cmd.setLong(longDesc); - String result = null; - try { - result = cmd.call(); - } catch (RefNotFoundException e) { - throw die(CLIText.get().noNamesFound, e); - } - if (result == null) - throw die(CLIText.get().noNamesFound); + protected void run() { + try (Git git = new Git(db)) { + DescribeCommand cmd = git.describe(); + if (tree != null) { + cmd.setTarget(tree); + } + cmd.setLong(longDesc); + cmd.setAll(useAll); + cmd.setTags(useTags); + cmd.setAlways(always); + cmd.setMatch(patterns.toArray(new String[0])); + cmd.setExclude(excludes.toArray(new String[0])); + if (abbrev != null) { + cmd.setAbbrev(abbrev.intValue()); + } + String result = null; + try { + result = cmd.call(); + } catch (RefNotFoundException e) { + throw die(CLIText.get().noNamesFound, e); + } + if (result == null) { + throw die(CLIText.get().noNamesFound); + } - outw.println(result); + outw.println(result); + } catch (IOException | InvalidPatternException | GitAPIException e) { + throw die(e.getMessage(), e); + } } - } 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..365cf6f158 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 @@ -1,51 +1,19 @@ /* * Copyright (C) 2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; /** - * Indicates a {@link TextBuiltin} implementation has failed during execution. + * Indicates a {@link org.eclipse.jgit.pgm.TextBuiltin} implementation has + * failed during execution. * <p> * Typically the stack trace for a Die exception is not shown to the user as it * may indicate a simple error condition that the end-user can fix on their own, @@ -62,7 +30,7 @@ public class Die extends RuntimeException { * @param why * the message to show to the end-user. */ - public Die(final String why) { + public Die(String why) { super(why); } @@ -74,7 +42,7 @@ public class Die extends RuntimeException { * @param cause * why the command has failed. */ - public Die(final String why, final Throwable cause) { + public Die(String why, Throwable cause) { super(why, cause); } @@ -86,6 +54,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, Throwable cause) { + super(cause != null ? cause.getMessage() : null, cause); this.aborted = aborted; } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java index 61a385df83..52665a1c71 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java @@ -1,51 +1,17 @@ /* * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com> * Copyright (C) 2009, Johannes E. Schindelin - * Copyright (C) 2009, Johannes Schindelin <johannes.schindelin@gmx.de> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2009, Johannes Schindelin <johannes.schindelin@gmx.de> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; -import static java.lang.Integer.valueOf; import static org.eclipse.jgit.lib.Constants.HEAD; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH; @@ -62,6 +28,7 @@ import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.RawTextComparator; import org.eclipse.jgit.diff.RenameDetector; import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.errors.RevisionSyntaxException; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; @@ -80,16 +47,20 @@ import org.kohsuke.args4j.Option; class Diff extends TextBuiltin { private DiffFormatter diffFmt; + private boolean showNameOnly = false; + + private boolean showNameAndStatusOnly = false; + @Argument(index = 0, metaVar = "metaVar_treeish") private AbstractTreeIterator oldTree; @Argument(index = 1, metaVar = "metaVar_treeish") private AbstractTreeIterator newTree; - @Option(name = "--cached", usage = "usage_cached") + @Option(name = "--cached", aliases = { "--staged" }, usage = "usage_cached") private boolean cached; - @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = PathTreeFilterHandler.class) + @Option(name = "--", metaVar = "metaVar_paths", handler = PathTreeFilterHandler.class) private TreeFilter pathFilter = TreeFilter.ALL; // BEGIN -- Options shared with Log @@ -113,7 +84,22 @@ class Diff extends TextBuiltin { private Integer renameLimit; @Option(name = "--name-status", usage = "usage_nameStatus") - private boolean showNameAndStatusOnly; + void nameAndStatusOnly(boolean on) { + if (showNameOnly) { + throw new IllegalArgumentException( + CLIText.get().cannotUseNameStatusOnlyAndNameOnly); + } + showNameAndStatusOnly = on; + } + + @Option(name = "--name-only", usage = "usage_nameOnly") + void nameOnly(boolean on) { + if (showNameAndStatusOnly) { + throw new IllegalArgumentException( + CLIText.get().cannotUseNameStatusOnlyAndNameOnly); + } + showNameOnly = on; + } @Option(name = "--ignore-space-at-eol") void ignoreSpaceAtEol(@SuppressWarnings("unused") boolean on) { @@ -150,12 +136,12 @@ class Diff extends TextBuiltin { diffFmt.setAbbreviationLength(OBJECT_ID_STRING_LENGTH); } - @Option(name = "--src-prefix", usage = "usage_srcPrefix") + @Option(name = "--src-prefix", metaVar = "metaVar_prefix", usage = "usage_srcPrefix") void sourcePrefix(String path) { diffFmt.setOldPrefix(path); } - @Option(name = "--dst-prefix", usage = "usage_dstPrefix") + @Option(name = "--dst-prefix", metaVar = "metaVar_prefix", usage = "usage_dstPrefix") void dstPrefix(String path) { diffFmt.setNewPrefix(path); } @@ -169,20 +155,21 @@ class Diff extends TextBuiltin { // END -- Options shared with Log @Override - protected void init(final Repository repository, final String gitDir) { + protected void init(Repository repository, String gitDir) { super.init(repository, gitDir); diffFmt = new DiffFormatter(new BufferedOutputStream(outs)); } @Override - protected void run() throws Exception { + protected void run() { diffFmt.setRepository(db); try { if (cached) { if (oldTree == null) { ObjectId head = db.resolve(HEAD + "^{tree}"); //$NON-NLS-1$ - if (head == null) + if (head == null) { die(MessageFormat.format(CLIText.get().notATree, HEAD)); + } CanonicalTreeParser p = new CanonicalTreeParser(); try (ObjectReader reader = db.newObjectReader()) { p.reset(reader, head); @@ -193,15 +180,17 @@ class Diff extends TextBuiltin { } else if (oldTree == null) { oldTree = new DirCacheIterator(db.readDirCache()); newTree = new FileTreeIterator(db); - } else if (newTree == null) + } else if (newTree == null) { newTree = new FileTreeIterator(db); + } TextProgressMonitor pm = new TextProgressMonitor(errw); pm.setDelayStart(2, TimeUnit.SECONDS); diffFmt.setProgressMonitor(pm); diffFmt.setPathFilter(pathFilter); - if (detectRenames != null) + if (detectRenames != null) { diffFmt.setDetectRenames(detectRenames.booleanValue()); + } if (renameLimit != null && diffFmt.isDetectRenames()) { RenameDetector rd = diffFmt.getRenameDetector(); rd.setRenameLimit(renameLimit.intValue()); @@ -210,11 +199,15 @@ class Diff extends TextBuiltin { if (showNameAndStatusOnly) { nameStatus(outw, diffFmt.scan(oldTree, newTree)); outw.flush(); - + } else if(showNameOnly) { + nameOnly(outw, diffFmt.scan(oldTree, newTree)); + outw.flush(); } else { diffFmt.format(oldTree, newTree); diffFmt.flush(); } + } catch (RevisionSyntaxException | IOException e) { + throw die(e.getMessage(), e); } finally { diffFmt.close(); } @@ -234,16 +227,41 @@ class Diff extends TextBuiltin { out.println("M\t" + ent.getNewPath()); //$NON-NLS-1$ break; case COPY: - out.format("C%1$03d\t%2$s\t%3$s", valueOf(ent.getScore()), // //$NON-NLS-1$ - ent.getOldPath(), ent.getNewPath()); + out.format("C%1$03d\t%2$s\t%3$s", //$NON-NLS-1$ + Integer.valueOf(ent.getScore()), ent.getOldPath(), + ent.getNewPath()); out.println(); break; case RENAME: - out.format("R%1$03d\t%2$s\t%3$s", valueOf(ent.getScore()), // //$NON-NLS-1$ - ent.getOldPath(), ent.getNewPath()); + out.format("R%1$03d\t%2$s\t%3$s", //$NON-NLS-1$ + Integer.valueOf(ent.getScore()), ent.getOldPath(), + ent.getNewPath()); out.println(); break; } } } + + static void nameOnly(ThrowingPrintWriter out, List<DiffEntry> files) + throws IOException { + for (DiffEntry ent : files) { + switch (ent.getChangeType()) { + case ADD: + out.println(ent.getNewPath()); + break; + case DELETE: + out.println(ent.getOldPath()); + break; + case MODIFY: + out.println(ent.getNewPath()); + break; + case COPY: + out.println(ent.getNewPath()); + break; + case RENAME: + out.println(ent.getNewPath()); + break; + } + } + } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java new file mode 100644 index 0000000000..87c71795ec --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com> + * Copyright (C) 2019, Tim Neumann <tim.neumann@advantest.com> + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import static org.eclipse.jgit.lib.Constants.HEAD; +import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jgit.diff.ContentSource; +import org.eclipse.jgit.diff.ContentSource.Pair; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.diff.DiffEntry.Side; +import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.dircache.DirCacheCheckout; +import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; +import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.errors.AmbiguousObjectException; +import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.errors.RevisionSyntaxException; +import org.eclipse.jgit.internal.diffmergetool.DiffTools; +import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool; +import org.eclipse.jgit.internal.diffmergetool.FileElement; +import org.eclipse.jgit.internal.diffmergetool.PromptContinueHandler; +import org.eclipse.jgit.internal.diffmergetool.ToolException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.CoreConfig.EolStreamType; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.TextProgressMonitor; +import org.eclipse.jgit.lib.internal.BooleanTriState; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.AbstractTreeIterator; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.WorkingTreeIterator; +import org.eclipse.jgit.treewalk.WorkingTreeOptions; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.eclipse.jgit.util.FS.ExecutionResult; +import org.eclipse.jgit.util.SystemReader; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +@Command(name = "difftool", common = true, usage = "usage_DiffTool") +class DiffTool extends TextBuiltin { + private DiffFormatter diffFmt; + + private DiffTools diffTools; + + @Argument(index = 0, metaVar = "metaVar_treeish") + private AbstractTreeIterator oldTree; + + @Argument(index = 1, metaVar = "metaVar_treeish") + private AbstractTreeIterator newTree; + + private Optional<String> toolName = Optional.empty(); + + @Option(name = "--tool", aliases = { + "-t" }, metaVar = "metaVar_tool", usage = "usage_ToolForDiff") + void setToolName(String name) { + toolName = Optional.of(name); + } + + @Option(name = "--cached", aliases = { "--staged" }, usage = "usage_cached") + private boolean cached; + + private BooleanTriState prompt = BooleanTriState.UNSET; + + @Option(name = "--prompt", usage = "usage_prompt") + void setPrompt(@SuppressWarnings("unused") boolean on) { + prompt = BooleanTriState.TRUE; + } + + @Option(name = "--no-prompt", aliases = { "-y" }, usage = "usage_noPrompt") + void noPrompt(@SuppressWarnings("unused") boolean on) { + prompt = BooleanTriState.FALSE; + } + + @Option(name = "--tool-help", usage = "usage_toolHelp") + private boolean toolHelp; + + private boolean gui = false; + + @Option(name = "--gui", aliases = { "-g" }, usage = "usage_DiffGuiTool") + void setGui(@SuppressWarnings("unused") boolean on) { + gui = true; + } + + @Option(name = "--no-gui", usage = "usage_noGui") + void noGui(@SuppressWarnings("unused") boolean on) { + gui = false; + } + + private BooleanTriState trustExitCode = BooleanTriState.UNSET; + + @Option(name = "--trust-exit-code", usage = "usage_trustExitCode") + void setTrustExitCode(@SuppressWarnings("unused") boolean on) { + trustExitCode = BooleanTriState.TRUE; + } + + @Option(name = "--no-trust-exit-code", usage = "usage_noTrustExitCode") + void noTrustExitCode(@SuppressWarnings("unused") boolean on) { + trustExitCode = BooleanTriState.FALSE; + } + + @Option(name = "--", metaVar = "metaVar_paths", handler = PathTreeFilterHandler.class) + private TreeFilter pathFilter = TreeFilter.ALL; + + private BufferedReader inputReader; + + @Override + protected void init(Repository repository, String gitDir) { + super.init(repository, gitDir); + diffFmt = new DiffFormatter(new BufferedOutputStream(outs)); + diffTools = new DiffTools(repository); + inputReader = new BufferedReader(new InputStreamReader(ins, + SystemReader.getInstance().getDefaultCharset())); + } + + @Override + protected void run() { + try { + if (toolHelp) { + showToolHelp(); + } else { + // get the changed files + List<DiffEntry> files = getFiles(); + if (files.size() > 0) { + compare(files); + } + } + } catch (RevisionSyntaxException | IOException e) { + throw die(e.getMessage(), e); + } finally { + diffFmt.close(); + } + } + + private void informUserNoTool(List<String> tools) { + try { + StringBuilder toolNames = new StringBuilder(); + for (String name : tools) { + toolNames.append(name + " "); //$NON-NLS-1$ + } + outw.println(MessageFormat.format( + CLIText.get().diffToolPromptToolName, toolNames)); + outw.flush(); + } catch (IOException e) { + throw new IllegalStateException("Cannot output text", e); //$NON-NLS-1$ + } + } + + private class CountingPromptContinueHandler + implements PromptContinueHandler { + private final int fileIndex; + + private final int fileCount; + + private final String fileName; + + public CountingPromptContinueHandler(int fileIndex, int fileCount, + String fileName) { + this.fileIndex = fileIndex; + this.fileCount = fileCount; + this.fileName = fileName; + } + + @SuppressWarnings("boxing") + @Override + public boolean prompt(String toolToLaunchName) { + try { + boolean launchCompare = true; + outw.println(MessageFormat.format(CLIText.get().diffToolLaunch, + fileIndex, fileCount, fileName, toolToLaunchName) + + " "); //$NON-NLS-1$ + outw.flush(); + BufferedReader br = inputReader; + String line = null; + if ((line = br.readLine()) != null) { + if (!line.equalsIgnoreCase("Y")) { //$NON-NLS-1$ + launchCompare = false; + } + } + return launchCompare; + } catch (IOException e) { + throw new IllegalStateException("Cannot output text", e); //$NON-NLS-1$ + } + } + } + + private void compare(List<DiffEntry> files) throws IOException { + ContentSource.Pair sourcePair = new ContentSource.Pair(source(oldTree), + source(newTree)); + try { + for (int fileIndex = 0; fileIndex < files.size(); fileIndex++) { + DiffEntry ent = files.get(fileIndex); + + String filePath = ent.getNewPath(); + if (filePath.equals(DiffEntry.DEV_NULL)) { + filePath = ent.getOldPath(); + } + + try { + FileElement local = createFileElement( + FileElement.Type.LOCAL, sourcePair, Side.OLD, ent); + FileElement remote = createFileElement( + FileElement.Type.REMOTE, sourcePair, Side.NEW, ent); + + PromptContinueHandler promptContinueHandler = new CountingPromptContinueHandler( + fileIndex + 1, files.size(), filePath); + + Optional<ExecutionResult> optionalResult = diffTools + .compare(local, remote, toolName, prompt, gui, + trustExitCode, promptContinueHandler, + this::informUserNoTool); + + if (optionalResult.isPresent()) { + ExecutionResult result = optionalResult.get(); + // TODO: check how to return the exit-code of the tool + // to jgit / java runtime ? + // int rc =... + Charset defaultCharset = SystemReader.getInstance() + .getDefaultCharset(); + outw.println( + new String(result.getStdout().toByteArray(), + defaultCharset)); + outw.flush(); + errw.println( + new String(result.getStderr().toByteArray(), + defaultCharset)); + errw.flush(); + } + } catch (ToolException e) { + outw.println(e.getResultStdout()); + outw.flush(); + errw.println(e.getMessage()); + errw.flush(); + throw die(MessageFormat.format( + CLIText.get().diffToolDied, filePath, e), e); + } + } + } finally { + sourcePair.close(); + } + } + + private void showToolHelp() throws IOException { + Map<String, ExternalDiffTool> predefTools = diffTools + .getPredefinedTools(true); + StringBuilder availableToolNames = new StringBuilder(); + StringBuilder notAvailableToolNames = new StringBuilder(); + for (String name : predefTools.keySet()) { + if (predefTools.get(name).isAvailable()) { + availableToolNames.append(MessageFormat.format("\t\t{0}\n", name)); //$NON-NLS-1$ + } else { + notAvailableToolNames.append(MessageFormat.format("\t\t{0}\n", name)); //$NON-NLS-1$ + } + } + StringBuilder userToolNames = new StringBuilder(); + Map<String, ExternalDiffTool> userTools = diffTools + .getUserDefinedTools(); + for (String name : userTools.keySet()) { + userToolNames.append(MessageFormat.format("\t\t{0}.cmd {1}\n", //$NON-NLS-1$ + name, userTools.get(name).getCommand())); + } + outw.println(MessageFormat.format( + CLIText.get().diffToolHelpSetToFollowing, availableToolNames, + userToolNames, notAvailableToolNames)); + } + + private List<DiffEntry> getFiles() + throws RevisionSyntaxException, AmbiguousObjectException, + IncorrectObjectTypeException, IOException { + diffFmt.setRepository(db); + if (cached) { + if (oldTree == null) { + ObjectId head = db.resolve(HEAD + "^{tree}"); //$NON-NLS-1$ + if (head == null) { + die(MessageFormat.format(CLIText.get().notATree, HEAD)); + } + CanonicalTreeParser p = new CanonicalTreeParser(); + try (ObjectReader reader = db.newObjectReader()) { + p.reset(reader, head); + } + oldTree = p; + } + newTree = new DirCacheIterator(db.readDirCache()); + } else if (oldTree == null) { + oldTree = new DirCacheIterator(db.readDirCache()); + newTree = new FileTreeIterator(db); + } else if (newTree == null) { + newTree = new FileTreeIterator(db); + } + + TextProgressMonitor pm = new TextProgressMonitor(errw); + pm.setDelayStart(2, TimeUnit.SECONDS); + diffFmt.setProgressMonitor(pm); + diffFmt.setPathFilter(pathFilter); + + List<DiffEntry> files = diffFmt.scan(oldTree, newTree); + return files; + } + + private FileElement createFileElement(FileElement.Type elementType, + Pair pair, Side side, DiffEntry entry) throws NoWorkTreeException, + CorruptObjectException, IOException, ToolException { + String entryPath = side == Side.NEW ? entry.getNewPath() + : entry.getOldPath(); + FileElement fileElement = new FileElement(entryPath, elementType, + db.getWorkTree()); + if (!pair.isWorkingTreeSource(side) && !fileElement.isNullPath()) { + try (RevWalk revWalk = new RevWalk(db); + TreeWalk treeWalk = new TreeWalk(db, + revWalk.getObjectReader())) { + treeWalk.setFilter( + PathFilterGroup.createFromStrings(entryPath)); + if (side == Side.NEW) { + newTree.reset(); + treeWalk.addTree(newTree); + } else { + oldTree.reset(); + treeWalk.addTree(oldTree); + } + if (treeWalk.next()) { + final EolStreamType eolStreamType = treeWalk + .getEolStreamType(CHECKOUT_OP); + final String filterCommand = treeWalk.getFilterCommand( + Constants.ATTR_FILTER_TYPE_SMUDGE); + WorkingTreeOptions opt = db.getConfig() + .get(WorkingTreeOptions.KEY); + CheckoutMetadata checkoutMetadata = new CheckoutMetadata( + eolStreamType, filterCommand); + DirCacheCheckout.getContent(db, entryPath, + checkoutMetadata, pair.open(side, entry), opt, + new FileOutputStream( + fileElement.createTempFile(null))); + } else { + throw new ToolException("Cannot find path '" + entryPath //$NON-NLS-1$ + + "' in staging area!", //$NON-NLS-1$ + null); + } + } + } + return fileElement; + } + + private ContentSource source(AbstractTreeIterator iterator) { + if (iterator instanceof WorkingTreeIterator) { + return ContentSource.create((WorkingTreeIterator) iterator); + } + return ContentSource.create(db.newObjectReader()); + } + +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java index d89053c4cb..352ffde26c 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTree.java @@ -1,60 +1,28 @@ /* * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import java.io.IOException; import java.util.ArrayList; import java.util.List; -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; @Command(usage = "usage_ShowDiffTree") class DiffTree extends TextBuiltin { @@ -67,53 +35,59 @@ class DiffTree extends TextBuiltin { } @Argument(index = 1, metaVar = "metaVar_treeish", required = true) - private final List<AbstractTreeIterator> trees = new ArrayList<AbstractTreeIterator>(); + private List<AbstractTreeIterator> trees = new ArrayList<>(); - @Option(name = "--", metaVar = "metaVar_path", multiValued = true, handler = PathTreeFilterHandler.class) + @Option(name = "--", metaVar = "metaVar_path", handler = PathTreeFilterHandler.class) private TreeFilter pathFilter = TreeFilter.ALL; @Override - protected void run() throws Exception { - final TreeWalk walk = new TreeWalk(db); - walk.setRecursive(recursive); - for (final AbstractTreeIterator i : trees) - walk.addTree(i); - walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter)); + protected void run() { + try (TreeWalk walk = new TreeWalk(db)) { + walk.setRecursive(recursive); + for (AbstractTreeIterator i : trees) + walk.addTree(i); + walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter)); - final int nTree = walk.getTreeCount(); - while (walk.next()) { - for (int i = 1; i < nTree; i++) - outw.print(':'); - for (int i = 0; i < nTree; i++) { - final FileMode m = walk.getFileMode(i); - final String s = m.toString(); - for (int pad = 6 - s.length(); pad > 0; pad--) - outw.print('0'); - outw.print(s); - outw.print(' '); - } + final int nTree = walk.getTreeCount(); + while (walk.next()) { + for (int i = 1; i < nTree; i++) { + outw.print(':'); + } + for (int i = 0; i < nTree; i++) { + final FileMode m = walk.getFileMode(i); + final String s = m.toString(); + for (int pad = 6 - s.length(); pad > 0; pad--) { + outw.print('0'); + } + outw.print(s); + outw.print(' '); + } - for (int i = 0; i < nTree; i++) { - outw.print(walk.getObjectId(i).name()); - outw.print(' '); - } + for (int i = 0; i < nTree; i++) { + outw.print(walk.getObjectId(i).name()); + outw.print(' '); + } - char chg = 'M'; - if (nTree == 2) { - final int m0 = walk.getRawMode(0); - final int m1 = walk.getRawMode(1); - if (m0 == 0 && m1 != 0) - chg = 'A'; - else if (m0 != 0 && m1 == 0) - chg = 'D'; - else if (m0 != m1 && walk.idEqual(0, 1)) - chg = 'T'; - } - outw.print(chg); + char chg = 'M'; + if (nTree == 2) { + final int m0 = walk.getRawMode(0); + final int m1 = walk.getRawMode(1); + if (m0 == 0 && m1 != 0) { + chg = 'A'; + } else if (m0 != 0 && m1 == 0) { + chg = 'D'; + } else if (m0 != m1 && walk.idEqual(0, 1)) { + chg = 'T'; + } + } + outw.print(chg); - outw.print('\t'); - outw.print(walk.getPathString()); - outw.println(); + outw.print('\t'); + outw.print(walk.getPathString()); + outw.println(); + } + } catch (IOException e) { + throw die(e.getMessage(), e); } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java index 186fdd8a22..7a007e3b58 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Fetch.java @@ -1,56 +1,30 @@ /* * Copyright (C) 2008-2009, Google Inc. * Copyright (C) 2009, Mykola Nikishov <mn@mn.com.ua> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import java.io.IOException; +import java.text.MessageFormat; +import java.time.Instant; +import java.util.ArrayList; import java.util.List; import org.eclipse.jgit.api.FetchCommand; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode; import org.eclipse.jgit.lib.TextProgressMonitor; +import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.TagOpt; @@ -58,7 +32,7 @@ import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_updateRemoteRefsFromAnotherRepository") -class Fetch extends AbstractFetchCommand { +class Fetch extends AbstractFetchCommand implements FetchCommand.Callback { @Option(name = "--timeout", metaVar = "metaVar_seconds", usage = "usage_abortConnectionIfNoActivity") int timeout = -1; @@ -90,12 +64,49 @@ class Fetch extends AbstractFetchCommand { @Option(name = "--tags", usage="usage_tags", aliases = { "-t" }) private Boolean tags; + @Option(name = "--depth", metaVar = "metaVar_depth", usage = "usage_depth") + private Integer depth = null; + + @Option(name = "--shallow-since", metaVar = "metaVar_shallowSince", usage = "usage_shallowSince") + private Instant shallowSince = null; + + @Option(name = "--shallow-exclude", metaVar = "metaVar_shallowExclude", usage = "usage_shallowExclude") + private List<String> shallowExcludes = new ArrayList<>(); + @Option(name = "--no-tags", usage = "usage_notags", aliases = { "-n" }) void notags(@SuppressWarnings("unused") final boolean ignored) { tags = Boolean.FALSE; } + @Option(name = "--force", usage = "usage_forcedFetch", aliases = { "-f" }) + private Boolean force; + + private FetchRecurseSubmodulesMode recurseSubmodules; + + @Option(name = "--recurse-submodules", usage = "usage_recurseSubmodules") + void recurseSubmodules(String mode) { + if (mode == null || mode.isEmpty()) { + recurseSubmodules = FetchRecurseSubmodulesMode.YES; + } else { + for (FetchRecurseSubmodulesMode m : FetchRecurseSubmodulesMode + .values()) { + if (m.matchConfigValue(mode)) { + recurseSubmodules = m; + return; + } + } + throw die(MessageFormat + .format(CLIText.get().invalidRecurseSubmodulesMode, mode)); + } + } + + @Option(name = "--no-recurse-submodules", usage = "usage_noRecurseSubmodules") + void noRecurseSubmodules(@SuppressWarnings("unused") + final boolean ignored) { + recurseSubmodules = FetchRecurseSubmodulesMode.NO; + } + @Argument(index = 0, metaVar = "metaVar_uriish") private String remote = Constants.DEFAULT_REMOTE_NAME; @@ -103,32 +114,66 @@ class Fetch extends AbstractFetchCommand { private List<RefSpec> toget; @Override - protected void run() throws Exception { - Git git = new Git(db); - FetchCommand fetch = git.fetch(); - if (fsck != null) - fetch.setCheckFetchedObjects(fsck.booleanValue()); - if (prune != null) - fetch.setRemoveDeletedRefs(prune.booleanValue()); - if (toget != null) - fetch.setRefSpecs(toget); - if (tags != null) { - fetch.setTagOpt(tags.booleanValue() ? TagOpt.FETCH_TAGS - : TagOpt.NO_TAGS); + protected void run() { + try (Git git = new Git(db)) { + FetchCommand fetch = git.fetch(); + if (fsck != null) { + fetch.setCheckFetchedObjects(fsck.booleanValue()); + } + if (prune != null) { + fetch.setRemoveDeletedRefs(prune.booleanValue()); + } + if (toget != null) { + fetch.setRefSpecs(toget); + } + if (tags != null) { + fetch.setTagOpt(tags.booleanValue() ? TagOpt.FETCH_TAGS + : TagOpt.NO_TAGS); + } + if (depth != null) { + fetch.setDepth(depth.intValue()); + } + if (shallowSince != null) { + fetch.setShallowSince(shallowSince); + } + for (String shallowExclude : shallowExcludes) { + fetch.addShallowExclude(shallowExclude); + } + if (0 <= timeout) { + fetch.setTimeout(timeout); + } + fetch.setDryRun(dryRun); + fetch.setRemote(remote); + if (thin != null) { + fetch.setThin(thin.booleanValue()); + } + if (quiet == null || !quiet.booleanValue()) { + fetch.setProgressMonitor(new TextProgressMonitor(errw)); + } + fetch.setRecurseSubmodules(recurseSubmodules).setCallback(this); + if (force != null) { + fetch.setForceUpdate(force.booleanValue()); + } + + FetchResult result = fetch.call(); + if (result.getTrackingRefUpdates().isEmpty() + && result.submoduleResults().isEmpty()) { + return; + } + showFetchResult(result); + } catch (GitAPIException | IOException e) { + throw die(e.getMessage(), e); + } + } + + @Override + public void fetchingSubmodule(String name) { + try { + outw.println(MessageFormat.format(CLIText.get().fetchingSubmodule, + name)); + outw.flush(); + } catch (IOException e) { + // ignore } - if (0 <= timeout) - fetch.setTimeout(timeout); - fetch.setDryRun(dryRun); - fetch.setRemote(remote); - if (thin != null) - fetch.setThin(thin.booleanValue()); - if (quiet == null || !quiet.booleanValue()) - fetch.setProgressMonitor(new TextProgressMonitor(errw)); - - FetchResult result = fetch.call(); - if (result.getTrackingRefUpdates().isEmpty()) - return; - - showFetchResult(result); } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java index bf454760af..35ac7a162a 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java @@ -1,49 +1,18 @@ /* - * Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import org.eclipse.jgit.api.GarbageCollectCommand; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.TextProgressMonitor; import org.kohsuke.args4j.Option; @@ -52,10 +21,34 @@ class Gc extends TextBuiltin { @Option(name = "--aggressive", usage = "usage_Aggressive") private boolean aggressive; + @Option(name = "--preserve-oldpacks", usage = "usage_PreserveOldPacks") + private Boolean preserveOldPacks; + + @Option(name = "--prune-preserved", usage = "usage_PrunePreserved") + private Boolean prunePreserved; + + @Option(name = "--pack-kept-objects", usage = "usage_PackKeptObjects") + private Boolean packKeptObjects; + + /** {@inheritDoc} */ @Override - protected void run() throws Exception { + protected void run() { Git git = Git.wrap(db); - git.gc().setAggressive(aggressive) - .setProgressMonitor(new TextProgressMonitor(errw)).call(); + try { + GarbageCollectCommand command = git.gc().setAggressive(aggressive) + .setProgressMonitor(new TextProgressMonitor(errw)); + if (preserveOldPacks != null) { + command.setPreserveOldPacks(preserveOldPacks.booleanValue()); + } + if (prunePreserved != null) { + command.setPrunePreserved(prunePreserved.booleanValue()); + } + if (packKeptObjects != null) { + command.setPackKeptObjects(packKeptObjects.booleanValue()); + } + command.call(); + } catch (GitAPIException e) { + throw die(e.getMessage(), e); + } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Glog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Glog.java index f07c3ca8b5..ce687c4639 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Glog.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Glog.java @@ -1,45 +1,12 @@ /* * Copyright (C) 2010, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -47,7 +14,6 @@ package org.eclipse.jgit.pgm; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; @@ -75,7 +41,7 @@ class Glog extends RevWalkTextBuiltin { frame = new JFrame(); frame.addWindowListener(new WindowAdapter() { @Override - public void windowClosing(final WindowEvent e) { + public void windowClosing(WindowEvent e) { frame.dispose(); } }); @@ -87,10 +53,8 @@ class Glog extends RevWalkTextBuiltin { final JPanel buttons = new JPanel(new FlowLayout()); final JButton repaint = new JButton(); repaint.setText(CLIText.get().repaint); - repaint.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - graphPane.repaint(); - } + repaint.addActionListener((ActionEvent e) -> { + graphPane.repaint(); }); buttons.add(repaint); @@ -113,7 +77,7 @@ class Glog extends RevWalkTextBuiltin { } @Override - protected void show(final RevCommit c) throws Exception { + protected void show(RevCommit c) throws Exception { throw new UnsupportedOperationException(); } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java index 22f3be9afd..b3808d6fda 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java @@ -1,50 +1,18 @@ /* * Copyright (C) 2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; import java.io.BufferedInputStream; +import java.io.IOException; import org.eclipse.jgit.internal.storage.file.ObjectDirectoryPackParser; import org.eclipse.jgit.lib.ObjectInserter; @@ -61,7 +29,7 @@ class IndexPack extends TextBuiltin { private int indexVersion = -1; @Override - protected void run() throws Exception { + protected void run() { BufferedInputStream in = new BufferedInputStream(ins); try (ObjectInserter inserter = db.newObjectInserter()) { PackParser p = inserter.newPackParser(in); @@ -72,6 +40,8 @@ class IndexPack extends TextBuiltin { } p.parse(new TextProgressMonitor(errw)); inserter.flush(); + } catch (IOException e) { + throw die(e.getMessage(), e); } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java index b3e73b5d99..9c4af813a4 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java @@ -4,56 +4,28 @@ * Copyright (C) 2010, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com> * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2016, Rüdiger Herrmann <ruediger.herrmann@gmx.de> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; import java.io.File; +import java.io.IOException; import java.text.MessageFormat; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.InitCommand; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.util.StringUtils; +import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_CreateAnEmptyGitRepository") @@ -61,20 +33,39 @@ class Init extends TextBuiltin { @Option(name = "--bare", usage = "usage_CreateABareRepository") private boolean bare; + @Option(name = "--initial-branch", aliases = { "-b" }, + metaVar = "metaVar_branchName", usage = "usage_initialBranch") + private String branch; + + @Argument(index = 0, metaVar = "metaVar_directory") + private String directory; + @Override protected final boolean requiresRepository() { return false; } @Override - protected void run() throws Exception { + protected void run() { InitCommand command = Git.init(); command.setBare(bare); - if (gitdir != null) + if (gitdir != null) { command.setDirectory(new File(gitdir)); - Repository repository = command.call().getRepository(); - outw.println(MessageFormat.format( - CLIText.get().initializedEmptyGitRepositoryIn, repository - .getDirectory().getAbsolutePath())); + } + if (directory != null) { + command.setDirectory(new File(directory)); + } + Repository repository; + try { + if (!StringUtils.isEmptyOrNull(branch)) { + command.setInitialBranch(branch); + } + repository = command.call().getRepository(); + outw.println(MessageFormat.format( + CLIText.get().initializedEmptyGitRepositoryIn, + repository.getDirectory().getAbsolutePath())); + } catch (GitAPIException | IOException e) { + throw die(e.getMessage(), e); + } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java index d43424c7ce..958e566986 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java @@ -1,46 +1,13 @@ /* * Copyright (C) 2010, Google Inc. - * Copyright (C) 2006-2008, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2006, 2008, Robin Rosenberg <robin.rosenberg@dewire.com> + * Copyright (C) 2008, 2021, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -53,6 +20,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -63,12 +31,16 @@ import org.eclipse.jgit.diff.RenameDetector; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.GpgConfig; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SignatureVerifiers; import org.eclipse.jgit.notes.NoteMap; import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.internal.VerificationUtils; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.util.GitDateFormatter; @@ -87,23 +59,30 @@ class Log extends RevWalkTextBuiltin { private Map<String, NoteMap> noteMaps; + private boolean showNameOnly = false; + + private boolean showNameAndStatusOnly = false; + @Option(name="--decorate", usage="usage_showRefNamesMatchingCommits") private boolean decorate; @Option(name = "--no-standard-notes", usage = "usage_noShowStandardNotes") private boolean noStandardNotes; - private List<String> additionalNoteRefs = new ArrayList<String>(); + private List<String> additionalNoteRefs = new ArrayList<>(); @Option(name = "--show-notes", usage = "usage_showNotes", metaVar = "metaVar_ref") void addAdditionalNoteRef(String notesRef) { additionalNoteRefs.add(notesRef); } + @Option(name = "--show-signature", usage = "usage_showSignature") + private boolean showSignature; + @Option(name = "--date", usage = "usage_date") void dateFormat(String date) { - if (date.toLowerCase().equals(date)) - date = date.toUpperCase(); + if (date.toLowerCase(Locale.ROOT).equals(date)) + date = date.toUpperCase(Locale.ROOT); dateFormatter = new GitDateFormatter(Format.valueOf(date)); } @@ -123,7 +102,22 @@ class Log extends RevWalkTextBuiltin { private Integer renameLimit; @Option(name = "--name-status", usage = "usage_nameStatus") - private boolean showNameAndStatusOnly; + void nameAndStatusOnly(boolean on) { + if (showNameOnly) { + throw new IllegalArgumentException( + CLIText.get().cannotUseNameStatusOnlyAndNameOnly); + } + showNameAndStatusOnly = on; + } + + @Option(name = "--name-only", usage = "usage_nameOnly") + void nameOnly(boolean on) { + if (showNameAndStatusOnly) { + throw new IllegalArgumentException( + CLIText.get().cannotUseNameStatusOnlyAndNameOnly); + } + showNameOnly = on; + } @Option(name = "--ignore-space-at-eol") void ignoreSpaceAtEol(@SuppressWarnings("unused") boolean on) { @@ -179,23 +173,27 @@ class Log extends RevWalkTextBuiltin { // END -- Options shared with Diff + private GpgConfig config; + Log() { dateFormatter = new GitDateFormatter(Format.DEFAULT); } @Override - protected void init(final Repository repository, final String gitDir) { + protected void init(Repository repository, String gitDir) { super.init(repository, gitDir); diffFmt = new DiffFormatter(new BufferedOutputStream(outs)); } @Override - protected void run() throws Exception { + protected void run() { + config = new GpgConfig(db.getConfig()); diffFmt.setRepository(db); try { diffFmt.setPathFilter(pathFilter); - if (detectRenames != null) + if (detectRenames != null) { diffFmt.setDetectRenames(detectRenames.booleanValue()); + } if (renameLimit != null && diffFmt.isDetectRenames()) { RenameDetector rd = diffFmt.getRenameDetector(); rd.setRenameLimit(renameLimit.intValue()); @@ -203,7 +201,7 @@ class Log extends RevWalkTextBuiltin { if (!noStandardNotes || !additionalNoteRefs.isEmpty()) { createWalk(); - noteMaps = new LinkedHashMap<String, NoteMap>(); + noteMaps = new LinkedHashMap<>(); if (!noStandardNotes) { addNoteMap(Constants.R_NOTES_COMMITS); } @@ -217,18 +215,20 @@ class Log extends RevWalkTextBuiltin { } } - if (decorate) + if (decorate) { allRefsByPeeledObjectId = getRepository() .getAllRefsByPeeledObjectId(); - + } super.run(); + } catch (Exception e) { + throw die(e.getMessage(), e); } finally { diffFmt.close(); } } private void addNoteMap(String notesRef) throws IOException { - Ref notes = db.getRef(notesRef); + Ref notes = db.exactRef(notesRef); if (notes == null) return; RevCommit notesCommit = argWalk.parseCommit(notes.getObjectId()); @@ -237,7 +237,7 @@ class Log extends RevWalkTextBuiltin { } @Override - protected void show(final RevCommit c) throws Exception { + protected void show(RevCommit c) throws Exception { outw.print(CLIText.get().commitLabel); outw.print(" "); //$NON-NLS-1$ c.getId().copyTo(outbuffer, outw); @@ -255,6 +255,9 @@ class Log extends RevWalkTextBuiltin { } outw.println(); + if (showSignature) { + showSignature(c); + } final PersonIdent author = c.getAuthorIdent(); outw.println(MessageFormat.format(CLIText.get().authorInfo, author.getName(), author.getEmailAddress())); outw.println(MessageFormat.format(CLIText.get().dateInfo, @@ -262,7 +265,7 @@ class Log extends RevWalkTextBuiltin { outw.println(); final String[] lines = c.getFullMessage().split("\n"); //$NON-NLS-1$ - for (final String s : lines) { + for (String s : lines) { outw.print(" "); //$NON-NLS-1$ outw.print(s); outw.println(); @@ -273,16 +276,35 @@ class Log extends RevWalkTextBuiltin { if (showNotes(c)) outw.println(); - if (c.getParentCount() <= 1 && (showNameAndStatusOnly || showPatch)) + if (c.getParentCount() <= 1 && (showNameAndStatusOnly || showPatch + || showNameOnly)) { showDiff(c); + } outw.flush(); } + private void showSignature(RevCommit c) throws IOException { + if (c.getRawGpgSignature() == null) { + return; + } + SignatureVerification verification = SignatureVerifiers.verify(db, + config, c); + if (verification == null) { + return; + } + VerificationUtils.writeVerification(outw, verification, + verification.verifierName(), c.getCommitterIdent()); + } + /** + * Show notes for given commit + * * @param c + * given commit * @return <code>true</code> if at least one note was printed, * <code>false</code> otherwise * @throws IOException + * if an IO error occurred */ private boolean showNotes(RevCommit c) throws IOException { if (noteMaps == null) @@ -309,12 +331,17 @@ class Log extends RevWalkTextBuiltin { /** * @param c + * given commit * @param map + * note map * @param label + * label * @param emptyLine + * whether to start with an empty line * @return <code>true</code> if note was printed, <code>false</code> * otherwise * @throws IOException + * if an IO error occurred */ private boolean showNotes(RevCommit c, NoteMap map, String label, boolean emptyLine) @@ -324,7 +351,7 @@ class Log extends RevWalkTextBuiltin { return false; if (emptyLine) outw.println(); - outw.print("Notes"); + outw.print("Notes"); //$NON-NLS-1$ if (label != null) { outw.print(" ("); //$NON-NLS-1$ outw.print(label); @@ -350,9 +377,11 @@ class Log extends RevWalkTextBuiltin { : null; final RevTree b = c.getTree(); - if (showNameAndStatusOnly) + if (showNameAndStatusOnly) { Diff.nameStatus(outw, diffFmt.scan(a, b)); - else { + } else if (showNameOnly) { + Diff.nameOnly(outw, diffFmt.scan(a, b)); + } else { outw.flush(); diffFmt.format(a, b); diffFmt.flush(); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java new file mode 100644 index 0000000000..741e02a881 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsFiles.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2017, Matthias Sohn <matthias.sohn@sap.com> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.pgm; + +import static java.util.function.Predicate.isEqual; +import static org.eclipse.jgit.lib.FileMode.EXECUTABLE_FILE; +import static org.eclipse.jgit.lib.FileMode.GITLINK; +import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE; +import static org.eclipse.jgit.lib.FileMode.SYMLINK; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.errors.RevisionSyntaxException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.util.QuotedString; +import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.StopOptionHandler; + +@Command(common = true, usage = "usage_LsFiles") +class LsFiles extends TextBuiltin { + + @Option(name = "--", metaVar = "metaVar_paths", handler = StopOptionHandler.class) + private List<String> paths = new ArrayList<>(); + + @Override + protected void run() { + try (RevWalk rw = new RevWalk(db); + TreeWalk tw = new TreeWalk(db)) { + final ObjectId head = db.resolve(Constants.HEAD); + if (head == null) { + return; + } + RevCommit c = rw.parseCommit(head); + CanonicalTreeParser p = new CanonicalTreeParser(); + p.reset(rw.getObjectReader(), c.getTree()); + tw.reset(); // drop the first empty tree, which we do not need here + if (!paths.isEmpty()) { + tw.setFilter(PathFilterGroup.createFromStrings(paths)); + } + tw.addTree(p); + tw.addTree(new DirCacheIterator(db.readDirCache())); + tw.setRecursive(true); + while (tw.next()) { + if (filterFileMode(tw, EXECUTABLE_FILE, GITLINK, REGULAR_FILE, + SYMLINK)) { + outw.println( + QuotedString.GIT_PATH.quote(tw.getPathString())); + } + } + } catch (RevisionSyntaxException | IOException e) { + throw die(e.getMessage(), e); + } + } + + private boolean filterFileMode(TreeWalk tw, FileMode... modes) { + return Arrays.stream(modes).anyMatch(isEqual(tw.getFileMode(0)) + .or(isEqual(tw.getFileMode(1)))); + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java index 6262ad2469..89ceed256d 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java @@ -1,56 +1,23 @@ /* * Copyright (C) 2009, Google Inc. * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; import java.io.IOException; -import java.util.Comparator; import java.util.TreeSet; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.LsRemoteCommand; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Ref; import org.kohsuke.args4j.Argument; @@ -67,24 +34,31 @@ class LsRemote extends TextBuiltin { @Option(name = "--timeout", metaVar = "metaVar_service", usage = "usage_abortConnectionIfNoActivity") int timeout = -1; + @Option(name = "--symref", usage = "usage_lsRemoteSymref") + private boolean symref; + @Argument(index = 0, metaVar = "metaVar_uriish", required = true) private String remote; @Override - protected void run() throws Exception { + protected void run() { LsRemoteCommand command = Git.lsRemoteRepository().setRemote(remote) .setTimeout(timeout).setHeads(heads).setTags(tags); - TreeSet<Ref> refs = new TreeSet<Ref>(new Comparator<Ref>() { - - public int compare(Ref r1, Ref r2) { - return r1.getName().compareTo(r2.getName()); + TreeSet<Ref> refs = new TreeSet<>( + (Ref r1, Ref r2) -> r1.getName().compareTo(r2.getName())); + try { + refs.addAll(command.call()); + for (Ref r : refs) { + if (symref && r.isSymbolic()) { + show(r.getTarget(), r.getName()); + } + show(r.getObjectId(), r.getName()); + if (r.getPeeledObjectId() != null) { + show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$ + } } - }); - refs.addAll(command.call()); - for (final Ref r : refs) { - show(r.getObjectId(), r.getName()); - if (r.getPeeledObjectId() != null) - show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$ + } catch (GitAPIException | IOException e) { + throw die(e.getMessage(), e); } } @@ -93,11 +67,20 @@ class LsRemote extends TextBuiltin { return false; } - private void show(final AnyObjectId id, final String name) + private void show(AnyObjectId id, String name) throws IOException { outw.print(id.name()); outw.print('\t'); outw.print(name); outw.println(); } + + private void show(Ref ref, String name) + throws IOException { + outw.print("ref: "); //$NON-NLS-1$ + outw.print(ref.getName()); + outw.print('\t'); + outw.print(name); + outw.println(); + } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java index 4b16ed8800..34b48c1b1a 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsTree.java @@ -1,50 +1,18 @@ /* * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -67,32 +35,37 @@ class LsTree extends TextBuiltin { private AbstractTreeIterator tree; @Argument(index = 1) - @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class) - private List<String> paths = new ArrayList<String>(); + @Option(name = "--", metaVar = "metaVar_paths", handler = StopOptionHandler.class) + private List<String> paths = new ArrayList<>(); @Override - protected void run() throws Exception { - final TreeWalk walk = new TreeWalk(db); - walk.reset(); // drop the first empty tree, which we do not need here - if (paths.size() > 0) - walk.setFilter(PathFilterGroup.createFromStrings(paths)); - walk.setRecursive(recursive); - walk.addTree(tree); + protected void run() { + try (TreeWalk walk = new TreeWalk(db)) { + walk.reset(); // drop the first empty tree, which we do not need here + if (!paths.isEmpty()) { + walk.setFilter(PathFilterGroup.createFromStrings(paths)); + } + walk.setRecursive(recursive); + walk.addTree(tree); - while (walk.next()) { - final FileMode mode = walk.getFileMode(0); - if (mode == FileMode.TREE) - outw.print('0'); - outw.print(mode); - outw.print(' '); - outw.print(Constants.typeString(mode.getObjectType())); + while (walk.next()) { + final FileMode mode = walk.getFileMode(0); + if (mode == FileMode.TREE) { + outw.print('0'); + } + outw.print(mode); + outw.print(' '); + outw.print(Constants.typeString(mode.getObjectType())); - outw.print(' '); - outw.print(walk.getObjectId(0).name()); + outw.print(' '); + outw.print(walk.getObjectId(0).name()); - outw.print('\t'); - outw.print(QuotedString.GIT_PATH.quote(walk.getPathString())); - outw.println(); + outw.print('\t'); + outw.print(QuotedString.GIT_PATH.quote(walk.getPathString())); + outw.println(); + } + } catch (IOException e) { + throw die(e.getMessage(), e); } } } 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 7151de794d..8df9bad740 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 @@ -1,51 +1,21 @@ /* * Copyright (C) 2006, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import static java.nio.charset.StandardCharsets.UTF_8; + import java.io.File; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; @@ -53,22 +23,32 @@ import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; +import java.util.Locale; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import org.eclipse.jgit.awtui.AwtAuthenticator; import org.eclipse.jgit.awtui.AwtCredentialsProvider; import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.lfs.BuiltinLFS; import org.eclipse.jgit.lib.Repository; 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; -import org.kohsuke.args4j.ExampleMode; import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.OptionHandlerFilter; -/** Command line entry point. */ +/** + * Command line entry point. + */ public class Main { @Option(name = "--help", usage = "usage_displayThisHelpText", aliases = { "-h" }) private boolean help; @@ -86,15 +66,43 @@ public class Main { private TextBuiltin subcommand; @Argument(index = 1, metaVar = "metaVar_arg") - private List<String> arguments = new ArrayList<String>(); + private List<String> arguments = new ArrayList<>(); + + PrintWriter writer; + + private ExecutorService gcExecutor; + + /** + * <p>Constructor for Main.</p> + */ + public Main() { + HttpTransport.setConnectionFactory(new HttpClientConnectionFactory()); + BuiltinLFS.register(); + gcExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { + private final ThreadFactory baseFactory = Executors + .defaultThreadFactory(); + + @Override + public Thread newThread(Runnable taskBody) { + Thread thr = baseFactory.newThread(taskBody); + thr.setName("JGit-autoGc"); //$NON-NLS-1$ + return thr; + } + }); + } /** * Execute the command line. * * @param argv * arguments. + * @throws java.lang.Exception + * if an error occurred */ - public static void main(final String[] argv) { + public static void main(String[] argv) throws Exception { + // make sure built-in filters are registered + BuiltinLFS.register(); + new Main().run(argv); } @@ -113,8 +121,11 @@ public class Main { * * @param argv * arguments. + * @throws java.lang.Exception + * if an error occurred */ - protected void run(final String[] argv) { + protected void run(String[] argv) throws Exception { + writer = createErrorWriter(); try { if (!installConsole()) { AwtAuthenticator.install(); @@ -123,12 +134,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,52 +149,63 @@ 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); } + gcExecutor.shutdown(); + gcExecutor.awaitTermination(10, TimeUnit.MINUTES); + } + + PrintWriter createErrorWriter() { + return new PrintWriter(new OutputStreamWriter(System.err, UTF_8)); } - private void execute(final String[] argv) throws Exception { - final CmdLineParser clp = new CmdLineParser(this); - PrintWriter writer = new PrintWriter(System.err); + private void execute(String[] argv) throws Exception { + 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); } } if (argv.length == 0 || help) { - final String ex = clp.printExample(ExampleMode.ALL, CLIText.get().resourceBundle()); - writer.println("jgit" + ex + " command [ARG ...]"); //$NON-NLS-1$ + final String ex = clp.printExample(OptionHandlerFilter.ALL, + CLIText.get().resourceBundle()); + writer.println("jgit" + ex + " command [ARG ...]"); //$NON-NLS-1$ //$NON-NLS-2$ if (help) { writer.println(); clp.printUsage(writer, CLIText.get().resourceBundle()); @@ -191,44 +215,67 @@ public class Main { writer.println(CLIText.get().mostCommonlyUsedCommandsAre); final CommandRef[] common = CommandCatalog.common(); int width = 0; - for (final CommandRef c : common) + for (CommandRef c : common) { width = Math.max(width, c.getName().length()); + } width += 2; - for (final CommandRef c : common) { + for (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) { - String cmdId = Version.class.getSimpleName().toLowerCase(); + String cmdId = Version.class.getSimpleName() + .toLowerCase(Locale.ROOT); subcommand = CommandCatalog.get(cmdId).create(); } 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()])); + cmd.execute(arguments.toArray(new String[0])); } 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(TextBuiltin cmd) throws IOException { + if (cmd.requiresRepository()) { + cmd.init(openGitDir(gitdir), null); + } else { + cmd.init(null, gitdir); + } + } + + /** + * @param status + * exit status code, nonzero value indicates an error + * @param t + * can be {@code null} + * @throws Exception + * if an IO error occurred + */ + void exit(int status, Exception t) throws Exception { + writer.flush(); + System.exit(status); + } + /** * Evaluate the {@code --git-dir} option and open the repository. * @@ -236,7 +283,7 @@ public class Main { * the {@code --git-dir} option given on the command line. May be * null if it was not supplied. * @return the repository to operate on. - * @throws IOException + * @throws java.io.IOException * the repository cannot be opened. */ protected Repository openGitDir(String aGitdir) throws IOException { @@ -254,31 +301,21 @@ public class Main { install("org.eclipse.jgit.console.ConsoleAuthenticator"); //$NON-NLS-1$ install("org.eclipse.jgit.console.ConsoleCredentialsProvider"); //$NON-NLS-1$ return true; - } catch (ClassNotFoundException e) { - return false; - } catch (NoClassDefFoundError e) { + } catch (ClassNotFoundException | NoClassDefFoundError + | UnsupportedClassVersionError e) { return false; - } catch (UnsupportedClassVersionError e) { - return false; - - } catch (IllegalArgumentException e) { - throw new RuntimeException(CLIText.get().cannotSetupConsole, e); - } catch (SecurityException e) { - throw new RuntimeException(CLIText.get().cannotSetupConsole, e); - } catch (IllegalAccessException e) { - throw new RuntimeException(CLIText.get().cannotSetupConsole, e); - } catch (InvocationTargetException e) { - throw new RuntimeException(CLIText.get().cannotSetupConsole, e); - } catch (NoSuchMethodException e) { + } catch (IllegalArgumentException | SecurityException + | IllegalAccessException | InvocationTargetException + | NoSuchMethodException e) { throw new RuntimeException(CLIText.get().cannotSetupConsole, e); } } - private static void install(final String name) + private static void install(String name) 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(); @@ -291,39 +328,70 @@ public class Main { /** * Configure the JRE's standard HTTP based on <code>http_proxy</code>. * <p> - * The popular libcurl library honors the <code>http_proxy</code> - * environment variable as a means of specifying an HTTP proxy for requests - * made behind a firewall. This is not natively recognized by the JRE, so - * this method can be used by command line utilities to configure the JRE - * before the first request is sent. + * The popular libcurl library honors the <code>http_proxy</code>, + * <code>https_proxy</code> environment variables as a means of specifying + * an HTTP/S proxy for requests made behind a firewall. This is not natively + * recognized by the JRE, so this method can be used by command line + * utilities to configure the JRE before the first request is sent. The + * information found in the environment variables is copied to the + * associated system properties. This is not done when the system properties + * are already set. The default way of telling java programs about proxies + * (the system properties) takes precedence over environment variables. * * @throws MalformedURLException - * the value in <code>http_proxy</code> is unsupportable. + * the value in <code>http_proxy</code> or + * <code>https_proxy</code> is unsupportable. */ - private static void configureHttpProxy() throws MalformedURLException { - final String s = System.getenv("http_proxy"); //$NON-NLS-1$ - if (s == null || s.equals("")) //$NON-NLS-1$ - return; - - final URL u = new URL((s.indexOf("://") == -1) ? "http://" + s : s); //$NON-NLS-1$ //$NON-NLS-2$ - if (!"http".equals(u.getProtocol())) //$NON-NLS-1$ - throw new MalformedURLException(MessageFormat.format(CLIText.get().invalidHttpProxyOnlyHttpSupported, s)); - - final String proxyHost = u.getHost(); - final int proxyPort = u.getPort(); - - System.setProperty("http.proxyHost", proxyHost); //$NON-NLS-1$ - if (proxyPort > 0) - System.setProperty("http.proxyPort", String.valueOf(proxyPort)); //$NON-NLS-1$ - - final String userpass = u.getUserInfo(); - if (userpass != null && userpass.contains(":")) { //$NON-NLS-1$ - final int c = userpass.indexOf(':'); - final String user = userpass.substring(0, c); - final String pass = userpass.substring(c + 1); - CachedAuthenticator - .add(new CachedAuthenticator.CachedAuthentication( - proxyHost, proxyPort, user, pass)); + static void configureHttpProxy() throws MalformedURLException { + for (String protocol : new String[] { "http", "https" }) { //$NON-NLS-1$ //$NON-NLS-2$ + if (System.getProperty(protocol + ".proxyHost") != null) { //$NON-NLS-1$ + continue; + } + String s = System.getenv(protocol + "_proxy"); //$NON-NLS-1$ + if (s == null && protocol.equals("https")) { //$NON-NLS-1$ + s = System.getenv("HTTPS_PROXY"); //$NON-NLS-1$ + } + if (s == null || s.isEmpty()) { + continue; + } + + URL u = new URL(!s.contains("://") ? protocol + "://" + s : s); //$NON-NLS-1$ //$NON-NLS-2$ + if (!u.getProtocol().startsWith("http")) //$NON-NLS-1$ + throw new MalformedURLException(MessageFormat.format( + CLIText.get().invalidHttpProxyOnlyHttpSupported, s)); + + final String proxyHost = u.getHost(); + final int proxyPort = u.getPort(); + + System.setProperty(protocol + ".proxyHost", proxyHost); //$NON-NLS-1$ + if (proxyPort > 0) + System.setProperty(protocol + ".proxyPort", //$NON-NLS-1$ + String.valueOf(proxyPort)); + + final String userpass = u.getUserInfo(); + if (userpass != null && userpass.contains(":")) { //$NON-NLS-1$ + final int c = userpass.indexOf(':'); + final String user = userpass.substring(0, c); + final String pass = userpass.substring(c + 1); + CachedAuthenticator.add( + new CachedAuthenticator.CachedAuthentication(proxyHost, + proxyPort, user, pass)); + } + } + } + + /** + * 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 93c4388dbc..b78998dd74 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 @@ -1,61 +1,32 @@ /* - * Copyright (C) 2011, 2014 Christian Halstrick <christian.halstrick@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2011, 2014 Christian Halstrick <christian.halstrick@sap.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; + import java.io.IOException; import java.text.MessageFormat; import java.util.Map; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.MergeCommand; -import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.MergeCommand.FastForwardMode; +import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.errors.CheckoutConflictException; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.merge.ContentMergeStrategy; import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; import org.eclipse.jgit.pgm.internal.CLIText; @@ -101,117 +72,163 @@ class Merge extends TextBuiltin { @Option(name = "-m", usage = "usage_message") private String message; + private ContentMergeStrategy contentStrategy = null; + + @Option(name = "--strategy-option", aliases = { "-X" }, + metaVar = "metaVar_extraArgument", usage = "usage_extraArgument") + void extraArg(String name) { + if (ContentMergeStrategy.OURS.name().equalsIgnoreCase(name)) { + contentStrategy = ContentMergeStrategy.OURS; + } else if (ContentMergeStrategy.THEIRS.name().equalsIgnoreCase(name)) { + contentStrategy = ContentMergeStrategy.THEIRS; + } else { + throw die(MessageFormat.format(CLIText.get().unknownExtraArgument, name)); + } + } + @Override - protected void run() throws Exception { - if (squash && ff == FastForwardMode.NO_FF) + protected void run() { + if (squash && ff == FastForwardMode.NO_FF) { throw die(CLIText.get().cannotCombineSquashWithNoff); + } // determine the merge strategy if (strategyName != null) { mergeStrategy = MergeStrategy.get(strategyName); - if (mergeStrategy == null) + if (mergeStrategy == null) { throw die(MessageFormat.format( CLIText.get().unknownMergeStrategy, strategyName)); + } } - // determine the other revision we want to merge with HEAD - final Ref srcRef = db.getRef(ref); - final ObjectId src = db.resolve(ref + "^{commit}"); //$NON-NLS-1$ - if (src == null) - throw die(MessageFormat.format( - CLIText.get().refDoesNotExistOrNoCommit, ref)); - - Ref oldHead = db.getRef(Constants.HEAD); - Git git = new Git(db); - MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy) - .setSquash(squash).setFastForward(ff).setCommit(!noCommit); - if (srcRef != null) - mergeCmd.include(srcRef); - else - mergeCmd.include(src); - - if (message != null) - mergeCmd.setMessage(message); - - MergeResult result; try { - result = mergeCmd.call(); - } catch (CheckoutConflictException e) { - result = new MergeResult(e.getConflictingPaths()); // CHECKOUT_CONFLICT - } + // determine the other revision we want to merge with HEAD + final Ref srcRef = db.findRef(ref); + final ObjectId src = db.resolve(ref + "^{commit}"); //$NON-NLS-1$ + if (src == null) { + throw die(MessageFormat + .format(CLIText.get().refDoesNotExistOrNoCommit, ref)); + } + + Ref oldHead = getOldHead(); + MergeResult result; + try (Git git = new Git(db)) { + MergeCommand mergeCmd = git.merge() + .setStrategy(mergeStrategy) + .setContentMergeStrategy(contentStrategy) + .setSquash(squash) + .setFastForward(ff) + .setCommit(!noCommit); + if (srcRef != null) { + mergeCmd.include(srcRef); + } else { + mergeCmd.include(src); + } + + if (message != null) { + mergeCmd.setMessage(message); + } - switch (result.getMergeStatus()) { - case ALREADY_UP_TO_DATE: - if (squash) - outw.print(CLIText.get().nothingToSquash); - outw.println(CLIText.get().alreadyUpToDate); - break; - case FAST_FORWARD: - ObjectId oldHeadId = oldHead.getObjectId(); - outw.println(MessageFormat.format(CLIText.get().updating, oldHeadId - .abbreviate(7).name(), result.getNewHead().abbreviate(7) - .name())); - outw.println(result.getMergeStatus().toString()); - break; - case CHECKOUT_CONFLICT: - outw.println(CLIText.get().mergeCheckoutConflict); - for (String collidingPath : result.getCheckoutConflicts()) - outw.println("\t" + collidingPath); //$NON-NLS-1$ - outw.println(CLIText.get().mergeCheckoutFailed); - break; - case CONFLICTING: - for (String collidingPath : result.getConflicts().keySet()) - outw.println(MessageFormat.format(CLIText.get().mergeConflict, - collidingPath)); - outw.println(CLIText.get().mergeFailed); - break; - case FAILED: - for (Map.Entry<String, MergeFailureReason> entry : result - .getFailingPaths().entrySet()) - switch (entry.getValue()) { - case DIRTY_WORKTREE: - case DIRTY_INDEX: - outw.println(CLIText.get().dontOverwriteLocalChanges); - outw.println(" " + entry.getKey()); //$NON-NLS-1$ - break; - case COULD_NOT_DELETE: - outw.println(CLIText.get().cannotDeleteFile); - outw.println(" " + entry.getKey()); //$NON-NLS-1$ - break; + try { + result = mergeCmd.call(); + } catch (CheckoutConflictException e) { + result = new MergeResult(e.getConflictingPaths()); // CHECKOUT_CONFLICT + } + } + + switch (result.getMergeStatus()) { + case ALREADY_UP_TO_DATE: + if (squash) { + outw.print(CLIText.get().nothingToSquash); + } + outw.println(CLIText.get().alreadyUpToDate); + break; + case FAST_FORWARD: + ObjectId oldHeadId = oldHead.getObjectId(); + if (oldHeadId != null) { + String oldId = oldHeadId + .abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH).name(); + String newId = result.getNewHead() + .abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH).name(); + outw.println(MessageFormat.format(CLIText.get().updating, + oldId, newId)); } - break; - case MERGED: - String name; - if (!isMergedInto(oldHead, src)) - name = mergeStrategy.getName(); - else - name = "recursive"; //$NON-NLS-1$ - outw.println(MessageFormat.format(CLIText.get().mergeMadeBy, name)); - break; - case MERGED_NOT_COMMITTED: - outw.println(CLIText.get().mergeWentWellStoppedBeforeCommitting); - break; - case MERGED_SQUASHED: - case FAST_FORWARD_SQUASHED: - case MERGED_SQUASHED_NOT_COMMITTED: - outw.println(CLIText.get().mergedSquashed); - outw.println(CLIText.get().mergeWentWellStoppedBeforeCommitting); - break; - case ABORTED: - throw die(CLIText.get().ffNotPossibleAborting); - case NOT_SUPPORTED: - outw.println(MessageFormat.format( - CLIText.get().unsupportedOperation, result.toString())); + outw.println(result.getMergeStatus().toString()); + break; + case CHECKOUT_CONFLICT: + outw.println(CLIText.get().mergeCheckoutConflict); + for (String collidingPath : result.getCheckoutConflicts()) { + outw.println("\t" + collidingPath); //$NON-NLS-1$ + } + outw.println(CLIText.get().mergeCheckoutFailed); + break; + case CONFLICTING: + for (String collidingPath : result.getConflicts().keySet()) + outw.println(MessageFormat.format( + CLIText.get().mergeConflict, collidingPath)); + outw.println(CLIText.get().mergeFailed); + break; + case FAILED: + for (Map.Entry<String, MergeFailureReason> entry : result + .getFailingPaths().entrySet()) + switch (entry.getValue()) { + case DIRTY_WORKTREE: + case DIRTY_INDEX: + outw.println(CLIText.get().dontOverwriteLocalChanges); + outw.println(" " + entry.getKey()); //$NON-NLS-1$ + break; + case COULD_NOT_DELETE: + outw.println(CLIText.get().cannotDeleteFile); + outw.println(" " + entry.getKey()); //$NON-NLS-1$ + break; + } + break; + case MERGED: + MergeStrategy strategy = isMergedInto(oldHead, src) + ? MergeStrategy.RECURSIVE + : mergeStrategy; + outw.println(MessageFormat.format(CLIText.get().mergeMadeBy, + strategy.getName())); + break; + case MERGED_NOT_COMMITTED: + outw.println( + CLIText.get().mergeWentWellStoppedBeforeCommitting); + break; + case MERGED_SQUASHED: + case FAST_FORWARD_SQUASHED: + case MERGED_SQUASHED_NOT_COMMITTED: + outw.println(CLIText.get().mergedSquashed); + outw.println( + CLIText.get().mergeWentWellStoppedBeforeCommitting); + break; + case ABORTED: + throw die(CLIText.get().ffNotPossibleAborting); + case NOT_SUPPORTED: + outw.println(MessageFormat.format( + CLIText.get().unsupportedOperation, result.toString())); + } + } catch (GitAPIException | IOException e) { + throw die(e.getMessage(), e); + } + + } + + private Ref getOldHead() throws IOException { + Ref oldHead = db.exactRef(Constants.HEAD); + if (oldHead == null) { + throw die(CLIText.get().onBranchToBeBorn); } + return oldHead; } private boolean isMergedInto(Ref oldHead, AnyObjectId src) throws IOException { - RevWalk revWalk = new RevWalk(db); - ObjectId oldHeadObjectId = oldHead.getPeeledObjectId(); - if (oldHeadObjectId == null) - oldHeadObjectId = oldHead.getObjectId(); - RevCommit oldHeadCommit = revWalk.lookupCommit(oldHeadObjectId); - RevCommit srcCommit = revWalk.lookupCommit(src); - return revWalk.isMergedInto(oldHeadCommit, srcCommit); + try (RevWalk revWalk = new RevWalk(db)) { + ObjectId oldHeadObjectId = oldHead.getPeeledObjectId(); + if (oldHeadObjectId == null) + oldHeadObjectId = oldHead.getObjectId(); + RevCommit oldHeadCommit = revWalk.lookupCommit(oldHeadObjectId); + RevCommit srcCommit = revWalk.lookupCommit(src); + return revWalk.isMergedInto(oldHeadCommit, srcCommit); + } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java index 29cbb53a98..a29c4d9f36 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java @@ -1,56 +1,24 @@ /* * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import java.io.IOException; import java.util.ArrayList; import java.util.List; -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.filter.RevFilter; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; @Command(usage = "usage_MergeBase") class MergeBase extends TextBuiltin { @@ -58,24 +26,25 @@ class MergeBase extends TextBuiltin { private boolean all; @Argument(index = 0, metaVar = "metaVar_commitish", required = true) - void commit_0(final RevCommit c) { - commits.add(c); - } - - @Argument(index = 1, metaVar = "metaVar_commitish", required = true) - private final List<RevCommit> commits = new ArrayList<RevCommit>(); + private List<RevCommit> commits = new ArrayList<>(); @Override - protected void run() throws Exception { - for (final RevCommit c : commits) - argWalk.markStart(c); - argWalk.setRevFilter(RevFilter.MERGE_BASE); - int max = all ? Integer.MAX_VALUE : 1; - while (max-- > 0) { - final RevCommit b = argWalk.next(); - if (b == null) - break; - outw.println(b.getId().name()); + protected void run() { + try { + for (RevCommit c : commits) { + argWalk.markStart(c); + } + argWalk.setRevFilter(RevFilter.MERGE_BASE); + int max = all ? Integer.MAX_VALUE : 1; + while (max-- > 0) { + final RevCommit b = argWalk.next(); + if (b == null) { + break; + } + outw.println(b.getId().name()); + } + } catch (IOException e) { + throw die(e.getMessage(), e); } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java new file mode 100644 index 0000000000..9d0b65c479 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com> + * Copyright (C) 2019, Tim Neumann <tim.neumann@advantest.com> + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.TreeMap; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.Status; +import org.eclipse.jgit.api.StatusCommand; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.diff.ContentSource; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheCheckout; +import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.errors.RevisionSyntaxException; +import org.eclipse.jgit.internal.diffmergetool.ExternalMergeTool; +import org.eclipse.jgit.internal.diffmergetool.FileElement; +import org.eclipse.jgit.internal.diffmergetool.MergeTools; +import org.eclipse.jgit.internal.diffmergetool.ToolException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.CoreConfig.EolStreamType; +import org.eclipse.jgit.lib.IndexDiff.StageState; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.internal.BooleanTriState; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.WorkingTreeOptions; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.util.FS.ExecutionResult; +import org.eclipse.jgit.util.SystemReader; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.RestOfArgumentsHandler; + +@Command(name = "mergetool", common = true, usage = "usage_MergeTool") +class MergeTool extends TextBuiltin { + private MergeTools mergeTools; + + private Optional<String> toolName = Optional.empty(); + + @Option(name = "--tool", aliases = { + "-t" }, metaVar = "metaVar_tool", usage = "usage_ToolForMerge") + void setToolName(String name) { + toolName = Optional.of(name); + } + + private BooleanTriState prompt = BooleanTriState.UNSET; + + @Option(name = "--prompt", usage = "usage_prompt") + void setPrompt(@SuppressWarnings("unused") boolean on) { + prompt = BooleanTriState.TRUE; + } + + @Option(name = "--no-prompt", aliases = { "-y" }, usage = "usage_noPrompt") + void noPrompt(@SuppressWarnings("unused") boolean on) { + prompt = BooleanTriState.FALSE; + } + + @Option(name = "--tool-help", usage = "usage_toolHelp") + private boolean toolHelp; + + private boolean gui = false; + + @Option(name = "--gui", aliases = { "-g" }, usage = "usage_MergeGuiTool") + void setGui(@SuppressWarnings("unused") boolean on) { + gui = true; + } + + @Option(name = "--no-gui", usage = "usage_noGui") + void noGui(@SuppressWarnings("unused") boolean on) { + gui = false; + } + + @Argument(required = false, index = 0, metaVar = "metaVar_paths") + @Option(name = "--", metaVar = "metaVar_paths", handler = RestOfArgumentsHandler.class) + protected List<String> filterPaths; + + private BufferedReader inputReader; + + @Override + protected void init(Repository repository, String gitDir) { + super.init(repository, gitDir); + mergeTools = new MergeTools(repository); + inputReader = new BufferedReader( + new InputStreamReader(ins, + SystemReader.getInstance().getDefaultCharset())); + } + + enum MergeResult { + SUCCESSFUL, FAILED, ABORTED + } + + @Override + protected void run() { + try { + if (toolHelp) { + showToolHelp(); + } else { + // get the changed files + Map<String, StageState> files = getFiles(); + if (files.size() > 0) { + merge(files); + } else { + outw.println(CLIText.get().mergeToolNoFiles); + } + } + outw.flush(); + } catch (Exception e) { + throw die(e.getMessage(), e); + } + } + + private void informUserNoTool(List<String> tools) { + try { + StringBuilder toolNames = new StringBuilder(); + for (String name : tools) { + toolNames.append(name + " "); //$NON-NLS-1$ + } + outw.println(MessageFormat + .format(CLIText.get().mergeToolPromptToolName, toolNames)); + outw.flush(); + } catch (IOException e) { + throw new IllegalStateException("Cannot output text", e); //$NON-NLS-1$ + } + } + + private void merge(Map<String, StageState> files) throws Exception { + // sort file names + List<String> mergedFilePaths = new ArrayList<>(files.keySet()); + Collections.sort(mergedFilePaths); + // show the files + StringBuilder mergedFiles = new StringBuilder(); + for (String mergedFilePath : mergedFilePaths) { + mergedFiles.append(MessageFormat.format("{0}\n", mergedFilePath)); //$NON-NLS-1$ + } + outw.println(MessageFormat.format(CLIText.get().mergeToolMerging, + mergedFiles)); + outw.flush(); + boolean showPrompt = mergeTools.isInteractive(); + if (prompt != BooleanTriState.UNSET) { + showPrompt = prompt == BooleanTriState.TRUE; + } + // merge the files + MergeResult mergeResult = MergeResult.SUCCESSFUL; + for (String mergedFilePath : mergedFilePaths) { + // if last merge failed... + if (mergeResult == MergeResult.FAILED) { + // check if user wants to continue + if (showPrompt && !isContinueUnresolvedPaths()) { + mergeResult = MergeResult.ABORTED; + } + } + // aborted ? + if (mergeResult == MergeResult.ABORTED) { + break; + } + // get file stage state and merge + StageState fileState = files.get(mergedFilePath); + if (fileState == StageState.BOTH_MODIFIED) { + mergeResult = mergeModified(mergedFilePath, showPrompt); + } else if ((fileState == StageState.DELETED_BY_US) + || (fileState == StageState.DELETED_BY_THEM)) { + mergeResult = mergeDeleted(mergedFilePath, + fileState == StageState.DELETED_BY_US); + } else { + outw.println(MessageFormat.format( + CLIText.get().mergeToolUnknownConflict, + mergedFilePath)); + mergeResult = MergeResult.ABORTED; + } + } + } + + private MergeResult mergeModified(String mergedFilePath, boolean showPrompt) + throws Exception { + outw.println(MessageFormat.format(CLIText.get().mergeToolNormalConflict, + mergedFilePath)); + outw.flush(); + boolean isMergeSuccessful = true; + ContentSource baseSource = ContentSource.create(db.newObjectReader()); + ContentSource localSource = ContentSource.create(db.newObjectReader()); + ContentSource remoteSource = ContentSource.create(db.newObjectReader()); + // temporary directory if mergetool.writeToTemp == true + File tempDir = mergeTools.createTempDirectory(); + // the parent directory for temp files (can be same as tempDir or just + // the worktree dir) + File tempFilesParent = tempDir != null ? tempDir : db.getWorkTree(); + try { + FileElement base = null; + FileElement local = null; + FileElement remote = null; + FileElement merged = new FileElement(mergedFilePath, + FileElement.Type.MERGED, db.getWorkTree()); + DirCache cache = db.readDirCache(); + try (RevWalk revWalk = new RevWalk(db); + TreeWalk treeWalk = new TreeWalk(db, + revWalk.getObjectReader())) { + treeWalk.setFilter( + PathFilterGroup.createFromStrings(mergedFilePath)); + DirCacheIterator cacheIter = new DirCacheIterator(cache); + treeWalk.addTree(cacheIter); + while (treeWalk.next()) { + if (treeWalk.isSubtree()) { + treeWalk.enterSubtree(); + continue; + } + final EolStreamType eolStreamType = treeWalk + .getEolStreamType(CHECKOUT_OP); + final String filterCommand = treeWalk.getFilterCommand( + Constants.ATTR_FILTER_TYPE_SMUDGE); + WorkingTreeOptions opt = db.getConfig() + .get(WorkingTreeOptions.KEY); + CheckoutMetadata checkoutMetadata = new CheckoutMetadata( + eolStreamType, filterCommand); + DirCacheEntry entry = treeWalk + .getTree(DirCacheIterator.class).getDirCacheEntry(); + if (entry == null) { + continue; + } + ObjectId id = entry.getObjectId(); + switch (entry.getStage()) { + case DirCacheEntry.STAGE_1: + base = new FileElement(mergedFilePath, + FileElement.Type.BASE); + DirCacheCheckout.getContent(db, mergedFilePath, + checkoutMetadata, + baseSource.open(mergedFilePath, id), opt, + new FileOutputStream( + base.createTempFile(tempFilesParent))); + break; + case DirCacheEntry.STAGE_2: + local = new FileElement(mergedFilePath, + FileElement.Type.LOCAL); + DirCacheCheckout.getContent(db, mergedFilePath, + checkoutMetadata, + localSource.open(mergedFilePath, id), opt, + new FileOutputStream( + local.createTempFile(tempFilesParent))); + break; + case DirCacheEntry.STAGE_3: + remote = new FileElement(mergedFilePath, + FileElement.Type.REMOTE); + DirCacheCheckout.getContent(db, mergedFilePath, + checkoutMetadata, + remoteSource.open(mergedFilePath, id), opt, + new FileOutputStream(remote + .createTempFile(tempFilesParent))); + break; + } + } + } + if ((local == null) || (remote == null)) { + throw die(MessageFormat.format(CLIText.get().mergeToolDied, + mergedFilePath)); + } + long modifiedBefore = merged.getFile().lastModified(); + try { + // TODO: check how to return the exit-code of the + // tool to jgit / java runtime ? + // int rc =... + Optional<ExecutionResult> optionalResult = mergeTools.merge( + local, remote, merged, base, tempDir, toolName, prompt, + gui, this::promptForLaunch, this::informUserNoTool); + if (optionalResult.isPresent()) { + ExecutionResult result = optionalResult.get(); + Charset defaultCharset = SystemReader.getInstance() + .getDefaultCharset(); + outw.println(new String(result.getStdout().toByteArray(), + defaultCharset)); + outw.flush(); + errw.println(new String(result.getStderr().toByteArray(), + defaultCharset)); + errw.flush(); + } else { + return MergeResult.ABORTED; + } + } catch (ToolException e) { + isMergeSuccessful = false; + outw.println(e.getResultStdout()); + outw.flush(); + errw.println(e.getMessage()); + errw.println(MessageFormat.format( + CLIText.get().mergeToolMergeFailed, mergedFilePath)); + errw.flush(); + if (e.isCommandExecutionError()) { + throw die(CLIText.get().mergeToolExecutionError, e); + } + } + // if merge was successful check file modified + if (isMergeSuccessful) { + long modifiedAfter = merged.getFile().lastModified(); + if (modifiedBefore == modifiedAfter) { + outw.println(MessageFormat.format( + CLIText.get().mergeToolFileUnchanged, + mergedFilePath)); + isMergeSuccessful = !showPrompt || isMergeSuccessful(); + } + } + // if automatically or manually successful + // -> add the file to the index + if (isMergeSuccessful) { + addFile(mergedFilePath); + } + } finally { + baseSource.close(); + localSource.close(); + remoteSource.close(); + } + return isMergeSuccessful ? MergeResult.SUCCESSFUL : MergeResult.FAILED; + } + + private MergeResult mergeDeleted(String mergedFilePath, boolean deletedByUs) + throws Exception { + outw.println(MessageFormat.format(CLIText.get().mergeToolFileUnchanged, + mergedFilePath)); + if (deletedByUs) { + outw.println(CLIText.get().mergeToolDeletedConflictByUs); + } else { + outw.println(CLIText.get().mergeToolDeletedConflictByThem); + } + int mergeDecision = getDeletedMergeDecision(); + if (mergeDecision == 1) { + // add modified file + addFile(mergedFilePath); + } else if (mergeDecision == -1) { + // remove deleted file + rmFile(mergedFilePath); + } else { + return MergeResult.ABORTED; + } + return MergeResult.SUCCESSFUL; + } + + private void addFile(String fileName) throws Exception { + try (Git git = new Git(db)) { + git.add().addFilepattern(fileName).call(); + } + } + + private void rmFile(String fileName) throws Exception { + try (Git git = new Git(db)) { + git.rm().addFilepattern(fileName).call(); + } + } + + private boolean hasUserAccepted(String message) throws IOException { + boolean yes = true; + outw.print(message + " "); //$NON-NLS-1$ + outw.flush(); + BufferedReader br = inputReader; + String line = null; + while ((line = br.readLine()) != null) { + if (line.equalsIgnoreCase("y")) { //$NON-NLS-1$ + yes = true; + break; + } else if (line.equalsIgnoreCase("n")) { //$NON-NLS-1$ + yes = false; + break; + } + outw.print(message); + outw.flush(); + } + return yes; + } + + private boolean isContinueUnresolvedPaths() throws IOException { + return hasUserAccepted(CLIText.get().mergeToolContinueUnresolvedPaths); + } + + private boolean isMergeSuccessful() throws IOException { + return hasUserAccepted(CLIText.get().mergeToolWasMergeSuccessfull); + } + + private boolean promptForLaunch(String toolNamePrompt) { + try { + boolean launch = true; + outw.print(MessageFormat.format(CLIText.get().mergeToolLaunch, + toolNamePrompt) + " "); //$NON-NLS-1$ + outw.flush(); + BufferedReader br = inputReader; + String line = null; + if ((line = br.readLine()) != null) { + if (!line.equalsIgnoreCase("y") && !line.equalsIgnoreCase("")) { //$NON-NLS-1$ //$NON-NLS-2$ + launch = false; + } + } + return launch; + } catch (IOException e) { + throw new IllegalStateException("Cannot output text", e); //$NON-NLS-1$ + } + } + + private int getDeletedMergeDecision() throws IOException { + int ret = 0; // abort + final String message = CLIText.get().mergeToolDeletedMergeDecision + + " "; //$NON-NLS-1$ + outw.print(message); + outw.flush(); + BufferedReader br = inputReader; + String line = null; + while ((line = br.readLine()) != null) { + if (line.equalsIgnoreCase("m")) { //$NON-NLS-1$ + ret = 1; // modified + break; + } else if (line.equalsIgnoreCase("d")) { //$NON-NLS-1$ + ret = -1; // deleted + break; + } else if (line.equalsIgnoreCase("a")) { //$NON-NLS-1$ + break; + } + outw.print(message); + outw.flush(); + } + return ret; + } + + private void showToolHelp() throws IOException { + Map<String, ExternalMergeTool> predefTools = mergeTools + .getPredefinedTools(true); + StringBuilder availableToolNames = new StringBuilder(); + StringBuilder notAvailableToolNames = new StringBuilder(); + for (String name : predefTools.keySet()) { + if (predefTools.get(name).isAvailable()) { + availableToolNames.append(MessageFormat.format("\t\t{0}\n", name)); //$NON-NLS-1$ + } else { + notAvailableToolNames.append(MessageFormat.format("\t\t{0}\n", name)); //$NON-NLS-1$ + } + } + StringBuilder userToolNames = new StringBuilder(); + Map<String, ExternalMergeTool> userTools = mergeTools + .getUserDefinedTools(); + for (String name : userTools.keySet()) { + userToolNames.append(MessageFormat.format("\t\t{0}.cmd {1}\n", //$NON-NLS-1$ + name, userTools.get(name).getCommand())); + } + outw.println(MessageFormat.format( + CLIText.get().mergeToolHelpSetToFollowing, availableToolNames, + userToolNames, notAvailableToolNames)); + } + + private Map<String, StageState> getFiles() throws RevisionSyntaxException, + NoWorkTreeException, GitAPIException { + Map<String, StageState> files = new TreeMap<>(); + try (Git git = new Git(db)) { + StatusCommand statusCommand = git.status(); + if (filterPaths != null && filterPaths.size() > 0) { + for (String path : filterPaths) { + statusCommand.addPath(path); + } + } + Status status = statusCommand.call(); + files = status.getConflictingStageState(); + } + return files; + } + +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java new file mode 100644 index 0000000000..1844223cc9 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jgit.internal.storage.file.ObjectDirectory; +import org.eclipse.jgit.internal.storage.file.Pack; +import org.eclipse.jgit.internal.storage.file.PackFile; +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexPrettyPrinter; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +@Command(common = true, usage = "usage_MultiPackIndex") +@SuppressWarnings("nls") +class MultiPackIndex extends TextBuiltin { + @Argument(index = 0, required = true, usage = "write, print") + private String command; + + @Option(name = "--midx") + private String midxPath; + + /** {@inheritDoc} */ + @Override + protected void run() throws IOException { + switch (command) { + case "print": + printMultiPackIndex(); + break; + case "write": + writeMultiPackIndex(); + break; + default: + outw.println("Unknown command " + command); + } + } + + private void printMultiPackIndex() { + if (midxPath == null || midxPath.isEmpty()) { + throw die("'print' requires the path of a multipack " + + "index file with --midx option."); + } + + try (FileInputStream is = new FileInputStream(midxPath)) { + PrintWriter pw = new PrintWriter(outw, true); + MultiPackIndexPrettyPrinter.prettyPrint(is.readAllBytes(), pw); + } catch (FileNotFoundException e) { + throw die(true, e); + } catch (IOException e) { + throw die(true, e); + } + } + + private void writeMultiPackIndex() throws IOException { + if (!(db.getObjectDatabase() instanceof ObjectDirectory)) { + throw die("This repository object db doesn't have packs"); + } + + File midx; + if (midxPath == null || midxPath.isEmpty()) { + midx = new File(((ObjectDirectory) db.getObjectDatabase()) + .getPackDirectory(), "multi-pack-index"); + } else { + midx = new File(midxPath); + } + + errw.println("Writing " + midx.getAbsolutePath()); + + ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase(); + + Map<String, PackIndex> indexes = new HashMap<>(); + for (Pack pack : odb.getPacks()) { + PackFile packFile = pack.getPackFile().create(PackExt.INDEX); + try { + indexes.put(packFile.getName(), pack.getIndex()); + } catch (IOException e) { + throw die("Cannot open index in pack", e); + } + } + + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + try (FileOutputStream out = new FileOutputStream(midxPath)) { + writer.write(NullProgressMonitor.INSTANCE, out, indexes); + } catch (IOException e) { + throw die("Cannot write midx " + midxPath, e); + } + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ObjectSizeIndex.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ObjectSizeIndex.java new file mode 100644 index 0000000000..a40c3964fb --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ObjectSizeIndex.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_USE_OBJECT_SIZE_INDEX; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_PACK_SECTION; + +import java.io.IOException; + +import org.eclipse.jgit.internal.storage.file.ObjectDirectory; +import org.eclipse.jgit.internal.storage.file.Pack; +import org.eclipse.jgit.internal.storage.file.PackObjectSizeIndexHelper; +import org.eclipse.jgit.lib.TextProgressMonitor; +import org.kohsuke.args4j.Argument; + +@Command(common = true, usage = "usage_ObjectSizeIndex") +@SuppressWarnings("nls") +class ObjectSizeIndex extends TextBuiltin { + @Argument(index = 0, required = true, usage = "write, check") + private String command; + + @Override + protected void run() throws IOException { + switch (command) { + case "write": + writeObjectSizeIndex(); + break; + case "check": + checkObjectSizeIndex(); + break; + default: + outw.println("Unknown command " + command); + } + } + + private void writeObjectSizeIndex() throws IOException { + if (!(db.getObjectDatabase() instanceof ObjectDirectory)) { + throw die("This repository object db doesn't have packs"); + } + PackObjectSizeIndexHelper.forAllPacks( + (ObjectDirectory) db.getObjectDatabase(), + new TextProgressMonitor()); + } + + private void checkObjectSizeIndex() throws IOException { + if (!(db.getObjectDatabase() instanceof ObjectDirectory)) { + throw die("This repository object db doesn't have packs"); + } + + outw.println("Object size index configuration for this repo:"); + outw.println("\n* Writing:"); + printInt(CONFIG_PACK_SECTION, CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX); + + outw.println("\n* Reading:"); + printBoolean(CONFIG_PACK_SECTION, CONFIG_KEY_USE_OBJECT_SIZE_INDEX); + + outw.println("\n* Packs - have object size index:"); + for (Pack pack : ((ObjectDirectory) db.getObjectDatabase()) + .getPacks()) { + String name = pack.getPackName(); + boolean hasObjectSizeIndex = pack.hasObjectSizeIndex(); + outw.println( + String.format(" - %s - %b", name, hasObjectSizeIndex)); + } + } + + private void printInt(String section, String name) throws IOException { + Integer value = db.getConfig().getInt(section, name); + String key = String.join(".", section, name); + outw.println(" - " + key + " = " + value); + } + + private void printBoolean(String section, String name) throws IOException { + Boolean value = db.getConfig().getBoolean(section, name); + String key = String.join(".", section, name); + outw.println(" - " + key + " = " + value); + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java new file mode 100644 index 0000000000..ee05f5ca0b --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, 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 v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.TextProgressMonitor; +import org.kohsuke.args4j.Option; + +@Command(common = true, usage = "usage_PackRefs") +class PackRefs extends TextBuiltin { + @Option(name = "--all", usage = "usage_All") + private boolean all; + + @Override + protected void run() { + Git git = Git.wrap(db); + try { + git.packRefs().setProgressMonitor(new TextProgressMonitor(errw)) + .setAll(all).call(); + } catch (GitAPIException e) { + throw die(e.getMessage(), e); + } + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java index 4268f214fd..b1a5daaa65 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java @@ -1,51 +1,16 @@ /* * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> - * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; -import static java.lang.Character.valueOf; - import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; @@ -53,6 +18,7 @@ import java.util.List; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.PushCommand; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; @@ -77,11 +43,14 @@ class Push extends TextBuiltin { private String remote = Constants.DEFAULT_REMOTE_NAME; @Argument(index = 1, metaVar = "metaVar_refspec") - private final List<RefSpec> refSpecs = new ArrayList<RefSpec>(); + private List<RefSpec> refSpecs = new ArrayList<>(); @Option(name = "--all") private boolean all; + @Option(name = "--atomic") + private boolean atomic; + @Option(name = "--tags") private boolean tags; @@ -105,29 +74,41 @@ class Push extends TextBuiltin { @Option(name = "--dry-run") private boolean dryRun; + @Option(name = "--push-option", aliases = { "-t" }) + private List<String> pushOptions = new ArrayList<>(); + private boolean shownURI; @Override - protected void run() throws Exception { - Git git = new Git(db); - PushCommand push = git.push(); - push.setDryRun(dryRun); - push.setForce(force); - push.setProgressMonitor(new TextProgressMonitor(errw)); - push.setReceivePack(receivePack); - push.setRefSpecs(refSpecs); - if (all) - push.setPushAll(); - if (tags) - push.setPushTags(); - push.setRemote(remote); - push.setThin(thin); - push.setTimeout(timeout); - Iterable<PushResult> results = push.call(); - for (PushResult result : results) { - try (ObjectReader reader = db.newObjectReader()) { - printPushResult(reader, result.getURI(), result); + protected void run() { + try (Git git = new Git(db)) { + PushCommand push = git.push(); + push.setDryRun(dryRun); + push.setForce(force); + push.setProgressMonitor(new TextProgressMonitor(errw)); + push.setReceivePack(receivePack); + push.setRefSpecs(refSpecs); + if (all) { + push.setPushAll(); + } + if (tags) { + push.setPushTags(); + } + push.setRemote(remote); + push.setThin(thin); + push.setAtomic(atomic); + push.setTimeout(timeout); + if (!pushOptions.isEmpty()) { + push.setPushOptions(pushOptions); + } + Iterable<PushResult> results = push.call(); + for (PushResult result : results) { + try (ObjectReader reader = db.newObjectReader()) { + printPushResult(reader, result.getURI(), result); + } } + } catch (GitAPIException | IOException e) { + throw die(e.getMessage(), e); } } @@ -137,7 +118,7 @@ class Push extends TextBuiltin { boolean everythingUpToDate = true; // at first, print up-to-date ones... - for (final RemoteRefUpdate rru : result.getRemoteUpdates()) { + for (RemoteRefUpdate rru : result.getRemoteUpdates()) { if (rru.getStatus() == Status.UP_TO_DATE) { if (verbose) printRefUpdateResult(reader, uri, result, rru); @@ -145,13 +126,13 @@ class Push extends TextBuiltin { everythingUpToDate = false; } - for (final RemoteRefUpdate rru : result.getRemoteUpdates()) { + for (RemoteRefUpdate rru : result.getRemoteUpdates()) { // ...then successful updates... if (rru.getStatus() == Status.OK) printRefUpdateResult(reader, uri, result, rru); } - for (final RemoteRefUpdate rru : result.getRemoteUpdates()) { + for (RemoteRefUpdate rru : result.getRemoteUpdates()) { // ...finally, others (problematic) if (rru.getStatus() != Status.OK && rru.getStatus() != Status.UP_TO_DATE) @@ -177,15 +158,15 @@ class Push extends TextBuiltin { switch (rru.getStatus()) { case OK: if (rru.isDelete()) - printUpdateLine('-', "[deleted]", null, remoteName, null); + printUpdateLine('-', "[deleted]", null, remoteName, null); //$NON-NLS-1$ else { final Ref oldRef = result.getAdvertisedRef(remoteName); if (oldRef == null) { final String summary; if (remoteName.startsWith(Constants.R_TAGS)) - summary = "[new tag]"; + summary = "[new tag]"; //$NON-NLS-1$ else - summary = "[new branch]"; + summary = "[new branch]"; //$NON-NLS-1$ printUpdateLine('*', summary, srcRef, remoteName, null); } else { boolean fastForward = rru.isFastForward(); @@ -201,16 +182,16 @@ class Push extends TextBuiltin { break; case NON_EXISTING: - printUpdateLine('X', "[no match]", null, remoteName, null); + printUpdateLine('X', "[no match]", null, remoteName, null); //$NON-NLS-1$ break; case REJECTED_NODELETE: - printUpdateLine('!', "[rejected]", null, remoteName, + printUpdateLine('!', "[rejected]", null, remoteName, //$NON-NLS-1$ CLIText.get().remoteSideDoesNotSupportDeletingRefs); break; case REJECTED_NONFASTFORWARD: - printUpdateLine('!', "[rejected]", srcRef, remoteName, + printUpdateLine('!', "[rejected]", srcRef, remoteName, //$NON-NLS-1$ CLIText.get().nonFastForward); break; @@ -218,22 +199,22 @@ class Push extends TextBuiltin { final String message = MessageFormat.format( CLIText.get().remoteRefObjectChangedIsNotExpectedOne, safeAbbreviate(reader, rru.getExpectedOldObjectId())); - printUpdateLine('!', "[rejected]", srcRef, remoteName, message); + printUpdateLine('!', "[rejected]", srcRef, remoteName, message); //$NON-NLS-1$ break; case REJECTED_OTHER_REASON: - printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru + printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru //$NON-NLS-1$ .getMessage()); break; case UP_TO_DATE: if (verbose) - printUpdateLine('=', "[up to date]", srcRef, remoteName, null); + printUpdateLine('=', "[up to date]", srcRef, remoteName, null); //$NON-NLS-1$ break; case NOT_ATTEMPTED: case AWAITING_REPORT: - printUpdateLine('?', "[unexpected push-process behavior]", srcRef, + printUpdateLine('?', "[unexpected push-process behavior]", srcRef, //$NON-NLS-1$ remoteName, rru.getMessage()); break; } @@ -250,7 +231,7 @@ class Push extends TextBuiltin { private void printUpdateLine(final char flag, final String summary, final String srcRef, final String destRef, final String message) throws IOException { - outw.format(" %c %-17s", valueOf(flag), summary); //$NON-NLS-1$ + outw.format(" %c %-17s", Character.valueOf(flag), summary); //$NON-NLS-1$ if (srcRef != null) outw.format(" %s ->", abbreviateRef(srcRef, true)); //$NON-NLS-1$ diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java index d7f895a300..f89a4d12be 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ReceivePack.java @@ -1,50 +1,18 @@ /* * Copyright (C) 2008-2009, Google Inc. - * Copyright (C) 2009-2010, Robin Rosenberg <robin.rosenberg@dewire.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2009-2010, Robin Rosenberg <robin.rosenberg@dewire.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; import java.io.File; +import java.io.IOException; import java.text.MessageFormat; import org.eclipse.jgit.errors.RepositoryNotFoundException; @@ -64,7 +32,7 @@ class ReceivePack extends TextBuiltin { } @Override - protected void run() throws Exception { + protected void run() { final org.eclipse.jgit.transport.ReceivePack rp; try { @@ -72,10 +40,16 @@ class ReceivePack extends TextBuiltin { db = key.open(true /* must exist */); } catch (RepositoryNotFoundException notFound) { throw die(MessageFormat.format(CLIText.get().notAGitRepository, - dstGitdir.getPath())); + dstGitdir.getPath()), notFound); + } catch (IOException e) { + throw die(e.getMessage(), e); } rp = new org.eclipse.jgit.transport.ReceivePack(db); - rp.receive(ins, outs, errs); + try { + rp.receive(ins, outs, errs); + } catch (IOException e) { + throw die(e.getMessage(), e); + } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java index aa90f8d50c..46485cc5ef 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java @@ -1,51 +1,22 @@ /* - * Copyright (C) 2012, Tomasz Zarna <tomasz.zarna@tasktop.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2012, Tomasz Zarna <tomasz.zarna@tasktop.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; + +import java.io.IOException; import java.util.Collection; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ReflogCommand; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ReflogEntry; import org.eclipse.jgit.lib.Repository; @@ -58,20 +29,25 @@ class Reflog extends TextBuiltin { private String ref; @Override - protected void run() throws Exception { - ReflogCommand cmd = new Git(db).reflog(); - if (ref != null) - cmd.setRef(ref); - Collection<ReflogEntry> entries = cmd.call(); - int i = 0; - for (ReflogEntry entry : entries) { - outw.println(toString(entry, i++)); + protected void run() { + try (Git git = new Git(db)) { + ReflogCommand cmd = git.reflog(); + if (ref != null) + cmd.setRef(ref); + Collection<ReflogEntry> entries = cmd.call(); + int i = 0; + for (ReflogEntry entry : entries) { + outw.println(toString(entry, i++)); + } + } catch (GitAPIException | IOException e) { + throw die(e.getMessage(), e); } } private String toString(ReflogEntry entry, int i) { final StringBuilder s = new StringBuilder(); - s.append(entry.getNewId().abbreviate(7).name()); + s.append(entry.getNewId().abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH) + .name()); s.append(" "); //$NON-NLS-1$ s.append(ref == null ? Constants.HEAD : Repository.shortenRefName(ref)); s.append("@{" + i + "}:"); //$NON-NLS-1$ //$NON-NLS-2$ 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 new file mode 100644 index 0000000000..a3100ac8ed --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.pgm; + +import java.io.IOException; +import java.io.StringWriter; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.RemoteAddCommand; +import org.eclipse.jgit.api.RemoteListCommand; +import org.eclipse.jgit.api.RemoteRemoveCommand; +import org.eclipse.jgit.api.RemoteSetUrlCommand; +import org.eclipse.jgit.api.RemoteSetUrlCommand.UriType; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.opt.CmdLineParser; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.util.io.ThrowingPrintWriter; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +@Command(common = false, usage = "usage_Remote") +class Remote extends TextBuiltin { + + @Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beVerbose") + private boolean verbose = false; + + @Option(name = "--prune", aliases = { + "-p" }, usage = "usage_pruneStaleTrackingRefs") + private boolean prune; + + @Option(name = "--push", usage = "usage_pushUrls") + private boolean push; + + @Argument(index = 0, metaVar = "metaVar_command") + private String command; + + @Argument(index = 1, metaVar = "metaVar_remoteName") + private String name; + + @Argument(index = 2, metaVar = "metaVar_uriish") + private String uri; + + @Override + protected void run() { + try (Git git = new Git(db)) { + if (command == null) { + RemoteListCommand cmd = git.remoteList(); + List<RemoteConfig> remotes = cmd.call(); + print(remotes); + return; + } + switch (command) { + case "add": //$NON-NLS-1$ + RemoteAddCommand add = git.remoteAdd(); + add.setName(name); + add.setUri(new URIish(uri)); + add.call(); + break; + case "remove": //$NON-NLS-1$ + case "rm": //$NON-NLS-1$ + RemoteRemoveCommand rm = git.remoteRemove(); + rm.setRemoteName(name); + rm.call(); + break; + case "set-url": //$NON-NLS-1$ + RemoteSetUrlCommand remoteSetUrl = git.remoteSetUrl(); + remoteSetUrl.setRemoteName(name); + remoteSetUrl.setRemoteUri(new URIish(uri)); + remoteSetUrl.setUriType(push ? UriType.PUSH : UriType.FETCH); + remoteSetUrl.call(); + break; + case "update": //$NON-NLS-1$ + Fetch fetch = new Fetch(); + fetch.init(db, gitdir); + StringWriter osw = new StringWriter(); + fetch.outw = new ThrowingPrintWriter(osw); + StringWriter esw = new StringWriter(); + fetch.errw = new ThrowingPrintWriter(esw); + List<String> fetchArgs = new ArrayList<>(); + if (verbose) { + fetchArgs.add("--verbose"); //$NON-NLS-1$ + } + if (prune) { + fetchArgs.add("--prune"); //$NON-NLS-1$ + } + if (name != null) { + fetchArgs.add(name); + } + fetch.execute(fetchArgs.toArray(new String[0])); + fetch.outw.flush(); + fetch.errw.flush(); + outw.println(osw.toString()); + errw.println(esw.toString()); + break; + default: + throw new JGitInternalException(MessageFormat + .format(CLIText.get().unknownSubcommand, command)); + } + } catch (Exception e) { + throw die(e.getMessage(), e); + } + } + + @Override + public void printUsage(String message, CmdLineParser clp) + throws IOException { + errw.println(message); + errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$ + errw.println("jgit remote add name uri-ish [--help (-h)]"); //$NON-NLS-1$ + errw.println("jgit remote remove name [--help (-h)]"); //$NON-NLS-1$ + errw.println("jgit remote rm name [--help (-h)]"); //$NON-NLS-1$ + errw.println( + "jgit remote [--verbose (-v)] update [name] [--prune (-p)] [--help (-h)]"); //$NON-NLS-1$ + errw.println("jgit remote set-url name uri-ish [--push] [--help (-h)]"); //$NON-NLS-1$ + + errw.println(); + clp.printUsage(errw, getResourceBundle()); + errw.println(); + + errw.flush(); + } + + private void print(List<RemoteConfig> remotes) throws IOException { + for (RemoteConfig remote : remotes) { + String remoteName = remote.getName(); + if (verbose) { + List<URIish> fetchURIs = remote.getURIs(); + List<URIish> pushURIs = remote.getPushURIs(); + + String fetchURI = ""; //$NON-NLS-1$ + if (!fetchURIs.isEmpty()) { + fetchURI = fetchURIs.get(0).toString(); + } else if (!pushURIs.isEmpty()) { + fetchURI = pushURIs.get(0).toString(); + } + + String pushURI = ""; //$NON-NLS-1$ + if (!pushURIs.isEmpty()) { + pushURI = pushURIs.get(0).toString(); + } else if (!fetchURIs.isEmpty()) { + pushURI = fetchURIs.get(0).toString(); + } + + outw.println( + String.format("%s\t%s (fetch)", remoteName, fetchURI)); //$NON-NLS-1$ + outw.println( + String.format("%s\t%s (push)", remoteName, pushURI)); //$NON-NLS-1$ + } else { + outw.println(remoteName); + } + } + } + +} 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 9b191e6796..da622e1130 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 @@ -1,47 +1,15 @@ /* - * Copyright (C) 2014, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2014, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.gitrepo.RepoCommand; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @@ -55,15 +23,19 @@ 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; @Override - protected void run() throws Exception { - new RepoCommand(db) - .setURI(uri) - .setPath(path) - .setGroups(groups) - .call(); + protected void run() { + try { + new RepoCommand(db) + .setURI(uri) + .setPath(path) + .setGroups(groups) + .call(); + } catch (GitAPIException e) { + throw die(e.getMessage(), e); + } } } 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 f4cbcafed1..f33cb6be71 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 @@ -1,53 +1,26 @@ /* - * Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import java.util.ArrayList; +import java.util.List; + import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ResetCommand; import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.pgm.internal.CLIText; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.RestOfArgumentsHandler; @Command(common = true, usage = "usage_reset") class Reset extends TextBuiltin { @@ -61,29 +34,47 @@ class Reset extends TextBuiltin { @Option(name = "--hard", usage = "usage_resetHard") private boolean hard = false; - @Argument(required = true, metaVar = "metaVar_name", usage = "usage_reset") + @Argument(required = false, index = 0, metaVar = "metaVar_commitish", usage = "usage_resetReference") private String commit; + @Argument(required = false, index = 1, metaVar = "metaVar_paths") + @Option(name = "--", metaVar = "metaVar_paths", handler = RestOfArgumentsHandler.class) + private List<String> paths = new ArrayList<>(); + @Override - protected void run() throws Exception { - ResetCommand command = new Git(db).reset(); - command.setRef(commit); - ResetType mode = null; - if (soft) - mode = selectMode(mode, ResetType.SOFT); - if (mixed) - mode = selectMode(mode, ResetType.MIXED); - if (hard) - mode = selectMode(mode, ResetType.HARD); - if (mode == null) - throw die("no reset mode set"); - command.setMode(mode); - command.call(); + protected void run() { + try (Git git = new Git(db)) { + ResetCommand command = git.reset(); + command.setRef(commit); + if (!paths.isEmpty()) { + for (String path : paths) { + command.addPath(path); + } + } else { + ResetType mode = null; + if (soft) { + mode = selectMode(mode, ResetType.SOFT); + } + if (mixed) { + mode = selectMode(mode, ResetType.MIXED); + } + if (hard) { + mode = selectMode(mode, ResetType.HARD); + } + if (mode == null) { + throw die(CLIText.get().resetNoMode); + } + command.setMode(mode); + } + command.call(); + } catch (GitAPIException e) { + throw die(e.getMessage(), e); + } } private static ResetType selectMode(ResetType mode, ResetType want) { if (mode != null) - throw die("reset modes are mutually exclusive, select one"); + throw die("reset modes are mutually exclusive, select one"); //$NON-NLS-1$ return want; } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java index 4420abec16..59fc5f296c 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevList.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -52,7 +19,7 @@ import org.eclipse.jgit.revwalk.RevTree; @Command(usage = "usage_RevList") class RevList extends RevWalkTextBuiltin { @Override - protected void show(final RevCommit c) throws Exception { + protected void show(RevCommit c) throws Exception { if (c.has(RevFlag.UNINTERESTING)) outw.print('-'); c.getId().copyTo(outbuffer, outw); @@ -65,7 +32,7 @@ class RevList extends RevWalkTextBuiltin { } @Override - protected void show(final ObjectWalk ow, final RevObject obj) + protected void show(ObjectWalk ow, RevObject obj) throws Exception { if (obj.has(RevFlag.UNINTERESTING)) outw.print('-'); 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 5530ac5c99..b1fb07b5b8 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 @@ -1,77 +1,66 @@ /* * Copyright (C) 2009, Daniel Cheng (aka SDiZ) <git@sdiz.net> * Copyright (C) 2009, Daniel Cheng (aka SDiZ) <j16sdiz+freenet@gmail.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2015 Thomas Meyer <thomas@m3y3r.de> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; -import static org.eclipse.jgit.lib.RefDatabase.ALL; - +import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.opt.CmdLineParser; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.Option; @Command(usage = "usage_RevParse") class RevParse extends TextBuiltin { @Option(name = "--all", usage = "usage_RevParseAll") - boolean all = false; + boolean all; + + @Option(name = "--verify", usage = "usage_RevParseVerify") + boolean verify; @Argument(index = 0, metaVar = "metaVar_commitish") - private final List<ObjectId> commits = new ArrayList<ObjectId>(); + private List<ObjectId> commits = new ArrayList<>(); @Override - protected void run() throws Exception { - if (all) { - Map<String, Ref> allRefs = db.getRefDatabase().getRefs(ALL); - for (final Ref r : allRefs.values()) - outw.println(r.getObjectId().name()); - } else { - for (final ObjectId o : commits) - outw.println(o.name()); + protected void run() { + try { + if (all) { + for (Ref r : db.getRefDatabase().getRefs()) { + 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) { + final CmdLineParser clp = new CmdLineParser(this); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().needSingleRevision)); + } + + for (ObjectId o : commits) { + outw.println(o.name()); + } + } + } catch (IOException | CmdLineException e) { + throw die(e.getMessage(), e); } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java index d6063c31b4..51e597c57a 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -47,16 +14,12 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -import java.util.Map; -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; import org.eclipse.jgit.diff.DiffConfig; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; import org.eclipse.jgit.revwalk.FollowFilter; @@ -73,6 +36,8 @@ import org.eclipse.jgit.revwalk.filter.MessageRevFilter; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; abstract class RevWalkTextBuiltin extends TextBuiltin { RevWalk walk; @@ -93,7 +58,7 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { private final EnumSet<RevSort> sorting = EnumSet.noneOf(RevSort.class); - private void enableRevSort(final RevSort type, final boolean on) { + private void enableRevSort(RevSort type, boolean on) { if (on) sorting.add(type); else @@ -101,22 +66,22 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { } @Option(name = "--date-order") - void enableDateOrder(final boolean on) { + void enableDateOrder(boolean on) { enableRevSort(RevSort.COMMIT_TIME_DESC, on); } @Option(name = "--topo-order") - void enableTopoOrder(final boolean on) { + void enableTopoOrder(boolean on) { enableRevSort(RevSort.TOPO, on); } @Option(name = "--reverse") - void enableReverse(final boolean on) { + void enableReverse(boolean on) { enableRevSort(RevSort.REVERSE, on); } @Option(name = "--boundary") - void enableBoundary(final boolean on) { + void enableBoundary(boolean on) { enableRevSort(RevSort.BOUNDARY, on); } @@ -124,25 +89,25 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { private String followPath; @Argument(index = 0, metaVar = "metaVar_commitish") - private final List<RevCommit> commits = new ArrayList<RevCommit>(); + private List<RevCommit> commits = new ArrayList<>(); - @Option(name = "--", metaVar = "metaVar_path", multiValued = true, handler = PathTreeFilterHandler.class) + @Option(name = "--", metaVar = "metaVar_path", handler = PathTreeFilterHandler.class) protected TreeFilter pathFilter = TreeFilter.ALL; - private final List<RevFilter> revLimiter = new ArrayList<RevFilter>(); + private final List<RevFilter> revLimiter = new ArrayList<>(); @Option(name = "--author") - void addAuthorRevFilter(final String who) { + void addAuthorRevFilter(String who) { revLimiter.add(AuthorRevFilter.create(who)); } @Option(name = "--committer") - void addCommitterRevFilter(final String who) { + void addCommitterRevFilter(String who) { revLimiter.add(CommitterRevFilter.create(who)); } @Option(name = "--grep") - void addCMessageRevFilter(final String msg) { + void addCMessageRevFilter(String msg) { revLimiter.add(MessageRevFilter.create(msg)); } @@ -152,7 +117,7 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { @Override protected void run() throws Exception { walk = createWalk(); - for (final RevSort s : sorting) + for (RevSort s : sorting) walk.sort(s, true); if (pathFilter == TreeFilter.ALL) { @@ -163,6 +128,9 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { walk.setTreeFilter(AndTreeFilter.create(pathFilter, TreeFilter.ANY_DIFF)); } + if (parents) { + walk.setRewriteParents(true); + } if (revLimiter.size() == 1) walk.setRevFilter(revLimiter.get(0)); @@ -170,9 +138,7 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { walk.setRevFilter(AndRevFilter.create(revLimiter)); if (all) { - Map<String, Ref> refs = - db.getRefDatabase().getRefs(RefDatabase.ALL); - for (Ref a : refs.values()) { + for (Ref a : db.getRefDatabase().getRefs()) { ObjectId oid = a.getPeeledObjectId(); if (oid == null) oid = a.getObjectId(); @@ -190,7 +156,7 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { throw die(MessageFormat.format(CLIText.get().cannotResolve, Constants.HEAD)); commits.add(walk.parseCommit(head)); } - for (final RevCommit c : commits) { + for (RevCommit c : commits) { final RevCommit real = argWalk == walk ? c : walk.parseCommit(c); if (c.has(RevFlag.UNINTERESTING)) walk.markUninteresting(real); @@ -210,6 +176,11 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { } } + /** + * Create RevWalk + * + * @return a {@link org.eclipse.jgit.revwalk.RevWalk} object. + */ protected RevWalk createWalk() { RevWalk result; if (objects) @@ -222,9 +193,16 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { return result; } + /** + * Loop the walk + * + * @return number of RevCommits walked + * @throws java.lang.Exception + * if any. + */ protected int walkLoop() throws Exception { int n = 0; - for (final RevCommit c : walk) { + for (RevCommit c : walk) { if (++n > maxCount && maxCount >= 0) break; show(c); @@ -248,10 +226,11 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { * RevWalkTextBuiltin. * * @param c - * The current {@link RevCommit} + * The current {@link org.eclipse.jgit.revwalk.RevCommit} * @throws Exception + * if an error occurred */ - protected abstract void show(final RevCommit c) throws Exception; + protected abstract void show(RevCommit c) throws Exception; /** * "Show" the current RevCommit when called from the main processing loop. @@ -260,10 +239,12 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { * process RevCommits. * * @param objectWalk - * the {@link ObjectWalk} used by {@link #walkLoop()} + * the {@link org.eclipse.jgit.revwalk.ObjectWalk} used by + * {@link #walkLoop()} * @param currentObject - * The current {@link RevObject} + * The current {@link org.eclipse.jgit.revwalk.RevObject} * @throws Exception + * if an error occurred */ protected void show(final ObjectWalk objectWalk, final RevObject currentObject) throws Exception { diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java index 816b3104c2..234da1a1c5 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Rm.java @@ -1,45 +1,12 @@ /* * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> - * Copyright (C) 2008, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -49,24 +16,27 @@ import java.util.List; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.RmCommand; +import org.eclipse.jgit.api.errors.GitAPIException; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; import org.kohsuke.args4j.spi.StopOptionHandler; @Command(usage = "usage_StopTrackingAFile", common = true) class Rm extends TextBuiltin { - @Argument(metaVar = "metaVar_path", usage = "usage_path", multiValued = true, required = true) - + @Argument(metaVar = "metaVar_path", usage = "usage_path", required = true) @Option(name = "--", handler = StopOptionHandler.class) - private List<String> paths = new ArrayList<String>(); - + private List<String> paths = new ArrayList<>(); @Override - protected void run() throws Exception { - RmCommand command = new Git(db).rm(); - for (String p : paths) - command.addFilepattern(p); - command.call(); + protected void run() { + try (Git git = new Git(db)) { + RmCommand command = git.rm(); + for (String p : paths) { + command.addFilepattern(p); + } + command.call(); + } catch (GitAPIException e) { + throw die(e.getMessage(), e); + } } - } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java index b668139b5e..a3a6782a71 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java @@ -1,57 +1,23 @@ /* * Copyright (C) 2010, Google Inc. * Copyright (C) 2006-2008, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; import java.io.BufferedOutputStream; import java.io.IOException; -import java.text.DateFormat; import java.text.MessageFormat; -import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Locale; -import java.util.TimeZone; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.RawTextComparator; @@ -59,11 +25,17 @@ import org.eclipse.jgit.diff.RenameDetector; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.RevisionSyntaxException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.GpgConfig; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; +import org.eclipse.jgit.lib.SignatureVerifiers; import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.internal.VerificationUtils; import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevObject; @@ -72,24 +44,31 @@ import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.eclipse.jgit.util.RawParseUtils; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_show") class Show extends TextBuiltin { - private final TimeZone myTZ = TimeZone.getDefault(); + private final ZoneId myTZ = ZoneId.systemDefault(); - private final DateFormat fmt; + private final DateTimeFormatter fmt; - private final DiffFormatter diffFmt = new DiffFormatter( // - new BufferedOutputStream(System.out)); + private DiffFormatter diffFmt; + + private boolean showNameOnly = false; + + private boolean showNameAndStatusOnly = false; @Argument(index = 0, metaVar = "metaVar_object") private String objectName; - @Option(name = "--", metaVar = "metaVar_path", multiValued = true, handler = PathTreeFilterHandler.class) + @Option(name = "--", metaVar = "metaVar_path", handler = PathTreeFilterHandler.class) protected TreeFilter pathFilter = TreeFilter.ALL; + @Option(name = "--show-signature", usage = "usage_showSignature") + private boolean showSignature; + // BEGIN -- Options shared with Diff @Option(name = "-p", usage = "usage_showPatch") boolean showPatch; @@ -106,7 +85,22 @@ class Show extends TextBuiltin { private Integer renameLimit; @Option(name = "--name-status", usage = "usage_nameStatus") - private boolean showNameAndStatusOnly; + void nameAndStatusOnly(boolean on) { + if (showNameOnly) { + throw new IllegalArgumentException( + CLIText.get().cannotUseNameStatusOnlyAndNameOnly); + } + showNameAndStatusOnly = on; + } + + @Option(name = "--name-only", usage = "usage_nameOnly") + void nameOnly(boolean on) { + if (showNameAndStatusOnly) { + throw new IllegalArgumentException( + CLIText.get().cannotUseNameStatusOnlyAndNameOnly); + } + showNameOnly = on; + } @Option(name = "--ignore-space-at-eol") void ignoreSpaceAtEol(@SuppressWarnings("unused") boolean on) { @@ -162,27 +156,36 @@ class Show extends TextBuiltin { // END -- Options shared with Diff Show() { - fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US); //$NON-NLS-1$ + fmt = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy ZZ", //$NON-NLS-1$ + Locale.US); + } + + @Override + protected void init(Repository repository, String gitDir) { + super.init(repository, gitDir); + diffFmt = new DiffFormatter(new BufferedOutputStream(outs)); } @SuppressWarnings("boxing") @Override - protected void run() throws Exception { + protected void run() { diffFmt.setRepository(db); try { diffFmt.setPathFilter(pathFilter); - if (detectRenames != null) + if (detectRenames != null) { diffFmt.setDetectRenames(detectRenames.booleanValue()); + } if (renameLimit != null && diffFmt.isDetectRenames()) { RenameDetector rd = diffFmt.getRenameDetector(); rd.setRenameLimit(renameLimit.intValue()); } ObjectId objectId; - if (objectName == null) + if (objectName == null) { objectId = db.resolve(Constants.HEAD); - else + } else { objectId = db.resolve(objectName); + } try (RevWalk rw = new RevWalk(db)) { RevObject obj = rw.parseAny(objectId); @@ -216,6 +219,8 @@ class Show extends TextBuiltin { obj.getType())); } } + } catch (RevisionSyntaxException | IOException e) { + throw die(e.getMessage(), e); } finally { diffFmt.close(); } @@ -227,44 +232,54 @@ class Show extends TextBuiltin { outw.print(tag.getTagName()); outw.println(); - final PersonIdent tagger = tag.getTaggerIdent(); + PersonIdent tagger = tag.getTaggerIdent(); if (tagger != null) { outw.println(MessageFormat.format(CLIText.get().taggerInfo, tagger.getName(), tagger.getEmailAddress())); - final TimeZone taggerTZ = tagger.getTimeZone(); - fmt.setTimeZone(taggerTZ != null ? taggerTZ : myTZ); + ZoneId taggerTZ = tagger.getZoneId(); + String formattedTaggerTime = fmt + .withZone(taggerTZ != null ? taggerTZ : myTZ) + .format(tagger.getWhenAsInstant()); outw.println(MessageFormat.format(CLIText.get().dateInfo, - fmt.format(tagger.getWhen()))); + formattedTaggerTime)); } outw.println(); - final String[] lines = tag.getFullMessage().split("\n"); //$NON-NLS-1$ - for (final String s : lines) { - outw.print(" "); //$NON-NLS-1$ - outw.print(s); - outw.println(); + String fullMessage = tag.getFullMessage(); + if (!fullMessage.isEmpty()) { + String[] lines = tag.getFullMessage().split("\n"); //$NON-NLS-1$ + for (String s : lines) { + outw.println(s); + } + } + byte[] rawSignature = tag.getRawGpgSignature(); + if (rawSignature != null) { + String[] lines = RawParseUtils.decode(rawSignature).split("\n"); //$NON-NLS-1$ + for (String s : lines) { + outw.println(s); + } } - outw.println(); } private void show(RevTree obj) throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, IOException { - final TreeWalk walk = new TreeWalk(db); - walk.reset(); - walk.addTree(obj); - - while (walk.next()) { - outw.print(walk.getPathString()); - final FileMode mode = walk.getFileMode(0); - if (mode == FileMode.TREE) - outw.print("/"); //$NON-NLS-1$ - outw.println(); + try (TreeWalk walk = new TreeWalk(db)) { + walk.reset(); + walk.addTree(obj); + + while (walk.next()) { + outw.print(walk.getPathString()); + final FileMode mode = walk.getFileMode(0); + if (mode == FileMode.TREE) + outw.print("/"); //$NON-NLS-1$ + outw.println(); + } } } - private void show(RevWalk rw, final RevCommit c) throws Exception { + private void show(RevWalk rw, RevCommit c) throws IOException { char[] outbuffer = new char[Constants.OBJECT_ID_LENGTH * 2]; outw.print(CLIText.get().commitLabel); @@ -272,18 +287,24 @@ class Show extends TextBuiltin { c.getId().copyTo(outbuffer, outw); outw.println(); + if (showSignature) { + showSignature(c); + } + final PersonIdent author = c.getAuthorIdent(); outw.println(MessageFormat.format(CLIText.get().authorInfo, author.getName(), author.getEmailAddress())); - final TimeZone authorTZ = author.getTimeZone(); - fmt.setTimeZone(authorTZ != null ? authorTZ : myTZ); + final ZoneId authorTZ = author.getZoneId(); + String formattedAuthorTime = fmt + .withZone(authorTZ != null ? authorTZ : myTZ) + .format(author.getWhenAsInstant()); outw.println(MessageFormat.format(CLIText.get().dateInfo, - fmt.format(author.getWhen()))); + formattedAuthorTime)); outw.println(); final String[] lines = c.getFullMessage().split("\n"); //$NON-NLS-1$ - for (final String s : lines) { + for (String s : lines) { outw.print(" "); //$NON-NLS-1$ outw.print(s); outw.println(); @@ -301,13 +322,29 @@ class Show extends TextBuiltin { final RevTree a = c.getParent(0).getTree(); final RevTree b = c.getTree(); - if (showNameAndStatusOnly) + if (showNameAndStatusOnly) { Diff.nameStatus(outw, diffFmt.scan(a, b)); - else { + } else if (showNameOnly) { + Diff.nameOnly(outw, diffFmt.scan(a, b)); + } else { outw.flush(); diffFmt.format(a, b); diffFmt.flush(); } outw.println(); } + + private void showSignature(RevCommit c) throws IOException { + if (c.getRawGpgSignature() == null) { + return; + } + GpgConfig config = new GpgConfig(db.getConfig()); + SignatureVerification verification = SignatureVerifiers.verify(db, + config, c); + if (verification == null) { + throw die(CLIText.get().logNoSignatureVerifier, null); + } + VerificationUtils.writeVerification(outw, verification, + verification.verifierName(), c.getCommitterIdent()); + } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ShowRef.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ShowRef.java index e9d9df6a19..64b182e17d 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ShowRef.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ShowRef.java @@ -1,81 +1,48 @@ /* * Copyright (C) 2010, Google Inc. * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; -import static org.eclipse.jgit.lib.RefDatabase.ALL; - import java.io.IOException; -import java.util.Map; -import java.util.SortedMap; +import java.util.List; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefComparator; -import org.eclipse.jgit.util.RefMap; @Command(usage = "usage_ShowRef") class ShowRef extends TextBuiltin { @Override - protected void run() throws Exception { - for (final Ref r : getSortedRefs()) { - show(r.getObjectId(), r.getName()); - if (r.getPeeledObjectId() != null) - show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$ + protected void run() { + try { + for (Ref r : getSortedRefs()) { + show(r.getObjectId(), r.getName()); + if (r.getPeeledObjectId() != null) { + show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$ + } + } + } catch (IOException e) { + throw die(e.getMessage(), e); } } - private Iterable<Ref> getSortedRefs() throws Exception { - Map<String, Ref> all = db.getRefDatabase().getRefs(ALL); - if (all instanceof RefMap - || (all instanceof SortedMap && ((SortedMap) all).comparator() == null)) - return all.values(); - return RefComparator.sort(all.values()); + private Iterable<Ref> getSortedRefs() throws IOException { + List<Ref> all = db.getRefDatabase().getRefs(); + // TODO(jrn) check if we can reintroduce fast-path by e.g. implementing + // SortedList + return RefComparator.sort(all); } - private void show(final AnyObjectId id, final String name) + private void show(AnyObjectId id, String name) throws IOException { outw.print(id.name()); outw.print('\t'); 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 12d4208152..c96e475613 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 @@ -1,44 +1,11 @@ /* - * Copyright (C) 2011, 2015 François Rey <eclipse.org_@_francois_._rey_._name> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2011, 2015 François Rey <eclipse.org_@_francois_._rey_._name> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -54,14 +21,17 @@ import java.util.TreeSet; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.StatusCommand; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.lib.Constants; 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.Option; - import org.eclipse.jgit.pgm.opt.UntrackedFilesHandler; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.RestOfArgumentsHandler; /** * Status command @@ -69,8 +39,6 @@ import org.eclipse.jgit.pgm.opt.UntrackedFilesHandler; @Command(usage = "usage_Status", common = true) class Status extends TextBuiltin { - protected final String lineFormat = CLIText.get().lineFormat; - protected final String statusFileListFormat = CLIText.get().statusFileListFormat; protected final String statusFileListFormatWithPrefix = CLIText.get().statusFileListFormatWithPrefix; @@ -83,17 +51,24 @@ 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", handler = RestOfArgumentsHandler.class) protected List<String> filterPaths; @Override - protected void run() throws Exception { - StatusCommand statusCommand = new Git(db).status(); - if (filterPaths != null && filterPaths.size() > 0) - for (String path : filterPaths) - statusCommand.addPath(path); - org.eclipse.jgit.api.Status status = statusCommand.call(); - printStatus(status); + protected void run() { + try (Git git = new Git(db)) { + StatusCommand statusCommand = git.status(); + if (filterPaths != null) { + for (String path : filterPaths) { + statusCommand.addPath(path); + } + } + org.eclipse.jgit.api.Status status = statusCommand.call(); + printStatus(status); + } catch (GitAPIException | NoWorkTreeException | IOException e) { + throw die(e.getMessage(), e); + } } private void printStatus(org.eclipse.jgit.api.Status status) @@ -115,7 +90,7 @@ class Status extends TextBuiltin { Map<String, StageState> conflicting = status.getConflictingStageState(); // build a sorted list of all paths except untracked and ignored - TreeSet<String> sorted = new TreeSet<String>(); + TreeSet<String> sorted = new TreeSet<>(); sorted.addAll(added); sorted.addAll(changed); sorted.addAll(removed); @@ -183,7 +158,7 @@ class Status extends TextBuiltin { // untracked are always at the end of the list if ("all".equals(untrackedFilesMode)) { //$NON-NLS-1$ - TreeSet<String> untracked = new TreeSet<String>( + TreeSet<String> untracked = new TreeSet<>( status.getUntracked()); for (String path : untracked) printPorcelainLine('?', '?', path); @@ -200,7 +175,7 @@ class Status extends TextBuiltin { private void printLongStatus(org.eclipse.jgit.api.Status status) throws IOException { // Print current branch name - final Ref head = db.getRef(Constants.HEAD); + final Ref head = db.exactRef(Constants.HEAD); if (head != null && head.isSymbolic()) { String branch = Repository.shortenRefName(head.getLeaf().getName()); outw.println(CLIText.formatLine(MessageFormat.format( @@ -219,7 +194,7 @@ class Status extends TextBuiltin { Collection<String> untracked = status.getUntracked(); Map<String, StageState> unmergedStates = status .getConflictingStageState(); - Collection<String> toBeCommitted = new ArrayList<String>(added); + Collection<String> toBeCommitted = new ArrayList<>(added); toBeCommitted.addAll(changed); toBeCommitted.addAll(removed); int nbToBeCommitted = toBeCommitted.size(); @@ -230,7 +205,7 @@ class Status extends TextBuiltin { toBeCommitted, added, changed, removed); firstHeader = false; } - Collection<String> notStagedForCommit = new ArrayList<String>(modified); + Collection<String> notStagedForCommit = new ArrayList<>(modified); notStagedForCommit.addAll(missing); int nbNotStagedForCommit = notStagedForCommit.size(); if (nbNotStagedForCommit > 0) { @@ -251,7 +226,7 @@ class Status extends TextBuiltin { firstHeader = false; } int nbUntracked = untracked.size(); - if (nbUntracked > 0 && ("all".equals(untrackedFilesMode))) { //$NON-NLS-1$ + if (nbUntracked > 0 && "all".equals(untrackedFilesMode)) { //$NON-NLS-1$ if (!firstHeader) printSectionHeader(""); //$NON-NLS-1$ printSectionHeader(CLIText.get().untrackedFiles); @@ -259,20 +234,39 @@ class Status extends TextBuiltin { } } + /** + * Print section header + * + * @param pattern + * a {@link String} object. + * @param arguments + * a {@link Object} object. + * @throws IOException + * if an IO error occurred + */ protected void printSectionHeader(String pattern, Object... arguments) throws IOException { if (!porcelain) { outw.println(CLIText.formatLine(MessageFormat.format(pattern, arguments))); - if (!pattern.equals("")) //$NON-NLS-1$ + if (!pattern.isEmpty()) outw.println(CLIText.formatLine("")); //$NON-NLS-1$ outw.flush(); } } + /** + * Print String list + * + * @param list + * a {@link Collection} object. + * @return size of the list + * @throws IOException + * if an IO error occurred + */ protected int printList(Collection<String> list) throws IOException { if (!list.isEmpty()) { - List<String> sortedList = new ArrayList<String>(list); + List<String> sortedList = new ArrayList<>(list); java.util.Collections.sort(sortedList); for (String filename : sortedList) { outw.println(CLIText.formatLine(String.format( @@ -280,16 +274,37 @@ class Status extends TextBuiltin { } outw.flush(); return list.size(); - } else - return 0; + } + return 0; } + /** + * Print String list + * + * @param status1 + * a {@link String} object. + * @param status2 + * a {@link String} object. + * @param status3 + * a {@link String} object. + * @param list + * a {@link Collection} object. + * @param set1 + * a {@link Collection} object. + * @param set2 + * a {@link Collection} object. + * @param set3 + * a {@link Collection} object. + * @return a int. + * @throws IOException + * if an IO error occurred + */ protected int printList(String status1, String status2, String status3, Collection<String> list, Collection<String> set1, Collection<String> set2, - @SuppressWarnings("unused") Collection<String> set3) + Collection<String> set3) throws IOException { - List<String> sortedList = new ArrayList<String>(list); + List<String> sortedList = new ArrayList<>(list); java.util.Collections.sort(sortedList); for (String filename : sortedList) { String prefix; @@ -309,7 +324,7 @@ class Status extends TextBuiltin { private void printUnmerged(Map<String, StageState> unmergedStates) throws IOException { - List<String> paths = new ArrayList<String>(unmergedStates.keySet()); + List<String> paths = new ArrayList<>(unmergedStates.keySet()); Collections.sort(paths); for (String path : paths) { StageState state = unmergedStates.get(path); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java index a90d4c4dad..6be30c9447 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java @@ -4,72 +4,83 @@ * Copyright (C) 2008, Charles O'Farrell <charleso@charleso.org> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg.lists@dewire.com> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, 2021 Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import java.io.IOException; import java.text.MessageFormat; import java.util.List; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ListTagCommand; import org.eclipse.jgit.api.TagCommand; +import org.eclipse.jgit.api.VerificationResult; +import org.eclipse.jgit.api.VerifySignatureCommand; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.internal.VerificationUtils; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.revwalk.RevWalk; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_CreateATag") class Tag extends TextBuiltin { - @Option(name = "-f", usage = "usage_forceReplacingAnExistingTag") + + @Option(name = "--force", aliases = { "-f" }, forbids = { "--delete", + "--verify" }, usage = "usage_forceReplacingAnExistingTag") private boolean force; - @Option(name = "-m", metaVar = "metaVar_message", usage = "usage_tagMessage") - private String message = ""; //$NON-NLS-1$ + @Option(name = "--delete", aliases = { "-d" }, forbids = { + "--verify" }, usage = "usage_tagDelete") + private boolean delete; + + @Option(name = "--annotate", aliases = { + "-a" }, forbids = { "--delete", + "--verify" }, usage = "usage_tagAnnotated") + private boolean annotated; + + @Option(name = "-m", forbids = { "--delete", + "--verify" }, metaVar = "metaVar_message", usage = "usage_tagMessage") + private String message; + + @Option(name = "--sign", aliases = { "-s" }, forbids = { + "--no-sign", "--delete", "--verify" }, usage = "usage_tagSign") + private boolean sign; + + @Option(name = "--no-sign", usage = "usage_tagNoSign", forbids = { + "--sign", "--delete", "--verify" }) + private boolean noSign; + + @Option(name = "--local-user", aliases = { + "-u" }, forbids = { "--delete", + "--verify" }, metaVar = "metaVar_tagLocalUser", usage = "usage_tagLocalUser") + private String gpgKeyId; + + @Option(name = "--verify", aliases = { "-v" }, forbids = { "--delete", + "--force", "--annotate", "-m", "--sign", "--no-sign", + "--local-user" }, usage = "usage_tagVerify") + private boolean verify; + + @Option(name = "--contains", forbids = { "--delete", "--force", + "--annotate", "-m", "--sign", "--no-sign", + "--local-user" }, metaVar = "metaVar_commitish", usage = "usage_tagContains") + private RevCommit contains; @Argument(index = 0, metaVar = "metaVar_name") private String tagName; @@ -78,28 +89,107 @@ class Tag extends TextBuiltin { private ObjectId object; @Override - protected void run() throws Exception { - Git git = new Git(db); - if (tagName != null) { - TagCommand command = git.tag().setForceUpdate(force) - .setMessage(message).setName(tagName); - - if (object != null) { - RevWalk walk = new RevWalk(db); - command.setObjectId(walk.parseAny(object)); + protected void run() { + try (Git git = new Git(db)) { + if (tagName != null) { + if (verify) { + VerifySignatureCommand verifySig = git.verifySignature() + .setMode(VerifySignatureCommand.VerifyMode.TAGS) + .addName(tagName); + + VerificationResult verification = verifySig.call() + .get(tagName); + if (verification == null) { + showUnsigned(git, tagName); + } else { + Throwable error = verification.getException(); + if (error != null) { + throw die(error.getMessage(), error); + } + writeVerification( + verification.getVerification().verifierName(), + (RevTag) verification.getObject(), + verification.getVerification()); + } + } else if (delete) { + List<String> deletedTags = git.tagDelete().setTags(tagName) + .call(); + if (deletedTags.isEmpty()) { + throw die(MessageFormat + .format(CLIText.get().tagNotFound, tagName)); + } + } else { + TagCommand command = git.tag().setForceUpdate(force) + .setMessage(message).setName(tagName); + + if (object != null) { + try (RevWalk walk = new RevWalk(db)) { + command.setObjectId(walk.parseAny(object)); + } + } + if (noSign) { + command.setSigned(false); + } else if (sign) { + command.setSigned(true); + } + if (annotated) { + command.setAnnotated(true); + } else if (message == null && !sign && gpgKeyId == null) { + // None of -a, -m, -s, -u given + command.setAnnotated(false); + } + command.setSigningKey(gpgKeyId); + try { + command.call(); + } catch (RefAlreadyExistsException e) { + throw die(MessageFormat.format( + CLIText.get().tagAlreadyExists, tagName), e); + } + } + } else { + ListTagCommand command = git.tagList(); + if (contains != null) { + command.setContains(contains); + } + List<Ref> list = command.call(); + for (Ref ref : list) { + outw.println(Repository.shortenRefName(ref.getName())); + } } - try { - command.call(); - } catch (RefAlreadyExistsException e) { - throw die(MessageFormat.format(CLIText.get().tagAlreadyExists, - tagName)); + } catch (GitAPIException | IOException e) { + throw die(e.getMessage(), e); + } + } + + private void showUnsigned(Git git, String wantedTag) throws IOException { + ObjectId id = git.getRepository().resolve(wantedTag); + if (id != null && !ObjectId.zeroId().equals(id)) { + try (RevWalk walk = new RevWalk(git.getRepository())) { + showTag(walk.parseTag(id)); } } else { - ListTagCommand command = git.tagList(); - List<Ref> list = command.call(); - for (Ref ref : list) { - outw.println(Repository.shortenRefName(ref.getName())); - } + throw die( + MessageFormat.format(CLIText.get().tagNotFound, wantedTag)); + } + } + + private void showTag(RevTag tag) throws IOException { + outw.println("object " + tag.getObject().name()); //$NON-NLS-1$ + outw.println("type " + Constants.typeString(tag.getObject().getType())); //$NON-NLS-1$ + outw.println("tag " + tag.getTagName()); //$NON-NLS-1$ + outw.println("tagger " + tag.getTaggerIdent().toExternalString()); //$NON-NLS-1$ + outw.println(); + outw.print(tag.getFullMessage()); + } + + private void writeVerification(String name, RevTag tag, + SignatureVerification verification) throws IOException { + showTag(tag); + if (verification == null) { + outw.println(); + return; } + VerificationUtils.writeVerification(outw, verification, name, + tag.getTaggerIdent()); } } 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 8e8b82fe07..c572e3bc7d 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 @@ -1,49 +1,19 @@ /* * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_LOG_OUTPUT_ENCODING; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_SECTION_I18N; import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.eclipse.jgit.lib.Constants.R_REMOTES; import static org.eclipse.jgit.lib.Constants.R_TAGS; @@ -56,15 +26,21 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; -import java.io.PrintWriter; +import java.nio.charset.Charset; import java.text.MessageFormat; import java.util.ResourceBundle; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.pgm.internal.SshDriver; import org.eclipse.jgit.pgm.opt.CmdLineParser; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.SshSessionFactory; +import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory; +import org.eclipse.jgit.transport.sshd.DefaultProxyDataFactory; +import org.eclipse.jgit.transport.sshd.JGitKeyCache; +import org.eclipse.jgit.transport.sshd.SshdSessionFactory; import org.eclipse.jgit.util.io.ThrowingPrintWriter; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.Option; @@ -86,6 +62,9 @@ public abstract class TextBuiltin { @Option(name = "--help", usage = "usage_displayThisHelpText", aliases = { "-h" }) private boolean help; + @Option(name = "--ssh", usage = "usage_sshDriver") + private SshDriver sshDriver = SshDriver.APACHE; + /** * Input stream, typically this is standard input. * @@ -108,14 +87,6 @@ public abstract class TextBuiltin { protected OutputStream outs; /** - * Stream to output to, typically this is standard output. - * - * @deprecated Use outw instead - */ - @Deprecated - protected PrintWriter out; - - /** * Error writer, typically this is standard error. * * @since 3.4 @@ -138,52 +109,90 @@ public abstract class TextBuiltin { /** RevWalk used during command line parsing, if it was required. */ protected RevWalk argWalk; - final void setCommandName(final String name) { + final void setCommandName(String name) { commandName = name; } - /** @return true if {@link #db}/{@link #getRepository()} is required. */ + /** + * If this command requires a repository. + * + * @return true if {@link #db}/{@link #getRepository()} is required + */ protected boolean requiresRepository() { return true; } /** - * Initialize the command to work with a repository. + * Initializes the command to work with a repository, including setting the + * output and error streams. * * @param repository * the opened repository that the command should work on. * @param gitDir * value of the {@code --git-dir} command line option, if * {@code repository} is null. + * @param input + * input stream from which input will be read + * @param output + * output stream to which output will be written + * @param error + * error stream to which errors will be written + * @since 4.9 */ - protected void init(final Repository repository, final String gitDir) { - try { - final String outputEncoding = repository != null ? repository - .getConfig().getString("i18n", null, "logOutputEncoding") : null; //$NON-NLS-1$ //$NON-NLS-2$ - if (ins == null) - ins = new FileInputStream(FileDescriptor.in); - if (outs == null) - outs = new FileOutputStream(FileDescriptor.out); - if (errs == null) - errs = new FileOutputStream(FileDescriptor.err); - BufferedWriter outbufw; - if (outputEncoding != null) - outbufw = new BufferedWriter(new OutputStreamWriter(outs, - outputEncoding)); - else - outbufw = new BufferedWriter(new OutputStreamWriter(outs)); - out = new PrintWriter(outbufw); - outw = new ThrowingPrintWriter(outbufw); - BufferedWriter errbufw; - if (outputEncoding != null) - errbufw = new BufferedWriter(new OutputStreamWriter(errs, - outputEncoding)); - else - errbufw = new BufferedWriter(new OutputStreamWriter(errs)); - errw = new ThrowingPrintWriter(errbufw); - } catch (IOException e) { - throw die(CLIText.get().cannotCreateOutputStream); + public void initRaw(final Repository repository, final String gitDir, + InputStream input, OutputStream output, OutputStream error) { + this.ins = input; + this.outs = output; + this.errs = error; + init(repository, gitDir); + } + + /** + * Get the log output encoding specified in the repository's + * {@code i18n.logOutputEncoding} configuration. + * + * @param repository + * the repository. + * @return Charset corresponding to {@code i18n.logOutputEncoding}, or + * {@code UTF_8}. + */ + private Charset getLogOutputEncodingCharset(Repository repository) { + if (repository != null) { + String logOutputEncoding = repository.getConfig().getString( + CONFIG_SECTION_I18N, null, CONFIG_KEY_LOG_OUTPUT_ENCODING); + if (logOutputEncoding != null) { + try { + return Charset.forName(logOutputEncoding); + } catch (IllegalArgumentException e) { + throw die(CLIText.get().cannotCreateOutputStream, e); + } + } } + return UTF_8; + } + + /** + * Initialize the command to work with a repository. + * + * @param repository + * the opened repository that the command should work on. + * @param gitDir + * value of the {@code --git-dir} command line option, if + * {@code repository} is null. + */ + protected void init(Repository repository, String gitDir) { + Charset charset = getLogOutputEncodingCharset(repository); + + if (ins == null) + ins = new FileInputStream(FileDescriptor.in); + if (outs == null) + outs = new FileOutputStream(FileDescriptor.out); + if (errs == null) + errs = new FileOutputStream(FileDescriptor.err); + outw = new ThrowingPrintWriter(new BufferedWriter( + new OutputStreamWriter(outs, charset))); + errw = new ThrowingPrintWriter(new BufferedWriter( + new OutputStreamWriter(errs, charset))); if (repository != null && repository.getDirectory() != null) { db = repository; @@ -199,13 +208,34 @@ public abstract class TextBuiltin { * * @param args * command line arguments passed after the command name. - * @throws Exception + * @throws java.lang.Exception * an error occurred while processing the command. The main * framework will catch the exception and print a message on * standard error. */ public final void execute(String[] args) throws Exception { parseArguments(args); + switch (sshDriver) { + case APACHE: { + SshdSessionFactory factory = new SshdSessionFactory( + new JGitKeyCache(), new DefaultProxyDataFactory()); + try { + Runtime.getRuntime() + .addShutdownHook(new Thread(factory::close)); + } catch (IllegalStateException e) { + // ignore - the VM is already shutting down + } + SshSessionFactory.setInstance(factory); + break; + } + case JSCH: + JschConfigSessionFactory factory = new JschConfigSessionFactory(); + SshSessionFactory.setInstance(factory); + break; + default: + SshSessionFactory.setInstance(null); + break; + } run(); } @@ -218,21 +248,25 @@ public abstract class TextBuiltin { * * @param args * the arguments supplied on the command line, if any. - * @throws IOException + * @throws java.io.IOException + * if an IO error occurred */ - protected void parseArguments(final String[] args) throws IOException { + protected void parseArguments(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(); @@ -242,9 +276,11 @@ public abstract class TextBuiltin { * Print the usage line * * @param clp - * @throws IOException + * a {@link org.eclipse.jgit.pgm.opt.CmdLineParser} object. + * @throws java.io.IOException + * if an IO error occurred */ - public void printUsageAndExit(final CmdLineParser clp) throws IOException { + public void printUsageAndExit(CmdLineParser clp) throws IOException { printUsageAndExit("", clp); //$NON-NLS-1$ } @@ -252,10 +288,30 @@ public abstract class TextBuiltin { * Print an error message and the usage line * * @param message + * a {@link java.lang.String} object. * @param clp - * @throws IOException + * a {@link org.eclipse.jgit.pgm.opt.CmdLineParser} object. + * @throws java.io.IOException + * if an IO error occurred */ - public void printUsageAndExit(final String message, final CmdLineParser clp) throws IOException { + public void printUsageAndExit(String message, CmdLineParser clp) throws IOException { + printUsage(message, clp); + throw die(true); + } + + /** + * Print usage help text. + * + * @param message + * non null + * @param clp + * parser used to print options + * @throws java.io.IOException + * if an IO error occurred + * @since 4.2 + */ + protected void printUsage(String message, CmdLineParser clp) + throws IOException { errw.println(message); errw.print("jgit "); //$NON-NLS-1$ errw.print(commandName); @@ -267,12 +323,33 @@ 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 + * Get error writer + * + * @return error writer, typically this is standard error. + * @since 4.2 + */ + public ThrowingPrintWriter getErrorWriter() { + return errw; + } + + /** + * Get output writer + * + * @return output writer, typically this is standard output. + * @since 4.9 + */ + public ThrowingPrintWriter getOutputWriter() { + return outw; + } + + /** + * Get resource bundle with localized texts + * + * @return the resource bundle that will be passed to args4j for purpose of + * string localization */ protected ResourceBundle getResourceBundle() { return CLIText.get().resourceBundle(); @@ -283,7 +360,7 @@ public abstract class TextBuiltin { * <p> * This method should only be invoked by {@link #execute(String[])}. * - * @throws Exception + * @throws java.lang.Exception * an error occurred while processing the command. The main * framework will catch the exception and print a message on * standard error. @@ -291,13 +368,15 @@ public abstract class TextBuiltin { protected abstract void run() throws Exception; /** + * Get the repository + * * @return the repository this command accesses. */ public Repository getRepository() { return db; } - ObjectId resolve(final String s) throws IOException { + ObjectId resolve(String s) throws IOException { final ObjectId r = db.resolve(s); if (r == null) throw die(MessageFormat.format(CLIText.get().notARevision, s)); @@ -305,28 +384,35 @@ public abstract class TextBuiltin { } /** + * Exit the command with an error message + * * @param why * textual explanation * @return a runtime exception the caller is expected to throw */ - protected static Die die(final String why) { + protected static Die die(String why) { return new Die(why); } /** + * Exit the command with an error message and an exception + * * @param why * textual explanation * @param cause * why the command has failed. * @return a runtime exception the caller is expected to throw */ - protected static Die die(final String why, final Throwable cause) { + protected static Die die(String why, Throwable cause) { return new Die(why, cause); } /** + * Exit the command + * * @param aborted - * boolean indicating that the execution has been aborted before running + * boolean indicating that the execution has been aborted before + * running * @return a runtime exception the caller is expected to throw * @since 3.4 */ @@ -334,6 +420,21 @@ public abstract class TextBuiltin { return new Die(aborted); } + /** + * Exit the command + * + * @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, Throwable cause) { + return new Die(aborted, cause); + } + String abbreviateRef(String dst, boolean abbreviateRemote) { if (dst.startsWith(R_HEADS)) dst = dst.substring(R_HEADS.length()); @@ -343,4 +444,38 @@ public abstract class TextBuiltin { dst = dst.substring(R_REMOTES.length()); return dst; } + + /** + * Check if the arguments contain a help option + * + * @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/UploadPack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java index 447374d699..db2c393b9a 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/UploadPack.java @@ -1,50 +1,18 @@ /* * Copyright (C) 2008-2009, Google Inc. - * Copyright (C) 2009-2010, Robin Rosenberg <robin.rosenberg@dewire.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2009-2010, Robin Rosenberg <robin.rosenberg@dewire.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; import java.io.File; +import java.io.IOException; import java.text.MessageFormat; import org.eclipse.jgit.errors.RepositoryNotFoundException; @@ -68,20 +36,22 @@ class UploadPack extends TextBuiltin { } @Override - protected void run() throws Exception { - final org.eclipse.jgit.transport.UploadPack up; - + protected void run() { try { FileKey key = FileKey.lenient(srcGitdir, FS.DETECTED); db = key.open(true /* must exist */); + try (org.eclipse.jgit.transport.UploadPack up = new org.eclipse.jgit.transport.UploadPack( + db)) { + if (0 <= timeout) { + up.setTimeout(timeout); + } + up.upload(ins, outs, errs); + } } catch (RepositoryNotFoundException notFound) { throw die(MessageFormat.format(CLIText.get().notAGitRepository, - srcGitdir.getPath())); + srcGitdir.getPath()), notFound); + } catch (IOException e) { + throw die(e.getMessage(), e); } - - up = new org.eclipse.jgit.transport.UploadPack(db); - if (0 <= timeout) - up.setTimeout(timeout); - up.upload(ins, outs, errs); } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java index 6bed9c6025..8546094ac2 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2008, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm; @@ -56,21 +23,28 @@ import org.eclipse.jgit.pgm.internal.CLIText; @Command(common = true, usage = "usage_DisplayTheVersionOfJgit") class Version extends TextBuiltin { @Override - protected void run() throws Exception { + protected void run() { // read the Implementation-Version from Manifest String version = getImplementationVersion(); // if Implementation-Version is not available then try reading // Bundle-Version - if (version == null) + if (version == null) { version = getBundleVersion(); + } // if both Implementation-Version and Bundle-Version are not available // then throw an exception - if (version == null) + if (version == null) { throw die(CLIText.get().cannotReadPackageInformation); + } - outw.println(MessageFormat.format(CLIText.get().jgitVersion, version)); + try { + outw.println( + MessageFormat.format(CLIText.get().jgitVersion, version)); + } catch (IOException e) { + throw die(e.getMessage(), e); + } } @Override @@ -94,14 +68,9 @@ class Version extends TextBuiltin { } private static String getBundleVersion(URL url) { - try { - InputStream is = url.openStream(); - try { - Manifest manifest = new Manifest(is); - return manifest.getMainAttributes().getValue("Bundle-Version"); //$NON-NLS-1$ - } finally { - is.close(); - } + try (InputStream is = url.openStream()) { + Manifest manifest = new Manifest(is); + return manifest.getMainAttributes().getValue("Bundle-Version"); //$NON-NLS-1$ } catch (IOException e) { // do nothing - will return null } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java new file mode 100644 index 0000000000..b7a7ec2feb --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2017, Google Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm.debug; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.lib.Constants.HEAD; +import static org.eclipse.jgit.lib.Constants.MASTER; +import static org.eclipse.jgit.lib.Constants.R_HEADS; +import static org.eclipse.jgit.lib.Ref.Storage.NEW; +import static org.eclipse.jgit.lib.Ref.Storage.PACKED; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.jgit.internal.storage.file.FileReftableStack; +import org.eclipse.jgit.internal.storage.io.BlockSource; +import org.eclipse.jgit.internal.storage.reftable.RefCursor; +import org.eclipse.jgit.internal.storage.reftable.ReftableReader; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.SymbolicRef; +import org.eclipse.jgit.pgm.Command; +import org.eclipse.jgit.pgm.TextBuiltin; +import org.eclipse.jgit.util.RefList; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +@Command +class BenchmarkReftable extends TextBuiltin { + enum Test { + SCAN, + SEEK_COLD, SEEK_HOT, + BY_ID_COLD, BY_ID_HOT, + WRITE_STACK, + GET_REFS_EXCLUDING_REF + } + + @Option(name = "--tries") + private int tries = 10; + + @Option(name = "--test") + private Test test = Test.SCAN; + + @Option(name = "--ref") + private String ref; + + @Option(name = "--object-id") + private String objectId; + + @Argument(index = 0) + private String lsRemotePath; + + @Argument(index = 1) + private String reftablePath; + + @Override + protected void run() throws Exception { + switch (test) { + case SCAN: + scan(); + break; + + case SEEK_COLD: + seekCold(ref); + break; + case SEEK_HOT: + seekHot(ref); + break; + + case BY_ID_COLD: + byIdCold(ObjectId.fromString(objectId)); + break; + case BY_ID_HOT: + byIdHot(ObjectId.fromString(objectId)); + break; + case WRITE_STACK: + writeStack(); + break; + case GET_REFS_EXCLUDING_REF : + getRefsExcludingWithSeekPast(ref); + getRefsExcludingWithFilter(ref); + break; + } + } + + private void printf(String fmt, Object... args) throws IOException { + errw.println(String.format(fmt, args)); + } + + @SuppressWarnings({ "nls", "boxing" }) + private void writeStack() throws Exception { + File dir = new File(reftablePath); + + dir.mkdirs(); + + long start = System.currentTimeMillis(); + try (FileReftableStack stack = new FileReftableStack(dir, null, + () -> new Config())) { + + List<Ref> refs = readLsRemote().asList(); + for (Ref r : refs) { + final long j = stack.getMergedReftable().maxUpdateIndex() + 1; + if (!stack.addReftable(w -> { + w.setMaxUpdateIndex(j).setMinUpdateIndex(j).begin() + .writeRef(r); + })) { + throw new IOException("should succeed"); + } + } + long dt = System.currentTimeMillis() - start; + printf("%12s %10d ms avg %6d us/write", "reftable", dt, + (dt * 1000) / refs.size()); + } + } + + @SuppressWarnings({ "nls", "boxing" }) + private void scan() throws Exception { + long start, tot; + + start = System.currentTimeMillis(); + for (int i = 0; i < tries; i++) { + readLsRemote(); + } + tot = System.currentTimeMillis() - start; + printf("%12s %10d ms %6d ms/run", "packed-refs", tot, tot / tries); + + start = System.currentTimeMillis(); + for (int i = 0; i < tries; i++) { + try (FileInputStream in = new FileInputStream(reftablePath); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + try (RefCursor rc = reader.allRefs()) { + while (rc.next()) { + rc.getRef(); + } + } + } + } + tot = System.currentTimeMillis() - start; + printf("%12s %10d ms %6d ms/run", "reftable", tot, tot / tries); + } + + private RefList<Ref> readLsRemote() + throws IOException, FileNotFoundException { + RefList.Builder<Ref> list = new RefList.Builder<>(); + try (BufferedReader br = new BufferedReader(new InputStreamReader( + new FileInputStream(lsRemotePath), UTF_8))) { + Ref last = null; + String line; + while ((line = br.readLine()) != null) { + ObjectId id = ObjectId.fromString(line.substring(0, 40)); + String name = line.substring(41, line.length()); + if (last != null && name.endsWith("^{}")) { //$NON-NLS-1$ + last = new ObjectIdRef.PeeledTag(PACKED, last.getName(), + last.getObjectId(), id); + list.set(list.size() - 1, last); + continue; + } + + if (name.equals(HEAD)) { + last = new SymbolicRef(name, new ObjectIdRef.Unpeeled(NEW, + R_HEADS + MASTER, null)); + } else { + last = new ObjectIdRef.PeeledNonTag(PACKED, name, id); + } + list.add(last); + } + } + list.sort(); + return list.toRefList(); + } + + @SuppressWarnings({ "nls", "boxing" }) + private void seekCold(String refName) throws Exception { + long start, tot; + + int lsTries = Math.min(tries, 64); + start = System.nanoTime(); + for (int i = 0; i < lsTries; i++) { + readLsRemote().get(refName); + } + tot = System.nanoTime() - start; + printf("%12s %10d usec %9.1f usec/run %5d runs", "packed-refs", + tot / 1000, + (((double) tot) / lsTries) / 1000, + lsTries); + + start = System.nanoTime(); + for (int i = 0; i < tries; i++) { + try (FileInputStream in = new FileInputStream(reftablePath); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + try (RefCursor rc = reader.seekRef(refName)) { + while (rc.next()) { + rc.getRef(); + } + } + } + } + tot = System.nanoTime() - start; + printf("%12s %10d usec %9.1f usec/run %5d runs", "reftable", + tot / 1000, + (((double) tot) / tries) / 1000, + tries); + } + + @SuppressWarnings({ "nls", "boxing" }) + private void seekHot(String refName) throws Exception { + long start, tot; + + int lsTries = Math.min(tries, 64); + start = System.nanoTime(); + RefList<Ref> lsRemote = readLsRemote(); + for (int i = 0; i < lsTries; i++) { + lsRemote.get(refName); + } + tot = System.nanoTime() - start; + printf("%12s %10d usec %9.1f usec/run %5d runs", "packed-refs", + tot / 1000, (((double) tot) / lsTries) / 1000, lsTries); + + start = System.nanoTime(); + try (FileInputStream in = new FileInputStream(reftablePath); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + for (int i = 0; i < tries; i++) { + try (RefCursor rc = reader.seekRef(refName)) { + while (rc.next()) { + rc.getRef(); + } + } + } + } + tot = System.nanoTime() - start; + printf("%12s %10d usec %9.1f usec/run %5d runs", "reftable", + tot / 1000, (((double) tot) / tries) / 1000, tries); + } + + @SuppressWarnings({ "nls", "boxing" }) + private void byIdCold(ObjectId id) throws Exception { + long start, tot; + + int lsTries = Math.min(tries, 64); + start = System.nanoTime(); + for (int i = 0; i < lsTries; i++) { + for (Ref r : readLsRemote()) { + if (id.equals(r.getObjectId())) { + continue; + } + } + } + tot = System.nanoTime() - start; + printf("%12s %10d usec %9.1f usec/run %5d runs", "packed-refs", + tot / 1000, (((double) tot) / lsTries) / 1000, lsTries); + + start = System.nanoTime(); + for (int i = 0; i < tries; i++) { + try (FileInputStream in = new FileInputStream(reftablePath); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + try (RefCursor rc = reader.byObjectId(id)) { + while (rc.next()) { + rc.getRef(); + } + } + } + } + tot = System.nanoTime() - start; + printf("%12s %10d usec %9.1f usec/run %5d runs", "reftable", + tot / 1000, (((double) tot) / tries) / 1000, tries); + } + + @SuppressWarnings({ "nls", "boxing" }) + private void byIdHot(ObjectId id) throws Exception { + long start, tot; + + int lsTries = Math.min(tries, 64); + start = System.nanoTime(); + RefList<Ref> lsRemote = readLsRemote(); + for (int i = 0; i < lsTries; i++) { + for (Ref r : lsRemote) { + if (id.equals(r.getObjectId())) { + continue; + } + } + } + tot = System.nanoTime() - start; + printf("%12s %10d usec %9.1f usec/run %5d runs", "packed-refs", + tot / 1000, (((double) tot) / lsTries) / 1000, lsTries); + + start = System.nanoTime(); + try (FileInputStream in = new FileInputStream(reftablePath); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + for (int i = 0; i < tries; i++) { + try (RefCursor rc = reader.byObjectId(id)) { + while (rc.next()) { + rc.getRef(); + } + } + } + } + tot = System.nanoTime() - start; + printf("%12s %10d usec %9.1f usec/run %5d runs", "reftable", + tot / 1000, (((double) tot) / tries) / 1000, tries); + } + + @SuppressWarnings({"nls", "boxing"}) + private void getRefsExcludingWithFilter(String prefix) throws Exception { + long startTime = System.nanoTime(); + List<Ref> allRefs = new ArrayList<>(); + try (FileInputStream in = new FileInputStream(reftablePath); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + try (RefCursor rc = reader.allRefs()) { + while (rc.next()) { + allRefs.add(rc.getRef()); + } + } + } + int total = allRefs.size(); + allRefs = allRefs.stream().filter(r -> r.getName().startsWith(prefix)).collect(Collectors.toList()); + int notStartWithPrefix = allRefs.size(); + int startWithPrefix = total - notStartWithPrefix; + long totalTime = System.nanoTime() - startTime; + printf("total time the action took using filter: %10d usec", totalTime / 1000); + printf("number of refs that start with prefix: %d", startWithPrefix); + printf("number of refs that don't start with prefix: %d", notStartWithPrefix); + } + + @SuppressWarnings({"nls", "boxing"}) + private void getRefsExcludingWithSeekPast(String prefix) throws Exception { + long start = System.nanoTime(); + try (FileInputStream in = new FileInputStream(reftablePath); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + try (RefCursor rc = reader.allRefs()) { + while (rc.next()) { + if (rc.getRef().getName().startsWith(prefix)) { + break; + } + } + rc.seekPastPrefix(prefix); + while (rc.next()) { + rc.getRef(); + } + } + } + long tot = System.nanoTime() - start; + printf("total time the action took using seek: %10d usec", tot / 1000); + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java index 24d717dfd8..2bdca24336 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java @@ -1,58 +1,21 @@ /* - * Copyright (C) 2010, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2010, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; -import static java.lang.Integer.valueOf; -import static java.lang.Long.valueOf; - import java.io.File; import java.lang.management.ManagementFactory; import java.lang.management.ThreadMXBean; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import org.eclipse.jgit.diff.DiffAlgorithm; @@ -84,12 +47,14 @@ import org.kohsuke.args4j.Option; class DiffAlgorithms extends TextBuiltin { final Algorithm myers = new Algorithm() { + @Override DiffAlgorithm create() { return MyersDiff.INSTANCE; } }; final Algorithm histogram = new Algorithm() { + @Override DiffAlgorithm create() { HistogramDiff d = new HistogramDiff(); d.setFallbackAlgorithm(null); @@ -98,6 +63,7 @@ class DiffAlgorithms extends TextBuiltin { }; final Algorithm histogram_myers = new Algorithm() { + @Override DiffAlgorithm create() { HistogramDiff d = new HistogramDiff(); d.setFallbackAlgorithm(MyersDiff.INSTANCE); @@ -111,14 +77,14 @@ class DiffAlgorithms extends TextBuiltin { // // - @Option(name = "--algorithm", multiValued = true, metaVar = "NAME", usage = "Enable algorithm(s)") - List<String> algorithms = new ArrayList<String>(); + @Option(name = "--algorithm", metaVar = "NAME", usage = "Enable algorithm(s)") + List<String> algorithms = new ArrayList<>(); @Option(name = "--text-limit", metaVar = "LIMIT", usage = "Maximum size in KiB to scan per file revision") int textLimit = 15 * 1024; // 15 MiB as later we do * 1024. - @Option(name = "--repository", aliases = { "-r" }, multiValued = true, metaVar = "GIT_DIR", usage = "Repository to scan") - List<File> gitDirs = new ArrayList<File>(); + @Option(name = "--repository", aliases = { "-r" }, metaVar = "GIT_DIR", usage = "Repository to scan") + List<File> gitDirs = new ArrayList<>(); @Option(name = "--count", metaVar = "LIMIT", usage = "Number of file revisions to be compared") int count = 0; // unlimited @@ -136,7 +102,7 @@ class DiffAlgorithms extends TextBuiltin { protected void run() throws Exception { mxBean = ManagementFactory.getThreadMXBean(); if (!mxBean.isCurrentThreadCpuTimeSupported()) - throw die("Current thread CPU time not supported on this JRE"); + throw die("Current thread CPU time not supported on this JRE"); //$NON-NLS-1$ if (gitDirs.isEmpty()) { RepositoryBuilder rb = new RepositoryBuilder() // @@ -155,16 +121,13 @@ class DiffAlgorithms extends TextBuiltin { else rb.findGitDir(dir); - Repository db = rb.build(); - try { - run(db); - } finally { - db.close(); + try (Repository repo = rb.build()) { + run(repo); } } } - private void run(Repository db) throws Exception { + private void run(Repository repo) throws Exception { List<Test> all = init(); long files = 0; @@ -173,14 +136,14 @@ class DiffAlgorithms extends TextBuiltin { int maxN = 0; AbbreviatedObjectId startId; - try (ObjectReader or = db.newObjectReader()) { + try (ObjectReader or = repo.newObjectReader(); + RevWalk rw = new RevWalk(or)) { final MutableObjectId id = new MutableObjectId(); - RevWalk rw = new RevWalk(or); TreeWalk tw = new TreeWalk(or); tw.setFilter(TreeFilter.ANY_DIFF); tw.setRecursive(true); - ObjectId start = db.resolve(Constants.HEAD); + ObjectId start = repo.resolve(Constants.HEAD); startId = or.abbreviate(start); rw.markStart(rw.parseCommit(start)); for (;;) { @@ -205,7 +168,7 @@ class DiffAlgorithms extends TextBuiltin { } catch (LargeObjectException tooBig) { continue; } - if (RawText.isBinary(raw0)) + if (RawText.isBinary(raw0, raw0.length, true)) continue; byte[] raw1; @@ -215,7 +178,7 @@ class DiffAlgorithms extends TextBuiltin { } catch (LargeObjectException tooBig) { continue; } - if (RawText.isBinary(raw1)) + if (RawText.isBinary(raw1, raw1.length, true)) continue; RawText txt0 = new RawText(raw0); @@ -233,41 +196,41 @@ class DiffAlgorithms extends TextBuiltin { } } - Collections.sort(all, new Comparator<Test>() { - public int compare(Test a, Test b) { - int cmp = Long.signum(a.runningTimeNanos - b.runningTimeNanos); - if (cmp == 0) - cmp = a.algorithm.name.compareTo(b.algorithm.name); - return cmp; + Collections.sort(all, (Test a, Test b) -> { + int result = Long.signum(a.runningTimeNanos - b.runningTimeNanos); + if (result == 0) { + result = a.algorithm.name.compareTo(b.algorithm.name); } + return result; }); - if (db.getDirectory() != null) { - String name = db.getDirectory().getName(); - File parent = db.getDirectory().getParentFile(); + File directory = repo.getDirectory(); + if (directory != null) { + String name = directory.getName(); + File parent = directory.getParentFile(); if (name.equals(Constants.DOT_GIT) && parent != null) name = parent.getName(); - outw.println(name + ": start at " + startId.name()); + outw.println(name + ": start at " + startId.name()); //$NON-NLS-1$ } - outw.format(" %12d files, %8d commits\n", valueOf(files), - valueOf(commits)); - outw.format(" N=%10d min lines, %8d max lines\n", valueOf(minN), - valueOf(maxN)); + outw.format(" %12d files, %8d commits\n", Long.valueOf(files), //$NON-NLS-1$ + Integer.valueOf(commits)); + outw.format(" N=%10d min lines, %8d max lines\n", //$NON-NLS-1$ + Integer.valueOf(minN), Integer.valueOf(maxN)); - outw.format("%-25s %12s ( %12s %12s )\n", // - "Algorithm", "Time(ns)", "Time(ns) on", "Time(ns) on"); - outw.format("%-25s %12s ( %12s %12s )\n", // - "", "", "N=" + minN, "N=" + maxN); + outw.format("%-25s %12s ( %12s %12s )\n", //$NON-NLS-1$ + "Algorithm", "Time(ns)", "Time(ns) on", "Time(ns) on"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + outw.format("%-25s %12s ( %12s %12s )\n", //$NON-NLS-1$ + "", "", "N=" + minN, "N=" + maxN); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ outw.println("-----------------------------------------------------" //$NON-NLS-1$ + "----------------"); //$NON-NLS-1$ for (Test test : all) { outw.format("%-25s %12d ( %12d %12d )", // //$NON-NLS-1$ test.algorithm.name, // - valueOf(test.runningTimeNanos), // - valueOf(test.minN.runningTimeNanos), // - valueOf(test.maxN.runningTimeNanos)); + Long.valueOf(test.runningTimeNanos), // + Long.valueOf(test.minN.runningTimeNanos), // + Long.valueOf(test.maxN.runningTimeNanos)); outw.println(); } outw.println(); @@ -318,7 +281,7 @@ class DiffAlgorithms extends TextBuiltin { } private List<Test> init() { - List<Test> all = new ArrayList<Test>(); + List<Test> all = new ArrayList<>(); try { for (Field f : DiffAlgorithms.class.getDeclaredFields()) { @@ -333,12 +296,9 @@ class DiffAlgorithms extends TextBuiltin { } } } - } catch (IllegalArgumentException e) { - throw die("Cannot determine names", e); - } catch (IllegalAccessException e) { - throw die("Cannot determine names", e); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw die("Cannot determine names", e); //$NON-NLS-1$ } - return all; } @@ -352,7 +312,7 @@ class DiffAlgorithms extends TextBuiltin { return false; } - private static abstract class Algorithm { + private abstract static class Algorithm { String name; abstract DiffAlgorithm create(); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java new file mode 100644 index 0000000000..757c435722 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2015, Sasa Zivkov <sasa.zivkov@sap.com> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm.debug; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; +import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.lfs.server.LargeFileRepository; +import org.eclipse.jgit.lfs.server.LfsProtocolServlet; +import org.eclipse.jgit.lfs.server.fs.FileLfsRepository; +import org.eclipse.jgit.lfs.server.fs.FileLfsServlet; +import org.eclipse.jgit.lfs.server.s3.S3Config; +import org.eclipse.jgit.lfs.server.s3.S3Repository; +import org.eclipse.jgit.pgm.Command; +import org.eclipse.jgit.pgm.TextBuiltin; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.util.FS; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +@Command(common = true, usage = "usage_runLfsStore") +class LfsStore extends TextBuiltin { + + /** + * Tiny web application server for testing + */ + static class AppServer { + + private final Server server; + + private final ServerConnector connector; + + private final ContextHandlerCollection contexts; + + private URI uri; + + AppServer(int port) { + server = new Server(); + + HttpConfiguration http_config = new HttpConfiguration(); + http_config.setOutputBufferSize(32768); + + connector = new ServerConnector(server, + new HttpConnectionFactory(http_config)); + connector.setPort(port); + try { + String host = InetAddress.getByName("localhost") //$NON-NLS-1$ + .getHostAddress(); + connector.setHost(host); + if (host.contains(":") && !host.startsWith("[")) //$NON-NLS-1$ //$NON-NLS-2$ + host = "[" + host + "]"; //$NON-NLS-1$//$NON-NLS-2$ + uri = new URI("http://" + host + ":" + port); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (UnknownHostException e) { + throw new RuntimeException("Cannot find localhost", e); //$NON-NLS-1$ + } catch (URISyntaxException e) { + throw new RuntimeException("Unexpected URI error on " + uri, e); //$NON-NLS-1$ + } + + contexts = new ContextHandlerCollection(); + server.setHandler(contexts); + server.setConnectors(new Connector[] { connector }); + } + + /** + * Create a new servlet context within the server. + * <p> + * This method should be invoked before the server is started, once for + * each context the caller wants to register. + * + * @param path + * path of the context; use "/" for the root context if + * binding to the root is desired. + * @return the context to add servlets into. + */ + ServletContextHandler addContext(String path) { + assertNotRunning(); + if ("".equals(path)) //$NON-NLS-1$ + path = "/"; //$NON-NLS-1$ + + ServletContextHandler ctx = new ServletContextHandler(); + ctx.setContextPath(path); + contexts.addHandler(ctx); + + return ctx; + } + + void start() throws Exception { + server.start(); + } + + void stop() throws Exception { + server.stop(); + } + + URI getURI() { + return uri; + } + + private void assertNotRunning() { + if (server.isRunning()) { + throw new IllegalStateException("server is running"); //$NON-NLS-1$ + } + } + } + + private enum StoreType { + FS, S3; + } + + private enum StorageClass { + REDUCED_REDUNDANCY, STANDARD + } + + private static final String OBJECTS = "objects/"; //$NON-NLS-1$ + + private static final String STORE_PATH = "/" + OBJECTS + "*"; //$NON-NLS-1$//$NON-NLS-2$ + + private static final String PROTOCOL_PATH = "/lfs/objects/batch"; //$NON-NLS-1$ + + @Option(name = "--port", aliases = {"-p" }, + metaVar = "metaVar_port", usage = "usage_LFSPort") + int port; + + @Option(name = "--store", metaVar = "metaVar_lfsStorage", usage = "usage_LFSRunStore") + StoreType storeType; + + @Option(name = "--store-url", aliases = {"-u" }, metaVar = "metaVar_url", + usage = "usage_LFSStoreUrl") + String storeUrl; + + @Option(name = "--region", aliases = {"-r" }, + metaVar = "metaVar_s3Region", usage = "usage_S3Region") + String region; // $NON-NLS-1$ + + @Option(name = "--bucket", aliases = {"-b" }, + metaVar = "metaVar_s3Bucket", usage = "usage_S3Bucket") + String bucket; // $NON-NLS-1$ + + @Option(name = "--storage-class", aliases = {"-c" }, + metaVar = "metaVar_s3StorageClass", usage = "usage_S3StorageClass") + StorageClass storageClass = StorageClass.REDUCED_REDUNDANCY; + + @Option(name = "--expire", aliases = {"-e" }, + metaVar = "metaVar_seconds", usage = "usage_S3Expiration") + int expirationSeconds = 600; + + @Option(name = "--no-ssl-verify", usage = "usage_S3NoSslVerify") + boolean disableSslVerify = false; + + @Argument(required = false, metaVar = "metaVar_directory", usage = "usage_LFSDirectory") + String directory; + + String protocolUrl; + + String accessKey; + + String secretKey; + + @Override + protected boolean requiresRepository() { + return false; + } + + @Override + protected void run() throws Exception { + AppServer server = new AppServer(port); + URI baseURI = server.getURI(); + ServletContextHandler app = server.addContext("/"); //$NON-NLS-1$ + + final LargeFileRepository repository; + switch (storeType) { + case FS: + Path dir = Paths.get(directory); + FileLfsRepository fsRepo = new FileLfsRepository( + getStoreUrl(baseURI), dir); + FileLfsServlet content = new FileLfsServlet(fsRepo, 30000); + app.addServlet(new ServletHolder(content), STORE_PATH); + repository = fsRepo; + break; + + case S3: + readAWSKeys(); + checkOptions(); + S3Config config = new S3Config(region, bucket, + storageClass.toString(), accessKey, secretKey, + expirationSeconds, disableSslVerify); + repository = new S3Repository(config); + break; + default: + throw new IllegalArgumentException(MessageFormat + .format(CLIText.get().lfsUnknownStoreType, storeType)); + } + + LfsProtocolServlet protocol = new LfsProtocolServlet() { + + private static final long serialVersionUID = 1L; + + @Override + protected LargeFileRepository getLargeFileRepository( + LfsRequest request, String path, String auth) { + return repository; + } + }; + app.addServlet(new ServletHolder(protocol), PROTOCOL_PATH); + + server.start(); + + outw.println(MessageFormat.format(CLIText.get().lfsProtocolUrl, + getProtocolUrl(baseURI))); + if (storeType == StoreType.FS) { + outw.println(MessageFormat.format(CLIText.get().lfsStoreDirectory, + directory)); + outw.println(MessageFormat.format(CLIText.get().lfsStoreUrl, + getStoreUrl(baseURI))); + } + } + + private void checkOptions() { + if (bucket == null || bucket.length() == 0) { + throw die(MessageFormat.format(CLIText.get().s3InvalidBucket, + bucket)); + } + } + + private void readAWSKeys() throws IOException, ConfigInvalidException { + String credentialsPath = System.getProperty("user.home") //$NON-NLS-1$ + + "/.aws/credentials"; //$NON-NLS-1$ + FileBasedConfig c = new FileBasedConfig(new File(credentialsPath), + FS.DETECTED); + c.load(); + accessKey = c.getString("default", null, "accessKey"); //$NON-NLS-1$//$NON-NLS-2$ + secretKey = c.getString("default", null, "secretKey"); //$NON-NLS-1$ //$NON-NLS-2$ + if (accessKey == null || accessKey.isEmpty()) { + throw die(MessageFormat.format(CLIText.get().lfsNoAccessKey, + credentialsPath)); + } + if (secretKey == null || secretKey.isEmpty()) { + throw die(MessageFormat.format(CLIText.get().lfsNoSecretKey, + credentialsPath)); + } + } + + private String getStoreUrl(URI baseURI) { + if (storeUrl == null) { + if (storeType == StoreType.FS) { + storeUrl = baseURI + "/" + OBJECTS; //$NON-NLS-1$ + } else { + die("Local store not running and no --store-url specified"); //$NON-NLS-1$ + } + } + return storeUrl; + } + + private String getProtocolUrl(URI baseURI) { + if (protocolUrl == null) { + protocolUrl = baseURI + PROTOCOL_PATH; + } + return protocolUrl; + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java index d3a0a3e14e..eec10c774f 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/MakeCacheTree.java @@ -1,51 +1,16 @@ /* * Copyright (C) 2008, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; -import static java.lang.Integer.valueOf; - import java.io.IOException; import java.text.MessageFormat; @@ -64,10 +29,10 @@ class MakeCacheTree extends TextBuiltin { show(tree); } - private void show(final DirCacheTree tree) throws IOException { + private void show(DirCacheTree tree) throws IOException { outw.println(MessageFormat.format(CLIText.get().cacheTreePathInfo, - tree.getPathString(), valueOf(tree.getEntrySpan()), - valueOf(tree.getChildCount()))); + tree.getPathString(), Integer.valueOf(tree.getEntrySpan()), + Integer.valueOf(tree.getChildCount()))); for (int i = 0; i < tree.getChildCount(); i++) show(tree.getChild(i)); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadChangedPathFilter.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadChangedPathFilter.java new file mode 100644 index 0000000000..1414165e54 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadChangedPathFilter.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2023, Google LLC + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm.debug; + +import java.io.FileInputStream; +import java.util.HashSet; + +import org.eclipse.jgit.pgm.Command; +import org.eclipse.jgit.pgm.TextBuiltin; +import org.eclipse.jgit.util.NB; +import org.kohsuke.args4j.Argument; + +/** + * Prints the contents of the BDAT chunk from commit-graph file. + * <p> + * This is a debugging tool for changed path filter development. + */ +@Command +class ReadChangedPathFilter extends TextBuiltin { + + static final int CHUNK_ID_OID_FANOUT = 0x4f494446; /* "OIDF" */ + + static final int CHUNK_ID_BLOOM_FILTER_INDEX = 0x42494458; /* "BIDX" */ + + static final int CHUNK_ID_BLOOM_FILTER_DATA = 0x42444154; /* "BDAT" */ + + @Argument(index = 0) + private String input; + + static HashSet<String> changedPathStrings(byte[] data) { + int oidf_offset = -1; + int bidx_offset = -1; + int bdat_offset = -1; + for (int i = 8; i < data.length - 4; i += 12) { + switch (NB.decodeInt32(data, i)) { + case CHUNK_ID_OID_FANOUT: + oidf_offset = (int) NB.decodeInt64(data, i + 4); + break; + case CHUNK_ID_BLOOM_FILTER_INDEX: + bidx_offset = (int) NB.decodeInt64(data, i + 4); + break; + case CHUNK_ID_BLOOM_FILTER_DATA: + bdat_offset = (int) NB.decodeInt64(data, i + 4); + break; + } + } + bdat_offset += 12; // skip version, hash count, bits per entry + int commit_count = NB.decodeInt32(data, oidf_offset + 255 * 4); + int[] changed_path_length_cumuls = new int[commit_count]; + for (int i = 0; i < commit_count; i++) { + changed_path_length_cumuls[i] = NB.decodeInt32(data, + bidx_offset + i * 4); + } + HashSet<String> changed_paths = new HashSet<>(); + for (int i = 0; i < commit_count; i++) { + int prior_cumul = i == 0 ? 0 : changed_path_length_cumuls[i - 1]; + String changed_path = ""; //$NON-NLS-1$ + for (int j = prior_cumul; j < changed_path_length_cumuls[i]; j++) { + changed_path += data[bdat_offset + j] + ","; //$NON-NLS-1$ + } + changed_paths.add(changed_path); + } + return changed_paths; + } + + /** {@inheritDoc} */ + @Override + protected void run() throws Exception { + try (FileInputStream in = new FileInputStream(input) + ) { + byte[] data = in.readAllBytes(); + outw.println(changedPathStrings(data).toString()); + } + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadDirCache.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadDirCache.java index 07bfc4b5fe..3d20e01d3c 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadDirCache.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadDirCache.java @@ -1,51 +1,16 @@ /* * Copyright (C) 2008, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; -import static java.lang.Long.valueOf; - import java.text.MessageFormat; import org.eclipse.jgit.pgm.Command; @@ -63,6 +28,6 @@ class ReadDirCache extends TextBuiltin { final long end = System.currentTimeMillis(); outw.print(" "); //$NON-NLS-1$ outw.println(MessageFormat.format(CLIText.get().averageMSPerRead, - valueOf((end - start) / cnt))); + Long.valueOf((end - start) / cnt))); } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadReftable.java new file mode 100644 index 0000000000..a2443d315f --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ReadReftable.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2017, Google Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm.debug; + +import java.io.FileInputStream; +import java.io.IOException; + +import org.eclipse.jgit.internal.storage.io.BlockSource; +import org.eclipse.jgit.internal.storage.reftable.RefCursor; +import org.eclipse.jgit.internal.storage.reftable.ReftableReader; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.pgm.Command; +import org.eclipse.jgit.pgm.TextBuiltin; +import org.kohsuke.args4j.Argument; + +@Command +class ReadReftable extends TextBuiltin { + @Argument(index = 0) + private String input; + + @Argument(index = 1, required = false) + private String ref; + + @Override + protected void run() throws Exception { + try (FileInputStream in = new FileInputStream(input); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + try (RefCursor rc = ref != null + ? reader.seekRefsWithPrefix(ref) + : reader.allRefs()) { + while (rc.next()) { + write(rc.getRef()); + } + } + } + } + + private void write(Ref r) throws IOException { + if (r.isSymbolic()) { + outw.println(r.getTarget().getName() + '\t' + r.getName()); + return; + } + + ObjectId id1 = r.getObjectId(); + if (id1 != null) { + outw.println(id1.name() + '\t' + r.getName()); + } + + ObjectId id2 = r.getPeeledObjectId(); + if (id2 != null) { + outw.println('^' + id2.name()); + } + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java index 494055a265..22d9e3440a 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java @@ -1,49 +1,16 @@ /* - * Copyright (C) 2009-2010, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2009-2010, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; -import static org.eclipse.jgit.lib.RefDatabase.ALL; +import static java.nio.charset.StandardCharsets.UTF_8; import java.io.BufferedReader; import java.io.File; @@ -51,8 +18,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.text.MessageFormat; +import java.time.Instant; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.ListIterator; @@ -112,14 +79,17 @@ class RebuildCommitGraph extends TextBuiltin { private final ProgressMonitor pm = new TextProgressMonitor(errw); - private Map<ObjectId, ObjectId> rewrites = new HashMap<ObjectId, ObjectId>(); + private Map<ObjectId, ObjectId> rewrites = new HashMap<>(); @Override protected void run() throws Exception { - if (!really && !db.getRefDatabase().getRefs(ALL).isEmpty()) { + if (!really && db.getRefDatabase().hasRefs()) { + File directory = db.getDirectory(); + String absolutePath = directory == null ? "null" //$NON-NLS-1$ + : directory.getAbsolutePath(); errw.println( MessageFormat.format(CLIText.get().fatalThisProgramWillDestroyTheRepository - , db.getDirectory().getAbsolutePath(), REALLY)); + , absolutePath, REALLY)); throw die(CLIText.get().needApprovalToDestroyCurrentRepository); } if (!refList.isFile()) @@ -134,12 +104,12 @@ class RebuildCommitGraph extends TextBuiltin { } private void recreateCommitGraph() throws IOException { - final Map<ObjectId, ToRewrite> toRewrite = new HashMap<ObjectId, ToRewrite>(); - List<ToRewrite> queue = new ArrayList<ToRewrite>(); + final Map<ObjectId, ToRewrite> toRewrite = new HashMap<>(); + List<ToRewrite> queue = new ArrayList<>(); try (RevWalk rw = new RevWalk(db); final BufferedReader br = new BufferedReader( new InputStreamReader(new FileInputStream(graph), - Constants.CHARSET))) { + UTF_8))) { String line; while ((line = br.readLine()) != null) { final String[] parts = line.split("[ \t]{1,}"); //$NON-NLS-1$ @@ -164,7 +134,7 @@ class RebuildCommitGraph extends TextBuiltin { } } - pm.beginTask("Rewriting commits", queue.size()); + pm.beginTask("Rewriting commits", queue.size()); //$NON-NLS-1$ try (ObjectInserter oi = db.newObjectInserter()) { final ObjectId emptyTree = oi.insert(Constants.OBJ_TREE, new byte[] {}); @@ -173,7 +143,7 @@ class RebuildCommitGraph extends TextBuiltin { while (!queue.isEmpty()) { final ListIterator<ToRewrite> itr = queue .listIterator(queue.size()); - queue = new ArrayList<ToRewrite>(); + queue = new ArrayList<>(); REWRITE: while (itr.hasPrevious()) { final ToRewrite t = itr.previous(); final ObjectId[] newParents = new ObjectId[t.oldParents.length]; @@ -185,9 +155,8 @@ class RebuildCommitGraph extends TextBuiltin { // rewritten. queue.add(t); continue REWRITE; - } else { - newParents[k] = p.newId; } + newParents[k] = p.newId; } else { // We have the old parent object. Use it. // @@ -197,10 +166,11 @@ class RebuildCommitGraph extends TextBuiltin { final CommitBuilder newc = new CommitBuilder(); newc.setTreeId(emptyTree); - newc.setAuthor(new PersonIdent(me, new Date(t.commitTime))); + newc.setAuthor(new PersonIdent(me, + Instant.ofEpochSecond(t.commitTime))); newc.setCommitter(newc.getAuthor()); newc.setParentIds(newParents); - newc.setMessage("ORIGINAL " + t.oldId.name() + "\n"); //$NON-NLS-2$ + newc.setMessage("ORIGINAL " + t.oldId.name() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ t.newId = oi.insert(newc); rewrites.put(t.oldId, t.newId); pm.update(1); @@ -220,7 +190,7 @@ class RebuildCommitGraph extends TextBuiltin { ObjectId newId; - ToRewrite(final ObjectId o, final long t, final ObjectId[] p) { + ToRewrite(ObjectId o, long t, ObjectId[] p) { oldId = o; commitTime = t; oldParents = p; @@ -232,7 +202,7 @@ class RebuildCommitGraph extends TextBuiltin { final ObjectId id = db.resolve(Constants.HEAD); if (!ObjectId.isId(head) && id != null) { final LockFile lf; - lf = new LockFile(new File(db.getDirectory(), Constants.HEAD), db.getFS()); + lf = new LockFile(new File(db.getDirectory(), Constants.HEAD)); if (!lf.lock()) throw new IOException(MessageFormat.format(CLIText.get().cannotLock, Constants.HEAD)); lf.write(id); @@ -243,8 +213,7 @@ class RebuildCommitGraph extends TextBuiltin { private void deleteAllRefs() throws Exception { final RevWalk rw = new RevWalk(db); - Map<String, Ref> refs = db.getRefDatabase().getRefs(ALL); - for (final Ref r : refs.values()) { + for (Ref r : db.getRefDatabase().getRefs()) { if (Constants.HEAD.equals(r.getName())) continue; final RefUpdate u = db.updateRef(r.getName()); @@ -257,16 +226,18 @@ class RebuildCommitGraph extends TextBuiltin { final Map<String, Ref> refs = computeNewRefs(); new RefWriter(refs.values()) { @Override - protected void writeFile(final String name, final byte[] content) + protected void writeFile(String name, byte[] content) throws IOException { final File file = new File(db.getDirectory(), name); - final LockFile lck = new LockFile(file, db.getFS()); + final LockFile lck = new LockFile(file); if (!lck.lock()) throw new ObjectWritingException(MessageFormat.format(CLIText.get().cantWrite, file)); try { lck.write(content); } catch (IOException ioe) { - throw new ObjectWritingException(MessageFormat.format(CLIText.get().cantWrite, file)); + throw new ObjectWritingException( + MessageFormat.format(CLIText.get().cantWrite, file), + ioe); } if (!lck.commit()) throw new ObjectWritingException(MessageFormat.format(CLIText.get().cantWrite, file)); @@ -275,11 +246,11 @@ class RebuildCommitGraph extends TextBuiltin { } private Map<String, Ref> computeNewRefs() throws IOException { - final Map<String, Ref> refs = new HashMap<String, Ref>(); + final Map<String, Ref> refs = new HashMap<>(); try (RevWalk rw = new RevWalk(db); BufferedReader br = new BufferedReader( new InputStreamReader(new FileInputStream(refList), - Constants.CHARSET))) { + UTF_8))) { String line; while ((line = br.readLine()) != null) { final String[] parts = line.split("[ \t]{1,}"); //$NON-NLS-1$ @@ -297,7 +268,9 @@ class RebuildCommitGraph extends TextBuiltin { errw.println(MessageFormat.format(CLIText.get().skippingObject, type, name)); continue; } - throw new MissingObjectException(id, type); + MissingObjectException mue1 = new MissingObjectException(id, type); + mue1.initCause(mue); + throw mue1; } refs.put(name, new ObjectIdRef.Unpeeled(Ref.Storage.PACKED, name, id)); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCacheTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCacheTree.java index e287425d7b..da16b33701 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCacheTree.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCacheTree.java @@ -1,51 +1,16 @@ /* * Copyright (C) 2008, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; -import static java.lang.Integer.valueOf; - import java.io.IOException; import java.text.MessageFormat; @@ -66,10 +31,10 @@ class ShowCacheTree extends TextBuiltin { show(tree); } - private void show(final DirCacheTree tree) throws IOException { + private void show(DirCacheTree tree) throws IOException { outw.println(MessageFormat.format(CLIText.get().cacheTreePathInfo, - tree.getPathString(), valueOf(tree.getEntrySpan()), - valueOf(tree.getChildCount()))); + tree.getPathString(), Integer.valueOf(tree.getEntrySpan()), + Integer.valueOf(tree.getChildCount()))); for (int i = 0; i < tree.getChildCount(); i++) show(tree.getChild(i)); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java index aa258073b6..e46d703592 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; @@ -64,11 +31,11 @@ class ShowCommands extends TextBuiltin { final CommandRef[] list = CommandCatalog.all(); int width = 0; - for (final CommandRef c : list) + for (CommandRef c : list) width = Math.max(width, c.getName().length()); width += 2; - for (final CommandRef c : list) { + for (CommandRef c : list) { errw.print(c.isCommon() ? '*' : ' '); errw.print(' '); @@ -82,26 +49,29 @@ class ShowCommands extends TextBuiltin { errw.println(); } - static enum Format { - /** */ + enum Format { + /** Get usage */ USAGE { - void print(ThrowingPrintWriter err, final CommandRef c) throws IOException { + @Override + void print(ThrowingPrintWriter err, CommandRef c) throws IOException { String usage = c.getUsage(); if (usage != null && usage.length() > 0) err.print(CLIText.get().resourceBundle().getString(usage)); } }, - /** */ + /** Get implementation class name */ CLASSES { - void print(ThrowingPrintWriter err, final CommandRef c) throws IOException { + @Override + void print(ThrowingPrintWriter err, CommandRef c) throws IOException { err.print(c.getImplementationClassName()); } }, - /** */ + /** Get URL of implementation class */ URLS { - void print(ThrowingPrintWriter err, final CommandRef c) throws IOException { + @Override + void print(ThrowingPrintWriter err, CommandRef c) throws IOException { final ClassLoader ldr = c.getImplementationClassLoader(); String cn = c.getImplementationClassName(); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java index bb4f73d7d1..96add0f188 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowDirCache.java @@ -2,54 +2,21 @@ * Copyright (C) 2008, Google Inc. * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; -import static java.lang.Integer.valueOf; - -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Locale; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheEntry; @@ -66,25 +33,27 @@ class ShowDirCache extends TextBuiltin { @Override protected void run() throws Exception { - final SimpleDateFormat fmt; - fmt = new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss.SSS"); //$NON-NLS-1$ + final DateTimeFormatter fmt = DateTimeFormatter + .ofPattern("yyyy-MM-dd,HH:mm:ss.nnnnnnnnn") //$NON-NLS-1$ + .withLocale(Locale.getDefault()) + .withZone(ZoneId.systemDefault()); final DirCache cache = db.readDirCache(); for (int i = 0; i < cache.getEntryCount(); i++) { final DirCacheEntry ent = cache.getEntry(i); final FileMode mode = FileMode.fromBits(ent.getRawMode()); final int len = ent.getLength(); - long lastModified = ent.getLastModified(); - final Date mtime = new Date(lastModified); + Instant mtime = ent.getLastModifiedInstant(); final int stage = ent.getStage(); outw.print(mode); - outw.format(" %6d", valueOf(len)); //$NON-NLS-1$ + outw.format(" %6d", Integer.valueOf(len)); //$NON-NLS-1$ outw.print(' '); - if (millis) - outw.print(lastModified); - else + if (millis) { + outw.print(mtime.toEpochMilli()); + } else { outw.print(fmt.format(mtime)); + } outw.print(' '); outw.print(ent.getObjectId().name()); outw.print(' '); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java index 7b5cdbf8f7..80d3503851 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2010, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2010, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; @@ -64,6 +31,7 @@ import org.eclipse.jgit.pgm.Command; import org.eclipse.jgit.pgm.TextBuiltin; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.util.TemporaryBuffer; import org.kohsuke.args4j.Argument; @@ -75,7 +43,10 @@ class ShowPackDelta extends TextBuiltin { @Override protected void run() throws Exception { ObjectReader reader = db.newObjectReader(); - RevObject obj = new RevWalk(reader).parseAny(objectId); + RevObject obj; + try (RevWalk rw = new RevWalk(reader)) { + obj = rw.parseAny(objectId); + } byte[] delta = getDelta(reader, obj); // We're crossing our fingers that this will be a delta. Double @@ -84,9 +55,9 @@ class ShowPackDelta extends TextBuiltin { long size = reader.getObjectSize(obj, obj.getType()); try { if (BinaryDelta.getResultSize(delta) != size) - throw die("Object " + obj.name() + " is not a delta"); + throw die("Object " + obj.name() + " is not a delta"); //$NON-NLS-1$ //$NON-NLS-2$ } catch (ArrayIndexOutOfBoundsException bad) { - throw die("Object " + obj.name() + " is not a delta"); + throw die("Object " + obj.name() + " is not a delta", bad); //$NON-NLS-1$ //$NON-NLS-2$ } outw.println(BinaryDelta.format(delta)); @@ -98,10 +69,11 @@ class ShowPackDelta extends TextBuiltin { ObjectReuseAsIs asis = (ObjectReuseAsIs) reader; ObjectToPack target = asis.newObjectToPack(obj, obj.getType()); - PackWriter pw = new PackWriter(reader) { + PackWriter pw = new PackWriter(new PackConfig(), reader) { @Override - public void select(ObjectToPack otp, StoredObjectRepresentation next) { + public boolean select(ObjectToPack otp, StoredObjectRepresentation next) { otp.select(next); + return true; } }; @@ -121,12 +93,13 @@ class ShowPackDelta extends TextBuiltin { ptr++; ptr++; - @SuppressWarnings("resource" /* java 7 */) - TemporaryBuffer.Heap raw = new TemporaryBuffer.Heap(bufArray.length); - InflaterInputStream inf = new InflaterInputStream( - new ByteArrayInputStream(bufArray, ptr, bufArray.length)); - raw.copy(inf); - inf.close(); - return raw.toByteArray(); + try (TemporaryBuffer.Heap raw = new TemporaryBuffer.Heap( + bufArray.length); + InflaterInputStream inf = new InflaterInputStream( + new ByteArrayInputStream(bufArray, ptr, + bufArray.length))) { + raw.copy(inf); + return raw.toByteArray(); + } } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java index dcfa8cf00a..2ce1711404 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java @@ -1,51 +1,15 @@ /* - * Copyright (C) 2010, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2010, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; -import static java.lang.Integer.valueOf; -import static java.lang.Long.valueOf; - import java.io.File; import java.lang.reflect.Field; import java.security.MessageDigest; @@ -138,9 +102,8 @@ class TextHashFunctions extends TextBuiltin { Arrays.fill(buf16, (byte) 0); System.arraycopy(raw, ptr, buf16, 0, end - ptr); return rabin(buf16, 0); - } else { - return rabin(raw, ptr); } + return rabin(raw, ptr); } private int rabin(byte[] raw, int ptr) { @@ -250,17 +213,17 @@ class TextHashFunctions extends TextBuiltin { // // - @Option(name = "--hash", multiValued = true, metaVar = "NAME", usage = "Enable hash function(s)") - List<String> hashFunctions = new ArrayList<String>(); + @Option(name = "--hash", metaVar = "NAME", usage = "Enable hash function(s)") + List<String> hashFunctions = new ArrayList<>(); - @Option(name = "--fold", multiValued = true, metaVar = "NAME", usage = "Enable fold function(s)") - List<String> foldFunctions = new ArrayList<String>(); + @Option(name = "--fold", metaVar = "NAME", usage = "Enable fold function(s)") + List<String> foldFunctions = new ArrayList<>(); @Option(name = "--text-limit", metaVar = "LIMIT", usage = "Maximum size in KiB to scan") int textLimit = 15 * 1024; // 15 MiB as later we do * 1024. - @Option(name = "--repository", aliases = { "-r" }, multiValued = true, metaVar = "GIT_DIR", usage = "Repository to scan") - List<File> gitDirs = new ArrayList<File>(); + @Option(name = "--repository", aliases = { "-r" }, metaVar = "GIT_DIR", usage = "Repository to scan") + List<File> gitDirs = new ArrayList<>(); @Override protected boolean requiresRepository() { @@ -286,25 +249,22 @@ class TextHashFunctions extends TextBuiltin { else rb.findGitDir(dir); - Repository db = rb.build(); - try { - run(db); - } finally { - db.close(); + try (Repository repo = rb.build()) { + run(repo); } } } - private void run(Repository db) throws Exception { + private void run(Repository repo) throws Exception { List<Function> all = init(); long fileCnt = 0; long lineCnt = 0; - try (ObjectReader or = db.newObjectReader()) { - final MutableObjectId id = new MutableObjectId(); + try (ObjectReader or = repo.newObjectReader(); RevWalk rw = new RevWalk(or); - TreeWalk tw = new TreeWalk(or); - tw.reset(rw.parseTree(db.resolve(Constants.HEAD))); + TreeWalk tw = new TreeWalk(or)) { + final MutableObjectId id = new MutableObjectId(); + tw.reset(rw.parseTree(repo.resolve(Constants.HEAD))); tw.setRecursive(true); while (tw.next()) { @@ -321,13 +281,13 @@ class TextHashFunctions extends TextBuiltin { continue; } - if (RawText.isBinary(raw)) + if (RawText.isBinary(raw, raw.length, true)) continue; RawText txt = new RawText(raw); int[] lines = new int[txt.size()]; int cnt = 0; - HashSet<Line> u = new HashSet<Line>(); + HashSet<Line> u = new HashSet<>(); for (int i = 0; i < txt.size(); i++) { if (u.add(new Line(txt, i))) lines[cnt++] = i; @@ -341,17 +301,18 @@ class TextHashFunctions extends TextBuiltin { } } - if (db.getDirectory() != null) { - String name = db.getDirectory().getName(); - File parent = db.getDirectory().getParentFile(); + File directory = repo.getDirectory(); + if (directory != null) { + String name = directory.getName(); + File parent = directory.getParentFile(); if (name.equals(Constants.DOT_GIT) && parent != null) name = parent.getName(); outw.println(name + ":"); //$NON-NLS-1$ } - outw.format(" %6d files; %5d avg. unique lines/file\n", // - valueOf(fileCnt), // - valueOf(lineCnt / fileCnt)); - outw.format("%-20s %-15s %9s\n", "Hash", "Fold", "Max Len"); + outw.format(" %6d files; %5d avg. unique lines/file\n", //$NON-NLS-1$ + Long.valueOf(fileCnt), // + Long.valueOf(lineCnt / fileCnt)); + outw.format("%-20s %-15s %9s\n", "Hash", "Fold", "Max Len"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ outw.println("-----------------------------------------------"); //$NON-NLS-1$ String lastHashName = null; for (Function fun : all) { @@ -361,7 +322,7 @@ class TextHashFunctions extends TextBuiltin { outw.format("%-20s %-15s %9d\n", // //$NON-NLS-1$ hashName, // fun.fold.name, // - valueOf(fun.maxChainLength)); + Integer.valueOf(fun.maxChainLength)); lastHashName = fun.hash.name; } outw.println(); @@ -385,8 +346,8 @@ class TextHashFunctions extends TextBuiltin { } private List<Function> init() { - List<Hash> hashes = new ArrayList<Hash>(); - List<Fold> folds = new ArrayList<Fold>(); + List<Hash> hashes = new ArrayList<>(); + List<Fold> folds = new ArrayList<>(); try { for (Field f : TextHashFunctions.class.getDeclaredFields()) { @@ -403,13 +364,11 @@ class TextHashFunctions extends TextBuiltin { folds.add(fold); } } - } catch (IllegalArgumentException e) { - throw new RuntimeException("Cannot determine names", e); - } catch (IllegalAccessException e) { - throw new RuntimeException("Cannot determine names", e); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException("Cannot determine names", e); //$NON-NLS-1$ } - List<Function> all = new ArrayList<Function>(); + List<Function> all = new ArrayList<>(); for (Hash cmp : hashes) { if (include(cmp.name, hashFunctions)) { for (Fold f : folds) { @@ -446,7 +405,7 @@ class TextHashFunctions extends TextBuiltin { } /** Base class for any hashCode function to be tested. */ - private static abstract class Hash extends RawTextComparator { + private abstract static class Hash extends RawTextComparator { String name; @Override @@ -456,7 +415,7 @@ class TextHashFunctions extends TextBuiltin { } /** Base class for any hashCode folding function to be tested. */ - private static abstract class Fold { + private abstract static class Fold { String name; /** @@ -474,7 +433,7 @@ class TextHashFunctions extends TextBuiltin { } /** Utility to help us identify unique lines in a file. */ - private class Line { + private static class Line { private final RawText txt; private final int pos; @@ -499,7 +458,7 @@ class TextHashFunctions extends TextBuiltin { } } - private static int tableBits(final int sz) { + private static int tableBits(int sz) { int bits = 31 - Integer.numberOfLeadingZeros(sz); if (bits == 0) bits = 1; diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java new file mode 100644 index 0000000000..aa1b81f2b6 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2017, Google Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm.debug; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.eclipse.jgit.internal.storage.io.BlockSource; +import org.eclipse.jgit.internal.storage.reftable.RefCursor; +import org.eclipse.jgit.internal.storage.reftable.ReftableReader; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefComparator; +import org.eclipse.jgit.lib.TextProgressMonitor; +import org.eclipse.jgit.pgm.Command; +import org.eclipse.jgit.pgm.TextBuiltin; +import org.kohsuke.args4j.Argument; + +@Command +class VerifyReftable extends TextBuiltin { + private static final long SEED1 = 0xaba8bb4de4caf86cL; + private static final long SEED2 = 0x28bb5c25ad43ecb5L; + + @Argument(index = 0) + private String lsRemotePath; + + @Argument(index = 1) + private String reftablePath; + + @Override + protected void run() throws Exception { + List<Ref> refs = WriteReftable.readRefs(lsRemotePath); + + try (FileInputStream in = new FileInputStream(reftablePath); + BlockSource src = BlockSource.from(in); + ReftableReader reader = new ReftableReader(src)) { + scan(refs, reader); + seek(refs, reader); + byId(refs, reader); + } + } + + @SuppressWarnings("nls") + private void scan(List<Ref> refs, ReftableReader reader) + throws IOException { + errw.print(String.format("%-20s", "sequential scan...")); + errw.flush(); + try (RefCursor rc = reader.allRefs()) { + for (Ref exp : refs) { + verify(exp, rc); + } + if (rc.next()) { + throw die("expected end of table"); + } + } + errw.println(" OK"); + } + + @SuppressWarnings("nls") + private void seek(List<Ref> refs, ReftableReader reader) + throws IOException { + List<Ref> rnd = new ArrayList<>(refs); + Collections.shuffle(rnd, new Random(SEED1)); + + TextProgressMonitor pm = new TextProgressMonitor(errw); + pm.beginTask("random seek", rnd.size()); + for (Ref exp : rnd) { + try (RefCursor rc = reader.seekRef(exp.getName())) { + verify(exp, rc); + if (rc.next()) { + throw die("should not have ref after " + exp.getName()); + } + } + pm.update(1); + } + pm.endTask(); + } + + @SuppressWarnings("nls") + private void byId(List<Ref> refs, ReftableReader reader) + throws IOException { + Map<ObjectId, List<Ref>> want = groupById(refs); + List<List<Ref>> rnd = new ArrayList<>(want.values()); + Collections.shuffle(rnd, new Random(SEED2)); + + TextProgressMonitor pm = new TextProgressMonitor(errw); + pm.beginTask("byObjectId", rnd.size()); + for (List<Ref> exp : rnd) { + Collections.sort(exp, RefComparator.INSTANCE); + ObjectId id = exp.get(0).getObjectId(); + try (RefCursor rc = reader.byObjectId(id)) { + for (Ref r : exp) { + verify(r, rc); + } + } + pm.update(1); + } + pm.endTask(); + } + + private static Map<ObjectId, List<Ref>> groupById(List<Ref> refs) { + Map<ObjectId, List<Ref>> m = new HashMap<>(); + for (Ref r : refs) { + ObjectId id = r.getObjectId(); + if (id != null) { + List<Ref> c = m.get(id); + if (c == null) { + c = new ArrayList<>(2); + m.put(id, c); + } + c.add(r); + } + } + return m; + } + + @SuppressWarnings("nls") + private void verify(Ref exp, RefCursor rc) throws IOException { + if (!rc.next()) { + throw die("ended before " + exp.getName()); + } + + Ref act = rc.getRef(); + if (!exp.getName().equals(act.getName())) { + throw die(String.format("expected %s, found %s", + exp.getName(), + act.getName())); + } + + if (exp.isSymbolic()) { + if (!act.isSymbolic()) { + throw die("expected " + act.getName() + " to be symbolic"); + } + if (!exp.getTarget().getName().equals(act.getTarget().getName())) { + throw die(String.format("expected %s to be %s, found %s", + exp.getName(), + exp.getLeaf().getName(), + act.getLeaf().getName())); + } + return; + } + + if (!AnyObjectId.isEqual(exp.getObjectId(), act.getObjectId())) { + throw die(String.format("expected %s to be %s, found %s", + exp.getName(), + id(exp.getObjectId()), + id(act.getObjectId()))); + } + + if (exp.getPeeledObjectId() != null + && !AnyObjectId.isEqual(exp.getPeeledObjectId(), + act.getPeeledObjectId())) { + throw die(String.format("expected %s to be %s, found %s", + exp.getName(), + id(exp.getPeeledObjectId()), + id(act.getPeeledObjectId()))); + } + } + + @SuppressWarnings("nls") + private static String id(ObjectId id) { + return id != null ? id.name() : "<null>"; + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteDirCache.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteDirCache.java index 42428c7740..d367f02497 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteDirCache.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteDirCache.java @@ -1,45 +1,12 @@ /* * Copyright (C) 2008, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.debug; diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java new file mode 100644 index 0000000000..7aff2dd9cd --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2017, Google Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm.debug; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.lib.Constants.HEAD; +import static org.eclipse.jgit.lib.Constants.MASTER; +import static org.eclipse.jgit.lib.Constants.R_HEADS; +import static org.eclipse.jgit.lib.Ref.Storage.NEW; +import static org.eclipse.jgit.lib.Ref.Storage.PACKED; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.time.Instant; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; +import org.eclipse.jgit.internal.storage.reftable.ReftableWriter; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.SymbolicRef; +import org.eclipse.jgit.pgm.Command; +import org.eclipse.jgit.pgm.TextBuiltin; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +@Command +class WriteReftable extends TextBuiltin { + private static final int KIB = 1 << 10; + private static final int MIB = 1 << 20; + + @Option(name = "--block-size") + private int refBlockSize; + + @Option(name = "--log-block-size") + private int logBlockSize; + + @Option(name = "--restart-interval") + private int restartInterval; + + @Option(name = "--index-levels") + private int indexLevels; + + @Option(name = "--reflog-in") + private String reflogIn; + + @Option(name = "--no-index-objects") + private boolean noIndexObjects; + + @Argument(index = 0) + private String in; + + @Argument(index = 1) + private String out; + + @SuppressWarnings({ "nls", "boxing" }) + @Override + protected void run() throws Exception { + List<Ref> refs = readRefs(in); + List<LogEntry> logs = readLog(reflogIn); + + ReftableWriter.Stats stats; + try (OutputStream os = new FileOutputStream(out)) { + ReftableConfig cfg = new ReftableConfig(); + cfg.setIndexObjects(!noIndexObjects); + if (refBlockSize > 0) { + cfg.setRefBlockSize(refBlockSize); + } + if (logBlockSize > 0) { + cfg.setLogBlockSize(logBlockSize); + } + if (restartInterval > 0) { + cfg.setRestartInterval(restartInterval); + } + if (indexLevels > 0) { + cfg.setMaxIndexLevels(indexLevels); + } + + ReftableWriter w = new ReftableWriter(cfg, os); + w.setMinUpdateIndex(min(logs)).setMaxUpdateIndex(max(logs)); + w.begin(); + w.sortAndWriteRefs(refs); + for (LogEntry e : logs) { + w.writeLog(e.ref, e.updateIndex, e.who, + e.oldId, e.newId, e.message); + } + stats = w.finish().getStats(); + } + + double fileMiB = ((double) stats.totalBytes()) / MIB; + printf("Summary:"); + printf(" file sz : %.1f MiB (%d bytes)", fileMiB, stats.totalBytes()); + printf(" padding : %d KiB", stats.paddingBytes() / KIB); + errw.println(); + + printf("Refs:"); + printf(" ref blk : %d", stats.refBlockSize()); + printf(" restarts: %d", stats.restartInterval()); + printf(" refs : %d", stats.refCount()); + if (stats.refIndexLevels() > 0) { + int idxSize = (int) Math.round(((double) stats.refIndexSize()) / KIB); + printf(" idx sz : %d KiB", idxSize); + printf(" idx lvl : %d", stats.refIndexLevels()); + } + printf(" avg ref : %d bytes", stats.refBytes() / refs.size()); + errw.println(); + + if (stats.objCount() > 0) { + int objMiB = (int) Math.round(((double) stats.objBytes()) / MIB); + int idLen = stats.objIdLength(); + printf("Objects:"); + printf(" obj blk : %d", stats.refBlockSize()); + printf(" restarts: %d", stats.restartInterval()); + printf(" objects : %d", stats.objCount()); + printf(" obj sz : %d MiB (%d bytes)", objMiB, stats.objBytes()); + if (stats.objIndexSize() > 0) { + int s = (int) Math.round(((double) stats.objIndexSize()) / KIB); + printf(" idx sz : %d KiB", s); + printf(" idx lvl : %d", stats.objIndexLevels()); + } + printf(" id len : %d bytes (%d hex digits)", idLen, 2 * idLen); + printf(" avg obj : %d bytes", stats.objBytes() / stats.objCount()); + errw.println(); + } + if (stats.logCount() > 0) { + int logMiB = (int) Math.round(((double) stats.logBytes()) / MIB); + printf("Log:"); + printf(" log blk : %d", stats.logBlockSize()); + printf(" logs : %d", stats.logCount()); + printf(" log sz : %d MiB (%d bytes)", logMiB, stats.logBytes()); + printf(" avg log : %d bytes", stats.logBytes() / logs.size()); + errw.println(); + } + } + + private void printf(String fmt, Object... args) throws IOException { + errw.println(String.format(fmt, args)); + } + + static List<Ref> readRefs(String inputFile) throws IOException { + List<Ref> refs = new ArrayList<>(); + try (BufferedReader br = new BufferedReader( + new InputStreamReader(new FileInputStream(inputFile), UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + ObjectId id = ObjectId.fromString(line.substring(0, 40)); + String name = line.substring(41, line.length()); + if (name.endsWith("^{}")) { //$NON-NLS-1$ + int lastIdx = refs.size() - 1; + Ref last = refs.get(lastIdx); + refs.set(lastIdx, new ObjectIdRef.PeeledTag(PACKED, + last.getName(), last.getObjectId(), id)); + continue; + } + + Ref ref; + if (name.equals(HEAD)) { + ref = new SymbolicRef(name, new ObjectIdRef.Unpeeled(NEW, + R_HEADS + MASTER, null)); + } else { + ref = new ObjectIdRef.PeeledNonTag(PACKED, name, id); + } + refs.add(ref); + } + } + Collections.sort(refs, (a, b) -> a.getName().compareTo(b.getName())); + return refs; + } + + private static List<LogEntry> readLog(String logPath) + throws FileNotFoundException, IOException { + if (logPath == null) { + return Collections.emptyList(); + } + + List<LogEntry> log = new ArrayList<>(); + try (BufferedReader br = new BufferedReader( + new InputStreamReader(new FileInputStream(logPath), UTF_8))) { + @SuppressWarnings("nls") + Pattern pattern = Pattern.compile("([^,]+)" // 1: ref + + ",([0-9]+(?:[.][0-9]+)?)" // 2: time + + ",([^,]+)" // 3: who + + ",([^,]+)" // 4: old + + ",([^,]+)" // 5: new + + ",(.*)"); // 6: msg + String line; + while ((line = br.readLine()) != null) { + Matcher m = pattern.matcher(line); + if (!m.matches()) { + throw new IOException("unparsed line: " + line); //$NON-NLS-1$ + } + String ref = m.group(1); + double t = Double.parseDouble(m.group(2)); + Instant time = Instant.ofEpochSecond((long) t); + long index = (long) (t * 1e6); + String user = m.group(3); + ObjectId oldId = parseId(m.group(4)); + ObjectId newId = parseId(m.group(5)); + String msg = m.group(6); + String email = user + "@gerrit"; //$NON-NLS-1$ + PersonIdent who = new PersonIdent(user, email, time, + ZoneOffset.ofHours(-8)); + log.add(new LogEntry(ref, index, who, oldId, newId, msg)); + } + } + Collections.sort(log, LogEntry::compare); + return log; + } + + private static long min(List<LogEntry> log) { + return log.stream().mapToLong(e -> e.updateIndex).min().orElse(0); + } + + private static long max(List<LogEntry> log) { + return log.stream().mapToLong(e -> e.updateIndex).max().orElse(0); + } + + private static ObjectId parseId(String s) { + if ("NULL".equals(s)) { //$NON-NLS-1$ + return ObjectId.zeroId(); + } + return ObjectId.fromString(s); + } + + private static class LogEntry { + static int compare(LogEntry a, LogEntry b) { + int cmp = a.ref.compareTo(b.ref); + if (cmp == 0) { + cmp = Long.signum(b.updateIndex - a.updateIndex); + } + return cmp; + } + + final String ref; + final long updateIndex; + final PersonIdent who; + final ObjectId oldId; + final ObjectId newId; + final String message; + + LogEntry(String ref, long updateIndex, PersonIdent who, + ObjectId oldId, ObjectId newId, String message) { + this.ref = ref; + this.updateIndex = updateIndex; + this.who = who; + this.oldId = oldId; + this.newId = newId; + this.message = message; + } + } +} 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 433ddf2b13..bb1e950542 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 @@ -1,60 +1,65 @@ /* * Copyright (C) 2010, 2013 Sasa Zivkov <sasa.zivkov@sap.com> - * Copyright (C) 2013, Obeo - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2013, 2025 Obeo and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.internal; import java.text.MessageFormat; +import java.util.Locale; import org.eclipse.jgit.nls.NLS; import org.eclipse.jgit.nls.TranslationBundle; +import org.kohsuke.args4j.Localizable; /** * Translation bundle for JGit command line interface */ +@SuppressWarnings("MissingSummary") public class CLIText extends TranslationBundle { + /** + * Formats text strings using {@code Localizable}. + * + */ + public static class Format implements Localizable { + final String text; + + Format(String text) { + this.text = text; + } + + @Override + public String formatWithLocale(Locale locale, Object... args) { + // we don't care about Locale for now + return format(args); + } + + @Override + public String format(Object... args) { + return MessageFormat.format(text, args); + } + } /** + * Format text + * + * @param text + * the text to format. + * @return a new Format instance. + */ + public static Format format(String text) { + return new Format(text); + } + + /** + * Get an instance of this translation bundle + * * @return an instance of this translation bundle */ public static CLIText get() { @@ -68,13 +73,25 @@ public class CLIText extends TranslationBundle { * @param line * the line to format * @return the formatted line - * @since 2.2 */ public static String formatLine(String line) { 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 + */ + public static String fatalError(String message) { + return MessageFormat.format(get().fatalError, message); + } + // @formatter:off + /***/ public String addIncompatibleOptions; /***/ public String alreadyOnBranch; /***/ public String alreadyUpToDate; /***/ public String answerNo; @@ -85,11 +102,11 @@ 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; /***/ public String cannotBeRenamed; - /***/ public String cannotChekoutNoHeadsAdvertisedByRemote; /***/ public String cannotCombineSquashWithNoff; /***/ public String cannotCreateCommand; /***/ public String cannotCreateOutputStream; @@ -98,27 +115,35 @@ public class CLIText extends TranslationBundle { /***/ public String cannotDeleteTheBranchWhichYouAreCurrentlyOn; /***/ public String cannotGuessLocalNameFrom; /***/ public String cannotLock; - /***/ public String cannotMergeDetachedHead; /***/ public String cannotReadBecause; /***/ public String cannotReadPackageInformation; /***/ public String cannotRenameDetachedHEAD; /***/ public String cannotResolve; /***/ public String cannotSetupConsole; /***/ public String cannotUseObjectsWithGlog; + /***/ public String cannotUseNameStatusOnlyAndNameOnly; /***/ public String cantFindGitDirectory; /***/ public String cantWrite; /***/ public String changesNotStagedForCommit; /***/ public String changesToBeCommitted; + /***/ public String checkingOut; /***/ public String checkoutConflict; /***/ public String checkoutConflictPathLine; + /***/ public String cleanRequireForce; /***/ public String clonedEmptyRepository; /***/ public String cloningInto; /***/ public String commitLabel; + /***/ public String configOnlyListOptionSupported; /***/ public String conflictingUsageOf_git_dir_andArguments; /***/ public String couldNotCreateBranch; /***/ public String dateInfo; /***/ public String deletedBranch; /***/ public String deletedRemoteBranch; + /***/ public String diffToolHelpSetToFollowing; + /***/ public String diffToolLaunch; + /***/ public String diffToolDied; + /***/ public String diffToolPromptToolName; + /***/ public String diffToolUnknownToolName; /***/ public String doesNotExist; /***/ public String dontOverwriteLocalChanges; /***/ public String everythingUpToDate; @@ -126,20 +151,47 @@ public class CLIText extends TranslationBundle { /***/ public String exporting; /***/ public String failedToCommitIndex; /***/ public String failedToLockIndex; - /***/ public String failedToLockTag; /***/ public String fatalError; /***/ public String fatalThisProgramWillDestroyTheRepository; + /***/ public String fetchingSubmodule; /***/ public String fileIsRequired; /***/ public String ffNotPossibleAborting; /***/ public String forcedUpdate; /***/ public String fromURI; /***/ public String initializedEmptyGitRepositoryIn; /***/ public String invalidHttpProxyOnlyHttpSupported; + /***/ public String invalidRecurseSubmodulesMode; + /***/ public String invalidUntrackedFilesMode; /***/ public String jgitVersion; + /***/ public String lfsNoAccessKey; + /***/ public String lfsNoSecretKey; + /***/ public String lfsProtocolUrl; + /***/ public String lfsStoreDirectory; + /***/ public String lfsStoreUrl; + /***/ public String lfsUnknownStoreType; /***/ public String lineFormat; /***/ public String listeningOn; + /***/ public String logNoSignatureVerifier; /***/ public String mergeCheckoutConflict; /***/ public String mergeConflict; + /***/ public String mergeToolHelpSetToFollowing; + /***/ public String mergeToolLaunch; + /***/ public String mergeToolDied; + /***/ public String mergeToolNoFiles; + /***/ public String mergeToolMerging; + /***/ public String mergeToolUnknownConflict; + /***/ public String mergeToolNormalConflict; + /***/ public String mergeToolMergeFailed; + /***/ public String mergeToolExecutionError; + /***/ public String mergeToolFileUnchanged; + /***/ public String mergeToolDeletedConflict; + /***/ public String mergeToolDeletedConflictByUs; + /***/ public String mergeToolDeletedConflictByThem; + /***/ public String mergeToolContinueUnresolvedPaths; + /***/ public String mergeToolWasMergeSuccessfull; + /***/ public String mergeToolDeletedMergeDecision; + /***/ public String mergeToolPromptToolName; + /***/ public String mergeToolUnknownToolName; /***/ public String mergeFailed; /***/ public String mergeCheckoutFailed; /***/ public String mergeMadeBy; @@ -164,6 +216,8 @@ public class CLIText extends TranslationBundle { /***/ public String metaVar_filepattern; /***/ public String metaVar_gitDir; /***/ public String metaVar_hostName; + /***/ public String metaVar_instant; + /***/ public String metaVar_lfsStorage; /***/ public String metaVar_linesOfContext; /***/ public String metaVar_message; /***/ public String metaVar_n; @@ -173,24 +227,31 @@ public class CLIText extends TranslationBundle { /***/ public String metaVar_pass; /***/ public String metaVar_path; /***/ public String metaVar_paths; + /***/ public String metaVar_pattern; /***/ public String metaVar_port; /***/ public String metaVar_ref; /***/ public String metaVar_refs; /***/ public String metaVar_refspec; /***/ public String metaVar_remoteName; + /***/ public String metaVar_s3Bucket; + /***/ public String metaVar_s3Region; + /***/ public String metaVar_s3StorageClass; /***/ public String metaVar_seconds; /***/ public String metaVar_service; /***/ public String metaVar_treeish; /***/ 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; + /***/ public String needSingleRevision; /***/ public String noGitRepositoryConfigured; /***/ public String noNamesFound; /***/ public String noSuchFile; - /***/ public String noSuchRemoteRef; + /***/ public String noSuchPathInRef; + /***/ public String noSuchRef; /***/ public String noTREESectionInIndex; /***/ public String nonFastForward; /***/ public String noSystemConsoleAvailable; @@ -201,6 +262,7 @@ public class CLIText extends TranslationBundle { /***/ public String notARevision; /***/ public String notATree; /***/ public String notAValidRefName; + /***/ public String notAValidCommitName; /***/ public String notAnIndexFile; /***/ public String notAnObject; /***/ public String notFound; @@ -210,7 +272,7 @@ public class CLIText extends TranslationBundle { /***/ public String onBranchToBeBorn; /***/ public String onBranch; /***/ public String onlyOneMetaVarExpectedIn; - /***/ public String onlyOneOfIncludeOnlyAllInteractiveCanBeUsed; + /***/ public String onlyOneCommitOptionAllowed; /***/ public String password; /***/ public String pathspecDidNotMatch; /***/ public String pushTo; @@ -219,7 +281,10 @@ public class CLIText extends TranslationBundle { /***/ public String remoteMessage; /***/ public String remoteRefObjectChangedIsNotExpectedOne; /***/ public String remoteSideDoesNotSupportDeletingRefs; + /***/ public String removing; /***/ public String repaint; + /***/ public String resetNoMode; + /***/ public String s3InvalidBucket; /***/ public String serviceNotSupported; /***/ public String skippingObject; /***/ public String statusFileListFormat; @@ -235,16 +300,20 @@ public class CLIText extends TranslationBundle { /***/ public String statusDeletedByUs; /***/ public String statusBothAdded; /***/ public String statusBothModified; + /***/ public String submoduleRegistered; /***/ public String switchedToNewBranch; /***/ public String switchedToBranch; /***/ public String tagAlreadyExists; /***/ public String tagLabel; + /***/ public String tagNotFound; /***/ public String taggerInfo; /***/ public String timeInMilliSeconds; /***/ public String tooManyRefsGiven; /***/ public String treeIsRequired; /***/ public char[] unknownIoErrorStdout; + /***/ public String unknownExtraArgument; /***/ public String unknownMergeStrategy; + /***/ public String unknownSubcommand; /***/ public String unmergedPaths; /***/ public String unsupportedOperation; /***/ public String untrackedFiles; diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/SshDriver.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/SshDriver.java new file mode 100644 index 0000000000..4b7cba4729 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/SshDriver.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.pgm.internal; + +/** + * Simple enumeration for the available built-in ssh clients. + */ +public enum SshDriver { + + /** Default client: use JSch. */ + JSCH, + + /** Use the Apache MINA sshd client from org.eclipse.jgit.ssh.apache. */ + APACHE; + +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java new file mode 100644 index 0000000000..64ee602620 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.pgm.internal; + +import java.io.IOException; + +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.util.GitDateFormatter; +import org.eclipse.jgit.util.SignatureUtils; +import org.eclipse.jgit.util.io.ThrowingPrintWriter; + +/** + * Utilities for signature verification. + */ +public final class VerificationUtils { + + private VerificationUtils() { + // No instantiation + } + + /** + * Writes information about a signature verification to the given writer. + * + * @param out + * to write to + * @param verification + * to show + * @param name + * of the verifier used + * @param creator + * of the object verified; used for time zone information + * @throws IOException + * if writing fails + */ + public static void writeVerification(ThrowingPrintWriter out, + SignatureVerification verification, String name, + PersonIdent creator) throws IOException { + String[] text = SignatureUtils + .toString(verification, creator, + new GitDateFormatter(GitDateFormatter.Format.LOCALE)) + .split("\n"); //$NON-NLS-1$ + for (String line : text) { + out.print(name); + out.print(": "); //$NON-NLS-1$ + out.println(line); + } + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java index 229fb67b0c..cea2309f7f 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java @@ -1,45 +1,12 @@ /* * Copyright (C) 2008-2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; @@ -48,12 +15,6 @@ import java.io.File; import java.io.IOException; import java.text.MessageFormat; -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; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.errors.IncorrectObjectTypeException; @@ -66,9 +27,16 @@ import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeOptions; import org.eclipse.jgit.util.FS; +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; /** - * Custom argument handler {@link AbstractTreeIterator} from string values. + * Custom argument handler + * {@link org.eclipse.jgit.treewalk.AbstractTreeIterator} from string values. * <p> * Assumes the parser has been initialized with a Repository. */ @@ -82,8 +50,11 @@ public class AbstractTreeIteratorHandler extends * This constructor is used only by args4j. * * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. */ public AbstractTreeIteratorHandler(final CmdLineParser parser, final OptionDef option, @@ -93,7 +64,7 @@ public class AbstractTreeIteratorHandler extends } @Override - public int parseArguments(final Parameters params) throws CmdLineException { + public int parseArguments(Parameters params) throws CmdLineException { final String name = params.getParameter(0); if (new File(name).isDirectory()) { @@ -109,7 +80,7 @@ public class AbstractTreeIteratorHandler extends try { dirc = DirCache.read(new File(name), FS.DETECTED); } catch (IOException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().notAnIndexFile, name), e); + throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notAnIndexFile, name), e); } setter.addValue(new DirCacheIterator(dirc)); return 1; @@ -119,20 +90,24 @@ public class AbstractTreeIteratorHandler extends try { id = clp.getRepository().resolve(name); } catch (IOException e) { - throw new CmdLineException(e.getMessage()); + throw new CmdLineException(clp, CLIText.format(e.getMessage())); } if (id == null) - throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name)); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().notATree), name); final CanonicalTreeParser p = new CanonicalTreeParser(); try (ObjectReader curs = clp.getRepository().newObjectReader()) { p.reset(curs, clp.getRevWalk().parseTree(id)); - } catch (MissingObjectException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name)); - } catch (IncorrectObjectTypeException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name)); + } catch (MissingObjectException | IncorrectObjectTypeException e) { + CmdLineException cle = new CmdLineException(clp, + CLIText.format(CLIText.get().notATree), name); + cle.initCause(e); + throw cle; } catch (IOException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage())); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().cannotReadBecause), name, + e.getMessage()); } setter.addValue(p); 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..463213dc4f 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 @@ -1,61 +1,27 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; +import java.io.IOException; +import java.io.Writer; import java.lang.reflect.Field; +import java.time.Instant; import java.util.ArrayList; +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 +29,14 @@ 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.CmdLineException; +import org.kohsuke.args4j.IllegalAnnotationError; +import org.kohsuke.args4j.NamedOptionDef; +import org.kohsuke.args4j.OptionDef; +import org.kohsuke.args4j.OptionHandlerRegistry; +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. @@ -74,31 +48,39 @@ import org.eclipse.jgit.treewalk.AbstractTreeIterator; */ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { static { - registerHandler(AbstractTreeIterator.class, + OptionHandlerRegistry registry = OptionHandlerRegistry.getRegistry(); + registry.registerHandler(AbstractTreeIterator.class, AbstractTreeIteratorHandler.class); - registerHandler(ObjectId.class, ObjectIdHandler.class); - registerHandler(RefSpec.class, RefSpecHandler.class); - registerHandler(RevCommit.class, RevCommitHandler.class); - registerHandler(RevTree.class, RevTreeHandler.class); + registry.registerHandler(ObjectId.class, ObjectIdHandler.class); + registry.registerHandler(RefSpec.class, RefSpecHandler.class); + registry.registerHandler(RevCommit.class, RevCommitHandler.class); + registry.registerHandler(RevTree.class, RevTreeHandler.class); + registry.registerHandler(List.class, OptionWithValuesListHandler.class); + registry.registerHandler(Instant.class, InstantHandler.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. * * @param bean - * instance of a class annotated by {@link Option} and - * {@link Argument}. this object will receive values. - * + * instance of a class annotated by + * {@link org.kohsuke.args4j.Option} and + * {@link org.kohsuke.args4j.Argument}. this object will receive + * values. * @throws IllegalAnnotationError * if the option bean class is using args4j annotations * incorrectly. */ - public CmdLineParser(final Object bean) { + public CmdLineParser(Object bean) { this(bean, null); } @@ -107,24 +89,30 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { * them into the given object. * * @param bean - * instance of a class annotated by {@link Option} and - * {@link Argument}. this object will receive values. + * instance of a class annotated by + * {@link org.kohsuke.args4j.Option} and + * {@link org.kohsuke.args4j.Argument}. this object will receive + * values. * @param repo * repository this parser can translate options through. * @throws IllegalAnnotationError * if the option bean class is using args4j annotations * incorrectly. */ - public CmdLineParser(final Object bean, Repository repo) { + public CmdLineParser(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; } @Override - public void parseArgument(final String... args) throws CmdLineException { - final ArrayList<String> tmp = new ArrayList<String>(args.length); + public void parseArgument(String... args) throws CmdLineException { + final ArrayList<String> tmp = new ArrayList<>(args.length); for (int argi = 0; argi < args.length; argi++) { final String str = args[argi]; if (str.equals("--")) { //$NON-NLS-1$ @@ -143,9 +131,77 @@ 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[0])); + } 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); + } + + /** + * Check if array contains help option + * + * @param args + * non null + * @return true if the given array contains help option + * @since 4.2 + */ + protected boolean containsHelp(String... args) { + return TextBuiltin.containsHelp(args); } /** @@ -181,11 +237,11 @@ 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 - .isMultiValued()); + super(o.usage(), o.metaVar(), o.required(), o.help(), o.hidden(), + o.handler(), o.isMultiValued()); } @Override @@ -201,14 +257,52 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { return metaVar(); } } + + @Override + public boolean required() { + return seenHelp ? false : super.required(); + } } @Override protected OptionHandler createOptionHandler(OptionDef o, Setter setter) { - if (o instanceof NamedOptionDef) + if (o instanceof NamedOptionDef) { return super.createOptionHandler(o, setter); - else - return super.createOptionHandler(new MyOptionDef(o), setter); + } + return super.createOptionHandler(new MyOptionDef(o), setter); + + } + + @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/GpgSignHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/GpgSignHandler.java new file mode 100644 index 0000000000..56423ada41 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/GpgSignHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018, Salesforce. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.pgm.opt; + +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.OptionDef; +import org.kohsuke.args4j.spi.Parameters; +import org.kohsuke.args4j.spi.Setter; +import org.kohsuke.args4j.spi.StringOptionHandler; + +/** + * Special handler for the <code>--gpg-sign</code> option of the + * <code>commit</code> command. + * + * The following rules apply: + * <ul> + * <li>If no key is given, i.e. just <code>--gpg-sign</code> is passed, then it + * is the same as <code>--gpg-sign=default</code></li> + * </ul> + * + * @since 5.3 + */ +public class GpgSignHandler extends StringOptionHandler { + + /** + * The value "default" which will be used when just the option is specified + * without any argument + */ + public static final String DEFAULT = "default"; //$NON-NLS-1$ + + /** + * <p> + * Constructor for GpgSignHandler. + * </p> + * + * @param parser + * The parser to which this handler belongs. + * @param option + * The annotation. + * @param setter + * Object to be used for setting value. + */ + public GpgSignHandler(CmdLineParser parser, OptionDef option, + Setter<? super String> setter) { + super(parser, option, setter); + } + + @Override + public int parseArguments(Parameters params) throws CmdLineException { + String alias = params.getParameter(-1); + if ("--gpg-sign".equals(alias) || "-S".equals(alias)) { //$NON-NLS-1$ //$NON-NLS-2$ + try { + String key = params.getParameter(0); + if (key == null || key.startsWith("-")) { //$NON-NLS-1$ + // ignore invalid values and assume default + setter.addValue(DEFAULT); + return 0; + } + + // use what we have + setter.addValue(key); + return 1; + } catch (CmdLineException e) { + // no additional value, assume default + setter.addValue(DEFAULT); + return 0; + } + } + return 0; + } + +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/InstantHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/InstantHandler.java new file mode 100644 index 0000000000..9c54169888 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/InstantHandler.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022, Harald Weiner and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.pgm.opt; + +import java.time.Instant; + +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; + +/** + * Custom argument handler {@link java.time.Instant} from string values. + * <p> + * Assumes the parser has been initialized with a Repository. + * + * @since 6.5 + */ +public class InstantHandler extends OptionHandler<Instant> { + /** + * Create a new handler for the command name. + * <p> + * This constructor is used only by args4j. + * + * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. + * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. + * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. + */ + public InstantHandler(CmdLineParser parser, OptionDef option, + Setter<? super Instant> setter) { + super(parser, option, setter); + } + + @Override + public int parseArguments(Parameters params) throws CmdLineException { + Instant instant = Instant.parse(params.getParameter(0)); + setter.addValue(instant); + return 1; + } + + @Override + public String getDefaultMetaVariable() { + return CLIText.get().metaVar_instant; + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java index fa24d4b02f..b50df90788 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java @@ -1,63 +1,30 @@ /* * Copyright (C) 2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; import java.io.IOException; -import java.text.MessageFormat; +import org.eclipse.jgit.lib.ObjectId; +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; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.pgm.internal.CLIText; /** - * Custom argument handler {@link ObjectId} from string values. + * Custom argument handler {@link org.eclipse.jgit.lib.ObjectId} from string + * values. * <p> * Assumes the parser has been initialized with a Repository. */ @@ -70,8 +37,11 @@ public class ObjectIdHandler extends OptionHandler<ObjectId> { * This constructor is used only by args4j. * * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. */ public ObjectIdHandler(final CmdLineParser parser, final OptionDef option, final Setter<? super ObjectId> setter) { @@ -80,20 +50,21 @@ public class ObjectIdHandler extends OptionHandler<ObjectId> { } @Override - public int parseArguments(final Parameters params) throws CmdLineException { + public int parseArguments(Parameters params) throws CmdLineException { final String name = params.getParameter(0); final ObjectId id; try { id = clp.getRepository().resolve(name); } catch (IOException e) { - throw new CmdLineException(e.getMessage()); + throw new CmdLineException(clp, CLIText.format(e.getMessage())); } if (id != null) { setter.addValue(id); return 1; } - throw new CmdLineException(MessageFormat.format(CLIText.get().notAnObject, name)); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().notAnObject), name); } @Override 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..7bb2766fe0 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java @@ -0,0 +1,57 @@ +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<?>> { + + /** + * Constructor for OptionWithValuesListHandler. + * + * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. + * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. + * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. + */ + 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; + } + +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java index 122cce7dea..f215040499 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java @@ -1,44 +1,11 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; @@ -46,23 +13,23 @@ package org.eclipse.jgit.pgm.opt; import java.util.ArrayList; import java.util.List; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.treewalk.filter.PathFilter; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; -import org.kohsuke.args4j.Option; import org.kohsuke.args4j.OptionDef; import org.kohsuke.args4j.spi.OptionHandler; import org.kohsuke.args4j.spi.Parameters; import org.kohsuke.args4j.spi.Setter; -import org.eclipse.jgit.pgm.internal.CLIText; -import org.eclipse.jgit.treewalk.filter.PathFilter; -import org.eclipse.jgit.treewalk.filter.PathFilterGroup; -import org.eclipse.jgit.treewalk.filter.TreeFilter; /** - * Create a {@link TreeFilter} to patch math names. + * Create a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} to match path + * names. * <p> * This handler consumes all arguments to the end of the command line, and is - * meant to be used on an {@link Option} of name "--". + * meant to be used on an {@link org.kohsuke.args4j.Option} of name "--". */ public class PathTreeFilterHandler extends OptionHandler<TreeFilter> { /** @@ -71,8 +38,11 @@ public class PathTreeFilterHandler extends OptionHandler<TreeFilter> { * This constructor is used only by args4j. * * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. */ public PathTreeFilterHandler(final CmdLineParser parser, final OptionDef option, final Setter<? super TreeFilter> setter) { @@ -80,8 +50,8 @@ public class PathTreeFilterHandler extends OptionHandler<TreeFilter> { } @Override - public int parseArguments(final Parameters params) throws CmdLineException { - final List<PathFilter> filters = new ArrayList<PathFilter>(); + public int parseArguments(Parameters params) throws CmdLineException { + final List<PathFilter> filters = new ArrayList<>(); for (int idx = 0;; idx++) { final String path; try { @@ -92,7 +62,7 @@ public class PathTreeFilterHandler extends OptionHandler<TreeFilter> { filters.add(PathFilter.create(path)); } - if (filters.size() == 0) + if (filters.isEmpty()) return 0; if (filters.size() == 1) { setter.addValue(filters.get(0)); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java index dae0c47642..0491445879 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RefSpecHandler.java @@ -1,59 +1,27 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.transport.RefSpec; 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; -import org.eclipse.jgit.pgm.internal.CLIText; -import org.eclipse.jgit.transport.RefSpec; /** - * Custom argument handler {@link RefSpec} from string values. + * Custom argument handler {@link org.eclipse.jgit.transport.RefSpec} from + * string values. * <p> * Assumes the parser has been initialized with a Repository. */ @@ -64,8 +32,11 @@ public class RefSpecHandler extends OptionHandler<RefSpec> { * This constructor is used only by args4j. * * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. */ public RefSpecHandler(final CmdLineParser parser, final OptionDef option, final Setter<? super RefSpec> setter) { @@ -73,7 +44,7 @@ public class RefSpecHandler extends OptionHandler<RefSpec> { } @Override - public int parseArguments(final Parameters params) throws CmdLineException { + public int parseArguments(Parameters params) throws CmdLineException { setter.addValue(new RefSpec(params.getParameter(0))); return 1; } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java index b1be128db1..a095a28af8 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java @@ -1,67 +1,34 @@ /* * Copyright (C) 2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; import java.io.IOException; -import java.text.MessageFormat; -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; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevFlag; +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; /** - * Custom argument handler {@link RevCommit} from string values. + * Custom argument handler {@link org.eclipse.jgit.revwalk.RevCommit} from + * string values. * <p> * Assumes the parser has been initialized with a Repository. */ @@ -74,8 +41,11 @@ public class RevCommitHandler extends OptionHandler<RevCommit> { * This constructor is used only by args4j. * * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. */ public RevCommitHandler(final CmdLineParser parser, final OptionDef option, final Setter<? super RevCommit> setter) { @@ -84,7 +54,7 @@ public class RevCommitHandler extends OptionHandler<RevCommit> { } @Override - public int parseArguments(final Parameters params) throws CmdLineException { + public int parseArguments(Parameters params) throws CmdLineException { String name = params.getParameter(0); boolean interesting = true; @@ -96,8 +66,9 @@ public class RevCommitHandler extends OptionHandler<RevCommit> { final int dot2 = name.indexOf(".."); //$NON-NLS-1$ if (dot2 != -1) { if (!option.isMultiValued()) - throw new CmdLineException(MessageFormat.format(CLIText.get().onlyOneMetaVarExpectedIn - , option.metaVar(), name)); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().onlyOneMetaVarExpectedIn), + option.metaVar(), name); final String left = name.substring(0, dot2); final String right = name.substring(dot2 + 2); @@ -110,26 +81,30 @@ public class RevCommitHandler extends OptionHandler<RevCommit> { return 1; } - private void addOne(final String name, final boolean interesting) + private void addOne(String name, boolean interesting) throws CmdLineException { final ObjectId id; try { id = clp.getRepository().resolve(name); } catch (IOException e) { - throw new CmdLineException(e.getMessage()); + throw new CmdLineException(clp, CLIText.format(e.getMessage())); } if (id == null) - throw new CmdLineException(MessageFormat.format(CLIText.get().notACommit, name)); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().notACommit), name); final RevCommit c; try { c = clp.getRevWalk().parseCommit(id); - } catch (MissingObjectException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().notACommit, name)); - } catch (IncorrectObjectTypeException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().notACommit, name)); + } catch (MissingObjectException | IncorrectObjectTypeException e) { + CmdLineException cle = new CmdLineException(clp, + CLIText.format(CLIText.get().notACommit), name); + cle.initCause(e); + throw cle; } catch (IOException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage())); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().cannotReadBecause), name, + e.getMessage()); } if (interesting) diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java index eb155af9f4..08f1d28392 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java @@ -1,66 +1,33 @@ /* * Copyright (C) 2009, Google Inc. - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; import java.io.IOException; -import java.text.MessageFormat; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.pgm.internal.CLIText; +import org.eclipse.jgit.revwalk.RevTree; 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; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.pgm.internal.CLIText; -import org.eclipse.jgit.revwalk.RevTree; /** - * Custom argument handler {@link RevTree} from string values. + * Custom argument handler {@link org.eclipse.jgit.revwalk.RevTree} from string + * values. * <p> * Assumes the parser has been initialized with a Repository. */ @@ -73,8 +40,11 @@ public class RevTreeHandler extends OptionHandler<RevTree> { * This constructor is used only by args4j. * * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. */ public RevTreeHandler(final CmdLineParser parser, final OptionDef option, final Setter<? super RevTree> setter) { @@ -83,26 +53,30 @@ public class RevTreeHandler extends OptionHandler<RevTree> { } @Override - public int parseArguments(final Parameters params) throws CmdLineException { + public int parseArguments(Parameters params) throws CmdLineException { final String name = params.getParameter(0); final ObjectId id; try { id = clp.getRepository().resolve(name); } catch (IOException e) { - throw new CmdLineException(e.getMessage()); + throw new CmdLineException(clp, CLIText.format(e.getMessage())); } if (id == null) - throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name)); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().notATree), name); final RevTree c; try { c = clp.getRevWalk().parseTree(id); - } catch (MissingObjectException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name)); - } catch (IncorrectObjectTypeException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name)); + } catch (MissingObjectException | IncorrectObjectTypeException e) { + CmdLineException cle = new CmdLineException(clp, + CLIText.format(CLIText.get().notATree), name); + cle.initCause(e); + throw cle; } catch (IOException e) { - throw new CmdLineException(MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage())); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().cannotReadBecause), name, + e.getMessage()); } setter.addValue(c); return 1; diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java index c62ef0d2b8..e71ba90e4b 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java @@ -1,89 +1,61 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; -import java.text.MessageFormat; - +import org.eclipse.jgit.pgm.CommandCatalog; +import org.eclipse.jgit.pgm.CommandRef; +import org.eclipse.jgit.pgm.TextBuiltin; +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; -import org.eclipse.jgit.pgm.CommandCatalog; -import org.eclipse.jgit.pgm.CommandRef; -import org.eclipse.jgit.pgm.TextBuiltin; -import org.eclipse.jgit.pgm.internal.CLIText; /** * Custom Argument handler for jgit command selection. * <p> - * Translates a single argument string to a {@link TextBuiltin} instance which - * we can execute at runtime with the remaining arguments of the parser. + * Translates a single argument string to a + * {@link org.eclipse.jgit.pgm.TextBuiltin} instance which we can execute at + * runtime with the remaining arguments of the parser. */ public class SubcommandHandler extends OptionHandler<TextBuiltin> { + private final org.eclipse.jgit.pgm.opt.CmdLineParser clp; + /** * Create a new handler for the command name. * <p> * This constructor is used only by args4j. * * @param parser + * a {@link org.kohsuke.args4j.CmdLineParser} object. * @param option + * a {@link org.kohsuke.args4j.OptionDef} object. * @param setter + * a {@link org.kohsuke.args4j.spi.Setter} object. */ public SubcommandHandler(final CmdLineParser parser, final OptionDef option, final Setter<? super TextBuiltin> setter) { super(parser, option, setter); + clp = (org.eclipse.jgit.pgm.opt.CmdLineParser) parser; } @Override - public int parseArguments(final Parameters params) throws CmdLineException { + public int parseArguments(Parameters params) throws CmdLineException { final String name = params.getParameter(0); final CommandRef cr = CommandCatalog.get(name); if (cr == null) - throw new CmdLineException(MessageFormat.format( - CLIText.get().notAJgitCommand, name)); + throw new CmdLineException(clp, + CLIText.format(CLIText.get().notAJgitCommand), name); // Force option parsing to stop. Everything after us should // be arguments known only to this command and must not be diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java index c4e8b05378..2f99cff768 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/UntrackedFilesHandler.java @@ -1,47 +1,15 @@ /* - * Copyright (C) 2015 Zend Technologies Ltd. and others - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2015 Zend Technologies Ltd. and others and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.pgm.opt; +import org.eclipse.jgit.pgm.internal.CLIText; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.OptionDef; @@ -70,6 +38,8 @@ import org.kohsuke.args4j.spi.StringOptionHandler; public class UntrackedFilesHandler extends StringOptionHandler { /** + * <p>Constructor for UntrackedFilesHandler.</p> + * * @param parser * The parser to which this handler belongs to. * @param option @@ -102,8 +72,9 @@ public class UntrackedFilesHandler extends StringOptionHandler { if ("no".equals(mode) || "all".equals(mode)) { //$NON-NLS-1$ //$NON-NLS-2$ setter.addValue(mode); } else { - throw new CmdLineException(owner, String.format( - "Invalid untracked files mode '%s'", mode)); //$NON-NLS-1$ + throw new CmdLineException(owner, + CLIText.format(CLIText.get().invalidUntrackedFilesMode), + mode); } return 1; } else { @@ -111,4 +82,4 @@ public class UntrackedFilesHandler extends StringOptionHandler { } } -}
\ No newline at end of file +} |