diff --git a/updateMonotone/build.xml b/updateMonotone/build.xml
new file mode 100644
index 0000000..13cba37
--- /dev/null
+++ b/updateMonotone/build.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project updateMonotone.
+
+
+
diff --git a/updateMonotone/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar b/updateMonotone/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar
new file mode 100644
index 0000000..0297ed6
Binary files /dev/null and b/updateMonotone/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar differ
diff --git a/updateMonotone/lib/nblibraries-private.properties b/updateMonotone/lib/nblibraries-private.properties
new file mode 100644
index 0000000..e69de29
diff --git a/updateMonotone/lib/nblibraries.properties b/updateMonotone/lib/nblibraries.properties
new file mode 100644
index 0000000..b191095
--- /dev/null
+++ b/updateMonotone/lib/nblibraries.properties
@@ -0,0 +1,12 @@
+libs.junit.classpath=\
+ ${base}/junit/junit-3.8.2.jar
+libs.junit.javadoc=\
+ ${base}/junit/junit-3.8.2-api.zip
+libs.junit_4.classpath=\
+ ${base}/junit_4/junit-4.5.jar
+libs.junit_4.javadoc=\
+ ${base}/junit_4/junit-4.5-api.zip
+libs.junit_4.src=\
+ ${base}/junit_4/junit-4.5-src.jar
+libs.CopyLibs.classpath=\
+ ${base}/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar
diff --git a/updateMonotone/manifest.mf b/updateMonotone/manifest.mf
new file mode 100644
index 0000000..328e8e5
--- /dev/null
+++ b/updateMonotone/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/updateMonotone/nbproject/build-impl.xml b/updateMonotone/nbproject/build-impl.xml
new file mode 100644
index 0000000..9bab133
--- /dev/null
+++ b/updateMonotone/nbproject/build-impl.xml
@@ -0,0 +1,661 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set src.dir
+ Must set test.src.dir
+ Must set build.dir
+ Must set dist.dir
+ Must set build.classes.dir
+ Must set dist.javadoc.dir
+ Must set build.test.classes.dir
+ Must set build.test.results.dir
+ Must set build.classes.excludes
+ Must set dist.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+
+
+
+
+
+ java -cp "${run.classpath.with.dist.jar}" ${main.class}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+ java -jar "${dist.jar.resolved}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must set fix.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+ Must select one file in the IDE or set test.class
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/updateMonotone/nbproject/genfiles.properties b/updateMonotone/nbproject/genfiles.properties
new file mode 100644
index 0000000..5f89fbc
--- /dev/null
+++ b/updateMonotone/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=5b771ce9
+build.xml.script.CRC32=2e04d301
+build.xml.stylesheet.CRC32=958a1d3e
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=5b771ce9
+nbproject/build-impl.xml.script.CRC32=42081327
+nbproject/build-impl.xml.stylesheet.CRC32=65b8de21
diff --git a/updateMonotone/nbproject/private/private.properties b/updateMonotone/nbproject/private/private.properties
new file mode 100644
index 0000000..7fd79d7
--- /dev/null
+++ b/updateMonotone/nbproject/private/private.properties
@@ -0,0 +1,3 @@
+compile.on.save=true
+jaxws.endorsed.dir=/usr/local/netbeans-6.5.1/java2/modules/ext/jaxws21/api:/usr/local/netbeans-6.5.1/ide10/modules/ext/jaxb/api
+user.properties.file=/home/dream/.netbeans/6.5/build.properties
diff --git a/updateMonotone/nbproject/private/private.xml b/updateMonotone/nbproject/private/private.xml
new file mode 100644
index 0000000..c2b6ac5
--- /dev/null
+++ b/updateMonotone/nbproject/private/private.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ file:/home/dream/code/updateMonotone/src/updatemonotone/Main.java
+ file:/home/dream/code/updateMonotone/src/updatemonotone/Updater.java
+
+
diff --git a/updateMonotone/nbproject/project.properties b/updateMonotone/nbproject/project.properties
new file mode 100644
index 0000000..a672242
--- /dev/null
+++ b/updateMonotone/nbproject/project.properties
@@ -0,0 +1,61 @@
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/updateMonotone.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+excludes=
+includes=**
+jar.compress=false
+javac.classpath=
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.source=1.5
+javac.target=1.5
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}:\
+ ${libs.junit.classpath}:\
+ ${libs.junit_4.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=updatemonotone.Main
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+platform.active=default_platform
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project
+# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
+# or test-sys-prop.name=value to set system properties for unit tests):
+run.jvmargs=
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/updateMonotone/nbproject/project.xml b/updateMonotone/nbproject/project.xml
new file mode 100644
index 0000000..a99a874
--- /dev/null
+++ b/updateMonotone/nbproject/project.xml
@@ -0,0 +1,19 @@
+
+
+ org.netbeans.modules.java.j2seproject
+
+
+ updateMonotone
+ 1.6.5
+
+
+
+
+
+
+
+
+ ./lib/nblibraries.properties
+
+
+
diff --git a/updateMonotone/src/updatemonotone/Main.java b/updateMonotone/src/updatemonotone/Main.java
new file mode 100644
index 0000000..e2b6091
--- /dev/null
+++ b/updateMonotone/src/updatemonotone/Main.java
@@ -0,0 +1,30 @@
+package updatemonotone;
+
+import java.io.File;
+
+public class Main {
+
+ public static void main(String[] args) {
+ String[] modules = {
+ "i2p","www",
+ "scripts","Seedless",
+ "i2p-bote",
+ "plugins.jIRCii",
+ "translator"
+ };
+ final File top = new File(new File(System.getenv("HOME"),"packages"),"mtn");
+ top.mkdirs();
+ Updater monotone = new Updater(top,prefix("i2p",modules),new Range(8996,8999));
+ if(System.getenv("NOSYNC")==null) monotone.sync();
+ monotone.checkout();
+ System.exit(0);
+ }
+
+ private static String[] prefix(String string, String[] modules) {
+ for(int i=0;i {
+ final int bottom;
+ final int top;
+ final int span;
+ final int randthing;
+ int offset;
+
+ public RangeIterator(int bottom, int top) {
+ this.bottom = bottom;
+ this.top = top;
+ this.span = top - bottom;
+ // XXX: This is a horrid hack. Ranges do not work this way what are u doin
+ this.randthing = (int) (Math.random() * span);
+ offset = 0;
+ }
+
+ public boolean hasNext() {
+ return offset {
+ private final int top;
+ private final int bottom;
+ public Range(int bottom, int top) {
+ this.bottom = bottom;
+ this.top = top;
+ }
+
+ public Iterator iterator() {
+ return new RangeIterator(bottom,top);
+ }
+
+}
\ No newline at end of file
diff --git a/updateMonotone/src/updatemonotone/Updater.java b/updateMonotone/src/updatemonotone/Updater.java
new file mode 100644
index 0000000..0030d5d
--- /dev/null
+++ b/updateMonotone/src/updatemonotone/Updater.java
@@ -0,0 +1,202 @@
+package updatemonotone;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+class Updater {
+
+ final String[] modules;
+ final Range range;
+ final File top;
+ final File database;
+ final File keydir;
+ File monotone = null;
+ private static final ExecutorService executor = Executors.newFixedThreadPool(4);
+
+ OutputStream log;
+
+ public Updater(File top, String[] modules, Range range) {
+ this.keydir = new File(new File(System.getenv("HOME"),".monotone"),"keys");
+ for (String path : System.getenv("PATH").split(":")) {
+ final File test = new File(path, "mtn");
+ if (test.exists()) {
+ this.monotone = test;
+ break;
+ }
+ }
+ if (monotone == null) {
+ throw new RuntimeException("Could not find monotone mtn in " + System.getenv("PATH"));
+ }
+ System.out.println("Monotone: " + monotone);
+ this.modules = modules;
+ this.range = range;
+ this.top = top;
+ this.top.mkdirs();
+ File dbdir = new File(top, "db");
+ dbdir.mkdir();
+ try {
+ log = new FileOutputStream(new File(top, "monotone.log"));
+ } catch (FileNotFoundException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ log = System.err;
+ }
+ this.database = new File(dbdir, "monotone.sqlite");
+ if (!this.database.exists()) {
+ waitFor(doit("Initializing a new database",
+ top,
+ "db", "init"));
+ }
+ System.out.println("Database: " + database);
+ System.out.println("Keydir: " + keydir);
+ }
+
+ private String join(char separator, String[] ss) {
+ String sep = Character.toString(separator);
+ String result = null;
+ for (String s : ss) {
+ if (result == null) {
+ result = s;
+ } else {
+ result = result + sep + s;
+ }
+ }
+ return result;
+ }
+
+ public void sync() {
+ // can't sync in parallel it screws up the... yeah
+ for (Integer port : range) {
+ final URL url;
+ try {
+ url = new URL("http", "127.0.0.1", port, "?" + join(';', modules));
+ } catch (MalformedURLException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ continue;
+ }
+ waitFor(doit("Synchronizing with port "+port,
+ top,
+ "-k", "dream-transport@mail.i2p", "sync", url.toExternalForm()));
+ break;
+ }
+ }
+
+ public void checkout() {
+ // can't update in parallel it screws up the database
+ for (String module : modules) {
+ File dir = new File(top, module);
+ if (dir.exists()) {
+ waitFor(doit("Updating "+module,
+ dir,
+ "update"));
+ } else {
+ waitFor(doit("Checking out "+module,
+ top,
+ "co", "--branch=" + module));
+ }
+ }
+ System.out.println("Done checking out.");
+ }
+
+ private Future doit(String what, File cwd, String... args) {
+ return doit(args, cwd, what);
+ }
+
+ private Future doit(String[] args, final File cwd, final String what) {
+ System.out.print(what+"...");
+ System.out.flush();
+
+ final String[] fullargs = new String[args.length + 3];
+ fullargs[0] = monotone.getAbsolutePath();
+ fullargs[1] = "--db=" + database;
+ fullargs[2] = "--keydir=" + keydir;
+ //System.out.println("Doing " + join(' ', args));
+ System.arraycopy(args, 0, fullargs, 3, args.length);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ return executor.submit(new Runnable() {
+
+ public void run() {
+ final ProcessBuilder builder = new ProcessBuilder(fullargs);
+ builder.directory(cwd);
+ builder.redirectErrorStream(true);
+ final Process process;
+ try {
+ process = builder.start();
+ } catch (IOException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ throw new RuntimeException("There was an IO failure dealing with Monotone");
+ }
+ try {
+ process.getOutputStream().close();
+ } catch (IOException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ }
+
+ InputStream stdout = process.getInputStream();
+ byte[] buf = new byte[0x1000];
+ for (;;) {
+ try {
+ int amount = stdout.read(buf);
+ if(amount<=0) break;
+ log.write(buf, 0, amount);
+ log.flush();
+ } catch (IOException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ break;
+ }
+ }
+
+ for (;;) {
+ try {
+ process.waitFor();
+ break;
+ } catch (InterruptedException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ if (process.exitValue() != 0) {
+ System.err.print("Monotone failed for some reason");
+ System.exit(0);
+ }
+ }
+ });
+ }
+
+ private void waitFor(Future f) {
+ waitFor(Arrays.asList(new Future[]{f}));
+ System.out.println("done.");
+ }
+
+ private void waitFor(Iterable fs) {
+ for (Future f : fs) {
+ for (;;) {
+ try {
+ f.get();
+ break;
+ } catch (InterruptedException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ } catch (ExecutionException ex) {
+ Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+ }
+}