You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by xa...@apache.org on 2008/02/29 17:40:57 UTC

svn commit: r632381 - in /ant/ivy/core/trunk: ./ META-INF/ doc/ src/java/org/apache/ivy/ src/java/org/apache/ivy/util/ src/java/org/apache/ivy/util/cli/ test/java/org/apache/ivy/

Author: xavier
Date: Fri Feb 29 08:40:52 2008
New Revision: 632381

URL: http://svn.apache.org/viewvc?rev=632381&view=rev
Log:
IMPROVEMENT: Make Ivy standalone runnable with no required dependencies (IVY-757)

Added:
    ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/
    ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLine.java   (with props)
    ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLineParser.java   (with props)
    ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/Option.java   (with props)
    ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/OptionBuilder.java   (with props)
    ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/ParseException.java   (with props)
    ant/ivy/core/trunk/test/java/org/apache/ivy/MainTest.java   (with props)
Modified:
    ant/ivy/core/trunk/CHANGES.txt
    ant/ivy/core/trunk/META-INF/MANIFEST.MF
    ant/ivy/core/trunk/doc/standalone.html
    ant/ivy/core/trunk/ivy.xml
    ant/ivy/core/trunk/src/java/org/apache/ivy/Main.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/util/StringUtils.java

Modified: ant/ivy/core/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/CHANGES.txt?rev=632381&r1=632380&r2=632381&view=diff
==============================================================================
--- ant/ivy/core/trunk/CHANGES.txt (original)
+++ ant/ivy/core/trunk/CHANGES.txt Fri Feb 29 08:40:52 2008
@@ -64,6 +64,8 @@
 
    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)

Modified: ant/ivy/core/trunk/META-INF/MANIFEST.MF
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/META-INF/MANIFEST.MF?rev=632381&r1=632380&r2=632381&view=diff
==============================================================================
--- ant/ivy/core/trunk/META-INF/MANIFEST.MF (original)
+++ ant/ivy/core/trunk/META-INF/MANIFEST.MF Fri Feb 29 08:40:52 2008
@@ -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 @@
  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,

Modified: ant/ivy/core/trunk/doc/standalone.html
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/doc/standalone.html?rev=632381&r1=632380&r2=632381&view=diff
==============================================================================
--- ant/ivy/core/trunk/doc/standalone.html (original)
+++ ant/ivy/core/trunk/doc/standalone.html Fri Feb 29 08:40:52 2008
@@ -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 @@
 
 <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 @@
 <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
 

Modified: ant/ivy/core/trunk/ivy.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/ivy.xml?rev=632381&r1=632380&r2=632381&view=diff
==============================================================================
--- ant/ivy/core/trunk/ivy.xml (original)
+++ ant/ivy/core/trunk/ivy.xml Fri Feb 29 08:40:52 2008
@@ -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" />

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/Main.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/Main.java?rev=632381&r1=632380&r2=632381&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/Main.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/Main.java Fri Feb 29 08:40:52 2008
@@ -35,14 +35,6 @@
 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.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 @@
  * 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");
-
-        Options options = new Options();
-
-        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);
-
-        return options;
+                    + "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())
+
+            .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())
+
+            .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())
+
+            .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 @@
 
             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 @@
             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 @@
             } 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 @@
                 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 @@
                 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 @@
         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 @@
         } 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 @@
         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() {

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/util/StringUtils.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/util/StringUtils.java?rev=632381&r1=632380&r2=632381&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/util/StringUtils.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/util/StringUtils.java Fri Feb 29 08:40:52 2008
@@ -176,4 +176,12 @@
                 + "'. 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();
+    }
+
 }

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLine.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLine.java?rev=632381&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLine.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLine.java Fri Feb 29 08:40:52 2008
@@ -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;
+    }
+
+}

Propchange: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLine.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLineParser.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLineParser.java?rev=632381&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLineParser.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLineParser.java Fri Feb 29 08:40:52 2008
@@ -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();
+        }
+    }
+}

Propchange: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/CommandLineParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/Option.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/Option.java?rev=632381&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/Option.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/Option.java Fri Feb 29 08:40:52 2008
@@ -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();
+    }
+}

Propchange: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/Option.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/OptionBuilder.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/OptionBuilder.java?rev=632381&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/OptionBuilder.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/OptionBuilder.java Fri Feb 29 08:40:52 2008
@@ -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);
+    }
+}

Propchange: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/OptionBuilder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/ParseException.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/ParseException.java?rev=632381&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/ParseException.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/ParseException.java Fri Feb 29 08:40:52 2008
@@ -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);
+    }
+}

Propchange: ant/ivy/core/trunk/src/java/org/apache/ivy/util/cli/ParseException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ant/ivy/core/trunk/test/java/org/apache/ivy/MainTest.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/MainTest.java?rev=632381&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/MainTest.java (added)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/MainTest.java Fri Feb 29 08:40:52 2008
@@ -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);
+    }
+}

Propchange: ant/ivy/core/trunk/test/java/org/apache/ivy/MainTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain