Repository: logging-log4j2 Updated Branches: refs/heads/release-2.x ec10b16ec -> dd8ded97a
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/dd8ded97/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CustomLayoutDemo.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CustomLayoutDemo.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CustomLayoutDemo.java deleted file mode 100644 index b0c505a..0000000 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CustomLayoutDemo.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.tools.picocli; - -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Text; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.IOptionRenderer; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.IParameterRenderer; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Layout; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.TextTable; - -import java.lang.reflect.Field; - -import static org.apache.logging.log4j.core.tools.picocli.CommandLine.*; -import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.SPAN; -import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.TRUNCATE; -import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.WRAP; - -/** - * Demonstrates how the CommandLine.Help API can be used to create custom layouts for usage help messages. - */ -@Command(name = "picocli.CustomLayoutDemo", description = "Demonstrates picocli custom layouts.", - footer = { - "Run with -Dpicocli.ansi=true to force picocli to use ansi codes,", - "or with -Dpicocli.ansi=false to force picocli to NOT use ansi codes.", - "By default picocli will use ansi codes if the platform supports it." - } -) -public class CustomLayoutDemo implements Runnable { - public static void main(String[] args) { - CommandLine.run(new CustomLayoutDemo(), System.err, args); - } - - @Option(names = {"-z", "--zip"}, description = "Show usage help for a layout with 2 options per row.") - private boolean showZip; - - @Option(names = {"-n", "--netstat"}, description = "Show usage help for a layout with a narrow options column and a wide description column. Descriptions that wrap to the next row are not indented.") - private boolean showNetstat; - - @Override - public void run() { - if (!showZip && !showNetstat) { - CommandLine.usage(this, System.err); - return; - } - if (showZip) { System.out.println(createZipUsageFormat(Help.Ansi.AUTO)); } - if (showNetstat) { System.out.println(createNetstatUsageFormat(Help.Ansi.AUTO)); } - } - - - public static String createZipUsageFormat(Help.Ansi ansi) { - @Command(description = { - "Copyright (c) 1990-2008 Info-ZIP - Type 'zip \"-L\"' for software license.", - "Zip 3.0 (July 5th 2008). Command:", - "@|bold zip|@ [@|yellow -options|@] [@|yellow -b|@ @|underline path|@] [@|yellow -t|@ @|underline mmddyyyy|@] [@|yellow -n|@ @|underline suffixes|@] [@|yellow zipfile|@ @|underline list|@] [@|yellow -xi|@ @|underline list|@]", - " The default action is to add or replace zipfile entries from list, which", - " can include the special name - to compress standard input.", - " If @|yellow zipfile|@ and @|yellow list|@ are omitted, zip compresses stdin to stdout."} - ) - class Zip { - @Option(names = "-f", description = "freshen: only changed files") - boolean freshen; - @Option(names = "-u", description = "update: only changed or new files") - boolean update; - @Option(names = "-d", description = "delete entries in zipfile") - boolean delete; - @Option(names = "-m", description = "move into zipfile (delete OS files)") - boolean move; - @Option(names = "-r", description = "recurse into directories") - boolean recurse; - @Option(names = "-j", description = "junk (don't record) directory names") - boolean junk; - @Option(names = "-0", description = "store only") - boolean store; - @Option(names = "-l", description = "convert LF to CR LF (@|yellow -ll|@ CR LF to LF)") - boolean lf2crlf; - @Option(names = "-1", description = "compress faster") - boolean faster; - @Option(names = "-9", description = "compress better") - boolean better; - @Option(names = "-q", description = "quiet operation") - boolean quiet; - @Option(names = "-v", description = "verbose operation/print version info") - boolean verbose; - @Option(names = "-c", description = "add one-line comments") - boolean comments; - @Option(names = "-z", description = "add zipfile comment") - boolean zipComment; - @Option(names = "-@", description = "read names from stdin") - boolean readFileList; - @Option(names = "-o", description = "make zipfile as old as latest entry") - boolean old; - @Option(names = "-x", description = "exclude the following names") - boolean exclude; - @Option(names = "-i", description = "include only the following names") - boolean include; - @Option(names = "-F", description = "fix zipfile (@|yellow -FF|@ try harder)") - boolean fix; - @Option(names = "-D", description = "do not add directory entries") - boolean directories; - @Option(names = "-A", description = "adjust self-extracting exe") - boolean adjust; - @Option(names = "-J", description = "junk zipfile prefix (unzipsfx)") - boolean junkPrefix; - @Option(names = "-T", description = "test zipfile integrity") - boolean test; - @Option(names = "-X", description = "eXclude eXtra file attributes") - boolean excludeAttribs; - @Option(names = "-y", description = "store symbolic links as the link instead of the referenced file") - boolean symbolic; - @Option(names = "-e", description = "encrypt") - boolean encrypt; - @Option(names = "-n", description = "don't compress these suffixes") - boolean dontCompress; - @Option(names = "-h2", description = "show more help") - boolean moreHelp; - } - - class TwoOptionsPerRowLayout extends Layout { // define a custom layout - TextTable.Cell previous = new TextTable.Cell(0, 0); - - private TwoOptionsPerRowLayout(Help.ColorScheme colorScheme, TextTable textTable, - IOptionRenderer optionRenderer, - IParameterRenderer parameterRenderer) { - super(colorScheme, textTable, optionRenderer, parameterRenderer); - } - - @Override - public void layout(Field field, Text[][] values) { - Text[] columnValues = values[0]; // we know renderer creates a single row with two values - - // We want to show two options on one row, next to each other, - // unless the first option spanned multiple columns (in which case there are not enough columns left) - int col = previous.column + 1; - if (col == 1 || col + columnValues.length > table.columns.length) { // if true, write into next row - - // table also adds an empty row if a text value spanned multiple columns - if (table.rowCount() == 0 || table.rowCount() == previous.row + 1) { // avoid adding 2 empty rows - table.addEmptyRow(); // create the slots to write the text values into - } - col = 0; // we are starting a new row, reset the column to write into - } - for (int i = 0; i < columnValues.length; i++) { - // always write to the last row, column depends on what happened previously - previous = table.putValue(table.rowCount() - 1, col + i, columnValues[i]); - } - } - } - TextTable textTable = new TextTable(ansi, - new Column(5, 2, TRUNCATE), // values should fit - new Column(30, 2, SPAN), // overflow into adjacent columns - new Column(4, 1, TRUNCATE), // values should fit again - new Column(39, 2, WRAP)); - TwoOptionsPerRowLayout layout = new TwoOptionsPerRowLayout( - Help.defaultColorScheme(ansi), - textTable, - Help.createMinimalOptionRenderer(), - Help.createMinimalParameterRenderer()); - - Help help = new Help(new Zip(), ansi); - StringBuilder sb = new StringBuilder(); - sb.append(help.description()); // show the first 6 lines, including copyright, description and usage - - // Note that we don't sort the options, so they appear in the order the fields are declared in the Zip class. - layout.addOptions(help.optionFields, help.parameterLabelRenderer); - sb.append(layout); // finally, copy the options details help text into the StringBuilder - - return sb.toString(); - } - - /** for Netstat test */ - private enum Protocol {IP, IPv6, ICMP, ICMPv6, TCP, TCPv6, UDP, UDPv6} - - public static String createNetstatUsageFormat(Help.Ansi ansi) { - @Command(name = "NETSTAT", - separator = " ", - abbreviateSynopsis = true, - header = "Displays protocol statistics and current TCP/IP network connections.%n") - class Netstat { - @Option(names="-a", description="Displays all connections and listening ports.") - boolean displayAll; - @Option(names="-b", description="Displays the executable involved in creating each connection or " - + "listening port. In some cases well-known executables host " - + "multiple independent components, and in these cases the " - + "sequence of components involved in creating the connection " - + "or listening port is displayed. In this case the executable " - + "name is in [] at the bottom, on top is the component it called, " - + "and so forth until TCP/IP was reached. Note that this option " - + "can be time-consuming and will fail unless you have sufficient " - + "permissions.") - boolean displayExecutable; - @Option(names="-e", description="Displays Ethernet statistics. This may be combined with the -s option.") - boolean displayEthernetStats; - @Option(names="-f", description="Displays Fully Qualified Domain Names (FQDN) for foreign addresses.") - boolean displayFQCN; - @Option(names="-n", description="Displays addresses and port numbers in numerical form.") - boolean displayNumerical; - @Option(names="-o", description="Displays the owning process ID associated with each connection.") - boolean displayOwningProcess; - @Option(names="-p", paramLabel = "proto", - description="Shows connections for the protocol specified by proto; proto " - + "may be any of: TCP, UDP, TCPv6, or UDPv6. If used with the -s " - + "option to display per-protocol statistics, proto may be any of: " - + "IP, IPv6, ICMP, ICMPv6, TCP, TCPv6, UDP, or UDPv6.") - Protocol proto; - @Option(names="-q", description="Displays all connections, listening ports, and bound " - + "nonlistening TCP ports. Bound nonlistening ports may or may not " - + "be associated with an active connection.") - boolean query; - @Option(names="-r", description="Displays the routing table.") - boolean displayRoutingTable; - @Option(names="-s", description="Displays per-protocol statistics. By default, statistics are " - + "shown for IP, IPv6, ICMP, ICMPv6, TCP, TCPv6, UDP, and UDPv6; " - + "the -p option may be used to specify a subset of the default.") - boolean displayStatistics; - @Option(names="-t", description="Displays the current connection offload state.") - boolean displayOffloadState; - @Option(names="-x", description="Displays NetworkDirect connections, listeners, and shared endpoints.") - boolean displayNetDirect; - @Option(names="-y", description="Displays the TCP connection template for all connections. " - + "Cannot be combined with the other options.") - boolean displayTcpConnectionTemplate; - @Parameters(arity = "0..1", paramLabel = "interval", description = "" - + "Redisplays selected statistics, pausing interval seconds " - + "between each display. Press CTRL+C to stop redisplaying " - + "statistics. If omitted, netstat will print the current " - + "configuration information once.") - int interval; - } - StringBuilder sb = new StringBuilder(); - Help help = new Help(new Netstat(), ansi); - help.synopsisHeading = ""; - sb.append(help.header()).append(help.detailedSynopsis(0, null, false)); - sb.append(System.getProperty("line.separator")); - - TextTable textTable = new TextTable(ansi, - new Column(15, 2, TRUNCATE), - new Column(65, 1, WRAP)); - textTable.indentWrappedLines = 0; - Layout layout = new Layout( - Help.defaultColorScheme(ansi), - textTable, - Help.createMinimalOptionRenderer(), - Help.createMinimalParameterRenderer()); - layout.addOptions(help.optionFields, help.parameterLabelRenderer); - layout.addPositionalParameters(help.positionalParametersFields, Help.createMinimalParamLabelRenderer()); - sb.append(layout); - return sb.toString(); - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/dd8ded97/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/Demo.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/Demo.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/Demo.java deleted file mode 100644 index 084443f..0000000 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/Demo.java +++ /dev/null @@ -1,719 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.core.tools.picocli; - -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Command; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Option; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Parameters; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - -/** - * Demonstrates picocli subcommands. - * <p> - * Banner ascii art thanks to <a href="http://patorjk.com/software/taag/">http://patorjk.com/software/taag/</a>. - * </p> - */ -@Command(name = "picocli.Demo", sortOptions = false, - header = { - "@|green .__ .__ .__ |@", - "@|green ______ |__| ____ ____ ____ | | |__||@", - "@|green \\____ \\| |/ ___\\/ _ \\_/ ___\\| | | ||@", - "@|green | |_> > \\ \\__( <_> ) \\___| |_| ||@", - "@|green | __/|__|\\___ >____/ \\___ >____/__||@", - "@|green |__| \\/ \\/ |@", - ""}, - //descriptionHeading = "@|bold %nDescription|@:%n", - description = { - "", - "Demonstrates picocli subcommands parsing and usage help.", }, - optionListHeading = "@|bold %nOptions|@:%n", - footer = { - "", - "@|bold VM Options|@:", - "Run with @|yellow -ea|@ to enable assertions used in the tests.", - "Run with @|yellow -Dpicocli.ansi|@=@|italic true|@ to force picocli to use ansi codes,", - " or with @|yellow -Dpicocli.ansi|@=@|italic false|@ to force picocli to NOT use ansi codes.", - "(By default picocli will use ansi codes if the platform supports it.)", - "", - "@|cyan If you would like to contribute or report an issue|@", - "@|cyan go to github: https://github.com/remkop/picocli|@", - "", - "@|cyan If you like the project star it on github and follow me on twitter!|@", - "@|cyan This project is created and maintained by Remko Popma (@remkopopma)|@", - ""}) -public class Demo implements Runnable { - public static void main(String[] args) { - CommandLine.run(new Demo(), System.err, args); - } - - @Option(names = {"-a", "--autocomplete"}, description = "Generate sample autocomplete script for git") - private boolean autocomplete; - - @Option(names = {"-1", "--showUsageForSubcommandGitCommit"}, description = "Shows usage help for the git-commit subcommand") - private boolean showUsageForSubcommandGitCommit; - - @Option(names = {"-2", "--showUsageForMainCommand"}, description = "Shows usage help for a command with subcommands") - private boolean showUsageForMainCommand; - - @Option(names = {"-3", "--showUsageForSubcommandGitStatus"}, description = "Shows usage help for the git-status subcommand") - private boolean showUsageForSubcommandGitStatus; - - @Option(names = "--simple", description = "Show help for the first simple Example in the manual") - private boolean showSimpleExample; - - @Option(names = "--mixed", hidden = true, description = "Show help with mixed Ansi colors and styles in description") - private boolean showAnsiInDescription; - - @Option(names = {"-i", "--index"}, description = "" + - "@|fg(21) S|@" + - "@|fg(57) h|@" + - "@|fg(93) o|@" + - "@|fg(129) w|@" + - "@|fg(129) |@" + - "@|fg(165) 2|@" + - "@|fg(201) 5|@" + - "@|fg(225) 6|@" + - "@|fg(123) |@" + - "@|fg(122) c|@" + - "@|fg(120) o|@" + - "@|fg(118) l|@" + - "@|fg(148) o|@" + - "@|fg(142) r|@" + - "@|fg(136) |@" + - "@|fg(136) p|@" + - "@|fg(130) a|@" + - "@|fg(124) l|@" + - "@|fg(160) e|@" + - "@|fg(196) t|@" + - "@|fg(198) t|@" + - "@|fg(199) e|@" + - "@|fg(200) |@" + - "@|fg(201) i|@" + - "@|fg(213) n|@" + - "@|fg(219) d|@" + - "@|fg(225) e|@" + - "@|fg(231) x|@" + - "@|fg(230) |@" + - "@|fg(229) v|@" + - "@|fg(228) a|@" + - "@|fg(227) l|@" + - "@|fg(226) u|@" + - "@|fg(190) e|@" + - "@|fg(154) s|@") - private boolean showIndexedColorPalette; - - @Option(names = {"-r", "--rgb"}, description = "" + - "@|fg(0;0;5) S|@" + - "@|fg(1;0;5) h|@" + - "@|fg(2;0;5) o|@" + - "@|fg(3;0;5) w|@" + - "@|fg(3;0;5) |@" + - "@|fg(4;0;5) 2|@" + - "@|fg(5;0;5) 5|@" + - "@|fg(5;4;5) 6|@" + - "@|fg(2;5;5) |@" + - "@|fg(2;5;4) c|@" + - "@|fg(2;5;2) o|@" + - "@|fg(2;5;0) l|@" + - "@|fg(3;4;0) o|@" + - "@|fg(3;3;0) r|@" + - "@|fg(3;2;0) |@" + - "@|fg(3;2;0) p|@" + - "@|fg(3;1;0) a|@" + - "@|fg(3;0;0) l|@" + - "@|fg(4;0;0) e|@" + - "@|fg(5;0;0) t|@" + - "@|fg(5;0;2) t|@" + - "@|fg(5;0;3) e|@" + - "@|fg(5;0;4) |@" + - "@|fg(5;0;5) R|@" + - "@|fg(5;2;5) G|@" + - "@|fg(5;3;5) B|@" + - "@|fg(5;4;5) |@" + - "@|fg(5;5;5) c|@" + - "@|fg(5;5;4) o|@" + - "@|fg(5;5;3) m|@" + - "@|fg(5;5;2) p|@" + - "@|fg(5;5;1) o|@" + - "@|fg(5;5;0) n|@" + - "@|fg(4;5;0) e|@" + - "@|fg(3;5;0) n|@" + - "@|fg(2;5;0) t|@" + - "@|fg(1;5;0) |@" + - "@|fg(1;5;0) v|@" + - "@|fg(0;5;0) a|@" + - "@|fg(0;4;0) l|@" + - "@|fg(0;3;0) u|@" + - "@|fg(0;2;0) e|@" + - "@|fg(0;1;0) s|@" + - "") - private boolean showRgbColorPalette; - - @Option(names = {"-t", "--tests"}, description = "Runs all tests in this class") - private boolean runTests; - - @Override - public void run() { - if (!runTests && - !showSimpleExample && - !showAnsiInDescription && - !showIndexedColorPalette && - !showRgbColorPalette && - !showUsageForMainCommand && - !showUsageForSubcommandGitCommit && - !showUsageForSubcommandGitStatus && - !autocomplete) { - CommandLine.usage(this, System.err); - return; - } - if (runTests) { testParseSubCommands(); System.out.println("Ran tests OK.");} - if (showSimpleExample) { showSimpleExampleUsage(); } - if (showAnsiInDescription) { showAnsiInDescription(); } - if (showIndexedColorPalette) { showIndexedColorPalette(); } - if (showRgbColorPalette) { showRgbColorPalette(); } - if (showUsageForMainCommand) { testUsageMainCommand(); } - if (showUsageForSubcommandGitStatus) { testUsageSubCommandStatus(); } - if (showUsageForSubcommandGitCommit) { testUsageSubCommandCommit(); } - } - - private void showSimpleExampleUsage() { - class Example { - @Option(names = { "-v", "--verbose" }, description = "Be verbose.") - private boolean verbose = false; - - @Option(names = { "-h", "--help" }, help = true, - description = "Displays this help message and quits.") - private boolean helpRequested = false; - - @Parameters(arity = "1..*", paramLabel = "FILE", description = "File(s) to process.") - private File[] inputFiles; - } - CommandLine.usage(new Example(), System.out); - } - - private void showAnsiInDescription() { - @Command(description = "Custom @|bold,underline styles|@ and @|fg(red) colors|@.") - class AnsiDescription { } - CommandLine.usage(new AnsiDescription(), System.out); - } - - private void showIndexedColorPalette() { - int[] foregroundBackground = {38, 48}; - for (int fbg : foregroundBackground) { - for (int r = 0; r < 2; r++) { - for (int g = 0; g < 6; g++) { - for (int b = 0; b < 6; b++) { - int col = 16 + 36 * (0 + 3 * r) + 6 * g + b; - System.out.printf("\u001B[%d;5;%dm%3d \u001B[0m", fbg, col, col); - } - for (int b = 0; b < 6; b++) { - int col = 16 + 36 * (1 + 3 * r) + 6 * g + b; - System.out.printf("\u001B[%d;5;%dm%3d \u001B[0m", fbg, col, col); - } - for (int b = 0; b < 6; b++) { - int col = 16 + 36 * (2 + 3 * r) + 6 * g + b; - System.out.printf("\u001B[%d;5;%dm%3d \u001B[0m", fbg, col, col); - } - System.out.println(); - } - System.out.println(); - } - int r = 6; - for (int g = 0; g < 4; g++) { - for (int b = 0; b < 6; b++) { - int col = 16 + 36 * r + 6 * g + b; - System.out.printf("\u001B[%d;5;%dm%3d \u001B[0m", fbg, col, col); - } - System.out.println(); - } - System.out.println(); - } - } - - private void showRgbColorPalette() { - int[] foregroundBackground = {38, 48}; - for (int fbg : foregroundBackground) { - for (int r = 0; r < 2; r++) { - System.out.println("RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB RGB "); - for (int g = 0; g < 6; g++) { - for (int b = 0; b < 6; b++) { - int col = 16 + 36 * (0 + 3 * r) + 6 * g + b; - System.out.printf("\u001B[%d;5;%dm%d%d%d \u001B[0m", fbg, col, (0 + 3 * r),g,b); - } - for (int b = 0; b < 6; b++) { - int col = 16 + 36 * (1 + 3 * r) + 6 * g + b; - System.out.printf("\u001B[%d;5;%dm%d%d%d \u001B[0m", fbg, col, (1 + 3 * r),g,b); - } - for (int b = 0; b < 6; b++) { - int col = 16 + 36 * (2 + 3 * r) + 6 * g + b; - System.out.printf("\u001B[%d;5;%dm%d%d%d \u001B[0m", fbg, col, (2 + 3 * r),g,b); - } - System.out.println(); - } - System.out.println(); - } - System.out.println("RGB RGB RGB RGB RGB RGB"); - int r = 6; - for (int g = 0; g < 4; g++) { - for (int b = 0; b < 6; b++) { - int col = 16 + 36 * r + 6 * g + b; - System.out.printf("\u001B[%d;5;%dm%d%d%d \u001B[0m", fbg, col, r,g,b); - } - System.out.println(); - } - System.out.println(); - } - } - - //------------------------------------------ - static - // tag::Git[] - // tag::Git-declaration[] - @Command(name = "git", sortOptions = false, - description = "Git is a fast, scalable, distributed revision control " + - "system with an unusually rich command set that provides both " + - "high-level operations and full access to internals.", - commandListHeading = "%nCommands:%n%nThe most commonly used git commands are:%n") - class Git { // end::Git-declaration[] - @Option(names = {"-V", "--version"}, help = true, description = "Prints version information and exits") - boolean isVersionRequested; - - @Option(names = {"-h", "--help"}, help = true, description = "Prints this help message and exits") - boolean isHelpRequested; - - @Option(names = "--git-dir", description = "Set the path to the repository") - File gitDir; - } - // end::Git[] - - // the "status" subcommand's has an option "mode" with a fixed number of values, modeled by this enum - enum GitStatusMode {all, no, normal}; - - static - @Command(name = "git-status", - header = "Show the working tree status.", - showDefaultValues = true, - customSynopsis = "@|bold git-status|@ [@|yellow <options>|@...] [--] [@|yellow <pathspec>|@...]", - description = "Displays paths that have differences between the index file and the current HEAD commit, " + - "paths that have differences between the working tree and the index file, and paths in the " + - "working tree that are not tracked by Git (and are not ignored by gitignore(5)). The first " + - "are what you would commit by running git commit; the second and third are what you could " + - "commit by running git add before running git commit." - ) - class GitStatus { - @Option(names = {"-s", "--short"}, description = "Give the output in the short-format") - boolean shortFormat; - - @Option(names = {"-b", "--branch"}, description = "Show the branch and tracking info even in short-format") - boolean branchInfo; - - @Option(names = "--ignored", description = "Show ignored files as well") boolean showIgnored; - - @Option(names = {"-u", "--untracked"}, paramLabel = "<mode>", description = { - "Show untracked files.", - "The mode parameter is optional (defaults to `all`), and is used to specify the handling of untracked files.", - "The possible options are:", - " * @|yellow no|@ - Show no untracked files.", - " * @|yellow normal|@ - Shows untracked files and directories.", - " * @|yellow all|@ - Also shows individual files in untracked directories." - }) - GitStatusMode mode = GitStatusMode.all; - } - - static - // tag::GitCommit[] - // tag::GitCommit-declaration[] - @Command(name = "git-commit", - sortOptions = false, - headerHeading = "@|bold,underline Usage:|@%n%n", - synopsisHeading = "%n", - descriptionHeading = "%n@|bold,underline Description:|@%n%n", - parameterListHeading = "%n@|bold,underline Parameters:|@%n", - optionListHeading = "%n@|bold,underline Options:|@%n", - header = "Record changes to the repository.", - description = "Stores the current contents of the index in a new commit " + - "along with a log message from the user describing the changes.") - class GitCommit { // end::GitCommit-declaration[] - @Option(names = {"-a", "--all"}, - description = "Tell the command to automatically stage files that have been modified " + - "and deleted, but new files you have not told Git about are not affected.") - boolean all; - - @Option(names = {"-p", "--patch"}, description = "Use the interactive patch selection interface to chose which changes to commit") - boolean patch; - - @Option(names = {"-C", "--reuse-message"}, paramLabel = "<commit>", - description = "Take an existing commit object, and reuse the log message and the " + - "authorship information (including the timestamp) when creating the commit.") - String reuseMessageCommit; - - @Option(names = {"-c", "--reedit-message"}, paramLabel = "<commit>", - description = "Like -C, but with -c the editor is invoked, so that the user can" + - "further edit the commit message.") - String reEditMessageCommit; - - @Option(names = "--fixup", paramLabel = "<commit>", - description = "Construct a commit message for use with rebase --autosquash.") - String fixupCommit; - - @Option(names = "--squash", paramLabel = "<commit>", - description = "Construct a commit message for use with rebase --autosquash. The commit" + - "message subject line is taken from the specified commit with a prefix of " + - "\"squash! \". Can be used with additional commit message options (-m/-c/-C/-F).") - String squashCommit; - - @Option(names = {"-F", "--file"}, paramLabel = "<file>", - description = "Take the commit message from the given file. Use - to read the message from the standard input.") - File file; - - @Option(names = {"-m", "--message"}, paramLabel = "<msg>", - description = "Use the given <msg> as the commit message. If multiple -m options" + - " are given, their values are concatenated as separate paragraphs.") - List<String> message = new ArrayList<String>(); - - @Parameters(paramLabel = "<files>", description = "the files to commit") - List<File> files = new ArrayList<File>(); - } - // end::GitCommit[] - - // defines some commands to show in the list (option/parameters fields omitted for this demo) - @Command(name = "git-add", header = "Add file contents to the index.") static class GitAdd {} - @Command(name = "git-branch", header = "List, create, or delete branches.") static class GitBranch {} - @Command(name = "git-checkout", header = "Checkout a branch or paths to the working tree.") static class GitCheckout{} - @Command(name = "git-clone", header = "Clone a repository into a new directory.") static class GitClone{} - @Command(name = "git-diff", header = "Show changes between commits, commit and working tree, etc.") static class GitDiff{} - @Command(name = "git-merge", header = "Join two or more development histories together.") static class GitMerge{} - @Command(name = "git-push", header = "Update remote refs along with associated objects.") static class GitPush{} - @Command(name = "git-rebase", header = "Forward-port local commits to the updated upstream head.") static class GitRebase{} - @Command(name = "git-tag", header = "Create, list, delete or verify a tag object signed with GPG.") static class GitTag{} - - /** @see CommandLineTest#testParseSubCommands() The JUnit test implementation of this test. */ - public static void testParseSubCommands() { - CommandLine commandLine = mainCommand(); - - String[] args = { "--git-dir=/home/rpopma/picocli", "status", "-sbuno"}; - List<CommandLine> parsed = commandLine.parse(args); - assert parsed.size() == 2 : "found 2 commands"; - - assert parsed.get(0).getCommand().getClass() == Git.class; - assert parsed.get(1).getCommand().getClass() == GitStatus.class; - - Git git = (Git) parsed.get(0).getCommand(); - assert git.gitDir.equals(new File("/home/rpopma/picocli")); - - GitStatus status = (GitStatus) parsed.get(1).getCommand(); - assert status.shortFormat : "status -s"; - assert status.branchInfo : "status -b"; - assert !status.showIgnored : "status --showIgnored not specified"; - assert status.mode == GitStatusMode.no : "status -u=no"; - } - - static CommandLine mainCommand() { - CommandLine commandLine = new CommandLine(new Git()); - commandLine.addSubcommand("status", new GitStatus()); - commandLine.addSubcommand("commit", new GitCommit()); - commandLine.addSubcommand("add", new GitAdd()); - commandLine.addSubcommand("branch", new GitBranch()); - commandLine.addSubcommand("checkout", new GitCheckout()); - commandLine.addSubcommand("clone", new GitClone()); - commandLine.addSubcommand("diff", new GitDiff()); - commandLine.addSubcommand("merge", new GitMerge()); - commandLine.addSubcommand("push", new GitPush()); - commandLine.addSubcommand("rebase", new GitRebase()); - commandLine.addSubcommand("tag", new GitTag()); - return commandLine; - } - - public void testUsageMainCommand() { - CommandLine commandLine = mainCommand(); - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - commandLine.usage(new PrintStream(baos, true, "UTF8")); - String result = baos.toString("UTF8"); - System.out.println(result); - assert String.format(EXPECTED_USAGE_MAIN).equals(result); - } catch (UnsupportedEncodingException ex) { - throw new InternalError(ex.toString()); - } - } - static final String EXPECTED_USAGE_MAIN = "Usage: git [-hV] [--git-dir=<gitDir>]%n" + - "Git is a fast, scalable, distributed revision control system with an unusually%n" + - "rich command set that provides both high-level operations and full access to%n" + - "internals.%n" + - " -V, --version Prints version information and exits%n" + - " -h, --help Prints this help message and exits%n" + - " --git-dir=<gitDir> Set the path to the repository%n" + - "%n" + - "Commands:%n" + - "%n" + - "The most commonly used git commands are:%n" + - " status Show the working tree status.%n" + - " commit Record changes to the repository.%n" + - " add Add file contents to the index.%n" + - " branch List, create, or delete branches.%n" + - " checkout Checkout a branch or paths to the working tree.%n" + - " clone Clone a repository into a new directory.%n" + - " diff Show changes between commits, commit and working tree, etc.%n" + - " merge Join two or more development histories together.%n" + - " push Update remote refs along with associated objects.%n" + - " rebase Forward-port local commits to the updated upstream head.%n" + - " tag Create, list, delete or verify a tag object signed with GPG.%n"; - - static final String EXPECTED_USAGE_MAIN_ANSI = "Usage: @|bold git|@ [@|yellow -hV|@] [@|yellow --git-dir|@=@|italic <gitDir>|@]%n" + - "Git is a fast, scalable, distributed revision control system with an unusually%n" + - "rich command set that provides both high-level operations and full access to%n" + - "internals.%n" + - " @|yellow -V|@, @|yellow --version|@ Prints version information and exits%n" + - " @|yellow -h|@, @|yellow --help|@ Prints this help message and exits%n" + - " @|yellow --git-dir|@=@|italic <gitDir>|@ Set the path to the repository%n" + - "%n" + - "Commands:%n" + - "%n" + - "The most commonly used git commands are:%n" + - " @|bold status|@ Show the working tree status.%n" + - " @|bold commit|@ Record changes to the repository.%n" + - " @|bold add|@ Add file contents to the index.%n" + - " @|bold branch|@ List, create, or delete branches.%n" + - " @|bold checkout|@ Checkout a branch or paths to the working tree.%n" + - " @|bold clone|@ Clone a repository into a new directory.%n" + - " @|bold diff|@ Show changes between commits, commit and working tree, etc.%n" + - " @|bold merge|@ Join two or more development histories together.%n" + - " @|bold push|@ Update remote refs along with associated objects.%n" + - " @|bold rebase|@ Forward-port local commits to the updated upstream head.%n" + - " @|bold tag|@ Create, list, delete or verify a tag object signed with GPG.%n"; - - public void testUsageSubCommandStatus() { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - CommandLine.usage(new GitStatus(), new PrintStream(baos, true, "UTF8")); - String result = baos.toString("UTF8"); - System.out.println(result); - assert String.format(EXPECTED_USAGE_GITSTATUS).equals(result); - } catch (UnsupportedEncodingException ex) { - throw new InternalError(ex.toString()); - } - } - static final String EXPECTED_USAGE_GITSTATUS = "Show the working tree status.%n" + - "Usage: git-status [<options>...] [--] [<pathspec>...]%n" + - "Displays paths that have differences between the index file and the current%n" + - "HEAD commit, paths that have differences between the working tree and the index%n" + - "file, and paths in the working tree that are not tracked by Git (and are not%n" + - "ignored by gitignore(5)). The first are what you would commit by running git%n" + - "commit; the second and third are what you could commit by running git add%n" + - "before running git commit.%n" + - " --ignored Show ignored files as well%n" + - " -b, --branch Show the branch and tracking info even in%n" + - " short-format%n" + - " -s, --short Give the output in the short-format%n" + - " -u, --untracked=<mode> Show untracked files.%n" + - " The mode parameter is optional (defaults to%n" + - " `all`), and is used to specify the handling of%n" + - " untracked files.%n" + - " The possible options are:%n" + - " * no - Show no untracked files.%n" + - " * normal - Shows untracked files and directories.%n" + - " * all - Also shows individual files in untracked%n" + - " directories.%n" + - " Default: all%n"; - - static final String EXPECTED_USAGE_GITSTATUS_ANSI = "Show the working tree status.%n" + - "Usage: @|bold git-status|@ [@|yellow <options>|@...] [--] [@|yellow <pathspec>|@...]%n" + - "Displays paths that have differences between the index file and the current%n" + - "HEAD commit, paths that have differences between the working tree and the index%n" + - "file, and paths in the working tree that are not tracked by Git (and are not%n" + - "ignored by gitignore(5)). The first are what you would commit by running git%n" + - "commit; the second and third are what you could commit by running git add%n" + - "before running git commit.%n" + - " @|yellow --ignored|@ Show ignored files as well%n" + - " @|yellow -b|@, @|yellow --branch|@ Show the branch and tracking info even in%n" + - " short-format%n" + - " @|yellow -s|@, @|yellow --short|@ Give the output in the short-format%n" + - " @|yellow -u|@, @|yellow --untracked|@=@|italic <mode>|@ Show untracked files.%n" + - " The mode parameter is optional (defaults to%n" + - " `all`), and is used to specify the handling of%n" + - " untracked files.%n" + - " The possible options are:%n" + - " * @|yellow no|@ - Show no untracked files.%n" + - " * @|yellow normal|@ - Shows untracked files and directories.%n" + - " * @|yellow all|@ - Also shows individual files in untracked%n" + - " directories.%n" + - " Default: all%n"; - - public void testUsageSubCommandCommit() { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - CommandLine.usage(new GitCommit(), new PrintStream(baos, true, "UTF8")); - String result = baos.toString("UTF8"); - System.out.println(result); - assert String.format(EXPECTED_USAGE_GITCOMMIT).equals(result); - } catch (UnsupportedEncodingException ex) { - throw new InternalError(ex.toString()); - } - } - static final String EXPECTED_USAGE_GITCOMMIT = "Usage:%n" + - "%n" + - "Record changes to the repository.%n" + - "%n" + - "git-commit [-ap] [--fixup=<commit>] [--squash=<commit>] [-c=<commit>]%n" + - " [-C=<commit>] [-F=<file>] [-m=<msg>]... [<files>]...%n" + - "%n" + - "Description:%n" + - "%n" + - "Stores the current contents of the index in a new commit along with a log%n" + - "message from the user describing the changes.%n" + - "%n" + - "Parameters:%n" + - " [<files>]... the files to commit%n" + - "%n" + - "Options:%n" + - " -a, --all Tell the command to automatically stage files%n" + - " that have been modified and deleted, but new%n" + - " files you have not told Git about are not%n" + - " affected.%n" + - " -p, --patch Use the interactive patch selection interface to%n" + - " chose which changes to commit%n" + - " -C, --reuse-message=<commit>%n" + - " Take an existing commit object, and reuse the log%n" + - " message and the authorship information%n" + - " (including the timestamp) when creating the%n" + - " commit.%n" + - " -c, --reedit-message=<commit>%n" + - " Like -C, but with -c the editor is invoked, so%n" + - " that the user canfurther edit the commit%n" + - " message.%n" + - " --fixup=<commit> Construct a commit message for use with rebase%n" + - " --autosquash.%n" + - " --squash=<commit> Construct a commit message for use with rebase%n" + - " --autosquash. The commitmessage subject line is%n" + - " taken from the specified commit with a prefix%n" + - " of \"squash! \". Can be used with additional%n" + - " commit message options (-m/-c/-C/-F).%n" + - " -F, --file=<file> Take the commit message from the given file. Use%n" + - " - to read the message from the standard input.%n" + - " -m, --message=<msg> Use the given <msg> as the commit message. If%n" + - " multiple -m options are given, their values are%n" + - " concatenated as separate paragraphs.%n"; - - static final String EXPECTED_USAGE_GITCOMMIT_ANSI = "@|bold,underline Usage:|@%n" + - "%n" + - "Record changes to the repository.%n" + - "%n" + - "@|bold git-commit|@ [@|yellow -ap|@] [@|yellow --fixup|@=@|italic <commit>|@] [@|yellow --squash|@=@|italic <commit>|@] [@|yellow -c|@=@|italic <commit>|@]%n" + - " [@|yellow -C|@=@|italic <commit>|@] [@|yellow -F|@=@|italic <file>|@] [@|yellow -m|@=@|italic <msg>|@]... [@|yellow <files>|@]...%n" + - "%n" + - "@|bold,underline Description:|@%n" + - "%n" + - "Stores the current contents of the index in a new commit along with a log%n" + - "message from the user describing the changes.%n" + - "%n" + - "@|bold,underline Parameters:|@%n" + - " [@|yellow <files>|@]... the files to commit%n" + - "%n" + - "@|bold,underline Options:|@%n" + - " @|yellow -a|@, @|yellow --all|@ Tell the command to automatically stage files%n" + - " that have been modified and deleted, but new%n" + - " files you have not told Git about are not%n" + - " affected.%n" + - " @|yellow -p|@, @|yellow --patch|@ Use the interactive patch selection interface to%n" + - " chose which changes to commit%n" + - " @|yellow -C|@, @|yellow --reuse-message|@=@|italic <commit|@@|italic >|@%n" + - " Take an existing commit object, and reuse the log%n" + - " message and the authorship information%n" + - " (including the timestamp) when creating the%n" + - " commit.%n" + - " @|yellow -c|@, @|yellow --reedit-message|@=@|italic <commi|@@|italic t>|@%n" + - " Like -C, but with -c the editor is invoked, so%n" + - " that the user canfurther edit the commit%n" + - " message.%n" + - " @|yellow --fixup|@=@|italic <commit>|@ Construct a commit message for use with rebase%n" + - " --autosquash.%n" + - " @|yellow --squash|@=@|italic <commit>|@ Construct a commit message for use with rebase%n" + - " --autosquash. The commitmessage subject line is%n" + - " taken from the specified commit with a prefix%n" + - " of \"squash! \". Can be used with additional%n" + - " commit message options (-m/-c/-C/-F).%n" + - " @|yellow -F|@, @|yellow --file|@=@|italic <file>|@ Take the commit message from the given file. Use%n" + - " - to read the message from the standard input.%n" + - " @|yellow -m|@, @|yellow --message|@=@|italic <msg>|@ Use the given <msg> as the commit message. If%n" + - " multiple -m options are given, their values are%n" + - " concatenated as separate paragraphs.%n"; - - static - // tag::CheckSum[] - @Command(name = "checksum", description = "Prints the checksum (MD5 by default) of a file to STDOUT.") - class CheckSum implements Callable<Void> { - - @Parameters(index = "0", description = "The file whose checksum to calculate.") - private File file; - - @Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...") - private String algorithm = "MD5"; - - @Option(names = {"-h", "--help"}, usageHelp = true, description = "Show this help message and exit.") - private boolean helpRequested; - - public static void main(String[] args) throws Exception { - // CheckSum implements Callable, - // so parsing and error handling can be done in one line of code - CommandLine.call(new CheckSum(), System.err, args); - } - - @Override - public Void call() throws Exception { - // business logic: do different things depending on options the user specified - if (helpRequested) { - CommandLine.usage(this, System.err); - return null; - } - byte[] digest = MessageDigest.getInstance(algorithm).digest(readBytes(file)); - print(digest, System.out); - return null; - } - - byte[] readBytes(File f) throws IOException { - int pos = 0; - int len = 0; - byte[] buffer = new byte[(int) f.length()]; - FileInputStream fis = null; - try { - fis = new FileInputStream(f); - while ((len = fis.read(buffer, pos, buffer.length - pos)) > 0) { pos += len; } - } finally { - if (fis != null) { fis.close(); } - } - return buffer; - } - void print(byte[] digest, PrintStream out) { - for (int i = 0; i < digest.length; i++) { - if ((digest[i] & 0xFF) < 16) { out.print('0'); } - out.print(Integer.toHexString(digest[i] & 0xFF)); - } - out.println(); - } - } - // end::CheckSum[] -}
