Skip to content

Loading…

#55 Parse String[] args commandline parameter #64

Closed
wants to merge 1 commit into from

2 participants

@muuki88

This is a first implementation. It reuses the parseProperties implementation. The following things are possible

Single boolean parameters

val conf = ConfigFactory.parseArray(Array("-debug"))
conf.getBoolean("debug") // true: boolean

Multiple parameters

val conf = ConfigFactory.parseArray(Array("-foo", "bar", "-debug"))
conf.getString("foo") // bar: String
conf.getBoolean("debug") // true: boolean
@havocp
Typesafe Inc. member

I'm a little worried that too few people would use this API. I asked on twitter for people to tell me if they would.

I think parseArray might be expected to work more like parseMap; a clearer name might be something like parseCommandLineOptions or parseArgs perhaps.

I wonder if it's an issue that this would make a program accept any option ... there's no checking for typos or invalid options.

I do see how it could be useful though, to unify command line options with your overall config and have the command line options be just another way to config.

I haven't reviewed the code yet, I think the first question is just whether we should have this feature, could use feedback from more people.

@havocp
Typesafe Inc. member

Thanks for your pull request, by the way!

@muuki88

a clearer name might be something like parseCommandLineOptions or parseArgs perhaps

Yeah, the name is probably not the best.

I wonder if it's an issue that this would make a program accept any option ... there's no checking for typos or > invalid options.

I must say that I never used the checkValid method, but I thought this would be the way to check the command line args?

I think the first question is just whether we should have this feature, could use feedback from more people

Any suggestions where to post this?

@havocp
Typesafe Inc. member

checkValid() will detect some problems (like wrong-typed values or missing settings) but it allows "unknown" settings.

I posted on twitter asking for feedback. A few people there and via private email said they used various option-parsing libraries and would want to integrate with those. I guess option-parsing libs handle things like "--" and "-?/--help" and so forth. See http://stackoverflow.com/questions/367706/is-there-a-good-command-line-argument-parser-for-java (there are also several for Scala I guess).

Some people did say they liked the idea of converting command line options into config settings.

I'm a little worried about ending up maintaining something as complex as http://svn.apache.org/viewvc/commons/proper/cli/trunk/src/main/java/org/apache/commons/cli/ and not sure where to "draw the line" on that.

Basically, I'd expect to start getting reports and requests for all the features that full command line parser libraries have. But if we wanted this to be that complete, it really should be its own separate library.

So that's kind of my inclination, is that this is a useful thing but it might need to be in its own jar and either be more complete or be based on one of the popular option parser libs.

@muuki88

Point taken. I think it would be a really cool enhancement. However it's not useful for everybody.

I will try to integrate a third-party cmd parser in a separate project. As you mentioned, implementing a new one is nonsene, as there are plenty out there (and good ones, I think).

@muuki88 muuki88 closed this
@havocp
Typesafe Inc. member

Thanks for understanding - if you need any features in the config lib to support what you're doing, let me know.

@muuki88

I started a small project to close the gap between commandline arguments and config. https://github.com/muuki88/config4cli

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 20, 2013
  1. @muuki88

    First implementation

    muuki88 committed
This page is out of date. Refresh to see the latest.
View
9 config/src/main/java/com/typesafe/config/ConfigFactory.java
@@ -522,6 +522,15 @@ public static Config parseProperties(Properties properties,
public static Config parseProperties(Properties properties) {
return parseProperties(properties, ConfigParseOptions.defaults());
}
+
+ public static Config parseArray(String[] args,
+ ConfigParseOptions options) {
+ return Parseable.newArray(args, options).parse().toConfig();
+ }
+
+ public static Config parseArray(String[] args) {
+ return parseArray(args,ConfigParseOptions.defaults());
+ }
public static Config parseReader(Reader reader, ConfigParseOptions options) {
return Parseable.newReader(reader, options).parse().toConfig();
View
64 config/src/main/java/com/typesafe/config/impl/ArrayParser.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2011 Typesafe Inc. <http://typesafe.com>
+ */
+package com.typesafe.config.impl;
+
+import java.util.Properties;
+
+import com.typesafe.config.ConfigException;
+import com.typesafe.config.ConfigOrigin;
+
+final class ArrayParser {
+
+ static AbstractConfigObject fromArray(ConfigOrigin origin, String[] args) {
+ Properties props = new Properties();
+ int i = 0;
+ while (i < args.length) {
+ String key = args[i];
+
+ // Check parameter correctness
+ if (isParameter(key)) {
+ key = key.substring(1, key.length());
+ } else {
+ throw new ConfigException.Parse(origin, "Parameter " + key + " must start with '-'");
+ }
+
+ // Check if last parameter is a boolean parameter
+ if ((i + 1) == args.length) {
+ props.setProperty(key, Boolean.TRUE.toString());
+ break;
+ }
+
+ String value = args[i + 1];
+ // Check if boolean parameter
+ if (isParameter(value)) {
+ value = Boolean.TRUE.toString();
+ i -= 1;
+ }
+
+ props.setProperty(key, value);
+ // next parameter pair
+ i += 2;
+ }
+
+ // check if last parameter was skipped
+ if ((i - 1) == args.length) {
+ String key = args[i - 2];
+
+ // Check parameter correctness
+ if (isParameter(key)) {
+ key = key.substring(1, key.length());
+ } else {
+ throw new ConfigException.Parse(origin, "Parameter " + key + " must start with '-'");
+ }
+ props.setProperty(key, Boolean.TRUE.toString());
+ }
+
+ return PropertiesParser.fromProperties(origin, props);
+ }
+
+ static boolean isParameter(String key) {
+ return key.startsWith("-");
+ }
+
+}
View
43 config/src/main/java/com/typesafe/config/impl/Parseable.java
@@ -18,6 +18,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
@@ -674,4 +675,46 @@ public String toString() {
public static Parseable newProperties(Properties properties, ConfigParseOptions options) {
return new ParseableProperties(properties, options);
}
+
+ private final static class ParseableArray extends Parseable {
+
+ final private String[] args;
+
+ public ParseableArray(String[] args, ConfigParseOptions options) {
+ this.args = args;
+ postConstruct(options);
+ }
+
+ @Override
+ protected Reader reader() throws IOException {
+ throw new ConfigException.BugOrBroken("reader() should not be called on array (String[] args)");
+ }
+
+ @Override
+ protected AbstractConfigObject rawParseValue(ConfigOrigin origin, ConfigParseOptions finalOptions) {
+ if (ConfigImpl.traceLoadsEnabled()) {
+ trace("Loading config from properties " + Arrays.toString(args));
+ }
+ return ArrayParser.fromArray(origin, args);
+ }
+
+ @Override
+ ConfigSyntax guessSyntax() {
+ return ConfigSyntax.PROPERTIES;
+ }
+
+ @Override
+ protected ConfigOrigin createOrigin() {
+ return SimpleConfigOrigin.newSimple("array");
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "(" + args.length + " array items)";
+ }
+ }
+
+ public static Parseable newArray(String[] args, ConfigParseOptions options) {
+ return new ParseableArray(args, options);
+ }
}
View
44 config/src/test/scala/com/typesafe/config/impl/ArrayTest.scala
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2011 Typesafe Inc. <http://typesafe.com>
+ */
+package com.typesafe.config.impl
+
+import org.junit.Assert._
+import org.junit._
+import java.util.Properties
+import com.typesafe.config.Config
+import com.typesafe.config.ConfigParseOptions
+import com.typesafe.config.ConfigFactory
+
+class ArrayTest extends TestUtils {
+
+ @Test
+ def booleanOption() {
+ val conf1 = ConfigFactory.parseArray(Array("-debug"))
+ assertEquals(conf1.getBoolean("debug"), true)
+
+ val conf2 = ConfigFactory.parseArray(Array("-debug", "-foo"))
+ assertEquals(conf2.getBoolean("debug"), true)
+ assertEquals(conf2.getBoolean("foo"), true)
+
+ val conf3 = ConfigFactory.parseArray(Array("-debug", "-bar", "false", "-foo"))
+ assertEquals(conf3.getBoolean("debug"), true)
+ assertEquals(conf3.getBoolean("foo"), true)
+ assertEquals(conf3.getBoolean("bar"), false)
+ }
+
+ @Test
+ def mixedArguments() {
+ val conf = ConfigFactory.parseArray(Array("-foo", "bar", "-debug", "-min", "0.123"))
+ assertEquals(conf.getString("foo"), "bar")
+ assertEquals(conf.getBoolean("debug"), true)
+ assertEquals(conf.getDouble("min"), 0.123, 0.0)
+ }
+
+ @Test
+ def mixedArgumentsWithPath() {
+ val conf = ConfigFactory.parseArray(Array("-foo.bar", "1.0", "-dev.debug"))
+ assertEquals(conf.getConfig("foo").getDouble("bar"), 1.0, 0.0)
+ assertEquals(conf.getBoolean("dev.debug"), true)
+ }
+}
Something went wrong with that request. Please try again.