(.module: [lux (#- Name) ["." debug] ["." ffi (#+ import:)] [abstract [codec (#+ Codec)] [equivalence (#+ Equivalence)] [monad (#+ Monad do)]] [control ["." try (#+ Try) ("#\." functor)] ["." exception (#+ Exception exception:)] ["<>" parser ["<.>" xml (#+ Parser)]] [concurrency ["." promise (#+ Promise)]]] [data ["." binary (#+ Binary)] ["." name] ["." maybe] ["." 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: #export ( {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 Promise) Version Artifact Extension (-> Binary (Hash h)) (Codec Text (Hash h)) (Exception [Artifact Extension Text]) (Promise (Try (Maybe (Hash h)))))) (do promise.monad [?actual (\ repository download (///repository/remote.uri version_template artifact extension))] (case ?actual (#try.Success actual) (wrap (do {! try.monad} [output (\ ! map (|>> (:as java/lang/String) java/lang/String::trim (:as Text)) (\ utf8.codec decode actual)) actual (|> output (text.split_all_with " ") list.head (maybe.default output) (\ codec decode)) _ (exception.assert exception [artifact extension output] (\ ///hash.equivalence = (hash library) actual))] (wrap (#.Some actual)))) (#try.Failure error) (wrap (#try.Success #.None))))) (def: (hashed repository version_template artifact extension) (-> (Repository Promise) Version Artifact Extension (Promise (Try [Binary Status]))) (do (try.with promise.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)] (wrap [data (case [?sha-1 ?md5] [(#.Some sha-1) (#.Some md5)] (#//status.Verified sha-1 md5) [(#.Some sha-1) _] (#//status.Partial (#.Left sha-1)) [_ (#.Some md5)] (#//status.Partial (#.Right md5)) [#.None #.None] #//status.Unverified)]))) (def: #export (one repository dependency) (-> (Repository Promise) Dependency (Promise (Try Package))) (let [[artifact type] dependency extension (///artifact/extension.extension type)] (do (try.with promise.monad) [snapshot (///metadata/snapshot.read repository artifact) #let [version_template (get@ [#///metadata/snapshot.artifact #///artifact.version] snapshot) artifact_version (value.format {#value.version version_template #value.snapshot (get@ [#///metadata/snapshot.versioning #///artifact/versioning.snapshot] snapshot)}) artifact (set@ #///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)] (\ promise.monad wrap (do try.monad [pom (\ utf8.codec decode pom_data) pom (\ xml.codec decode pom) profile (.run ///pom.parser (list pom))] (wrap {#///package.origin (#///repository/origin.Remote "") #///package.library library_&_status #///package.pom [pom pom_data pom_status]})))))) (type: #export Resolution (Dictionary Dependency Package)) (def: #export empty Resolution (dictionary.new //.hash)) (def: #export equivalence (Equivalence Resolution) (dictionary.equivalence ///package.equivalence)) (exception: #export (cannot_resolve {dependency Dependency}) (exception.report ["Artifact" (%.text (///artifact.format (get@ #//.artifact dependency)))] ["Type" (%.text (get@ #//.type dependency))])) (template [ ] [(def: ( console repository artifact) (-> (Console Promise) (Repository Promise) Artifact (Promise (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: #export (any console repositories dependency) (-> (Console Promise) (List (Repository Promise)) Dependency (Promise (Try Package))) (case repositories #.Nil (|> dependency (exception.throw ..cannot_resolve) (\ promise.monad wrap)) (#.Cons repository alternatives) (do {! promise.monad} [_ (..announce_fetching console repository (get@ #//.artifact dependency)) outcome (..one repository dependency)] (case outcome (#try.Success package) (do ! [_ (..announce_success console repository (get@ #//.artifact dependency))] (wrap outcome)) (#try.Failure error) (do ! [_ (..announce_failure console repository (get@ #//.artifact dependency))] (any console alternatives dependency)))))) (def: #export (all console repositories new_repository dependencies resolution) (-> (Console Promise) (List (Repository Promise)) (-> URL (Repository Promise)) (List Dependency) Resolution (Promise [(List Dependency) (List Dependency) Resolution])) (loop [repositories repositories successes (: (List Dependency) (list)) failures (: (List Dependency) (list)) dependencies dependencies resolution resolution] (case dependencies #.Nil (\ promise.monad wrap [successes failures resolution]) (#.Cons head tail) (case (get@ [#//.artifact #///artifact.version] head) ## Skip if there is no version "" (recur repositories successes failures tail resolution) _ (do {! promise.monad} [?package (case (dictionary.get head resolution) (#.Some package) (wrap (#try.Success package)) #.None (..any console repositories head))] (case ?package (#try.Success package) (do ! [#let [sub_dependencies (|> package ///package.dependencies (try\map set.to_list) (try.default (list))) sub_repositories (|> package ///package.repositories (try\map set.to_list) (try.default (list)) (list\map new_repository) (list\compose repositories))] [successes failures resolution] (recur sub_repositories (#.Cons head successes) failures sub_dependencies (dictionary.put head package resolution))] (recur repositories successes failures tail resolution)) (#try.Failure error) (recur repositories successes (#.Cons head failures) tail resolution)))))))