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:
Xavier Hanin 2008-02-29 16:40:52 +00:00
parent 2d61ecf18a
commit f97ecea7e1
12 changed files with 616 additions and 136 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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" />

View File

@ -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() {

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}