(.module: [library [lux (#- Name) ["@" target] ["." debug] ["." ffi (#+ import:)] [abstract [codec (#+ Codec)] [equivalence (#+ Equivalence)] [monad (#+ do)]] [control ["." maybe] ["." try (#+ Try) ("#\." functor)] ["." exception (#+ Exception exception:)] ["<>" parser ["<.>" xml (#+ Parser)]] [concurrency ["." async (#+ Async)]]] [data ["." binary (#+ Binary)] ["." name] ["." text ["%" format (#+ format)] [encoding ["." utf8]]] [format ["." xml (#+ Tag XML)]] [collection ["." dictionary (#+ Dictionary)] ["." set] ["." list ("#\." functor monoid)]]] [math [number ["n" nat] ["." i64]]] [world [console (#+ Console)] [net (#+ URL) ["." uri] ["." http #_ ["#" client]]]]]] ["." // (#+ Dependency) ["#." status (#+ Status)] ["/#" // #_ ["/" profile] ["#." hash (#+ Hash SHA-1 MD5)] ["#." pom] ["#." package (#+ Package)] ["#." artifact (#+ Version Artifact) ["#/." extension (#+ Extension)] ["#/." versioning] ["." snapshot [version ["." value]]]] ["#." repository (#+ Repository) ["#/." remote (#+ Address)] ["#/." origin (#+ Origin)]] ["#." metadata ["#/." snapshot]]]]) (template [] [(exception: .public ( {artifact Artifact} {extension Extension} {hash Text}) (exception.report ["Artifact" (///artifact.format artifact)] ["Extension" (%.text extension)] ["Hash" (%.text hash)]))] [sha-1_does_not_match] [md5_does_not_match] ) (import: java/lang/String ["#::." (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 (\ repository download (///repository/remote.uri version_template artifact extension))] (case ?actual (#try.Success actual) (in (do {! try.monad} [output (\ ! each (for {@.old (|>> (:as java/lang/String) java/lang/String::trim (:as Text)) @.jvm (|>> java/lang/String::trim)}) (\ utf8.codec decoded actual)) actual (|> output (text.all_split_by " ") list.head (maybe.else output) (\ codec decoded)) _ (exception.assertion exception [artifact extension output] (\ ///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 (\ repository download (///repository/remote.uri version_template artifact extension)) ?sha-1 (..verified_hash data repository version_template artifact (format extension ///artifact/extension.sha-1) ///hash.sha-1 ///hash.sha-1_codec ..sha-1_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 (case [?sha-1 ?md5] [(#.Some sha-1) (#.Some md5)] (#//status.Verified sha-1 md5) [(#.Some sha-1) #.None] (#//status.Partial (#.Left sha-1)) [#.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 (value@ [#///metadata/snapshot.artifact #///artifact.version] snapshot) artifact_version (value.format {#value.version version_template #value.snapshot (value@ [#///metadata/snapshot.versioning #///artifact/versioning.snapshot] snapshot)}) artifact (with@ #///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)] (\ async.monad in (do try.monad [pom (\ utf8.codec decoded pom_data) pom (\ 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: .public (cannot_resolve {dependency Dependency}) (exception.report ["Artifact" (%.text (///artifact.format (value@ #//.artifact dependency)))] ["Type" (%.text (value@ #//.type dependency))])) (template [ ] [(def: ( console repository artifact) (-> (Console Async) (Repository Async) Artifact (Async (Try Any))) (\ console write (format "[" "]" " " " " (///artifact.format artifact) " " " " (%.text (\ 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))) (case repositories #.End (|> dependency (exception.except ..cannot_resolve) (\ async.monad in)) (#.Item repository alternatives) (do {! async.monad} [_ (..announce_fetching console repository (value@ #//.artifact dependency)) outcome (..one repository dependency)] (case outcome (#try.Success package) (do ! [_ (..announce_success console repository (value@ #//.artifact dependency))] (in outcome)) (#try.Failure error) (do ! [_ (..announce_failure console repository (value@ #//.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 [repositories repositories successes (: (List Dependency) (list)) failures (: (List Dependency) (list)) dependencies dependencies resolution resolution] (case dependencies #.End (\ async.monad in [successes failures resolution]) (#.Item head tail) (case (value@ [#//.artifact #///artifact.version] head) ... Skip if there is no version "" (recur repositories successes failures tail resolution) _ (do {! async.monad} [?package (case (dictionary.value head resolution) (#.Some package) (in (#try.Success package)) #.None (..any console repositories head))] (case ?package (#try.Success package) (do ! [.let [sub_dependencies (|> package ///package.dependencies (try\each set.list) (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) sub_repositories repositories] [successes failures resolution] (recur sub_repositories (#.Item head successes) failures sub_dependencies (dictionary.has head package resolution))] (recur repositories successes failures tail resolution)) (#try.Failure error) (recur repositories successes (#.Item head failures) tail resolution)))))))