Skip to content

Instantly share code, notes, and snippets.

@ato
Created August 1, 2011 04:52
Show Gist options
  • Save ato/1117588 to your computer and use it in GitHub Desktop.
Save ato/1117588 to your computer and use it in GitHub Desktop.
mucking with Aether
;; Maven hoopla
(defproject moopla "1.0.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]
;; Dependency hoops!
[org.sonatype.aether/aether-api "1.8"]
[org.sonatype.aether/aether-util "1.8"]
[org.sonatype.aether/aether-impl "1.8"]
[org.sonatype.aether/aether-connector-wagon "1.8"
:exclusions [commons-logging/commons-logging-api log4j junit
org.codehaus.plexus/plexus-container-default]]
[org.apache.maven/maven-aether-provider "3.0.1"]
[org.apache.maven.wagon/wagon-file "1.0-beta-7"]
[org.apache.maven.wagon/wagon-http-lightweight "1.0-beta-7"
:exclusions [commons-logging nekohtml
nekohtml/xercesMinimal]]])
(ns moopla.core
(:import org.apache.maven.repository.internal.DefaultServiceLocator
org.apache.maven.repository.internal.MavenRepositorySystemSession
org.apache.maven.wagon.providers.file.FileWagon
org.apache.maven.wagon.providers.http.LightweightHttpWagon
org.sonatype.aether.RepositorySystem
org.sonatype.aether.artifact.Artifact
org.sonatype.aether.collection.CollectRequest
org.sonatype.aether.connector.wagon.WagonProvider
org.sonatype.aether.connector.wagon.WagonRepositoryConnectorFactory
org.sonatype.aether.graph.Dependency
org.sonatype.aether.graph.DependencyNode
org.sonatype.aether.graph.Exclusion
org.sonatype.aether.repository.ArtifactRepository
org.sonatype.aether.repository.LocalRepository
org.sonatype.aether.repository.RemoteRepository
org.sonatype.aether.resolution.ArtifactRequest
org.sonatype.aether.resolution.MetadataRequest
org.sonatype.aether.spi.connector.RepositoryConnectorFactory
org.sonatype.aether.util.artifact.DefaultArtifact))
(def ^{:dynamic true} *wagons*
{"file" #(FileWagon.)
"http" #(LightweightHttpWagon.)})
(def ^{:dynamic true} *local-repository*
(str (System/getProperty "user.home") "/.m2/repository"))
(def ^{:dynamic true} *default-repositories*
[["clojars" "http://clojars.org/repo"]])
(def wagon-provider (reify WagonProvider
(lookup [this role] ((*wagons* role)))
(release [this wagon])))
(defn repo-system
{:tag org.sonatype.aether.RepositorySystem}
([] (-> (doto (DefaultServiceLocator.)
(.setServices WagonProvider (to-array [wagon-provider]))
(.addService RepositoryConnectorFactory
WagonRepositoryConnectorFactory))
(.getService RepositorySystem))))
(defn repo-session
{:tag org.sonatype.aether.RepositorySystemSession}
([] (repo-session (repo-system)))
([system]
(doto (MavenRepositorySystemSession.)
(.setLocalRepositoryManager
(.newLocalRepositoryManager
system (LocalRepository. *local-repository*))))))
(def ^{:dynamic true} *system* (repo-system))
(def ^{:dynamic true} *session* (repo-session *system*))
(defn- parse-lein-artifact
"Parse a Leiningen-style artifact vector returning a map.
[group-id/artifact-id \"version\" & [:option value ...]]"
[coords]
(let [[id version & opts] coords]
(assoc (apply hash-map opts)
:group-id (when (instance? clojure.lang.Named id) (namespace id))
:artifact-id (name id)
:version version)))
(defn ^Artifact make-artifact
"Create an Aether Artifact object. The coords may be a Maven-style coordinates
string \"groupId:artifactId[:extension[:classifier]]:version\", a
Leiningen-style vector [group-id/artifact-id \"version\" & opts] or a map
containing the keys :group-id, :artifact-id, :extension, :classifier and
:version."
([group-id artifact-id version]
(make-artifact {:group-id group-id
:artifact-id artifact-id
:version version}))
([coords]
(cond (instance? Artifact coords) coords
(string? coords) (DefaultArtifact. ^String coords)
(vector? coords) (recur (parse-lein-artifact coords))
:else (DefaultArtifact.
(or (:group-id coords) (:artifact-id coords))
(:artifact-id coords)
(:classifier coords "")
(:extension coords "jar")
(:version coords)))))
(defn ^Exclusion make-exclusion
"Create an Aether Exclusion object. The coords may be a Leiningen-style
vector [group-id/artifact-id & opts], a symbol group-id/symbol-id or a
map containing the keys :group-id, :artifact-id, :extension and :classifier."
([group-id artifact-id]
(make-exclusion {:group-id group-id, :artifact-id artifact-id}))
([coords]
(cond (instance? Exclusion coords) coords
(symbol? coords) (recur [coords])
(vector? coords) (let [[id & opts] coords]
(recur (assoc (apply hash-map opts)
:group-id (namespace id)
:artifact-id (name id))))
:else (Exclusion.
(or (:group-id coords) (:artifact-id coords))
(:artifact-id coords)
(:extension coords)
(:classifier coords)))))
(defn ^Dependency make-dependency
"Creates an Aether Dependency object. The coords may be one of the types
accepted by moopla.core/artifact with the additional options:
:scope scope of the dependency (eg \"compile\")
:optional? is this an optional dependency? (boolean)
:exclusions seq of artifacts to exclude from transitive
dependencies (see moopla.core/dependency)"
([group-id artifact-id version]
(make-dependency (make-artifact group-id artifact-id version)))
([coords]
(cond
(instance? Dependency coords) coords
(vector? coords) (recur (parse-lein-artifact coords))
(associative? coords) (Dependency.
(make-artifact coords)
(:scope coords)
(boolean (:optional? coords false))
(map make-exclusion (:exclusions coords)))
:else (Dependency. (make-artifact coords) nil))))
(defn ^ArtifactRepository make-repository
"Create an Aether ArtifactRepository object.
The settings may be a map of the options below or a Leiningen-style
[id url] or a [id settings] vector.
Options:
:id unique repository idenitifier
:url URL of the repository
:snapshots? contains snapshots versions?
:releases? contains release versions?
:proxy proxy settings
:authentication authentication settings"
([id url] (make-repository {:id id :url url}))
([settings]
(cond
(instance? ArtifactRepository settings) settings
(vector? settings) (let [[id url] settings]
(if (associative? url)
(recur (assoc (into {} url) :id id))
(recur {:id id :url url})))
:else (doto (RemoteRepository. (:id settings)
(:type settings "default")
(str (:url settings)))
(.setProxy (:proxy settings))
(.setAuthentication (:authentication settings))
(.setPolicy true (:snapshots? settings))
(.setPolicy false (:releases? settings))))))
(defn ^java.io.File resolve-artifact
"Resolves the local path for an artifact. The artifact will be downloaded to
the local repository if necessary."
([artifact] (resolve-artifact artifact *default-repositories*))
([artifact repositories]
(let [request (ArtifactRequest. (make-artifact artifact)
(map make-repository repositories)
nil)]
(-> (.resolveArtifact *system* *session* request)
(.getArtifact)
(.getFile)))))
(defn resolve-deps
"Collects all the transitive dependencies for an artifact and resolves them to
local paths. The artifacts will be downloaded to the local repository as
necessary."
([artifact] (resolve-deps artifact *default-repositories*))
([artifact repositories]
(let [request (CollectRequest. (make-dependency artifact)
(map make-repository repositories))]
(for [result (.resolveDependencies *system* *session* request nil)]
(.getFile (.getArtifact result))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment