(.module: [lux (#- Name) [abstract [monad (#+ do)]] [control ["." try (#+ Try)] ["." exception (#+ exception:)] ["." io (#+ IO)] [concurrency ["." promise (#+ Promise) ("#\." monad)]]] [data ["." product] ["." maybe] ["." text ("#\." equivalence) ["%" format (#+ format)]] [collection ["." list ("#\." functor)] ["." dictionary] ["." set]]] [math [number ["i" int]]] [world ["." program (#+ Program)] ["." file (#+ Path)] ["." shell (#+ Process Shell)] ["." console (#+ Console)] [net ["." uri]]]] ["." /// #_ ["#" profile] ["#." action] ["#." command (#+ Command)] ["#." local] ["#." repository] ["#." runtime] ["#." dependency (#+ Dependency) ["#/." resolution (#+ Resolution)]] ["#." artifact (#+ Group Name Artifact) ["#/." type]]]) (type: Finder (-> Resolution (Maybe Dependency))) (def: (dependency_finder group name) (-> Group Name Finder) (|>> dictionary.entries (list.one (function (_ [dependency package]) (if (and (text\= group (get@ [#///dependency.artifact #///artifact.group] dependency)) (text\= name (get@ [#///dependency.artifact #///artifact.name] dependency))) (#.Some dependency) #.None))))) (def: #export lux_group Group "com.github.luxlang") (def: #export jvm_compiler_name Name "lux-jvm") (def: #export js_compiler_name Name "lux-js") (template [ ] [(def: Finder (..dependency_finder ..lux_group ))] [jvm_compiler ..jvm_compiler_name] [js_compiler ..js_compiler_name] ) (exception: #export no_available_compiler) (exception: #export no_specified_program) (type: #export Compiler (#JVM Dependency) (#JS Dependency)) (def: (remove_dependency dependency) (-> Dependency (-> Resolution Resolution)) (|>> dictionary.entries (list.filter (|>> product.left (is? dependency) not)) (dictionary.from_list ///dependency.hash))) (def: (compiler resolution) (-> Resolution (Try [Resolution Compiler])) (case [(..jvm_compiler resolution) (..js_compiler resolution)] [(#.Some dependency) _] (#try.Success [(..remove_dependency dependency resolution) (#JVM dependency)]) [_ (#.Some dependency)] (#try.Success [(..remove_dependency dependency resolution) (#JS dependency)]) _ (exception.throw ..no_available_compiler []))) (def: (path fs home dependency) (All [!] (-> (file.System !) Path Dependency Path)) (let [/ (\ fs separator) artifact (get@ #///dependency.artifact dependency)] (|> artifact (///local.uri (get@ #///artifact.version artifact)) (text.replace_all uri.separator /) (format home /) (text.suffix (format "." (get@ #///dependency.type dependency)))))) (def: (libraries fs home) (All [!] (-> (file.System !) Path Resolution (List Path))) (|>> dictionary.keys (list.filter (|>> (get@ #///dependency.type) (text\= ///artifact/type.lux_library))) (list\map (..path fs home)))) (def: (singular name) (-> Text Text (List Text)) (|>> (list name))) (def: (plural name) (-> Text (List Text) (List Text)) (|>> (list\map (|>> (list name))) list.concat)) (def: #export start "[BUILD STARTED]") (def: #export success "[BUILD ENDED]") (def: #export failure "[BUILD FAILED]") (template [ ] [(def: #export ( console process) (-> (Console Promise) (Process Promise) (Promise (Try Any))) ## This is a very odd way of implementing this function. ## But it's written this way because the more straightforward way (i.e. by using (try.with promise.monad)) ## eventually led to the function hanging/freezing. ## I'm not sure why it happened, but I got this weirder implementation to work. (let [[read! write!] (: [(Promise (Try Any)) (promise.Resolver (Try Any))] (promise.promise [])) _ (|> (\ process []) (promise.await (function (recur ?line) (case ?line (#try.Failure error) (if (exception.match? shell.no_more_output error) (write! (#try.Success [])) (promise.await write! (console.write_line error console))) (#try.Success line) (promise.await (function (_ outcome) (case outcome (#try.Failure error) (write! (#try.Failure error)) (#try.Success _) (promise.await recur (\ process [])))) (console.write_line line console))))) io.run)] read!))] [log_output! read] [log_error! error] ) (def: #export (do! console program fs shell resolution) (-> (Console Promise) (Program Promise) (file.System Promise) (Shell Promise) Resolution (Command [Compiler Path])) (function (_ profile) (let [target (get@ #///.target profile)] (case (get@ #///.program profile) #.None (promise\wrap (exception.throw ..no_specified_program [])) (#.Some program_module) (do promise.monad [environment (program.environment promise.monad program) #let [home (\ program home) working_directory (\ program directory)]] (do ///action.monad [[resolution compiler] (promise\wrap (..compiler resolution)) #let [[[command compiler_params] output] (case compiler (#JVM dependency) [(///runtime.java (..path fs home dependency)) "program.jar"] (#JS dependency) [(///runtime.node (..path fs home dependency)) "program.js"]) / (\ fs separator) cache_directory (format working_directory / target)] _ (console.write_line ..start console) process (\ shell execute [environment working_directory command (list.concat (list compiler_params (list "build") (..plural "--library" (..libraries fs home resolution)) (..plural "--source" (set.to_list (get@ #///.sources profile))) (..singular "--target" cache_directory) (..singular "--module" program_module)))]) _ (..log_output! console process) _ (..log_error! console process) exit (\ process await []) _ (console.write_line (if (i.= shell.normal exit) ..success ..failure) console)] (wrap [compiler (format cache_directory / output)])))))))