(.module: [lux (#- Name) ["." host (#+ import:)] [abstract [codec (#+ Codec)] [equivalence (#+ Equivalence)] [monad (#+ Monad do)]] [control ["." try (#+ Try)] ["." exception (#+ Exception exception:)] ["<>" parser ["<.>" xml (#+ Parser)]] [concurrency ["." promise (#+ Promise)]]] [data ["." binary (#+ Binary)] ["." name] ["." maybe] [text ["%" format (#+ format)] ["." encoding]] [format ["." xml (#+ Tag XML)]] [collection ["." dictionary (#+ Dictionary)] ["." set]]] [math [number ["n" nat] ["." i64]]] [world [net (#+ URL) ["." uri]]]] ["." // (#+ Dependency) ["#." status (#+ Status)] ["/#" // #_ ["/" profile] ["#." hash (#+ Hash SHA-1 MD5)] ["#." pom] ["#." package (#+ Package)] ["#." artifact (#+ Artifact) ["#/." extension (#+ Extension)]] ["#." repository (#+ Repository) ["#/." remote (#+ Address)] ["#/." origin (#+ Origin)]]]]) (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] ) (def: (verified_hash library repository artifact extension hash codec exception) (All [h] (-> Binary (Repository Promise) Artifact Extension (-> Binary (Hash h)) (Codec Text (Hash h)) (Exception [Artifact Extension Text]) (Promise (Try (Hash h))))) (do (try.with promise.monad) [actual (\ repository download (///repository/remote.uri artifact extension))] (\ promise.monad wrap (do try.monad [output (\ encoding.utf8 decode actual) actual (\ codec decode output) _ (exception.assert exception [artifact extension output] (\ ///hash.equivalence = (hash library) actual))] (wrap actual))))) (def: (hashed repository artifact extension) (-> (Repository Promise) Artifact Extension (Promise (Try [Binary Status]))) (do (try.with promise.monad) [data (\ repository download (///repository/remote.uri artifact extension)) sha-1 (..verified_hash data repository artifact (format extension ///artifact/extension.sha-1) ///hash.sha-1 ///hash.sha-1_codec ..sha-1_does_not_match) md5 (..verified_hash data repository artifact (format extension ///artifact/extension.md5) ///hash.md5 ///hash.md5_codec ..md5_does_not_match)] (wrap [data (#//status.Verified sha-1 md5)]))) (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) [[pom pom_status] (..hashed repository artifact ///artifact/extension.pom) library_&_status (..hashed repository artifact extension)] (\ promise.monad wrap (do try.monad [pom (\ encoding.utf8 decode pom) pom (\ xml.codec decode pom) profile (.run ///pom.parser pom)] (wrap {#///package.origin (#///repository/origin.Remote "") #///package.library library_&_status #///package.pom [pom 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))])) (def: #export (any repositories dependency) (-> (List (Repository Promise)) Dependency (Promise (Try Package))) (case repositories #.Nil (|> dependency (exception.throw ..cannot_resolve) (\ promise.monad wrap)) (#.Cons repository alternatives) (do promise.monad [outcome (..one repository dependency)] (case outcome (#try.Success package) (wrap outcome) (#try.Failure error) (any alternatives dependency))))) (def: #export (all repositories dependencies resolution) (-> (List (Repository Promise)) (List Dependency) Resolution (Promise (Try Resolution))) (case dependencies #.Nil (\ (try.with promise.monad) wrap resolution) (#.Cons head tail) (do (try.with promise.monad) [package (case (dictionary.get head resolution) (#.Some package) (wrap package) #.None (..any repositories head)) sub_dependencies (\ promise.monad wrap (///package.dependencies package)) resolution (|> resolution (dictionary.put head package) (all repositories (set.to_list sub_dependencies)))] (all repositories tail resolution))))