aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/program/aedifex/command
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/source/program/aedifex/command')
-rw-r--r--stdlib/source/program/aedifex/command/auto.lux141
-rw-r--r--stdlib/source/program/aedifex/command/build.lux146
-rw-r--r--stdlib/source/program/aedifex/command/test.lux29
3 files changed, 316 insertions, 0 deletions
diff --git a/stdlib/source/program/aedifex/command/auto.lux b/stdlib/source/program/aedifex/command/auto.lux
new file mode 100644
index 000000000..5bf759a06
--- /dev/null
+++ b/stdlib/source/program/aedifex/command/auto.lux
@@ -0,0 +1,141 @@
+(.module:
+ [lux #*
+ ["." host (#+ import:)]
+ [abstract
+ ["." monad (#+ do)]]
+ [control
+ ["." try (#+ Try)]
+ ["." io (#+ IO)]
+ [concurrency
+ ["." promise]]]
+ [data
+ [collection
+ ["." array]
+ ["." list]]]
+ [world
+ [file (#+ Path)]]]
+ ["." // #_
+ ["/#" // #_
+ ["#" project]
+ ["#." action (#+ Action)]
+ ["#." command (#+ Command)]]])
+
+(import: #long java/nio/file/WatchKey
+ (reset [] #io boolean))
+
+(import: #long java/util/concurrent/TimeUnit
+ (#enum SECONDS))
+
+(import: #long java/nio/file/WatchService
+ (poll [long java/util/concurrent/TimeUnit] #io #try #? java/nio/file/WatchKey)
+ (poll #as fetch [] #io #try #? java/nio/file/WatchKey))
+
+(import: #long java/nio/file/FileSystem
+ (newWatchService [] #io #try java/nio/file/WatchService))
+
+(import: #long java/nio/file/FileSystems
+ (#static getDefault [] java/nio/file/FileSystem))
+
+(import: #long java/lang/Object)
+
+(import: #long java/lang/String)
+
+(import: #long (java/nio/file/WatchEvent$Kind a))
+
+(import: #long java/nio/file/StandardWatchEventKinds
+ (#static ENTRY_CREATE (java/nio/file/WatchEvent$Kind java/nio/file/Path))
+ (#static ENTRY_MODIFY (java/nio/file/WatchEvent$Kind java/nio/file/Path))
+ (#static ENTRY_DELETE (java/nio/file/WatchEvent$Kind java/nio/file/Path)))
+
+(import: #long java/nio/file/Path
+ (register [java/nio/file/WatchService [(java/nio/file/WatchEvent$Kind ?)]] #io #try java/nio/file/WatchKey))
+
+(import: #long java/io/File
+ (new [java/lang/String])
+ (exists [] #io #try boolean)
+ (isDirectory [] #io #try boolean)
+ (listFiles [] #io #try [java/io/File])
+ (getAbsolutePath [] #io #try java/lang/String)
+ (toPath [] java/nio/file/Path))
+
+(def: (targets path)
+ (-> Path (Action (List Path)))
+ (promise.future
+ (loop [path path]
+ (let [file (java/io/File::new path)]
+ (do {@ (try.with io.monad)}
+ [exists? (java/io/File::exists file)
+ directory? (java/io/File::isDirectory file)]
+ (if (and exists?
+ directory?)
+ (do @
+ [children (java/io/File::listFiles file)
+ children (|> children
+ array.to-list
+ (monad.map @ (|>> java/io/File::getAbsolutePath)))
+ descendants (monad.map @ recur children)]
+ (wrap (#.Cons path (list.concat descendants))))
+ (wrap (list))))))))
+
+(type: Watch-Event
+ (java/nio/file/WatchEvent$Kind java/lang/Object))
+
+(def: watch-events
+ (List Watch-Event)
+ (list (:coerce Watch-Event (java/nio/file/StandardWatchEventKinds::ENTRY_CREATE))
+ (:coerce Watch-Event (java/nio/file/StandardWatchEventKinds::ENTRY_MODIFY))
+ (:coerce Watch-Event (java/nio/file/StandardWatchEventKinds::ENTRY_DELETE))))
+
+(def: (watch! watcher path)
+ (-> java/nio/file/WatchService Path (Action Any))
+ (promise.future
+ (do (try.with io.monad)
+ [_ (java/nio/file/Path::register watcher
+ (array.from-list ..watch-events)
+ (|> path java/io/File::new java/io/File::toPath))]
+ (wrap []))))
+
+(def: (poll! watcher)
+ (-> java/nio/file/WatchService (Action (Maybe java/nio/file/WatchKey)))
+ (promise.future
+ (java/nio/file/WatchService::poll 1 java/util/concurrent/TimeUnit::SECONDS watcher)))
+
+(def: (drain! watcher)
+ (-> java/nio/file/WatchService (IO (Try Any)))
+ (do (try.with io.monad)
+ [?key (java/nio/file/WatchService::fetch watcher)]
+ (case ?key
+ (#.Some key)
+ (do io.monad
+ [valid? (java/nio/file/WatchKey::reset key)]
+ (if valid?
+ (drain! watcher)
+ (wrap (:: try.monad wrap []))))
+
+ #.None
+ (wrap []))))
+
+(def: #export (do! command project)
+ (All [a] (-> (Command a) (Command Any)))
+ (do {@ ///action.monad}
+ [#let [fs (java/nio/file/FileSystems::getDefault)]
+ watcher (promise.future (java/nio/file/FileSystem::newWatchService fs))
+ targets (|> project
+ (get@ #///.sources)
+ (monad.map @ ..targets)
+ (:: @ map list.concat))
+ _ (monad.map @ (..watch! watcher) targets)
+ _ (command project)]
+ (loop [_ []]
+ (do @
+ [?key (..poll! watcher)
+ _ (case ?key
+ (#.Some key)
+ (do @
+ [_ (promise.future (..drain! watcher))
+ _ (command project)]
+ (wrap []))
+
+ #.None
+ (wrap []))]
+ (recur [])))))
diff --git a/stdlib/source/program/aedifex/command/build.lux b/stdlib/source/program/aedifex/command/build.lux
new file mode 100644
index 000000000..0e5d1e229
--- /dev/null
+++ b/stdlib/source/program/aedifex/command/build.lux
@@ -0,0 +1,146 @@
+(.module:
+ [lux (#- Name)
+ ["." host (#+ import:)]
+ [abstract
+ [monad (#+ do)]]
+ [control
+ ["." try (#+ Try)]
+ ["." exception (#+ exception:)]
+ ["." io (#+ IO)]
+ [concurrency
+ ["." promise ("#@." monad)]]]
+ [data
+ ["." product]
+ ["." maybe]
+ ["." text ("#@." equivalence)
+ ["%" format (#+ format)]]
+ [collection
+ ["." list ("#@." functor)]
+ ["." dictionary]]]
+ [world
+ ["." file (#+ Path)]]]
+ ["." /// #_
+ ["#" project]
+ ["#." action]
+ ["#." command (#+ Command)]
+ ["#." local]
+ ["#." artifact (#+ Group Name Artifact)]
+ ["#." dependency (#+ Dependency Resolution)]
+ ["#." shell]])
+
+(type: Finder
+ (-> Resolution (Maybe Dependency)))
+
+(def: (dependency-finder group name)
+ (-> Group Name Finder)
+ (|>> dictionary.entries
+ (list.search (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: lux-group
+ Group
+ "com.github.luxlang")
+
+(template [<name> <finder>]
+ [(def: <finder>
+ Finder
+ (..dependency-finder ..lux-group <name>))]
+
+ ["lux-jvm" jvm-compiler]
+ ["lux-js" js-compiler]
+ )
+
+(exception: #export no-available-compiler)
+(exception: #export no-specified-program)
+
+(type: #export Compiler
+ (#JVM Artifact)
+ (#JS Artifact))
+
+(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 (get@ #///dependency.artifact dependency))])
+
+ [_ (#.Some dependency)]
+ (#try.Success [(..remove-dependency dependency resolution)
+ (#JS (get@ #///dependency.artifact dependency))])
+
+ _
+ (exception.throw ..no-available-compiler [])))
+
+(def: libraries
+ (-> Resolution (List Path))
+ (|>> dictionary.keys
+ (list.filter (|>> (get@ #///dependency.type) (text@= ///dependency.lux-library)))
+ (list@map (|>> (get@ #///dependency.artifact) (///local.path file.system)))))
+
+(import: #long java/lang/String)
+
+## https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
+(import: #long java/lang/System
+ (#static getProperty [java/lang/String] #io #? java/lang/String))
+
+(def: #export working-directory
+ (IO (Try Text))
+ (do io.monad
+ [?value (java/lang/System::getProperty "user.dir")]
+ (wrap (#try.Success (maybe.default "~" ?value)))))
+
+(def: (singular-parameter name value)
+ (-> Text Text Text)
+ (format name " " value))
+
+(def: (plural-parameter name values)
+ (-> Text (List Text) Text)
+ (|> values (list@map (|>> (format name " "))) (text.join-with " ")))
+
+(def: #export (do! project)
+ (Command [Compiler
+ Path])
+ (case (get@ #///.program project)
+ (#.Some program)
+ (do ///action.monad
+ [cache (///local.all-cached (file.async file.system)
+ (get@ #///.dependencies project)
+ ///dependency.empty)
+ resolution (promise.future
+ (///dependency.resolve-all (get@ #///.repositories project)
+ (get@ #///.dependencies project)
+ cache))
+ _ (///local.cache-all (file.async file.system)
+ resolution)
+ [resolution compiler] (promise@wrap (..compiler resolution))
+ working-directory (promise.future ..working-directory)
+ #let [libraries (..libraries resolution)
+ [prefix output] (case compiler
+ (#JVM artifact) [(format "java -jar " (///local.path file.system artifact))
+ "program.jar"]
+ (#JS artifact) [(format "node --stack_size=8192 " (///local.path file.system artifact))
+ "program.js"])
+ cache-directory (format working-directory (:: file.system separator) (get@ #///.target project))
+ command (format prefix " build"
+ " " (..plural-parameter "--library" libraries)
+ " " (..plural-parameter "--source" (get@ #///.sources project))
+ " " (..singular-parameter "--target" cache-directory)
+ " " (..singular-parameter "--module" program))]
+ #let [_ (log! "[BUILD STARTED]")]
+ outcome (///shell.execute command working-directory)
+ #let [_ (log! "[BUILD ENDED]")]]
+ (wrap [compiler
+ (format cache-directory (:: file.system separator) output)]))
+
+ #.None
+ (promise@wrap (exception.throw ..no-specified-program []))))
diff --git a/stdlib/source/program/aedifex/command/test.lux b/stdlib/source/program/aedifex/command/test.lux
new file mode 100644
index 000000000..a27c07f10
--- /dev/null
+++ b/stdlib/source/program/aedifex/command/test.lux
@@ -0,0 +1,29 @@
+(.module:
+ [lux (#- Name)
+ [abstract
+ [monad (#+ do)]]
+ [control
+ [concurrency
+ ["." promise]]]
+ [data
+ [text
+ ["%" format (#+ format)]]]]
+ ["." // #_
+ ["#." build]
+ ["/#" // #_
+ ["#." action]
+ ["#." command (#+ Command)]
+ ["#." shell]]])
+
+(def: #export (do! project)
+ (Command Any)
+ (do ///action.monad
+ [[compiler program] (//build.do! project)
+ working-directory (promise.future //build.working-directory)
+ #let [command (case compiler
+ (#//build.JVM artifact) (format "java -jar " program)
+ (#//build.JS artifact) (format "node --stack_size=8192 " program))]
+ #let [_ (log! "[TEST STARTED]")]
+ outcome (///shell.execute command working-directory)
+ #let [_ (log! "[TEST ENDED]")]]
+ (wrap [])))