Skip to content

Instantly share code, notes, and snippets.

@rlm
Created January 12, 2011 03:03
Show Gist options
  • Save rlm/775623 to your computer and use it in GitHub Desktop.
Save rlm/775623 to your computer and use it in GitHub Desktop.
export_files.clj
(ns rlm.classpath-utils
(:require [clojure.contrib [duck-streams :as ds]])
(:use [clojure.contrib java-utils]))
(defn classpath []
(get-system-property "java.class.path"))
(defn add-to-classpath [file-name]
(wall-hack-method java.net.URLClassLoader
'addURL [java.net.URL]
(ClassLoader/getSystemClassLoader)
(.toURL (ds/file-str file-name))))
(ns coderloop.export-files
(:use clojure.java.io)
(:use [clojure.contrib [duck-streams :only [file-str]]])
(:use [rlm
[classpath-utils :only [classpath]]
[shell-write :only [sw]]])
(:require clojure.string)
(:import java.io.File)
)
(import '[org.apache.commons.io FileUtils])
(defmulti source-location class)
(defmethod source-location clojure.lang.Var [sym]
(let [source? (:file (meta sym))]
(if source?
(.getResource (clojure.lang.RT/baseLoader) source?)
nil)))
(defmethod source-location java.lang.Class [sym]
(let [source? (.getCodeSource (.getProtectionDomain sym))]
(if source?
(.getLocation source?)
nil)))
(defn all-dependent-namespaces [namespace]
(set
(concat
[namespace]
(vals (ns-aliases namespace))
(map #(.ns %)
(filter #(= (class %) clojure.lang.Var)
(concat
(vals (ns-map namespace))
(vals (ns-refers namespace))
))))))
(defn deep-dependent-namespaces [namespace-set]
(let [new-namespaces (set (mapcat all-dependent-namespaces namespace-set))]
;;(println (count new-namespaces))
(if (= new-namespaces namespace-set)
namespace-set
(recur new-namespaces))))
(defn dependencies-url
"returns all of the files necessary to succesfully run the namespace."
[namespace]
(set
(remove nil?
(map source-location
(map second
(mapcat ns-map (deep-dependent-namespaces #{namespace})))))))
(defn trans-print [x] (println x) x)
(defn dependencies-file [namespace]
(map file-str
(set
(map #(.replaceFirst % "file:" "")
(map #(if (.contains % ".jar!/")
(clojure.string/replace % #"\.jar.*" ".jar")
%)
(map #(.getFile %) (dependencies-url namespace)))))))
(defn classpath-files []
(map file-str (clojure.string/split (classpath) #":")))
;;Every file that comes back from dependencies-file is also on the classpath.
;;In order to recreate the right project structure, we need to copy the files
;;with the appropiate classpath nesting.
(defn bifurcate
"split a collection between f and not f"
[f coll]
(list
(filter f coll)
(filter (comp not f) coll)))
(defn jar? [#^java.io.File f]
(re-matches #".*\.jar$" (.getCanonicalPath f)))
(defn contains-file? [#^java.io.File parent #^java.io.File child]
(let [new-child (.getParentFile child)]
(cond (nil? new-child) false
(= new-child parent) true
true (recur parent new-child))))
(defn destination [base-path-list #^java.io.File current-file #^java.io.File base-destination]
(let [base-path (last (filter #(contains-file? % current-file) base-path-list))]
(file-str
(.replaceFirst (.getCanonicalPath current-file)
(.getCanonicalPath base-path)
(.getCanonicalPath base-destination)))))
(defn export-dependencies [namespace #^java.io.File target]
(let [[jars sources] (bifurcate jar? (dependencies-file namespace))
lib (file-str (str (.getCanonicalPath target) File/separatorChar "lib"))
src (file-str (str (.getCanonicalPath target) File/separatorChar "src"))]
(dorun (map #(FileUtils/copyFileToDirectory % lib) jars))
(dorun (map #(FileUtils/copyFile % (destination (classpath-files) % src)) sources))))
(defn run-script-text [namespace]
(str
"#!/bin/bash\n"
"java -Xmn500M -Xms2000M -Xmx2000M -server -cp ./lib/*:./src clojure.main "
"./src/"
(.replace (.replace (str *ns*) \. File/separatorChar) \- \_)
".clj "
" $@\n"))
(defn make-run-script [namespace base-dir name]
(let [w (clojure.java.io/writer
(str (.getCanonicalPath base-dir) File/separatorChar name))]
(.write w (run-script-text namespace))
(.close w))
(let [f (file-str (str (.getCanonicalPath base-dir) File/separatorChar name))]
(.setExecutable f true)
))
(defn export-files [namespace base-dir name]
(export-dependencies namespace base-dir)
(make-run-script namespace base-dir name))
(defn bzip-folder [#^java.io.File destination #^java.io.File directory]
(apply (partial sw "tar" "-cvjf" (.getCanonicalPath destination))
(concat
(rest
(map #(.replaceFirst
%
(str (.getCanonicalPath directory) File/separatorChar ) "")
(map str (file-seq directory))))
[:dir (.getCanonicalPath directory)])))
(defn bzip-export-files [directory name]
(let [to (file-str "/home/r/coderloop/")]
(apply (partial sw "tar" "-cvjf"
(str (.getCanonicalPath to) File/separatorChar name "-clojure.tar.bz2"))
(concat
[name "lib" "src"]
[:dir (.getCanonicalPath directory)]))))
(def standard-base-directory (file-str "~/.clojure-exports/"))
(defn export-archive [namespace name]
(FileUtils/forceMkdir standard-base-directory)
(FileUtils/forceDelete standard-base-directory)
(FileUtils/forceMkdir standard-base-directory)
(let [new-dir (file-str (str
(.getCanonicalPath standard-base-directory)
(File/separatorChar)
name))]
(export-files namespace new-dir name)
(bzip-export-files new-dir name)
(FileUtils/copyFileToDirectory (file-str (str "~/coderloop/" name "-clojure.tar.bz2"))
(file-str "~/coderloop-test"))
))
(ns rlm.shell-write
(:use
[clojure.contrib
[duck-streams :only [file-str]]
command-line
str-utils
shell-out
])
(:import (java.io File BufferedReader ByteArrayOutputStream InputStreamReader))
(:import (org.apache.commons.exec PumpStreamHandler DefaultExecutor ExecuteWatchdog CommandLine)))
(defn sw
"same as sh but uses apache-commons to actually execute the process,
and prints output as soon as the subprocess returns output. Prints all
errors and normal ouput"
[& commands+args]
(let [[commands {:keys [dir]}] (split-with string? commands+args)]
(let
[
parsed-commands (str (CommandLine/parse (apply str (interpose " " commands))))
process (if dir
(.exec (Runtime/getRuntime) parsed-commands
(into-array String "") (file-str dir))
(.exec (Runtime/getRuntime) parsed-commands))]
(let [reader
(BufferedReader.
(InputStreamReader. (.getInputStream process)))
error-reader
(BufferedReader.
(InputStreamReader. (.getErrorStream process)))]
;output from program
(loop []
(let [line (.readLine reader )]
(if (not (nil? line))
(do (println line) (recur)) nil)))
;errors from program
(let [err-str
(loop [errors ""]
(let [line (.readLine error-reader )]
(if (not (nil? line))
(recur (str errors line "\n"))
errors)))]
(if (> (.length err-str) 0)
(do
(println "******************** Error Stream ********************")
(println err-str)
(println "******************************************************"))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment