mirror of https://github.com/apache/ant-ivy
IMPROVEMENT: Make Ivy standalone runnable with no required dependencies (IVY-757)
git-svn-id: https://svn.apache.org/repos/asf/ant/ivy/core/trunk@632381 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2d61ecf18a
commit
f97ecea7e1
|
|
@ -64,6 +64,8 @@ for detailed view of each issue, please consult http://issues.apache.org/jira/br
|
|||
|
||||
trunk version
|
||||
=====================================
|
||||
- IMPROVEMENT: Make Ivy standalone runnable with no required dependencies (IVY-757)
|
||||
|
||||
- FIX: PublishEventsTest fails when Ivy sources are located in a directory with a + (IVY-755)
|
||||
- FIX: XML entity parsing does not work properly (IVY-737) (thanks to Patrick Woodworth)
|
||||
- FIX: Cachefileset task silently fails with parent dir ".." construct (IVY-638)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
Manifest-Version: 1.0
|
||||
Main-Class: org.apache.ivy.Main
|
||||
Bundle-Version: 0.0.0
|
||||
Bundle-Name: Ivy
|
||||
Bundle-ManifestVersion: 2
|
||||
|
|
@ -15,7 +16,6 @@ Import-Package: javax.xml.parsers,
|
|||
com.jcraft.jsch;resolution:=optional,
|
||||
javax.swing;resolution:=optional,
|
||||
javax.swing.event;resolution:=optional,
|
||||
org.apache.commons.cli;resolution:=optional,
|
||||
org.apache.commons.httpclient;resolution:=optional,
|
||||
org.apache.commons.httpclient.methods;resolution:=optional,
|
||||
org.apache.commons.httpclient.params;resolution:=optional,
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@
|
|||
</head>
|
||||
<body>
|
||||
<textarea id="xooki-source">
|
||||
In the case you want to call ivy as a standalone program (outside from ant), you have to put commons-cli 1.0 and its dependencies in your classpath.
|
||||
Ivy can be used as a standalone program very easily. All you need is a java 1.4+ runtime environment (JRE)!
|
||||
|
||||
Then here is how to call it:
|
||||
<code>
|
||||
java org.apache.ivy.Main -?
|
||||
java -jar ivy.jar -?
|
||||
</code>
|
||||
It will indicate you what can be given as argument.
|
||||
It will display an help telling what can be given as argument.
|
||||
|
||||
|
||||
<span class="since">since 1.3</span> System properties are included as ivy variables, so you can easily define an ivy variable like this:
|
||||
|
|
@ -42,24 +42,24 @@ java -Dmyivyvar=myvalue org.apache.ivy.Main [parameters]
|
|||
|
||||
<h1>Examples</h1>
|
||||
<code>
|
||||
java org.apache.ivy.Main
|
||||
java -jar ivy.jar
|
||||
</code>
|
||||
calls ivy with default configuration using ivy.xml in the current dir
|
||||
<hr/>
|
||||
<code>
|
||||
java org.apache.ivy.Main -conf path/to/myivysettings.xml -ivy path/to/myivy.xml
|
||||
java -jar ivy.jar -conf path/to/myivysettings.xml -ivy path/to/myivy.xml
|
||||
</code>
|
||||
calls ivy with given ivysettings file using given ivy file
|
||||
<hr/>
|
||||
<span class="since">since 1.3</span>
|
||||
<code>
|
||||
java org.apache.ivy.Main -conf path/to/myivysettings.xml -dependency apache commons-lang 2.0
|
||||
java -jar ivy.jar -conf path/to/myivysettings.xml -dependency apache commons-lang 2.0
|
||||
</code>
|
||||
calls ivy with given ivysettings file and resolve apache commons-lang 2.0.
|
||||
|
||||
This is equivalent to:
|
||||
<code>
|
||||
java org.apache.ivy.Main -conf path/to/myivysettings.xml -ivy ivy.xml
|
||||
java -jar ivy.jar -conf path/to/myivysettings.xml -ivy ivy.xml
|
||||
</code>
|
||||
with ivy.xml like this:
|
||||
<code type="xml">
|
||||
|
|
@ -76,14 +76,14 @@ with ivy.xml like this:
|
|||
<hr/>
|
||||
<span class="since">since 1.3</span>
|
||||
<code>
|
||||
java org.apache.ivy.Main -conf path/to/myivysettings.xml -ivy path/to/myivy.xml -cachepath mycachefile.txt
|
||||
java -jar ivy.jar -conf path/to/myivysettings.xml -ivy path/to/myivy.xml -cachepath mycachefile.txt
|
||||
</code>
|
||||
calls ivy with given ivysettings file and resolve the dependencies found in the given ivy file, and then output the classpath of resolved artifacts in cache in a file. This file can then be used to define a classpath corresponding to all the resolved dependencies for any java program.
|
||||
|
||||
<hr/>
|
||||
<span class="since">since 1.4</span>
|
||||
<code>
|
||||
java org.apache.ivy.Main -conf path/to/myivysettings.xml -dependency bar foo 2.0 -main org.bar.foo.FooMain
|
||||
java -jar ivy.jar -conf path/to/myivysettings.xml -dependency bar foo 2.0 -main org.bar.foo.FooMain
|
||||
</code>
|
||||
calls ivy with given ivysettings file and resolve bar foo 2.0, and then run org.foo.FooMain class with the resolved artifacts as classpath
|
||||
|
||||
|
|
|
|||
1
ivy.xml
1
ivy.xml
|
|
@ -40,7 +40,6 @@
|
|||
<dependencies>
|
||||
<dependency org="ant" name="ant" rev="1.6" conf="default,ant->default"/>
|
||||
<dependency org="commons-httpclient" name="commons-httpclient" rev="3.0" conf="default,httpclient->runtime,master" />
|
||||
<dependency org="commons-cli" name="commons-cli" rev="1.0" conf="default,standalone->runtime,master" />
|
||||
<dependency org="oro" name="oro" rev="2.0.8" conf="default,oro->default"/>
|
||||
<dependency org="commons-vfs" name="commons-vfs" rev="1.0" conf="default,vfs->default" />
|
||||
<dependency org="jsch" name="jsch" rev="0.1.25" conf="default,sftp->default" />
|
||||
|
|
|
|||
|
|
@ -35,14 +35,6 @@ import java.util.LinkedHashSet;
|
|||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.GnuParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.OptionBuilder;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.ivy.core.cache.ResolutionCacheManager;
|
||||
import org.apache.ivy.core.deliver.DeliverOptions;
|
||||
import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
|
||||
|
|
@ -59,6 +51,10 @@ import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter;
|
|||
import org.apache.ivy.plugins.report.XmlReportParser;
|
||||
import org.apache.ivy.util.DefaultMessageLogger;
|
||||
import org.apache.ivy.util.Message;
|
||||
import org.apache.ivy.util.cli.CommandLine;
|
||||
import org.apache.ivy.util.cli.CommandLineParser;
|
||||
import org.apache.ivy.util.cli.OptionBuilder;
|
||||
import org.apache.ivy.util.cli.ParseException;
|
||||
import org.apache.ivy.util.url.CredentialsStore;
|
||||
import org.apache.ivy.util.url.URLHandler;
|
||||
import org.apache.ivy.util.url.URLHandlerDispatcher;
|
||||
|
|
@ -70,108 +66,114 @@ import org.apache.ivy.util.url.URLHandlerRegistry;
|
|||
* Valid arguments can be obtained with the -? argument.
|
||||
*/
|
||||
public final class Main {
|
||||
private static final int DEPENDENCY_ARG_COUNT = 3;
|
||||
private static final int HELP_WIDTH = 80;
|
||||
private static PrintWriter out = new PrintWriter(System.out);
|
||||
|
||||
private static Options getOptions() {
|
||||
Option settings = OptionBuilder.withArgName("settingsfile").hasArg().withDescription(
|
||||
"use given file for settings").create("settings");
|
||||
Option conf = OptionBuilder.withArgName("settingsfile").hasArg().withDescription(
|
||||
"DEPRECATED - use given file for settings").create("conf");
|
||||
Option cache = OptionBuilder.withArgName("cachedir").hasArg().withDescription(
|
||||
"use given directory for cache").create("cache");
|
||||
Option ivyfile = OptionBuilder.withArgName("ivyfile").hasArg().withDescription(
|
||||
"use given file as ivy file").create("ivy");
|
||||
Option dependency = OptionBuilder
|
||||
.withArgName("organisation module revision")
|
||||
.hasArgs()
|
||||
.withDescription(
|
||||
"use this instead of ivy file to do the rest "
|
||||
+ "of the work with this as a dependency.")
|
||||
.create("dependency");
|
||||
Option confs = OptionBuilder.withArgName("configurations").hasArgs().withDescription(
|
||||
"resolve given configurations").create("confs");
|
||||
Option retrieve = OptionBuilder.withArgName("retrievepattern").hasArg().withDescription(
|
||||
"use given pattern as retrieve pattern").create("retrieve");
|
||||
Option cachepath = OptionBuilder
|
||||
.withArgName("cachepathfile")
|
||||
.hasArg()
|
||||
.withDescription(
|
||||
"outputs a classpath consisting of all dependencies in cache "
|
||||
static CommandLineParser getParser() {
|
||||
return new CommandLineParser()
|
||||
.addCategory("settings options")
|
||||
.addOption(new OptionBuilder("settings").arg("settingsfile")
|
||||
.description("use given file for settings").create())
|
||||
.addOption(new OptionBuilder("cache").arg("cachedir")
|
||||
.description("use given directory for cache").create())
|
||||
.addOption(new OptionBuilder("novalidate")
|
||||
.description("do not validate ivy files against xsd").create())
|
||||
.addOption(new OptionBuilder("m2compatible")
|
||||
.description("use maven2 compatibility").create())
|
||||
.addOption(new OptionBuilder("conf").arg("settingsfile").deprecated()
|
||||
.description("use given file for settings").create())
|
||||
.addOption(new OptionBuilder("useOrigin").deprecated()
|
||||
.description("use original artifact location "
|
||||
+ "with local resolvers instead of copying to the cache").create())
|
||||
|
||||
.addCategory("resolve options")
|
||||
.addOption(new OptionBuilder("ivy").arg("ivyfile")
|
||||
.description("use given file as ivy file").create())
|
||||
.addOption(new OptionBuilder("dependency")
|
||||
.arg("organisation").arg("module").arg("revision")
|
||||
.description("use this instead of ivy file to do the rest "
|
||||
+ "of the work with this as a dependency.").create())
|
||||
.addOption(new OptionBuilder("confs").arg("configurations").countArgs(false)
|
||||
.description("resolve given configurations").create())
|
||||
|
||||
.addCategory("retrieve options")
|
||||
.addOption(new OptionBuilder("retrieve").arg("retrievepattern")
|
||||
.description("use given pattern as retrieve pattern").create())
|
||||
.addOption(new OptionBuilder("sync")
|
||||
.description("use sync mode for retrieve").create())
|
||||
|
||||
.addCategory("cache path options")
|
||||
.addOption(new OptionBuilder("cachepath").arg("cachepathfile")
|
||||
.description("outputs a classpath consisting of all dependencies in cache "
|
||||
+ "(including transitive ones) "
|
||||
+ "of the given ivy file to the given cachepathfile")
|
||||
.create("cachepath");
|
||||
Option revision = OptionBuilder.withArgName("revision").hasArg().withDescription(
|
||||
"use given revision to publish the module").create("revision");
|
||||
Option status = OptionBuilder.withArgName("status").hasArg().withDescription(
|
||||
"use given status to publish the module").create("status");
|
||||
Option deliver = OptionBuilder.withArgName("ivypattern").hasArg().withDescription(
|
||||
"use given pattern as resolved ivy file pattern").create("deliverto");
|
||||
Option publishResolver = OptionBuilder.withArgName("resolvername").hasArg()
|
||||
.withDescription("use given resolver to publish to").create("publish");
|
||||
Option publishPattern = OptionBuilder.withArgName("artpattern").hasArg().withDescription(
|
||||
"use given pattern to find artifacts to publish").create("publishpattern");
|
||||
Option realm = OptionBuilder.withArgName("realm").hasArg().withDescription(
|
||||
"use given realm for HTTP AUTH").create("realm");
|
||||
Option host = OptionBuilder.withArgName("host").hasArg().withDescription(
|
||||
"use given host for HTTP AUTH").create("host");
|
||||
Option username = OptionBuilder.withArgName("username").hasArg().withDescription(
|
||||
"use given username for HTTP AUTH").create("username");
|
||||
Option passwd = OptionBuilder.withArgName("passwd").hasArg().withDescription(
|
||||
"use given password for HTTP AUTH").create("passwd");
|
||||
Option main = OptionBuilder.withArgName("main").hasArg().withDescription(
|
||||
"the main class to runtime process").create("main");
|
||||
Option args = OptionBuilder.withArgName("args").hasArgs().withDescription(
|
||||
"the arguments to runtime process").create("args");
|
||||
Option cp = OptionBuilder.withArgName("cp").hasArg().withDescription(
|
||||
"extra classpath, used only in combination with option main").create("cp");
|
||||
+ "of the given ivy file to the given cachepathfile").create())
|
||||
|
||||
.addCategory("deliver options")
|
||||
.addOption(new OptionBuilder("deliverto").arg("ivypattern")
|
||||
.description("use given pattern as resolved ivy file pattern").create())
|
||||
|
||||
Options options = new Options();
|
||||
.addCategory("publish options")
|
||||
.addOption(new OptionBuilder("publish").arg("resolvername")
|
||||
.description("use given resolver to publish to").create())
|
||||
.addOption(new OptionBuilder("publishpattern").arg("artpattern")
|
||||
.description("use given pattern to find artifacts to publish").create())
|
||||
.addOption(new OptionBuilder("revision").arg("revision")
|
||||
.description("use given revision to publish the module").create())
|
||||
.addOption(new OptionBuilder("status").arg("status")
|
||||
.description("use given status to publish the module").create())
|
||||
|
||||
options.addOption("debug", false, "set message level to debug");
|
||||
options.addOption("verbose", false, "set message level to verbose");
|
||||
options.addOption("warn", false, "set message level to warn");
|
||||
options.addOption("error", false, "set message level to error");
|
||||
options.addOption("novalidate", false, "do not validate ivy files against xsd");
|
||||
options.addOption("useOrigin", false,
|
||||
"DEPRECATED: use original artifact location "
|
||||
+ "with local resolvers instead of copying to the cache");
|
||||
options.addOption("sync", false, "in conjonction with -retrieve, does a synced retrieve");
|
||||
options.addOption("m2compatible", false, "use maven2 compatibility");
|
||||
options.addOption("?", false, "display this help");
|
||||
options.addOption(conf);
|
||||
options.addOption(settings);
|
||||
options.addOption(confs);
|
||||
options.addOption(cache);
|
||||
options.addOption(ivyfile);
|
||||
options.addOption(dependency);
|
||||
options.addOption(retrieve);
|
||||
options.addOption(cachepath);
|
||||
options.addOption(revision);
|
||||
options.addOption(status);
|
||||
options.addOption(deliver);
|
||||
options.addOption(publishResolver);
|
||||
options.addOption(publishPattern);
|
||||
options.addOption(realm);
|
||||
options.addOption(host);
|
||||
options.addOption(username);
|
||||
options.addOption(passwd);
|
||||
options.addOption(main);
|
||||
options.addOption(args);
|
||||
options.addOption(cp);
|
||||
.addCategory("http auth options")
|
||||
.addOption(new OptionBuilder("realm").arg("realm")
|
||||
.description("use given realm for HTTP AUTH").create())
|
||||
.addOption(new OptionBuilder("host").arg("host")
|
||||
.description("use given host for HTTP AUTH").create())
|
||||
.addOption(new OptionBuilder("username").arg("username")
|
||||
.description("use given username for HTTP AUTH").create())
|
||||
.addOption(new OptionBuilder("passwd").arg("passwd")
|
||||
.description("use given password for HTTP AUTH").create())
|
||||
|
||||
return options;
|
||||
.addCategory("launcher options")
|
||||
.addOption(new OptionBuilder("main").arg("main")
|
||||
.description("the FQCN of the main class to launch").create())
|
||||
.addOption(new OptionBuilder("args").arg("args").countArgs(false)
|
||||
.description("the arguments to give to the launched process").create())
|
||||
.addOption(new OptionBuilder("cp").arg("cp")
|
||||
.description("extra classpath to use when launching process").create())
|
||||
|
||||
.addCategory("message options")
|
||||
.addOption(new OptionBuilder("debug")
|
||||
.description("set message level to debug").create())
|
||||
.addOption(new OptionBuilder("verbose")
|
||||
.description("set message level to verbose").create())
|
||||
.addOption(new OptionBuilder("warn")
|
||||
.description("set message level to warn").create())
|
||||
.addOption(new OptionBuilder("error")
|
||||
.description("set message level to error").create())
|
||||
|
||||
.addCategory("help options")
|
||||
.addOption(new OptionBuilder("?")
|
||||
.description("display this help").create())
|
||||
.addOption(new OptionBuilder("deprecated")
|
||||
.description("show deprecated options").create());
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Options options = getOptions();
|
||||
|
||||
CommandLineParser parser = new GnuParser();
|
||||
CommandLineParser parser = getParser();
|
||||
try {
|
||||
run(parser, args);
|
||||
} catch (ParseException ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
usage(parser, false);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void run(CommandLineParser parser, String[] args) throws Exception {
|
||||
// parse the command line arguments
|
||||
CommandLine line = parser.parse(options, args);
|
||||
CommandLine line = parser.parse(args);
|
||||
|
||||
if (line.hasOption("?")) {
|
||||
usage(options);
|
||||
usage(parser, line.hasOption("deprecated"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -180,14 +182,14 @@ public final class Main {
|
|||
|
||||
Ivy ivy = Ivy.newInstance();
|
||||
initMessage(line, ivy);
|
||||
IvySettings settings = initSettings(line, options, ivy);
|
||||
IvySettings settings = initSettings(line, ivy);
|
||||
|
||||
File cache = new File(settings.substitute(line.getOptionValue("cache", settings
|
||||
.getDefaultCache().getAbsolutePath())));
|
||||
if (!cache.exists()) {
|
||||
cache.mkdirs();
|
||||
} else if (!cache.isDirectory()) {
|
||||
error(options, cache + " is not a directory");
|
||||
error(cache + " is not a directory");
|
||||
}
|
||||
|
||||
String[] confs;
|
||||
|
|
@ -200,11 +202,6 @@ public final class Main {
|
|||
File ivyfile;
|
||||
if (line.hasOption("dependency")) {
|
||||
String[] dep = line.getOptionValues("dependency");
|
||||
if (dep.length != DEPENDENCY_ARG_COUNT) {
|
||||
error(options,
|
||||
"dependency should be expressed with exactly 3 arguments: "
|
||||
+ "organisation module revision");
|
||||
}
|
||||
ivyfile = File.createTempFile("ivy", ".xml");
|
||||
ivyfile.deleteOnExit();
|
||||
DefaultModuleDescriptor md = DefaultModuleDescriptor
|
||||
|
|
@ -221,9 +218,9 @@ public final class Main {
|
|||
} else {
|
||||
ivyfile = new File(settings.substitute(line.getOptionValue("ivy", "ivy.xml")));
|
||||
if (!ivyfile.exists()) {
|
||||
error(options, "ivy file not found: " + ivyfile);
|
||||
error("ivy file not found: " + ivyfile);
|
||||
} else if (ivyfile.isDirectory()) {
|
||||
error(options, "ivy file is not a file: " + ivyfile);
|
||||
error("ivy file is not a file: " + ivyfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +278,7 @@ public final class Main {
|
|||
if (fargs == null) {
|
||||
fargs = new String[0];
|
||||
}
|
||||
String[] extra = line.getArgs();
|
||||
String[] extra = line.getLeftOverArgs();
|
||||
if (extra == null) {
|
||||
extra = new String[0];
|
||||
}
|
||||
|
|
@ -292,12 +289,6 @@ public final class Main {
|
|||
invoke(ivy, cache, md, confs, fileList, line.getOptionValue("main"), params);
|
||||
}
|
||||
ivy.getLoggerEngine().popLogger();
|
||||
} catch (ParseException exp) {
|
||||
// oops, something went wrong
|
||||
System.err.println("Parsing failed. Reason: " + exp.getMessage());
|
||||
|
||||
usage(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -335,8 +326,8 @@ public final class Main {
|
|||
return fileList;
|
||||
}
|
||||
|
||||
private static IvySettings initSettings(CommandLine line, Options options, Ivy ivy)
|
||||
throws java.text.ParseException, IOException {
|
||||
private static IvySettings initSettings(CommandLine line, Ivy ivy)
|
||||
throws java.text.ParseException, IOException, ParseException {
|
||||
IvySettings settings = ivy.getSettings();
|
||||
settings.addAllVariables(System.getProperties());
|
||||
if (line.hasOption("m2compatible")) {
|
||||
|
|
@ -358,9 +349,9 @@ public final class Main {
|
|||
} else {
|
||||
File conffile = new File(settingsPath);
|
||||
if (!conffile.exists()) {
|
||||
error(options, "ivy configuration file not found: " + conffile);
|
||||
error("ivy configuration file not found: " + conffile);
|
||||
} else if (conffile.isDirectory()) {
|
||||
error(options, "ivy configuration file is not a file: " + conffile);
|
||||
error("ivy configuration file is not a file: " + conffile);
|
||||
}
|
||||
ivy.configure(conffile);
|
||||
}
|
||||
|
|
@ -491,16 +482,15 @@ public final class Main {
|
|||
URLHandlerRegistry.setDefault(dispatcher);
|
||||
}
|
||||
|
||||
private static void error(Options options, String msg) {
|
||||
System.err.println(msg);
|
||||
usage(options);
|
||||
System.exit(1);
|
||||
private static void error(String msg) throws ParseException {
|
||||
throw new ParseException(msg);
|
||||
}
|
||||
|
||||
private static void usage(Options options) {
|
||||
private static void usage(CommandLineParser parser, boolean showDeprecated) {
|
||||
// automatically generate the help statement
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("ivy", options);
|
||||
PrintWriter pw = new PrintWriter(System.out);
|
||||
parser.printHelp(pw, HELP_WIDTH, "ivy", showDeprecated);
|
||||
pw.flush();
|
||||
}
|
||||
|
||||
private Main() {
|
||||
|
|
|
|||
|
|
@ -176,4 +176,12 @@ public final class StringUtils {
|
|||
+ "'. Unhandled character.");
|
||||
}
|
||||
|
||||
public static String repeat(String str, int count) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.append(str);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.ivy.util.cli;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CommandLine {
|
||||
private Map/*<String, String[]>*/ optionValues = new HashMap();
|
||||
private String[] leftOverArgs;
|
||||
|
||||
void addOptionValues(String option, String[] values) {
|
||||
optionValues.put(option, values);
|
||||
}
|
||||
|
||||
void setLeftOverArgs(String[] args) {
|
||||
leftOverArgs = args;
|
||||
}
|
||||
|
||||
public boolean hasOption(String option) {
|
||||
return optionValues.containsKey(option);
|
||||
}
|
||||
|
||||
public String getOptionValue(String option) {
|
||||
String[] values = getOptionValues(option);
|
||||
return values == null || values.length == 0 ? null : values[0];
|
||||
}
|
||||
|
||||
public String getOptionValue(String option, String defaultValue) {
|
||||
String value = getOptionValue(option);
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
public String[] getOptionValues(String option) {
|
||||
return (String[]) optionValues.get(option);
|
||||
}
|
||||
|
||||
public String[] getLeftOverArgs() {
|
||||
return leftOverArgs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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.ivy.util.cli;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.ivy.util.StringUtils;
|
||||
|
||||
public class CommandLineParser {
|
||||
private static final int MIN_DESC_WIDTH = 40;
|
||||
private static final int MAX_SPEC_WIDTH = 30;
|
||||
private Map/*<String, Option>*/ options = new LinkedHashMap();
|
||||
private Map/*<String, List<Option>>*/ categories = new LinkedHashMap();
|
||||
|
||||
public CommandLineParser() {
|
||||
}
|
||||
|
||||
public CommandLineParser addCategory(String category) {
|
||||
categories.put(category, new ArrayList());
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandLineParser addOption(Option option) {
|
||||
options.put(option.getName(), option);
|
||||
if (!categories.isEmpty()) {
|
||||
((List) categories.values().toArray()[categories.values().size() - 1])
|
||||
.add(option);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandLine parse(String[] args) throws ParseException {
|
||||
CommandLine line = new CommandLine();
|
||||
for (ListIterator iterator = Arrays.asList(args).listIterator(); iterator.hasNext();) {
|
||||
String arg = (String) iterator.next();
|
||||
if (arg.startsWith("-")) {
|
||||
Option option = (Option) options.get(arg.substring(1));
|
||||
if (option == null) {
|
||||
throw new ParseException("Unrecognized option: " + arg);
|
||||
}
|
||||
line.addOptionValues(arg.substring(1), option.parse(iterator));
|
||||
} else {
|
||||
// left over args
|
||||
int index = iterator.previousIndex() + 1;
|
||||
String[] leftOverArgs = new String[args.length - index];
|
||||
System.arraycopy(args, index, leftOverArgs, 0, leftOverArgs.length);
|
||||
line.setLeftOverArgs(leftOverArgs);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
public void printHelp(PrintWriter pw, int width, String command, boolean showDeprecated) {
|
||||
pw.println("usage: " + command);
|
||||
// compute the largest option spec
|
||||
int specWidth = 0;
|
||||
for (Iterator iterator = options.values().iterator(); iterator.hasNext();) {
|
||||
Option option = (Option) iterator.next();
|
||||
if (option.isDeprecated() && !showDeprecated) {
|
||||
continue;
|
||||
}
|
||||
specWidth = Math.min(MAX_SPEC_WIDTH,
|
||||
Math.max(specWidth, option.getSpec().length()));
|
||||
}
|
||||
|
||||
// print options help
|
||||
for (Iterator iterator = categories.entrySet().iterator(); iterator.hasNext();) {
|
||||
Entry entry = (Entry) iterator.next();
|
||||
String category = (String) entry.getKey();
|
||||
pw.println("==== " + category);
|
||||
List/*<Option>*/ options = (List) entry.getValue();
|
||||
for (Iterator it = options.iterator(); it.hasNext();) {
|
||||
Option option = (Option) it.next();
|
||||
if (option.isDeprecated() && !showDeprecated) {
|
||||
continue;
|
||||
}
|
||||
// print option spec: option name + argument names
|
||||
String spec = option.getSpec();
|
||||
pw.print(" " + spec);
|
||||
int specLength = spec.length() + 1;
|
||||
pw.print(StringUtils.repeat(" ", specWidth - specLength));
|
||||
|
||||
// print description
|
||||
StringBuffer desc = new StringBuffer(
|
||||
(option.isDeprecated() ? "DEPRECATED: " : "") + option.getDescription());
|
||||
int count = Math.min(desc.length(), width - Math.max(specLength, specWidth));
|
||||
// see if we have enough space to start on the same line as the spec
|
||||
if (count > MIN_DESC_WIDTH || desc.length() + specLength < width) {
|
||||
pw.print(desc.substring(0, count));
|
||||
desc.delete(0, count);
|
||||
}
|
||||
pw.println();
|
||||
|
||||
// print remaining description
|
||||
while (desc.length() > 0) {
|
||||
pw.print(StringUtils.repeat(" ", specWidth));
|
||||
count = Math.min(desc.length(), width - specWidth);
|
||||
pw.println(desc.substring(0, count));
|
||||
desc.delete(0, count);
|
||||
}
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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.ivy.util.cli;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class Option {
|
||||
private String name;
|
||||
private String[] args;
|
||||
private String description;
|
||||
private boolean required;
|
||||
private boolean countArgs;
|
||||
private boolean deprecated;
|
||||
|
||||
Option(String name, String[] args, String description,
|
||||
boolean required, boolean countArgs, boolean deprecated) {
|
||||
this.name = name;
|
||||
this.args = args;
|
||||
this.description = description;
|
||||
this.required = required;
|
||||
this.countArgs = countArgs;
|
||||
this.deprecated = deprecated;
|
||||
if (required) {
|
||||
throw new UnsupportedOperationException("required option not supported yet");
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public boolean isRequired() {
|
||||
return required;
|
||||
}
|
||||
public boolean isCountArgs() {
|
||||
return countArgs;
|
||||
}
|
||||
public boolean isDeprecated() {
|
||||
return deprecated;
|
||||
}
|
||||
|
||||
String[] parse(ListIterator iterator) throws ParseException {
|
||||
if (isCountArgs()) {
|
||||
String[] values = new String[args.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (!iterator.hasNext()) {
|
||||
missingArgument(i);
|
||||
}
|
||||
values[i] = (String) iterator.next();
|
||||
if (values[i].startsWith("-")) {
|
||||
missingArgument(i);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
} else {
|
||||
List values = new ArrayList();
|
||||
while (iterator.hasNext()) {
|
||||
String value = (String) iterator.next();
|
||||
if (value.startsWith("-")) {
|
||||
iterator.previous();
|
||||
break;
|
||||
}
|
||||
values.add(value);
|
||||
}
|
||||
return (String[]) values.toArray(new String[values.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
private void missingArgument(int i) throws ParseException {
|
||||
if (i == 0) {
|
||||
throw new ParseException("no argument for: " + name);
|
||||
} else {
|
||||
throw new ParseException("missing argument for: " + name
|
||||
+ ". Expected: " + getArgsSpec());
|
||||
}
|
||||
}
|
||||
|
||||
public String getSpec() {
|
||||
return "-" + name + " " + getArgsSpec();
|
||||
}
|
||||
|
||||
private String getArgsSpec() {
|
||||
if (args.length == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
sb.append("<").append(args[i]).append("> ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.ivy.util.cli;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OptionBuilder {
|
||||
private String name;
|
||||
private List/*<String>*/ args = new ArrayList();
|
||||
private String description = "";
|
||||
private boolean required = false;
|
||||
private boolean countArgs = true;
|
||||
private boolean deprecated = false;
|
||||
|
||||
public OptionBuilder(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public OptionBuilder required(boolean required) {
|
||||
this.required = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionBuilder description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionBuilder arg(String argName) {
|
||||
this.args.add(argName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionBuilder countArgs(boolean countArgs) {
|
||||
this.countArgs = countArgs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionBuilder deprecated() {
|
||||
this.deprecated = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Option create() {
|
||||
return new Option(
|
||||
name, (String[]) args.toArray(new String[args.size()]),
|
||||
description, required, countArgs, deprecated);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.ivy.util.cli;
|
||||
|
||||
public class ParseException extends Exception {
|
||||
public ParseException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.ivy;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.ivy.core.cache.DefaultRepositoryCacheManager;
|
||||
import org.apache.ivy.core.module.id.ModuleRevisionId;
|
||||
import org.apache.ivy.util.CacheCleaner;
|
||||
import org.apache.ivy.util.cli.ParseException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class MainTest extends TestCase {
|
||||
|
||||
private File cache;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
cache = new File("build/cache");
|
||||
System.setProperty("ivy.cache.dir", cache.getAbsolutePath());
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
CacheCleaner.deleteDir(cache);
|
||||
}
|
||||
|
||||
public void testHelp() throws Exception {
|
||||
run(new String[] {"-?"});
|
||||
}
|
||||
|
||||
public void testBadOption() throws Exception {
|
||||
try {
|
||||
run(new String[] {"-bad"});
|
||||
fail("running Ivy Main with -bad option should raise an exception");
|
||||
} catch (ParseException ex) {
|
||||
assertEquals("Unrecognized option: -bad", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testMissingParameter() throws Exception {
|
||||
try {
|
||||
run(new String[] {"-ivy"});
|
||||
fail("running Ivy Main with missing argument for -ivy option should raise an exception");
|
||||
} catch (ParseException ex) {
|
||||
assertEquals("no argument for: ivy", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testResolveSimple() throws Exception {
|
||||
run(new String[] {
|
||||
"-settings", "test/repositories/ivysettings.xml",
|
||||
"-ivy", "test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml"
|
||||
});
|
||||
assertTrue(new File("build/cache/org1/mod1.2/ivy-2.0.xml").exists());
|
||||
}
|
||||
|
||||
public void testResolveSimpleWithConfs() throws Exception {
|
||||
run(new String[] {
|
||||
"-settings", "test/repositories/ivysettings.xml",
|
||||
"-ivy", "test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml",
|
||||
"-confs", "default"
|
||||
});
|
||||
assertTrue(new File("build/cache/org1/mod1.2/ivy-2.0.xml").exists());
|
||||
}
|
||||
|
||||
public void testResolveSimpleWithConfs2() throws Exception {
|
||||
run(new String[] {
|
||||
"-settings", "test/repositories/ivysettings.xml",
|
||||
"-confs", "default",
|
||||
"-ivy", "test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml"
|
||||
});
|
||||
assertTrue(new File("build/cache/org1/mod1.2/ivy-2.0.xml").exists());
|
||||
}
|
||||
|
||||
private void run(String[] args) throws Exception {
|
||||
Main.run(Main.getParser(), args);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue