pax_global_header00006660000000000000000000000064120551672330014516gustar00rootroot0000000000000052 comment=1b2e8f14ce7eccfd2ba6e4a731aca110728cda3a dynapath-0.2.1/000077500000000000000000000000001205516723300133265ustar00rootroot00000000000000dynapath-0.2.1/.gitignore000066400000000000000000000001661205516723300153210ustar00rootroot00000000000000/target /lib /classes /checkouts pom.xml *.jar *.class .lein-deps-sum .lein-failures .lein-plugins .lein-repl-history dynapath-0.2.1/.travis.yml000066400000000000000000000002151205516723300154350ustar00rootroot00000000000000language: clojure lein: lein2 before_script: "echo '{:user {:plugins [[lein-midje \"2.0.1\"]]}}' > ~/.lein/profiles.clj" script: lein2 midje dynapath-0.2.1/README.md000066400000000000000000000066351205516723300146170ustar00rootroot00000000000000# dynapath [![Build Status](https://secure.travis-ci.org/tobias/dynapath.png?branch=master)](https://travis-ci.org/tobias/dynapath) dynapath provides a protocol and util functions for class loaders that make their effective classpaths readable and/or modifiable. ## Rationale Clojure uses a `clojure.lang.DynamicClassLoader` by default (an extension of `java.net.URLClassLoader`), which provides `.getURLs` for reading the effective classpath and `.addURL` for modifying it. It's common for projects that need to read or modify the effective classpath to assume that a `URLClassLoader` is always available. But in some environments, the available class loader may not be a `URLClassLoader`, and may not be readable or modifiable. Some projects (notably `pomegranate`) handle this by providing a protocol that can be implemented for other class loaders that may provide similar functionality. dynapath provides a protocol that is based on an extraction of pomegranate's protocol, and is intended to be a standard way for accessing or modifying the effective classpath. Using dynapath in your library instead of assuming a class loader or implementing your own protocol provides the following benefits: * Your library can work with any modifiable/readable class loader without any changes * Any project that has already implemented `DynamicClasspath` for whatever esoteric class loader they are using will not need any other changes to use your library as well ## Usage Add it as a dependency: For a Leiningen project: [org.tcrawley/dynapath "0.2.1"] For a maven project: org.tcrawley dynapath 0.2.1 If you need to access or modify the effective classpath: (require '[dynapath.util :as dp]) ;; returns a seq of the urls for the classloader. Takes any classloader ;; (whether it implements DynamicClasspath or not) and does the right thing (dp/classpath-urls a-classloader) ;; returns a seq of all the urls available from the classloader and its ;; parentage chain (dp/all-classpath-urls a-classloader) ;; adds a url to the given classloader if it is addable (dp/add-classpath-url a-classloader a-url) Loading the `dynapath.defaults` namespace will automatically implement `classpath-urls` and `add-classpath-url` for `URLClassLoader` and `DynamicClassLoader`. If you need to implement `DynamicClasspath`: (require '[dynapath.dynamic-classpath :as dc]) (extend-type AReadableButNotModfiableClassLoader dc/DynamicClasspath (can-read? [_] true) (can-add? [_] false) (classpath-urls [cl] (seq ...))) (extend AReadableAndModifiableClassLoader dc/DynamicClasspath (assoc dc/base-readable-addable-classpath ;; implements can-read? and can-add? :classpath-urls (fn [cl] ...) :add-classpath-url (fn [cl url] ...))) ## Who's using it? * [bultitude](https://github.com/Raynes/bultitude) * [immutant](https://github.com/immutant/immutant) * [ritz](https://github.com/pallet/ritz) * [tair-repl](https://github.com/xumingming/tair-repl) There are currently pending pull requests for: * [pomegranate](https://github.com/cemerick/pomegranate) Are you using it? If so, add yourself to this list and send me a PR. ## License Copyright © 2012 Tobias Crawley Distributed under the Eclipse Public License. dynapath-0.2.1/project.clj000066400000000000000000000021301205516723300154620ustar00rootroot00000000000000(defproject org.tcrawley/dynapath "0.2.1" :description "An abstraction for modifiable/readable class loaders." :url "https://github.com/tobias/dynapath" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :deploy-repositories {"releases" {:url "https://oss.sonatype.org/service/local/staging/deploy/maven2/" :creds :gpg} "snapshots" {:url "https://oss.sonatype.org/content/repositories/snapshots/" :creds :gpg}} :scm {:url "git@github.com:tobias/dynapath.git"} :pom-addition [:developers [:developer [:name "Toby Crawley"] [:url "https://github.com/tobias/"] [:email "toby@tcrawley.org"] [:timezone "-5"]]] :profiles {:dev {:dependencies [[org.clojure/clojure "1.4.0"] [lein-midje "2.0.1"] [midje "1.4.0"]]}}) dynapath-0.2.1/src/000077500000000000000000000000001205516723300141155ustar00rootroot00000000000000dynapath-0.2.1/src/dynapath/000077500000000000000000000000001205516723300157255ustar00rootroot00000000000000dynapath-0.2.1/src/dynapath/defaults.clj000066400000000000000000000016331205516723300202310ustar00rootroot00000000000000(ns dynapath.defaults "Provides default DynamicClasspath implementations for DynamicClassLoader and URLClassLoader." (:use dynapath.dynamic-classpath) (:import clojure.lang.DynamicClassLoader (java.net URL URLClassLoader))) (let [base-url-classloader (assoc base-readable-addable-classpath :classpath-urls #(seq (.getURLs %)))] (extend URLClassLoader DynamicClasspath (assoc base-url-classloader :add-classpath-url (fn [cl url] (-> URLClassLoader (.getDeclaredMethod "addURL" (into-array Class [URL])) (doto (.setAccessible true)) (.invoke cl (into-array URL [url])))))) (extend DynamicClassLoader DynamicClasspath (assoc base-url-classloader :add-classpath-url (fn [cl url] (.addURL cl url))))) dynapath-0.2.1/src/dynapath/dynamic_classpath.clj000066400000000000000000000013011205516723300221000ustar00rootroot00000000000000(ns dynapath.dynamic-classpath "Provides the implementation of the DynamicClasspath protocol.") (defprotocol DynamicClasspath (can-read? [cl] "Must return true if classpath-urls is implemented.") (can-add? [cl] "Must return true if add-classpath-url is implemented.") (classpath-urls [cl] "Returns a seq of the given ClassLoader's URLs.") (add-classpath-url [cl url] "Adds the url to the classpath of the given ClassLoader.")) (def ^{:doc "A map that provides implementations of can-read? and can-add? that return true. Useful as a base for a DynamicClasspath implementation."} base-readable-addable-classpath {:can-add? (constantly true) :can-read? (constantly true)}) dynapath-0.2.1/src/dynapath/util.clj000066400000000000000000000025631205516723300174020ustar00rootroot00000000000000(ns dynapath.util "Abstracts the getURLs and addURL functionality of URLClassLoader to a protocol." (:require [dynapath.dynamic-classpath :as dc] dynapath.defaults)) ;; trigger the default implementations (defn addable-classpath? "Returns true if the given ClassLoader provides add-claspath-url." [cl] (and (satisfies? dc/DynamicClasspath cl) (dc/can-add? cl))) (defn readable-classpath? "Returns true if the given ClassLoader provides classpath-urls." [cl] (and (satisfies? dc/DynamicClasspath cl) (dc/can-read? cl))) (defn classpath-urls "Returns the URLs for the given ClassLoader, or nil if the ClassLoader is not readable." [cl] (if (readable-classpath? cl) (dc/classpath-urls cl))) (defn all-classpath-urls "Walks up the parentage chain for a ClassLoader, concatenating any URLs it retrieves. If no ClassLoader is provided, RT/baseLoader is assumed." ([] (all-classpath-urls (clojure.lang.RT/baseLoader))) ([cl] (->> (iterate #(.getParent %) cl) (take-while identity) reverse (mapcat classpath-urls) distinct))) (defn add-classpath-url "Attempts to add a url to the given ClassLoader, returning true on success. If the ClassLoader is not addable, does nothing and returns nil." [cl url] (when (addable-classpath? cl) (dc/add-classpath-url cl url) true)) dynapath-0.2.1/test/000077500000000000000000000000001205516723300143055ustar00rootroot00000000000000dynapath-0.2.1/test/dynapath/000077500000000000000000000000001205516723300161155ustar00rootroot00000000000000dynapath-0.2.1/test/dynapath/defaults_test.clj000066400000000000000000000016241205516723300214600ustar00rootroot00000000000000(ns dynapath.defaults-test (:use midje.sweet dynapath.defaults dynapath.dynamic-classpath) (:import (java.net URL URLClassLoader) clojure.lang.DynamicClassLoader)) (deftype Frobble []) (let [url-cl (URLClassLoader. (make-array URL 0) nil) dyn-cl (DynamicClassLoader.)] (fact "DynamicClassLoader should be extended" (satisfies? DynamicClasspath dyn-cl) => true) (fact "URLClassLoader should be extended" (satisfies? DynamicClasspath url-cl) => true) (fact "add-classpath-url/get-classpath-urls should work for a URLClassLoader" (let [url (URL. "http://ham.biscuit")] (add-classpath-url url-cl url) (classpath-urls url-cl) => [url])) (fact "add-classpath-url/get-classpath-urls should work for a DynamicClassLoader" (let [url (URL. "http://ham.biscuit")] (add-classpath-url dyn-cl url) (classpath-urls dyn-cl) => [url]))) dynapath-0.2.1/test/dynapath/util_test.clj000066400000000000000000000040231205516723300206220ustar00rootroot00000000000000(ns dynapath.util-test (:use midje.sweet dynapath.util [dynapath.dynamic-classpath :only [DynamicClasspath]]) (:import (java.net URL URLClassLoader))) (deftype Frobble []) (let [urls [(URL. "http://ham.biscuit")] all-urls (conj urls (URL. "http://gravy.biscuit")) url-cl (URLClassLoader. (into-array urls) nil) basic-cl (proxy [ClassLoader] [])] (fact "classpath-urls should work for a readable classloader" (classpath-urls url-cl) => urls) (fact "classpath-urls should work for a non-readable classloader" (classpath-urls basic-cl) => nil) (fact "all-classpath-urls should work for a parent with the urls" (all-classpath-urls (proxy [ClassLoader] [url-cl])) => urls) (fact "all-classpath-urls should order urls properly" (all-classpath-urls (URLClassLoader. (into-array [(last all-urls)]) url-cl)) => all-urls) (fact "all-classpath-urls should use the baseLoader when called with a zero arity" (add-classpath-url (clojure.lang.RT/baseLoader) (first urls)) (last (all-classpath-urls)) => (first urls)) (fact "add-classpath-url should work for an addable classpath" (add-classpath-url url-cl (last all-urls)) => true (classpath-urls url-cl) => all-urls) (fact "add-classpath-url should work for an non-addable classpath" (add-classpath-url basic-cl (last all-urls)) => nil (classpath-urls basic-cl) => nil)) (fact "addable-classpath? should work" (let [frobble (Frobble.)] (addable-classpath? frobble) => false (extend-type Frobble DynamicClasspath (can-add? [_] false)) (addable-classpath? frobble) => false (extend-type Frobble DynamicClasspath (can-add? [_] true)) (addable-classpath? frobble) => true)) (fact "readable-classpath? should work" (let [frobble (Frobble.)] (extend-type Frobble DynamicClasspath (can-read? [_] false)) (readable-classpath? frobble) => false (extend-type Frobble DynamicClasspath (can-read? [_] true)) (readable-classpath? frobble) => true))