diff --git a/.gitignore b/.gitignore index a08a502..39efdc2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,11 @@ # IDE settings -**/.classpath -**/.project -**/.settings -**/*.jardesc -**/.settings/** +/*/.classpath +/*/.project +/*/.settings +/*/*.jardesc +/*/.settings/ # Manually added artifacts -/liverepl-server/lib/clojure.jar /jars/ # Build artifacts diff --git a/README.TXT b/README.TXT deleted file mode 100644 index 9b46380..0000000 --- a/README.TXT +++ /dev/null @@ -1,68 +0,0 @@ -LiveRepl -======== - -Start a Clojure REPL connected to any running Java or Clojure process -without needing the process to be setup in any special way beforehand. - -Now supports connecting to Tomcat web applications. - -You can use the repl to run code, inspect variables, and -redefine Clojure functions. - - -Clojure Live REPL - 2009-10-18 -David Powell - - -This software is distributed under the MIT licence. - ----------------------------------------- - -Build -===== - -To build: - - Copy clojure.jar to: ./liverepl-server/lib/clojure.jar - - Run ant - -The build will be copied to: ./build/ - ----------------------------------------- - -Configuration -============= - -Edit liverepl.bat to point to your installed JDK - -Place any extra jars you would like loaded into the JVM into ./jars/ -(creating it if necessary.) - ----------------------------------------- - -Operation -========= - -To see a list of running Java processes on the system, and their -process ids, enter: - - liverepl - -To see the available ClassLoaders for a specific process, enter: - - liverepl - - -- where the pid is the process id for the process, obtained in - the step above. - -To connect a repl to the process, enter: - - liverepl - - -- where the pid is the process id for the process. - -- and the classloader-id was obtained in the step above. - - if you aren't sure which ClassLoader to use, try '0', which - will always be the System ClassLoader. - diff --git a/README.md b/README.md new file mode 100644 index 0000000..eafc44f --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +LiveRepl +======== + +Start a Clojure REPL connected to any running Java or Clojure process +without needing the process to be setup in any special way beforehand. + +Now supports connecting to Tomcat web applications. + +You can use the repl to run code, inspect variables, and +redefine Clojure functions. + +Build +----- + +To build: + +``` +(cd client; lein uberjar) && (cd agent; lein jar) && (cd server; lein uberjar) +``` + +This produces jar files in the following locations: + +``` +client/target/liverepl-client-standalone.jar +agent/target/liverepl-agent.jar +server/target/liverepl-server-standalone.jar +``` + +Operation +--------- + +Call liverepl.sh as follows: + +``` +export JDK_HOME=/usr/lib/jvm/java-7-oracle +./liverepl.sh +``` + +To see a list of running Java processes on the system, and their +process ids, enter: + + liverepl.sh + +To see the available ClassLoaders for a specific process, enter: + + liverepl.sh + + -- where the pid is the process id for the process, obtained in + the step above. + +To connect a repl to the process, enter: + + liverepl.sh + + -- where the pid is the process id for the process. + -- and the classloader-id was obtained in the step above. + +If you aren't sure which ClassLoader to use, try '0', which will +always be the System ClassLoader. + +If the directory `./jars/` is present in the same location as +liverepl.sh, any jars inside will be loaded and made available inside +the target JVM. They must be at the top level inside the directory and +have a name ending in `.jar`. + +License and credits +------------------- + +This software is distributed under the MIT licence. + +http://github.com/djpowell/liverepl + +Original author: David Powell 2009-10-18 + +Other contributions by: + +- Kurt Harriger +- Kevin A. Archie +- Brightcove, Inc. (authors Chris Jeris, Tim McCormack) diff --git a/agent/project.clj b/agent/project.clj new file mode 100644 index 0000000..7851b0d --- /dev/null +++ b/agent/project.clj @@ -0,0 +1,13 @@ +(defproject com.brightcove.liverepl/agent "0.1.1-SNAPSHOT" + :description "LiveREPL agent" + :license {:name "MIT License" + :distribution :repo + :comments "Copyright (C) 2009 David J. Powell and others. See README for contributors."} + :url "https://github.com/djpowell/liverepl" + :min-lein-version "2.0.0" + :dependencies [] + :source-paths [] + :java-source-paths ["src"] + :manifest {"Agent-Class" "net.djpowell.liverepl.agent.Agent"} + :lein-release {:scm :git, :deploy-via :lein-install} + :jar-name "liverepl-agent.jar") diff --git a/liverepl-agent/src/net/djpowell/liverepl/agent/Agent.java b/agent/src/net/djpowell/liverepl/agent/Agent.java similarity index 88% rename from liverepl-agent/src/net/djpowell/liverepl/agent/Agent.java rename to agent/src/net/djpowell/liverepl/agent/Agent.java index 1e79965..c6f4080 100644 --- a/liverepl-agent/src/net/djpowell/liverepl/agent/Agent.java +++ b/agent/src/net/djpowell/liverepl/agent/Agent.java @@ -11,12 +11,21 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; -import net.djpowell.liverepl.client.Main; import net.djpowell.liverepl.discovery.ClassLoaderInfo; import net.djpowell.liverepl.discovery.Discovery; public class Agent { + // bind to localhost to keep things more secure + public static final InetAddress LOCALHOST; + static { + try { + LOCALHOST = InetAddress.getByAddress(new byte[] {127, 0, 0, 1}); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + private static final Discovery discovery = new Discovery(); public static interface ConnectNotifyingTask { @@ -46,7 +55,7 @@ public void run() { } public static void runAfterConnect(int port, int connectTimeout, String threadName, final ConnectNotifyingTask task) throws Exception { - final ServerSocket serverSocket = new ServerSocket(port, 0, Main.LOCALHOST); + final ServerSocket serverSocket = new ServerSocket(port, 0, LOCALHOST); final AtomicBoolean connected = new AtomicBoolean(false); Thread taskThread = new Thread(new Runnable() { public void run() { @@ -107,10 +116,10 @@ private static void popClassLoader(ClassLoader old) { Thread.currentThread().setContextClassLoader(old); } - private static boolean isClojureLoaded() { + private static boolean isServerLoaded() { try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); - cl.loadClass("clojure.lang.RT"); + cl.loadClass("net.djpowell.liverepl.server.Repl"); return true; } catch (ClassNotFoundException e) { return false; @@ -121,13 +130,12 @@ public static void agentmain(String agentArgs, Instrumentation inst) { TRC.fine("Started Attach agent"); StringTokenizer stok = new StringTokenizer(agentArgs, "\n"); - if (stok.countTokens() != 5) { + if (stok.countTokens() != 4) { throw new RuntimeException("Invalid parameters: " + agentArgs); } int port = Integer.parseInt(stok.nextToken()); TRC.fine("Port: " + port); - String clojurePath = stok.nextToken(); String serverPath = stok.nextToken(); String jarsPath = stok.nextToken(); String classLoaderId = stok.nextToken(); @@ -137,14 +145,14 @@ public static void agentmain(String agentArgs, Instrumentation inst) { return; } - boolean clojureLoaded = isClojureLoaded(); - TRC.fine("Clojure is " + (clojureLoaded ? "" : "not ") + "loaded"); + boolean serverLoaded = isServerLoaded(); + TRC.fine("Server is " + (serverLoaded ? "" : "not ") + "loaded"); List urls; - if (clojureLoaded) { - urls = getJarUrls(serverPath); + if (serverLoaded) { + urls = new ArrayList(); } else { - urls = getJarUrls(clojurePath, serverPath); + urls = getJarUrls(serverPath); } File jarsDir = new File(jarsPath); if (jarsDir.exists()) { @@ -162,8 +170,8 @@ public boolean accept(File dir, String path) { ClassLoader old = pushClassLoader(urls, classLoaderId); try { - if (!clojureLoaded) { // if clojure wasn't loaded before, print current status - TRC.fine("Clojure is " + (isClojureLoaded() ? "" : "not ") + "loaded"); + if (!serverLoaded) { // if server wasn't loaded before, print current status + TRC.fine("Server is " + (isServerLoaded() ? "" : "not ") + "loaded"); } startRepl(port, inst); } finally { @@ -195,7 +203,7 @@ private static void startRepl(int port, Instrumentation inst) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Class repl = Class.forName("net.djpowell.liverepl.server.Repl", true, cl); Method method = repl.getMethod("main", InetAddress.class, Integer.TYPE, Instrumentation.class); - method.invoke(null, Main.LOCALHOST, port, inst); + method.invoke(null, LOCALHOST, port, inst); } catch (RuntimeException e) { throw e; } catch (Exception e) { diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/ClassLoaderDiscovery.java b/agent/src/net/djpowell/liverepl/discovery/ClassLoaderDiscovery.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/ClassLoaderDiscovery.java rename to agent/src/net/djpowell/liverepl/discovery/ClassLoaderDiscovery.java diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/ClassLoaderInfo.java b/agent/src/net/djpowell/liverepl/discovery/ClassLoaderInfo.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/ClassLoaderInfo.java rename to agent/src/net/djpowell/liverepl/discovery/ClassLoaderInfo.java diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/ClassLoaderRegistry.java b/agent/src/net/djpowell/liverepl/discovery/ClassLoaderRegistry.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/ClassLoaderRegistry.java rename to agent/src/net/djpowell/liverepl/discovery/ClassLoaderRegistry.java diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/Discovery.java b/agent/src/net/djpowell/liverepl/discovery/Discovery.java similarity index 93% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/Discovery.java rename to agent/src/net/djpowell/liverepl/discovery/Discovery.java index 20ad2f1..8ec0f68 100644 --- a/liverepl-agent/src/net/djpowell/liverepl/discovery/Discovery.java +++ b/agent/src/net/djpowell/liverepl/discovery/Discovery.java @@ -24,7 +24,7 @@ public Discovery() { } public Collection listClassLoaders() { - List ret = new ArrayList(); + List ret = new ArrayList(); for (ClassLoaderDiscovery discovery : impls) { ret.addAll(discovery.listClassLoaders()); } diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/Function.java b/agent/src/net/djpowell/liverepl/discovery/Function.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/Function.java rename to agent/src/net/djpowell/liverepl/discovery/Function.java diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/impl/JMXDiscovery.java b/agent/src/net/djpowell/liverepl/discovery/impl/JMXDiscovery.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/impl/JMXDiscovery.java rename to agent/src/net/djpowell/liverepl/discovery/impl/JMXDiscovery.java diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/impl/SystemDiscovery.java b/agent/src/net/djpowell/liverepl/discovery/impl/SystemDiscovery.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/impl/SystemDiscovery.java rename to agent/src/net/djpowell/liverepl/discovery/impl/SystemDiscovery.java diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/impl/ThreadDiscovery.java b/agent/src/net/djpowell/liverepl/discovery/impl/ThreadDiscovery.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/impl/ThreadDiscovery.java rename to agent/src/net/djpowell/liverepl/discovery/impl/ThreadDiscovery.java diff --git a/liverepl-agent/src/net/djpowell/liverepl/discovery/impl/TomcatDiscovery.java b/agent/src/net/djpowell/liverepl/discovery/impl/TomcatDiscovery.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/discovery/impl/TomcatDiscovery.java rename to agent/src/net/djpowell/liverepl/discovery/impl/TomcatDiscovery.java diff --git a/client/project.clj b/client/project.clj new file mode 100644 index 0000000..83b407e --- /dev/null +++ b/client/project.clj @@ -0,0 +1,16 @@ +(defproject com.brightcove.liverepl/client "0.1.1-SNAPSHOT" + :description "LiveREPL client" + :license {:name "MIT License" + :distribution :repo + :comments "Copyright (C) 2009 David J. Powell and others. See README for contributors."} + :url "https://github.com/djpowell/liverepl" + :min-lein-version "2.0.0" + :dependencies [] + :source-paths [] + :java-source-paths ["src"] + :plugins [[lein-jdk-tools "0.1.1"]] + ;; Mention :skip-aot to suppress warning + :main ^:skip-aot net.djpowell.liverepl.client.Main + :lein-release {:scm :git, :deploy-via :lein-install} + :uberjar-exclusions [#"^.*\.jar$"] + :uberjar-name "liverepl-client-standalone.jar") diff --git a/liverepl-agent/src/net/djpowell/liverepl/client/Console.java b/client/src/net/djpowell/liverepl/client/Console.java similarity index 100% rename from liverepl-agent/src/net/djpowell/liverepl/client/Console.java rename to client/src/net/djpowell/liverepl/client/Console.java diff --git a/liverepl-agent/src/net/djpowell/liverepl/client/Main.java b/client/src/net/djpowell/liverepl/client/Main.java similarity index 86% rename from liverepl-agent/src/net/djpowell/liverepl/client/Main.java rename to client/src/net/djpowell/liverepl/client/Main.java index 8221ecc..312d3f3 100644 --- a/liverepl-agent/src/net/djpowell/liverepl/client/Main.java +++ b/client/src/net/djpowell/liverepl/client/Main.java @@ -48,23 +48,22 @@ private static void listPids() { } public static void main(String[] args) throws Exception { - // Usage: - if (args.length < 5) { + // Usage: + if (args.length < 4) { listPids(); System.exit(0); } - String clojurepath = args[0]; - String agentpath = args[1]; - String serverpath = args[2]; - String jarsdir = args[3]; - String pid = args[4]; + String agentpath = args[0]; + String serverpath = args[1]; + String jarsdir = args[2]; + String pid = args[3]; String classLoaderId; - if (args.length < 6) { + if (args.length < 5) { classLoaderId = "L"; System.out.println(); System.out.println("List of ClassLoaders for process #" + pid); } else { - classLoaderId = args[5]; + classLoaderId = args[4]; } TRC.fine("Attaching to pid: " + pid); @@ -72,7 +71,7 @@ public static void main(String[] args) throws Exception { int port = getFreePort(LOCALHOST); // start the agent, which will create the server socket, then return - String agentArgs = String.valueOf(port) + "\n" + clojurepath + "\n" + serverpath + "\n" + jarsdir + "\n" + classLoaderId; + String agentArgs = String.valueOf(port) + "\n" + serverpath + "\n" + jarsdir + "\n" + classLoaderId; vm.loadAgent(agentpath, agentArgs); boolean listClassLoaders = "L".equals(classLoaderId); diff --git a/liverepl-agent/project.clj b/liverepl-agent/project.clj deleted file mode 100644 index cc7f49d..0000000 --- a/liverepl-agent/project.clj +++ /dev/null @@ -1,11 +0,0 @@ -(defproject com.brightcove.liverepl/liverepl-agent "0.1.1-SNAPSHOT" - :description "Brightcove local version of liverepl-agent" - :license {:name "Copyright (C) 2009 David J. Powell. See GitHub for license."} - :url "https://github.com/djpowell/liverepl" - :dependencies [] - :java-source-paths ["src"] - :resource-paths ["/usr/java/default/lib/tools.jar"] - :lein-release {:scm :git ;; I guess you have to say it explicitly - :deploy-via :lein-install} ;; don't attempt to do real deploy, we can't - :manifest {"Agent-Class" "net.djpowell.liverepl.agent.Agent"} - :main net.djpowell.liverepl.client.Main) diff --git a/liverepl-server/project.clj b/liverepl-server/project.clj deleted file mode 100644 index 5000442..0000000 --- a/liverepl-server/project.clj +++ /dev/null @@ -1,10 +0,0 @@ -(defproject com.brightcove.liverepl/liverepl-server "0.1.1-SNAPSHOT" - :description "Brightcove local version of liverepl-server" - :license {:name "Copyright (C) 2009 David J. Powell. See GitHub for license."} - :url "https://github.com/djpowell/liverepl" - :dependencies [[org.clojure/clojure "1.4.0"]] - :source-paths ["src/clojure"] - :java-source-paths ["src/java"] - :lein-release {:scm :git ;; I guess you have to say it explicitly - :deploy-via :lein-install}) ;; don't attempt to do real deploy, we can't - diff --git a/liverepl.sh b/liverepl.sh index c661c1e..176c89a 100755 --- a/liverepl.sh +++ b/liverepl.sh @@ -1,14 +1,13 @@ -#!/bin/sh +#!/bin/bash # Starter script for Clojure liverepl -# NB. This doesn't work with the Leiningen-ized version yet. [ -z "$JDK_HOME" ] && JDK_HOME=/usr/lib/jvm/default-java LIVEREPL_HOME="$(cd -P -- "$(dirname -- "$0")" && pwd -P)" MAIN=net.djpowell.liverepl.client.Main -CLOJURE_JAR=$(find $LIVEREPL_HOME/build -name 'clojure-*[0-9].jar' | head -1) -AGENT_JAR="$LIVEREPL_HOME/build/liverepl-agent.jar" -SERVER_JAR="$LIVEREPL_HOME/build/liverepl-server.jar" +CLIENT_JAR="$LIVEREPL_HOME/client/target/liverepl-client-standalone.jar" +AGENT_JAR="$LIVEREPL_HOME/agent/target/liverepl-agent.jar" +SERVER_JAR="$LIVEREPL_HOME/server/target/liverepl-server-standalone.jar" EXTRA_JARS="$LIVEREPL_HOME/jars/" if [ "Darwin" = "`uname -s`" ]; then @@ -29,9 +28,9 @@ if [ "$TERM" != "dumb" ]; then fi fi -CLASSPATH="$CLASSPATH:$AGENT_JAR" +CLASSPATH="$CLASSPATH:$CLIENT_JAR:$AGENT_JAR" -${WRAP}java -cp $CLASSPATH $MAIN "$CLOJURE_JAR" "$AGENT_JAR" "$SERVER_JAR" "$EXTRA_JARS" "$@" +${WRAP}java -cp $CLASSPATH $MAIN "$AGENT_JAR" "$SERVER_JAR" "$EXTRA_JARS" "$@" diff --git a/server/project.clj b/server/project.clj new file mode 100644 index 0000000..20c1733 --- /dev/null +++ b/server/project.clj @@ -0,0 +1,12 @@ +(defproject com.brightcove.liverepl/server "0.1.1-SNAPSHOT" + :description "LiveREPL repl server" + :license {:name "MIT License" + :distribution :repo + :comments "Copyright (C) 2009 David J. Powell and others. See README for contributors."} + :url "https://github.com/djpowell/liverepl" + :min-lein-version "2.0.0" + :dependencies [[org.clojure/clojure "1.6.0"]] + :source-paths ["src/clojure"] + :java-source-paths ["src/java"] + :lein-release {:scm :git, :deploy-via :lein-install} + :uberjar-name "liverepl-server-standalone.jar") diff --git a/liverepl-server/src/clojure/net/djpowell/liverepl/server/repl.clj b/server/src/clojure/net/djpowell/liverepl/server/repl.clj similarity index 100% rename from liverepl-server/src/clojure/net/djpowell/liverepl/server/repl.clj rename to server/src/clojure/net/djpowell/liverepl/server/repl.clj diff --git a/liverepl-server/src/java/net/djpowell/liverepl/server/Repl.java b/server/src/java/net/djpowell/liverepl/server/Repl.java similarity index 100% rename from liverepl-server/src/java/net/djpowell/liverepl/server/Repl.java rename to server/src/java/net/djpowell/liverepl/server/Repl.java