rlm@0: (ns coderloop.export-files rlm@0: (:use clojure.java.io) rlm@0: (:use [clojure.contrib [duck-streams :only [file-str]]]) rlm@0: (:use [rlm rlm@0: [classpath-utils :only [classpath]] rlm@0: [shell-write :only [sw]]]) rlm@0: (:require clojure.string) rlm@0: (:import java.io.File) rlm@0: (:import [org.apache.commons.io FileUtils]) rlm@0: ) rlm@0: rlm@0: rlm@0: (defn trans-print [x] (println x) x) rlm@0: rlm@0: (def *nailgun* true) rlm@0: rlm@0: ;;; put standard base-path on the classpath rlm@0: (def standard-base-directory (file-str "~/.clojure-exports/")) rlm@0: rlm@0: (defn better-export-files [namespace name] rlm@0: (binding [*compile-path* (.getPath standard-base-directory)] rlm@0: ;;clear out classes -- prepare temp directory rlm@0: (FileUtils/forceMkdir standard-base-directory) rlm@0: (FileUtils/deleteDirectory standard-base-directory) rlm@0: (FileUtils/forceMkdir standard-base-directory) rlm@0: ;; make classes rlm@0: (compile (symbol (str namespace))) rlm@0: rlm@0: ;; make jar rlm@0: ;; (jar {:jarfile jar-name :basedir temp-class-dir}) rlm@0: rlm@0: ;; move jar rlm@0: ;; (FileUtils/copyFileToDirectory jar-name target-lib-dir) rlm@0: )) rlm@0: rlm@0: (defmulti source-location class) rlm@0: rlm@0: (defmethod source-location clojure.lang.Var [sym] rlm@0: (let [source? (:file (meta sym))] rlm@0: (if source? rlm@0: (.getResource (clojure.lang.RT/baseLoader) source?) rlm@0: nil))) rlm@0: rlm@0: (defmethod source-location java.lang.Class [sym] rlm@0: (let [source? (.getCodeSource (.getProtectionDomain sym))] rlm@0: (if source? rlm@0: (.getLocation source?) rlm@0: nil))) rlm@0: rlm@0: (defn all-dependent-namespaces [namespace] rlm@0: (set rlm@0: (concat rlm@0: [namespace] rlm@0: (vals (ns-aliases namespace)) rlm@0: (map #(.ns %) rlm@0: (filter #(= (class %) clojure.lang.Var) rlm@0: (concat rlm@0: (vals (ns-map namespace)) rlm@0: (vals (ns-refers namespace)))))))) rlm@0: rlm@0: (defn deep-dependent-namespaces [namespace-set] rlm@0: (let [new-namespaces (set (mapcat all-dependent-namespaces namespace-set))] rlm@0: ;;(println (count new-namespaces)) rlm@0: (if (= new-namespaces namespace-set) rlm@0: namespace-set rlm@0: (recur new-namespaces)))) rlm@0: rlm@0: (defn dependencies-url rlm@0: "returns all of the files necessary to succesfully run the namespace." rlm@0: [namespace] rlm@0: (set rlm@0: (remove rlm@0: nil? rlm@0: (map source-location rlm@0: (map second rlm@0: (mapcat ns-map (deep-dependent-namespaces #{namespace}))))))) rlm@0: rlm@0: (defn dependencies-file [namespace] rlm@0: (map file-str rlm@0: (set rlm@0: (map #(.replaceFirst % "file:" "") rlm@0: (map #(if (.contains % ".jar!/") rlm@0: (clojure.string/replace % #"\.jar.*" ".jar") %) rlm@0: (map #(.getFile %) (dependencies-url namespace))))))) rlm@0: rlm@0: (defn classpath-files [] rlm@0: (map file-str (clojure.string/split (classpath) #":"))) rlm@0: rlm@0: ;;Every file that comes back from dependencies-file is also on the classpath. rlm@0: ;;In order to recreate the right project structure, we need to copy the files rlm@0: ;;with the appropiate classpath nesting. rlm@0: rlm@0: (defn bifurcate rlm@0: "split a collection between f and not f" rlm@0: [f coll] rlm@0: (list rlm@0: (filter f coll) rlm@0: (filter (comp not f) coll))) rlm@0: rlm@0: (defn jar? [#^java.io.File f] rlm@0: (re-matches #".*\.jar$" (.getCanonicalPath f))) rlm@0: rlm@0: (defn contains-file? [#^java.io.File parent #^java.io.File child] rlm@0: (let [new-child (.getParentFile child)] rlm@0: (cond (nil? new-child) false rlm@0: (= new-child parent) true rlm@0: true (recur parent new-child)))) rlm@0: rlm@0: (defn destination [base-path-list #^java.io.File current-file #^java.io.File base-destination] rlm@0: (let [base-path (last (filter #(contains-file? % current-file) base-path-list))] rlm@0: (file-str rlm@0: (.replaceFirst (.getCanonicalPath current-file) rlm@0: (.getCanonicalPath base-path) rlm@0: (.getCanonicalPath base-destination))))) rlm@0: rlm@0: (defn export-dependencies [namespace #^java.io.File target] rlm@0: (let [[jars sources] (bifurcate jar? (dependencies-file namespace)) rlm@0: jars (if *nailgun* rlm@0: (conj jars (file-str "~/roBin/nailgun-0.7.1/nailgun-0.7.1.jar")) rlm@0: jars) rlm@0: rlm@0: lib (file-str (str (.getCanonicalPath target) File/separatorChar "lib")) rlm@0: src (file-str (str (.getCanonicalPath target) File/separatorChar "src"))] rlm@0: (if *nailgun* rlm@0: (do rlm@0: (FileUtils/copyFileToDirectory (file-str "~/roBin/nailgun-0.7.1/ng") lib) rlm@0: (sw (str "chmod +x " (.getCanonicalPath target) File/separatorChar "lib/ng")))) rlm@0: (dorun (map #(FileUtils/copyFileToDirectory % lib) jars)) rlm@0: (dorun (map #(FileUtils/copyFile % (destination (classpath-files) % src)) sources)))) rlm@0: rlm@0: (defn run-script-text [namespace] rlm@0: rlm@0: (if *nailgun* rlm@0: (str rlm@0: rlm@0: "#!/usr/bin/perl rlm@0: rlm@0: if (`./lib/ng ng-alias 2>&1 1>/dev/null` eq \"connect: Connection refused\\n\"){ rlm@0: rlm@0: $nailgun_init = rlm@0: \"java -Xmn500M -Xms2000M -Xmx2000M \" . rlm@0: \"-classpath ./src/:lib/*\" . \" -server \". rlm@0: \"com.martiansoftware.nailgun.NGServer \". rlm@0: \" >/dev/null 2>/dev/null &\"; rlm@0: `$nailgun_init`; rlm@0: }\n\n" rlm@0: rlm@0: rlm@0: "while (`./lib/ng ng-alias 2>&1 1>/dev/null` eq \"connect: Connection refused\\n\"){ rlm@0: }\n\n" rlm@0: rlm@0: "$command = " rlm@0: rlm@0: rlm@0: "\"./lib/ng clojure.main " rlm@0: "./src/" rlm@0: (.replace (.replace (str *ns*) \. File/separatorChar) \- \_) rlm@0: ".clj " rlm@0: " @ARGV\";\n" rlm@0: rlm@0: "print `$command`;\n") rlm@0: (str rlm@0: "#!/bin/bash\n" rlm@0: "java -Xmn500M -Xms2000M -Xmx2000M -server -cp ./lib/*:./src clojure.main " rlm@0: "./src/" rlm@0: (.replace (.replace (str *ns*) \. File/separatorChar) \- \_) rlm@0: ".clj " rlm@0: " $@\n"))) rlm@0: rlm@0: rlm@0: rlm@0: (defn make-run-script [namespace base-dir name] rlm@0: (let [w (clojure.java.io/writer rlm@0: (str (.getCanonicalPath base-dir) File/separatorChar name))] rlm@0: (.write w (run-script-text namespace)) rlm@0: (.close w)) rlm@0: (let [f (file-str (str (.getCanonicalPath base-dir) File/separatorChar name))] rlm@0: (.setExecutable f true))) rlm@0: rlm@0: (defn export-files [namespace base-dir name] rlm@0: (export-dependencies namespace base-dir) rlm@0: (make-run-script namespace base-dir name)) rlm@0: rlm@0: (defn bzip-folder [#^java.io.File destination #^java.io.File directory] rlm@0: (apply (partial sw "tar" "-cvjf" (.getCanonicalPath destination)) rlm@0: (concat rlm@0: (rest rlm@0: (map #(.replaceFirst rlm@0: % rlm@0: (str (.getCanonicalPath directory) File/separatorChar ) "") rlm@0: (map str (file-seq directory)))) rlm@0: [:dir (.getCanonicalPath directory)]))) rlm@0: rlm@0: (defn bzip-export-files [directory target-dir name] rlm@0: (apply (partial sw "tar" "-cvjf" rlm@0: (str (.getCanonicalPath target-dir) File/separatorChar name)) rlm@0: (concat rlm@0: [name "lib" "src"] rlm@0: [:dir (.getCanonicalPath directory)]))) rlm@0: rlm@0: (defn export-archive rlm@0: ([name] rlm@0: (export-archive *ns* name)) rlm@0: rlm@0: ([namespace name nailgun?] rlm@0: (binding [*nailgun* nailgun?] rlm@0: (export-archive namespace name))) rlm@0: rlm@0: ([namespace name] rlm@0: (FileUtils/forceMkdir standard-base-directory) rlm@0: (FileUtils/forceDelete standard-base-directory) rlm@0: (FileUtils/forceMkdir standard-base-directory) rlm@0: (let [new-dir rlm@0: (file-str rlm@0: (str rlm@0: (.getCanonicalPath standard-base-directory) rlm@0: (File/separatorChar) rlm@0: name))] rlm@0: rlm@0: (export-files namespace new-dir name) rlm@0: rlm@0: (bzip-export-files new-dir (file-str "~/coderloop/") (str name "-clojure.tar.bz2")) rlm@0: (FileUtils/copyFileToDirectory rlm@0: (file-str (str "~/coderloop/" name "-clojure.tar.bz2")) rlm@0: (file-str "~/coderloop-test")))))