(.require [library [lux (.except all) ["[0]" debug] ["[0]" ffi (.only import)] [abstract [codec (.only Codec)] [equivalence (.only Equivalence)] [monad (.only do)]] [control ["[0]" maybe] ["[0]" try (.only Try) (.use "[1]#[0]" functor)] ["[0]" exception (.only Exception)] [function ["[0]" predicate (.only Predicate)]] [concurrency ["[0]" async (.only Async)]]] [data ["[0]" binary (.only Binary)] ["[0]" text (.only) ["%" \\format (.only format)] [encoding ["[0]" utf8]]] [format ["[0]" xml (.only Tag XML) ["<[1]>" \\parser (.only Parser)]]] [collection ["[0]" dictionary (.only Dictionary)] ["[0]" set] ["[0]" list (.use "[1]#[0]" functor monoid)]]] [math [number ["n" nat] ["[0]" i64]]] [meta ["@" target]] [world [console (.only Console)] [net (.only URL) ["[0]" uri] ["[0]" http ["[1]" client]]]]]] ["[0]" // (.only Dependency) ["[1][0]" status (.only Status)] ["/[1]" // ["/" profile] ["[1][0]" hash (.only Hash SHA1 MD5)] ["[1][0]" pom] ["[1][0]" package (.only Package)] ["[1][0]" artifact (.only Version Artifact) ["[1]/[0]" extension (.only Extension)] ["[1]/[0]" versioning] ["[0]" snapshot (.only) [version ["[0]" value]]]] ["[1][0]" repository (.only Repository) ["[1]/[0]" remote (.only Address)] ["[1]/[0]" origin (.only Origin)]] ["[1][0]" metadata ["[1]/[0]" snapshot]]]]) (with_template [] [(exception.def .public ( [artifact extension hash]) (Exception [Artifact Extension Text]) (exception.report (list ["Artifact" (///artifact.format artifact)] ["Extension" (%.text extension)] ["Hash" (%.text hash)])))] [sha1_does_not_match] [md5_does_not_match] ) (import java/lang/String "[1]::[0]" (trim [] java/lang/String)) (def (verified_hash library repository version_template artifact extension hash codec exception) (All (_ h) (-> Binary (Repository Async) Version Artifact Extension (-> Binary (Hash h)) (Codec Text (Hash h)) (Exception [Artifact Extension Text]) (Async (Try (Maybe (Hash h)))))) (do async.monad [?actual (of repository download (///repository/remote.uri version_template artifact extension))] (when ?actual {try.#Success actual} (in (do [! try.monad] [output (of ! each (|>> ffi.as_string java/lang/String::trim ffi.of_string) (of utf8.codec decoded actual)) actual (|> output (text.all_split_by " ") list.head (maybe.else output) (of codec decoded)) _ (exception.assertion exception [artifact extension output] (of ///hash.equivalence = (hash library) actual))] (in {.#Some actual}))) {try.#Failure error} (in {try.#Success {.#None}})))) (def (hashed repository version_template artifact extension) (-> (Repository Async) Version Artifact Extension (Async (Try [Binary Status]))) (do (try.with async.monad) [data (of repository download (///repository/remote.uri version_template artifact extension)) ?sha1 (..verified_hash data repository version_template artifact (format extension ///artifact/extension.sha1) ///hash.sha1 ///hash.sha1_codec ..sha1_does_not_match) ?md5 (..verified_hash data repository version_template artifact (format extension ///artifact/extension.md5) ///hash.md5 ///hash.md5_codec ..md5_does_not_match)] (in [data (when [?sha1 ?md5] [{.#Some sha1} {.#Some md5}] {//status.#Verified sha1 md5} [{.#Some sha1} {.#None}] {//status.#Partial {.#Left sha1}} [{.#None} {.#Some md5}] {//status.#Partial {.#Right md5}} [{.#None} {.#None}] {//status.#Unverified})]))) (def .public (one repository dependency) (-> (Repository Async) Dependency (Async (Try Package))) (let [[artifact type] dependency extension (///artifact/extension.extension type)] (do (try.with async.monad) [snapshot (///metadata/snapshot.read repository artifact) .let [version_template (the [///metadata/snapshot.#artifact ///artifact.#version] snapshot) artifact_version (value.format [value.#version version_template value.#snapshot (the [///metadata/snapshot.#versioning ///artifact/versioning.#snapshot] snapshot)]) artifact (has ///artifact.#version artifact_version artifact)] [pom_data pom_status] (..hashed repository version_template artifact ///artifact/extension.pom) library_&_status (..hashed repository version_template artifact extension)] (of async.monad in (do try.monad [pom (of utf8.codec decoded pom_data) pom (of xml.codec decoded pom) profile (.result ///pom.parser (list pom))] (in [///package.#origin {///repository/origin.#Remote ""} ///package.#library library_&_status ///package.#pom [pom pom_data pom_status]])))))) (type .public Resolution (Dictionary Dependency Package)) (def .public empty Resolution (dictionary.empty //.hash)) (def .public equivalence (Equivalence Resolution) (dictionary.equivalence ///package.equivalence)) (exception.def .public (cannot_resolve dependency) (Exception Dependency) (exception.report (list ["Artifact" (%.text (///artifact.format (the //.#artifact dependency)))] ["Type" (%.text (the //.#type dependency))]))) (with_template [ ] [(def ( console repository artifact) (-> (Console Async) (Repository Async) Artifact (Async (Try Any))) (of console write (format "[" "]" " " " " (///artifact.format artifact) " " " " (%.text (of repository description)) text.new_line)))] ["?" announce_fetching "Fetching" "from"] ["O" announce_success "Found" "at"] ["X" announce_failure "Missed" "from"] ) (def .public (any console repositories dependency) (-> (Console Async) (List (Repository Async)) Dependency (Async (Try Package))) (when repositories {.#End} (|> dependency (exception.except ..cannot_resolve) (of async.monad in)) {.#Item repository alternatives} (do [! async.monad] [_ (..announce_fetching console repository (the //.#artifact dependency)) outcome (..one repository dependency)] (when outcome {try.#Success package} (do ! [_ (..announce_success console repository (the //.#artifact dependency))] (in outcome)) {try.#Failure error} (do ! [_ (..announce_failure console repository (the //.#artifact dependency))] (any console alternatives dependency)))))) (def .public (all console repositories new_repository dependencies resolution) (-> (Console Async) (List (Repository Async)) (-> URL (Repository Async)) (List Dependency) Resolution (Async [(List Dependency) (List Dependency) Resolution])) (loop (again [repositories repositories successes (is (List Dependency) (list)) failures (is (List Dependency) (list)) dependencies dependencies resolution resolution]) (when dependencies {.#End} (of async.monad in [successes failures resolution]) {.#Item head tail} (when (the [//.#artifact ///artifact.#version] head) ... Skip if there is no version "" (again repositories successes failures tail resolution) _ (do [! async.monad] [?package (is (Async (Try Package)) (when (dictionary.value head resolution) {.#Some package} (in {try.#Success package}) {.#None} (..any console repositories head)))] (when ?package {try.#Success package} (do ! [.let [redundant? (is (Predicate Dependency) (predicate.or (of //.equivalence = head) (dictionary.key? resolution))) sub_dependencies (|> package ///package.dependencies (try#each (|>> set.list (list.only (|>> redundant? not)))) (try.else (list))) ... For security reasons, it's not a good idea to allow dependencies to introduce repositories. ... package_repositories (|> package ... ///package.repositories ... (try#each set.list) ... (try.else (list)) ... (list#each new_repository)) ... sub_repositories (list#composite repositories package_repositories) ]] (again repositories {.#Item head successes} failures (set.list (set.union (set.of_list //.hash tail) (set.of_list //.hash sub_dependencies))) (dictionary.has head package resolution))) {try.#Failure error} (again repositories successes {.#Item head failures} tail resolution)))))))