();
+ for (String line : FileUtil.readLines(config)) {
+ // nix comments
+ int cidx = line.indexOf("#");
+ if (cidx != -1) {
+ line = line.substring(0, cidx);
+ }
+
+ // trim whitespace and skip blank lines
+ line = line.trim();
+ if (StringUtil.isBlank(line)) {
+ continue;
+ }
+
+ // parse our key/value pair
+ String[] pair = new String[2];
+ int eidx = line.indexOf("=");
+ if (eidx != -1) {
+ pair[0] = line.substring(0, eidx).trim();
+ pair[1] = line.substring(eidx+1).trim();
+ } else {
+ pair[0] = line;
+ pair[1] = "";
+ }
+
+ // if the pair has an os qualifier, we need to process it
+ if (pair[1].startsWith("[")) {
+ int qidx = pair[1].indexOf("]");
+ if (qidx == -1) {
+ log.warning("Bogus platform specifier", "key", pair[0], "value", pair[1]);
+ continue; // omit the pair entirely
+ }
+ // if we're checking qualifiers and the os doesn't match this qualifier, skip it
+ String quals = pair[1].substring(1, qidx);
+ if (osname != null && !checkQualifiers(quals, osname, osarch)) {
+ log.info("Skipping", "quals", quals, "osname", osname, "osarch", osarch,
+ "key", pair[0], "value", pair[1]);
+ continue;
+ }
+ // otherwise filter out the qualifier text
+ pair[1] = pair[1].substring(qidx+1).trim();
+ }
+
+ pairs.add(pair);
+ }
+
+ return pairs;
+ }
+
+ /**
+ * A helper function for {@link #parsePairs(Reader,String,String)}. Qualifiers have the
+ * following form:
+ *
+ * id = os[-arch]
+ * ids = id | id,ids
+ * quals = !id | ids
+ *
+ * Examples: [linux-amd64,linux-x86_64], [windows], [mac os x], [!windows].
+ */
+ protected static boolean checkQualifiers (String quals, String osname, String osarch)
+ {
+ for (String qual : quals.split(",")) {
+ String[] bits = qual.trim().toLowerCase().split("-");
+ String os = bits[0], arch = (bits.length > 1) ? bits[1] : "";
+ if (os.startsWith("!")) {
+ // if we have a negative match, we can immediately return false
+ if (osname.indexOf(os.substring(1)) != -1 && osarch.indexOf(arch) != -1) {
+ return false;
+ }
+ } else {
+ // if we have a positive match, we can immediately return true
+ if (osname.indexOf(os) != -1 && osarch.indexOf(arch) != -1) {
+ return true;
+ }
+ }
+ }
+ // we had no positive matches, so return false
+ return false;
+ }
}
diff --git a/src/main/java/com/threerings/getdown/util/FileUtil.java b/src/main/java/com/threerings/getdown/util/FileUtil.java
index b9bfa96..c5f7131 100644
--- a/src/main/java/com/threerings/getdown/util/FileUtil.java
+++ b/src/main/java/com/threerings/getdown/util/FileUtil.java
@@ -23,10 +23,15 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.threerings.getdown.util;
+import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.Reader;
+
+import java.util.ArrayList;
+import java.util.List;
import com.samskivert.io.StreamUtil;
@@ -92,4 +97,21 @@ public class FileUtil
StreamUtil.close(fout);
}
}
+
+ /**
+ * Reads the contents of the supplied input stream into a list of lines. Closes the reader on
+ * successful or failed completion.
+ */
+ public static List readLines (Reader in)
+ throws IOException
+ {
+ List lines = new ArrayList();
+ try {
+ BufferedReader bin = new BufferedReader(in);
+ for (String line = null; (line = bin.readLine()) != null; lines.add(line)) {}
+ } finally {
+ StreamUtil.close(in);
+ }
+ return lines;
+ }
}
diff --git a/src/test/java/com/threerings/getdown/util/ConfigUtilTest.java b/src/test/java/com/threerings/getdown/util/ConfigUtilTest.java
new file mode 100644
index 0000000..e88496f
--- /dev/null
+++ b/src/test/java/com/threerings/getdown/util/ConfigUtilTest.java
@@ -0,0 +1,170 @@
+//
+// $Id$
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2010 Three Rings Design, Inc.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted
+// provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+// conditions and the following disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.threerings.getdown.util;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+
+import com.samskivert.util.RandomUtil;
+import com.samskivert.util.StringUtil;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+/**
+ * Tests {@link ConfigUtil}.
+ */
+public class ConfigUtilTest
+{
+ public static class Pair {
+ public final String key;
+ public final String value;
+ public Pair (String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+ }
+
+ public static final Pair[] SIMPLE_PAIRS = {
+ new Pair("one", "two"),
+ new Pair("three", "four"),
+ new Pair("five", "six"),
+ new Pair("seven", "eight"),
+ new Pair("nine", "ten"),
+ };
+
+ @Test public void testSimplePairs () throws IOException
+ {
+ List pairs = ConfigUtil.parsePairs(toReader(SIMPLE_PAIRS), true);
+ for (int ii = 0; ii < SIMPLE_PAIRS.length; ii++) {
+ assertEquals(SIMPLE_PAIRS[ii].key, pairs.get(ii)[0]);
+ assertEquals(SIMPLE_PAIRS[ii].value, pairs.get(ii)[1]);
+ }
+ }
+
+ @Test public void testQualifiedPairs () throws IOException
+ {
+ Pair linux = new Pair("one", "[linux] two");
+ Pair mac = new Pair("three", "[mac os x] four");
+ Pair linuxAndMac = new Pair("five", "[linux, mac os x] six");
+ Pair linux64 = new Pair("seven", "[linux-x86_64] eight");
+ Pair linux64s = new Pair("nine", "[linux-x86_64, linux-amd64] ten");
+ Pair mac64 = new Pair("eleven", "[mac os x-x86_64] twelve");
+ Pair win64 = new Pair("thirteen", "[windows-x86_64] fourteen");
+ Pair[] pairs = { linux, mac, linuxAndMac, linux64, linux64s, mac64, win64 };
+
+ List parsed = ConfigUtil.parsePairs(toReader(pairs), "linux", "i386");
+ assertTrue(exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+
+ parsed = ConfigUtil.parsePairs(toReader(pairs), "linux", "x86_64");
+ assertTrue(exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(exists(parsed, linuxAndMac.key));
+ assertTrue(exists(parsed, linux64.key));
+ assertTrue(exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+
+ parsed = ConfigUtil.parsePairs(toReader(pairs), "linux", "amd64");
+ assertTrue(exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+
+ parsed = ConfigUtil.parsePairs(toReader(pairs), "mac os x", "x86_64");
+ assertTrue(!exists(parsed, linux.key));
+ assertTrue(exists(parsed, mac.key));
+ assertTrue(exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+
+ parsed = ConfigUtil.parsePairs(toReader(pairs), "windows", "i386");
+ assertTrue(!exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(!exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+
+ parsed = ConfigUtil.parsePairs(toReader(pairs), "windows", "x86_64");
+ assertTrue(!exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(!exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(exists(parsed, win64.key));
+
+ parsed = ConfigUtil.parsePairs(toReader(pairs), "windows", "amd64");
+ assertTrue(!exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(!exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+ }
+
+ protected static boolean exists (List pairs, String key)
+ {
+ for (String[] pair : pairs) {
+ if (pair[0].equals(key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected static StringReader toReader (Pair[] pairs)
+ {
+ StringBuilder builder = new StringBuilder();
+ for (Pair pair : pairs) {
+ // throw some whitespace in to ensure it's trimmed
+ builder.append(whitespace()).append(pair.key).
+ append(whitespace()).append("=").
+ append(whitespace()).append(pair.value).
+ append(whitespace()).append("\n");
+ }
+ return new StringReader(builder.toString());
+ }
+
+ protected static String whitespace ()
+ {
+ return RandomUtil.getBoolean() ? " " : "";
+ }
+}
diff --git a/src/test/java/com/threerings/getdown/util/FileUtilTest.java b/src/test/java/com/threerings/getdown/util/FileUtilTest.java
new file mode 100644
index 0000000..9c1f40c
--- /dev/null
+++ b/src/test/java/com/threerings/getdown/util/FileUtilTest.java
@@ -0,0 +1,49 @@
+//
+// $Id$
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2010 Three Rings Design, Inc.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted
+// provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+// conditions and the following disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.threerings.getdown.util;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+/**
+ * Tests {@link FileUtil}.
+ */
+public class FileUtilTest
+{
+ @Test public void testReadLines () throws IOException
+ {
+ String data = "This is a test\nof a file with\na few lines\n";
+ List lines = FileUtil.readLines(new StringReader(data));
+ String[] linesBySplit = data.split("\n");
+ assertEquals(linesBySplit.length, lines.size());
+ for (int ii = 0; ii < lines.size(); ii++) {
+ assertEquals(linesBySplit[ii], lines.get(ii));
+ }
+ }
+}