diff options
Diffstat (limited to 'stdlib/source/library/lux/world/file.lux')
-rw-r--r-- | stdlib/source/library/lux/world/file.lux | 1308 |
1 files changed, 654 insertions, 654 deletions
diff --git a/stdlib/source/library/lux/world/file.lux b/stdlib/source/library/lux/world/file.lux index c2e799be8..63fa2e88b 100644 --- a/stdlib/source/library/lux/world/file.lux +++ b/stdlib/source/library/lux/world/file.lux @@ -25,8 +25,8 @@ ["[0]" list ("[1]#[0]" functor)] ["[0]" dictionary {"+" Dictionary}]]] ["[0]" ffi - (~~ (.for ["JavaScript" (~~ (.as_is ["[0]" node_js])) - "{old}" (~~ (.as_is ["node_js" //control/thread]))] + (~~ (.for "JavaScript" (~~ (.as_is ["[0]" node_js])) + "{old}" (~~ (.as_is ["node_js" //control/thread])) (~~ (.as_is))))] [macro ["[0]" template]] @@ -298,662 +298,662 @@ java/io/File::new (java/io/File::renameTo (java/io/File::new (ffi.as_string destination))))) )))] - (for [@.old (as_is <for_jvm>) - @.jvm (as_is <for_jvm>) - - @.js - (as_is (ffi.import: Buffer - "[1]::[0]" - ("static" from [Binary] ..Buffer)) - - (ffi.import: FileDescriptor - "[1]::[0]") - - (ffi.import: Stats - "[1]::[0]" - (size ffi.Number) - (mtimeMs ffi.Number) - (isFile [] ffi.Boolean) - (isDirectory [] ffi.Boolean)) - - (ffi.import: FsConstants - "[1]::[0]" - (F_OK ffi.Number) - (R_OK ffi.Number) - (W_OK ffi.Number) - (X_OK ffi.Number)) - - (ffi.import: Error - "[1]::[0]" - (toString [] ffi.String)) - - (template: (with_async <write> <type> <body>) - [(template.with_locals [<read>] - (let [[<read> <write>] (: [(Async <type>) (async.Resolver <type>)] - (async.async []))] - (exec - <body> - <read>)))]) - - (ffi.import: Fs - "[1]::[0]" - (constants FsConstants) - (readFile [ffi.String ffi.Function] Any) - (appendFile [ffi.String Buffer ffi.Function] Any) - (writeFile [ffi.String Buffer ffi.Function] Any) - (stat [ffi.String ffi.Function] Any) - (access [ffi.String ffi.Number ffi.Function] Any) - (rename [ffi.String ffi.String ffi.Function] Any) - (utimes [ffi.String ffi.Number ffi.Number ffi.Function] Any) - (readdir [ffi.String ffi.Function] Any) - (mkdir [ffi.String ffi.Function] Any) - (unlink [ffi.String ffi.Function] Any) - (rmdir [ffi.String ffi.Function] Any)) - - (def: (any_callback write!) - (-> (async.Resolver (Try Any)) ffi.Function) - (<| (ffi.function (_ [error Error]) Any) - io.run! - write! - (if (ffi.null? error) - {try.#Success []} - {try.#Failure (Error::toString error)}))) - - (def: (value_callback write!) - (All (_ a) (-> (async.Resolver (Try a)) ffi.Function)) - (<| (ffi.function (_ [error Error datum Any]) Any) - io.run! - write! - (if (ffi.null? error) - {try.#Success (:expected datum)} - {try.#Failure (Error::toString error)}))) - - (ffi.import: JsPath - "[1]::[0]" - (sep ffi.String)) - - (def: .public default - (Maybe (System Async)) - (do maybe.monad - [node_fs (node_js.require "fs") - node_path (node_js.require "path") - .let [node_fs (:as ..Fs node_fs) - js_separator (if ffi.on_node_js? - (JsPath::sep (:as ..JsPath node_path)) - "/")]] - (in (: (System Async) - (`` (implementation - (def: separator - js_separator) - - (~~ (template [<name> <method>] - [(def: (<name> path) - (do async.monad - [?stats (with_async write! (Try Stats) - (Fs::stat path (..value_callback write!) - node_fs))] - (in (case ?stats - {try.#Success stats} - (<method> stats) - - {try.#Failure _} - false))))] - - [file? Stats::isFile] - [directory? Stats::isDirectory] - )) - - (def: (make_directory path) - (do async.monad - [outcome (with_async write! (Try Any) - (Fs::access path - (|> node_fs Fs::constants FsConstants::F_OK) - (..any_callback write!) - node_fs))] - (case outcome - {try.#Success _} - (in (exception.except ..cannot_make_directory [path])) - - {try.#Failure _} - (with_async write! (Try Any) - (Fs::mkdir path (..any_callback write!) node_fs))))) - - (~~ (template [<name> <method>] - [(def: (<name> path) - (do [! (try.with async.monad)] - [subs (with_async write! (Try (Array ffi.String)) - (Fs::readdir path (..value_callback write!) node_fs))] - (|> subs - (array.list {.#None}) - (list#each (|>> (format path js_separator))) - (monad.each ! (function (_ sub) - (# ! each (|>> <method> [sub]) - (with_async write! (Try Stats) - (Fs::stat sub (..value_callback write!) node_fs))))) - (# ! each (|>> (list.only product.right) - (list#each product.left))))))] - - [directory_files Stats::isFile] - [sub_directories Stats::isDirectory] - )) - - (def: (file_size path) - (do (try.with async.monad) - [stats (with_async write! (Try Stats) - (Fs::stat path (..value_callback write!) - node_fs))] - (in (|> stats - Stats::size - f.nat)))) - - (def: (last_modified path) - (do (try.with async.monad) - [stats (with_async write! (Try Stats) - (Fs::stat path (..value_callback write!) - node_fs))] - (in (|> stats - Stats::mtimeMs - f.int - duration.of_millis - instant.absolute)))) - - (def: (can_execute? path) - (# async.monad each - (|>> (case> {try.#Success _} - true - - {try.#Failure _} - false) - {try.#Success}) + (for @.old (as_is <for_jvm>) + @.jvm (as_is <for_jvm>) + + @.js + (as_is (ffi.import: Buffer + "[1]::[0]" + ("static" from [Binary] ..Buffer)) + + (ffi.import: FileDescriptor + "[1]::[0]") + + (ffi.import: Stats + "[1]::[0]" + (size ffi.Number) + (mtimeMs ffi.Number) + (isFile [] ffi.Boolean) + (isDirectory [] ffi.Boolean)) + + (ffi.import: FsConstants + "[1]::[0]" + (F_OK ffi.Number) + (R_OK ffi.Number) + (W_OK ffi.Number) + (X_OK ffi.Number)) + + (ffi.import: Error + "[1]::[0]" + (toString [] ffi.String)) + + (template: (with_async <write> <type> <body>) + [(template.with_locals [<read>] + (let [[<read> <write>] (: [(Async <type>) (async.Resolver <type>)] + (async.async []))] + (exec + <body> + <read>)))]) + + (ffi.import: Fs + "[1]::[0]" + (constants FsConstants) + (readFile [ffi.String ffi.Function] Any) + (appendFile [ffi.String Buffer ffi.Function] Any) + (writeFile [ffi.String Buffer ffi.Function] Any) + (stat [ffi.String ffi.Function] Any) + (access [ffi.String ffi.Number ffi.Function] Any) + (rename [ffi.String ffi.String ffi.Function] Any) + (utimes [ffi.String ffi.Number ffi.Number ffi.Function] Any) + (readdir [ffi.String ffi.Function] Any) + (mkdir [ffi.String ffi.Function] Any) + (unlink [ffi.String ffi.Function] Any) + (rmdir [ffi.String ffi.Function] Any)) + + (def: (any_callback write!) + (-> (async.Resolver (Try Any)) ffi.Function) + (<| (ffi.function (_ [error Error]) Any) + io.run! + write! + (if (ffi.null? error) + {try.#Success []} + {try.#Failure (Error::toString error)}))) + + (def: (value_callback write!) + (All (_ a) (-> (async.Resolver (Try a)) ffi.Function)) + (<| (ffi.function (_ [error Error datum Any]) Any) + io.run! + write! + (if (ffi.null? error) + {try.#Success (:expected datum)} + {try.#Failure (Error::toString error)}))) + + (ffi.import: JsPath + "[1]::[0]" + (sep ffi.String)) + + (def: .public default + (Maybe (System Async)) + (do maybe.monad + [node_fs (node_js.require "fs") + node_path (node_js.require "path") + .let [node_fs (:as ..Fs node_fs) + js_separator (if ffi.on_node_js? + (JsPath::sep (:as ..JsPath node_path)) + "/")]] + (in (: (System Async) + (`` (implementation + (def: separator + js_separator) + + (~~ (template [<name> <method>] + [(def: (<name> path) + (do async.monad + [?stats (with_async write! (Try Stats) + (Fs::stat path (..value_callback write!) + node_fs))] + (in (case ?stats + {try.#Success stats} + (<method> stats) + + {try.#Failure _} + false))))] + + [file? Stats::isFile] + [directory? Stats::isDirectory] + )) + + (def: (make_directory path) + (do async.monad + [outcome (with_async write! (Try Any) + (Fs::access path + (|> node_fs Fs::constants FsConstants::F_OK) + (..any_callback write!) + node_fs))] + (case outcome + {try.#Success _} + (in (exception.except ..cannot_make_directory [path])) + + {try.#Failure _} (with_async write! (Try Any) - (Fs::access path - (|> node_fs Fs::constants FsConstants::X_OK) - (..any_callback write!) - node_fs)))) - - (def: (read path) - (with_async write! (Try Binary) - (Fs::readFile path (..value_callback write!) - node_fs))) - - (def: (delete path) - (do (try.with async.monad) - [stats (with_async write! (Try Stats) - (Fs::stat path (..value_callback write!) node_fs))] + (Fs::mkdir path (..any_callback write!) node_fs))))) + + (~~ (template [<name> <method>] + [(def: (<name> path) + (do [! (try.with async.monad)] + [subs (with_async write! (Try (Array ffi.String)) + (Fs::readdir path (..value_callback write!) node_fs))] + (|> subs + (array.list {.#None}) + (list#each (|>> (format path js_separator))) + (monad.each ! (function (_ sub) + (# ! each (|>> <method> [sub]) + (with_async write! (Try Stats) + (Fs::stat sub (..value_callback write!) node_fs))))) + (# ! each (|>> (list.only product.right) + (list#each product.left))))))] + + [directory_files Stats::isFile] + [sub_directories Stats::isDirectory] + )) + + (def: (file_size path) + (do (try.with async.monad) + [stats (with_async write! (Try Stats) + (Fs::stat path (..value_callback write!) + node_fs))] + (in (|> stats + Stats::size + f.nat)))) + + (def: (last_modified path) + (do (try.with async.monad) + [stats (with_async write! (Try Stats) + (Fs::stat path (..value_callback write!) + node_fs))] + (in (|> stats + Stats::mtimeMs + f.int + duration.of_millis + instant.absolute)))) + + (def: (can_execute? path) + (# async.monad each + (|>> (case> {try.#Success _} + true + + {try.#Failure _} + false) + {try.#Success}) (with_async write! (Try Any) - (if (Stats::isFile stats) - (Fs::unlink path (..any_callback write!) node_fs) - (Fs::rmdir path (..any_callback write!) node_fs))))) - - (def: (modify time_stamp path) - (with_async write! (Try Any) - (let [when (|> time_stamp instant.relative duration.millis i.frac)] - (Fs::utimes path when when (..any_callback write!) + (Fs::access path + (|> node_fs Fs::constants FsConstants::X_OK) + (..any_callback write!) node_fs)))) - (~~ (template [<name> <method>] - [(def: (<name> data path) - (with_async write! (Try Any) - (<method> path (Buffer::from data) (..any_callback write!) - node_fs)))] - - [write Fs::writeFile] - [append Fs::appendFile] - )) - - (def: (move destination origin) - (with_async write! (Try Any) - (Fs::rename origin destination (..any_callback write!) - node_fs)))))))))) - - @.python - (as_is (type: (Tuple/2 left right) - (Primitive "python_tuple[2]" [left right])) - - (ffi.import: PyFile - "[1]::[0]" - (read [] "io" "try" Binary) - (write [Binary] "io" "try" "?" Any) - (close [] "io" "try" "?" Any)) - - (ffi.import: (open [ffi.String ffi.String] "io" "try" PyFile)) - (ffi.import: (tuple [[ffi.Integer ffi.Integer]] (Tuple/2 ffi.Integer ffi.Integer))) - - (ffi.import: os - "[1]::[0]" - ("static" F_OK ffi.Integer) - ("static" R_OK ffi.Integer) - ("static" W_OK ffi.Integer) - ("static" X_OK ffi.Integer) - - ("static" mkdir [ffi.String] "io" "try" "?" Any) - ("static" access [ffi.String ffi.Integer] "io" "try" ffi.Boolean) - ("static" remove [ffi.String] "io" "try" "?" Any) - ("static" rmdir [ffi.String] "io" "try" "?" Any) - ("static" rename [ffi.String ffi.String] "io" "try" "?" Any) - ("static" utime [ffi.String (Tuple/2 ffi.Integer ffi.Integer)] "io" "try" "?" Any) - ("static" listdir [ffi.String] "io" "try" (Array ffi.String))) - - (ffi.import: os/path - "[1]::[0]" - ("static" isfile [ffi.String] "io" "try" ffi.Boolean) - ("static" isdir [ffi.String] "io" "try" ffi.Boolean) - ("static" sep ffi.String) - ("static" getsize [ffi.String] "io" "try" ffi.Integer) - ("static" getmtime [ffi.String] "io" "try" ffi.Float)) - - (def: python_separator - (os/path::sep)) - - (`` (implementation: .public default - (System IO) - - (def: separator - ..python_separator) - - (~~ (template [<name> <method>] - [(def: <name> - (|>> <method> - (io#each (|>> (try.else false)))))] - - [file? os/path::isfile] - [directory? os/path::isdir] - )) - - (def: make_directory - os::mkdir) - - (~~ (template [<name> <method>] - [(def: (<name> path) - (let [! (try.with io.monad)] - (|> path - os::listdir - (# ! each (|>> (array.list {.#None}) - (list#each (|>> (format path ..python_separator))) - (monad.each ! (function (_ sub) - (# ! each (|>> [sub]) (<method> sub)))) - (# ! each (|>> (list.only product.right) - (list#each product.left))))) - (# ! conjoint))))] - - [directory_files os/path::isfile] - [sub_directories os/path::isdir] - )) - - (def: file_size - (|>> os/path::getsize - (# (try.with io.monad) each (|>> .nat)))) - - (def: last_modified - (|>> os/path::getmtime - (# (try.with io.monad) each (|>> f.int - (i.* +1,000) - duration.of_millis - instant.absolute)))) - - (def: (can_execute? path) - (os::access path (os::X_OK))) - - (def: (read path) - (do (try.with io.monad) - [file (..open path "rb") - data (PyFile::read file) - _ (PyFile::close file)] - (in data))) - - (def: (delete path) - (do (try.with io.monad) - [? (os/path::isfile path)] - (if ? - (os::remove path) - (os::rmdir path)))) - - (def: (modify time_stamp path) - (let [when (|> time_stamp instant.relative duration.millis (i./ +1,000))] - (os::utime path (..tuple [when when])))) - - (~~ (template [<name> <mode>] - [(def: (<name> data path) - (do (try.with io.monad) - [file (..open path <mode>) - _ (PyFile::write data file)] - (PyFile::close file)))] - - [write "w+b"] - [append "ab"] - )) - - (def: (move destination origin) - (os::rename origin destination)) - ))) - - @.ruby - (as_is (ffi.import: Time - "[1]::[0]" - ("static" at [Frac] Time) - (to_f [] Frac)) - - (ffi.import: Stat - "[1]::[0]" - (executable? [] Bit) - (size Int) - (mtime [] Time)) - - (ffi.import: File "as" RubyFile - "[1]::[0]" - ("static" SEPARATOR ffi.String) - ("static" open [Path ffi.String] "io" "try" RubyFile) - ("static" stat [Path] "io" "try" Stat) - ("static" delete [Path] "io" "try" Int) - ("static" file? [Path] "io" "try" Bit) - ("static" directory? [Path] "io" "try" Bit) - ("static" utime [Time Time Path] "io" "try" Int) - - (read [] "io" "try" Binary) - (write [Binary] "io" "try" Int) - (flush [] "io" "try" "?" Any) - (close [] "io" "try" "?" Any)) - - (ffi.import: Dir - "[1]::[0]" - ("static" open [Path] "io" "try" Dir) - - (children [] "io" "try" (Array Path)) - (close [] "io" "try" "?" Any)) - - (ffi.import: "fileutils" FileUtils - "[1]::[0]" - ("static" move [Path Path] "io" "try" "?" Any) - ("static" rmdir [Path] "io" "try" "?" Any) - ("static" mkdir [Path] "io" "try" "?" Any)) - - (def: ruby_separator - Text - (..RubyFile::SEPARATOR)) - - (`` (implementation: .public default - (System IO) - - (def: separator - ..ruby_separator) - - (~~ (template [<name> <test>] - [(def: <name> - (|>> <test> - (io#each (|>> (try.else false)))))] - - [file? RubyFile::file?] - [directory? RubyFile::directory?] - )) - - (def: make_directory - FileUtils::mkdir) - - (~~ (template [<name> <test>] - [(def: (<name> path) - (do [! (try.with io.monad)] - [self (Dir::open path) - children (Dir::children self) - output (loop [input (|> children - (array.list {.#None}) - (list#each (|>> (format path ..ruby_separator)))) - output (: (List ..Path) - (list))] - (case input - {.#End} - (in output) - - {.#Item head tail} - (do ! - [verdict (<test> head)] - (again tail (if verdict - {.#Item head output} - output))))) - _ (Dir::close self)] - (in output)))] - - [directory_files RubyFile::file?] - [sub_directories RubyFile::directory?] - )) - - (~~ (template [<name> <pipeline>] - [(def: <name> - (let [! (try.with io.monad)] - (|>> RubyFile::stat - (# ! each (`` (|>> (~~ (template.spliced <pipeline>))))))))] - - [file_size [Stat::size .nat]] - [last_modified [Stat::mtime - Time::to_f - (f.* +1,000.0) - f.int - duration.of_millis - instant.absolute]] - [can_execute? [Stat::executable?]] - )) - - (def: (read path) - (do (try.with io.monad) - [file (RubyFile::open path "rb") - data (RubyFile::read file) - _ (RubyFile::close file)] - (in data))) - - (def: (delete path) - (do (try.with io.monad) - [? (RubyFile::file? path)] - (if ? - (RubyFile::delete path) - (FileUtils::rmdir path)))) - - (def: (modify moment path) - (let [moment (|> moment - instant.relative - duration.millis - i.frac - (f./ +1,000.0) - Time::at)] - (RubyFile::utime moment moment path))) - - (~~ (template [<mode> <name>] - [(def: (<name> data path) - (do [! (try.with io.monad)] - [file (RubyFile::open path <mode>) - data (RubyFile::write data file) - _ (RubyFile::flush file) - _ (RubyFile::close file)] - (in [])))] - - ["wb" write] - ["ab" append] - )) - - (def: (move destination origin) - (do (try.with io.monad) - [_ (FileUtils::move origin destination)] - (in []))) - ))) - - ... @.php - ... (as_is (ffi.import: (FILE_APPEND Int)) - ... ... https://www.php.net/manual/en/dir.constants.php - ... (ffi.import: (DIRECTORY_SEPARATOR ffi.String)) - ... ... https://www.php.net/manual/en/function.pack.php - ... ... https://www.php.net/manual/en/function.unpack.php - ... (ffi.import: (unpack [ffi.String ffi.String] Binary)) - ... ... https://www.php.net/manual/en/ref.filesystem.php - ... ... https://www.php.net/manual/en/function.file-get-contents.php - ... (ffi.import: (file_get_contents [Path] "io" "try" ffi.String)) - ... ... https://www.php.net/manual/en/function.file-put-contents.php - ... (ffi.import: (file_put_contents [Path ffi.String Int] "io" "try" ffi.Integer)) - ... (ffi.import: (filemtime [Path] "io" "try" ffi.Integer)) - ... (ffi.import: (filesize [Path] "io" "try" ffi.Integer)) - ... (ffi.import: (is_executable [Path] "io" "try" ffi.Boolean)) - ... (ffi.import: (touch [Path ffi.Integer] "io" "try" ffi.Boolean)) - ... (ffi.import: (rename [Path Path] "io" "try" ffi.Boolean)) - ... (ffi.import: (unlink [Path] "io" "try" ffi.Boolean)) - - ... ... https://www.php.net/manual/en/function.rmdir.php - ... (ffi.import: (rmdir [Path] "io" "try" ffi.Boolean)) - ... ... https://www.php.net/manual/en/function.scandir.php - ... (ffi.import: (scandir [Path] "io" "try" (Array Path))) - ... ... https://www.php.net/manual/en/function.is-file.php - ... (ffi.import: (is_file [Path] "io" "try" ffi.Boolean)) - ... ... https://www.php.net/manual/en/function.is-dir.php - ... (ffi.import: (is_dir [Path] "io" "try" ffi.Boolean)) - ... ... https://www.php.net/manual/en/function.mkdir.php - ... (ffi.import: (mkdir [Path] "io" "try" ffi.Boolean)) - - ... (def: byte_array_format "C*") - ... (def: default_separator (..DIRECTORY_SEPARATOR)) - - ... (template [<name>] - ... [(exception: .public (<name> [file Path]) - ... (exception.report - ... ["Path" file]))] - - ... [cannot_write_to_file] - ... ) - - ... (`` (implementation: (file path) - ... (-> Path (File IO)) - - ... (~~ (template [<name> <mode>] - ... [(def: (<name> data) - ... (do [! (try.with io.monad)] - ... [outcome (..file_put_contents [path ("php pack" ..byte_array_format data) <mode>])] - ... (if (bit#= false (:as Bit outcome)) - ... (# io.monad in (exception.except ..cannot_write_to_file [path])) - ... (in []))))] - - ... [over_write +0] - ... [append (..FILE_APPEND)] - ... )) - - ... (def: (content _) - ... (do [! (try.with io.monad)] - ... [data (..file_get_contents [path])] - ... (if (bit#= false (:as Bit data)) - ... (# io.monad in (exception.except ..cannot_find_file [path])) - ... (in (..unpack [..byte_array_format data]))))) - - ... (def: path - ... path) - - ... (~~ (template [<name> <ffi> <pipeline>] - ... [(def: (<name> _) - ... (do [! (try.with io.monad)] - ... [value (<ffi> [path])] - ... (if (bit#= false (:as Bit value)) - ... (# io.monad in (exception.except ..cannot_find_file [path])) - ... (in (`` (|> value (~~ (template.spliced <pipeline>))))))))] - - ... [size ..filesize [.nat]] - ... [last_modified ..filemtime [(i.* +1,000) duration.of_millis instant.absolute]] - ... )) - - ... (def: (can_execute? _) - ... (..is_executable [path])) - - ... (def: (modify moment) - ... (do [! (try.with io.monad)] - ... [verdict (..touch [path (|> moment instant.relative duration.millis (i./ +1,000))])] - ... (if (bit#= false (:as Bit verdict)) - ... (# io.monad in (exception.except ..cannot_find_file [path])) - ... (in [])))) - - ... (def: (move destination) - ... (do [! (try.with io.monad)] - ... [verdict (..rename [path destination])] - ... (if (bit#= false (:as Bit verdict)) - ... (# io.monad in (exception.except ..cannot_find_file [path])) - ... (in (file destination))))) - - ... (def: (delete _) - ... (do (try.with io.monad) - ... [verdict (..unlink [path])] - ... (if (bit#= false (:as Bit verdict)) - ... (# io.monad in (exception.except ..cannot_find_file [path])) - ... (in [])))) - ... )) - - ... (`` (implementation: (directory path) - ... (-> Path (Directory IO)) - - ... (def: scope - ... path) - - ... (~~ (template [<name> <test> <constructor> <capability>] - ... [(def: (<name> _) - ... (do [! (try.with io.monad)] - ... [children (..scandir [path])] - ... (loop [input (|> children - ... (array.list {.#None}) - ... (list.only (function (_ child) - ... (not (or (text#= "." child) - ... (text#= ".." child)))))) - ... output (: (List (<capability> IO)) - ... (list))] - ... (case input - ... {.#End} - ... (in output) - - ... {.#Item head tail} - ... (do ! - ... [verdict (<test> head)] - ... (if verdict - ... (again tail {.#Item (<constructor> head) output}) - ... (again tail output)))))))] - - ... [files ..is_file ..file File] - ... [directories ..is_dir directory Directory] - ... )) - - ... (def: (discard _) - ... (do (try.with io.monad) - ... [verdict (..rmdir [path])] - ... (if (bit#= false (:as Bit verdict)) - ... (# io.monad in (exception.except ..cannot_find_directory [path])) - ... (in [])))) - ... )) - - ... (`` (implementation: .public default - ... (System IO) - - ... (~~ (template [<name> <test> <constructor> <exception>] - ... [(def: (<name> path) - ... (do [! (try.with io.monad)] - ... [verdict (<test> path)] - ... (# io.monad in - ... (if verdict - ... {try.#Success (<constructor> path)} - ... (exception.except <exception> [path])))))] - - ... [file ..is_file ..file ..cannot_find_file] - ... [directory ..is_dir ..directory ..cannot_find_directory] - ... )) - - ... (def: (make_file path) - ... (do [! (try.with io.monad)] - ... [verdict (..touch [path (|> instant.now io.run! instant.relative duration.millis (i./ +1,000))])] - ... (# io.monad in - ... (if verdict - ... {try.#Success (..file path)} - ... (exception.except ..cannot_make_file [path]))))) - - ... (def: (make_directory path) - ... (do [! (try.with io.monad)] - ... [verdict (..mkdir path)] - ... (# io.monad in - ... (if verdict - ... {try.#Success (..directory path)} - ... (exception.except ..cannot_make_directory [path]))))) - - ... (def: separator - ... ..default_separator) - ... )) - ... ) - ] + (def: (read path) + (with_async write! (Try Binary) + (Fs::readFile path (..value_callback write!) + node_fs))) + + (def: (delete path) + (do (try.with async.monad) + [stats (with_async write! (Try Stats) + (Fs::stat path (..value_callback write!) node_fs))] + (with_async write! (Try Any) + (if (Stats::isFile stats) + (Fs::unlink path (..any_callback write!) node_fs) + (Fs::rmdir path (..any_callback write!) node_fs))))) + + (def: (modify time_stamp path) + (with_async write! (Try Any) + (let [when (|> time_stamp instant.relative duration.millis i.frac)] + (Fs::utimes path when when (..any_callback write!) + node_fs)))) + + (~~ (template [<name> <method>] + [(def: (<name> data path) + (with_async write! (Try Any) + (<method> path (Buffer::from data) (..any_callback write!) + node_fs)))] + + [write Fs::writeFile] + [append Fs::appendFile] + )) + + (def: (move destination origin) + (with_async write! (Try Any) + (Fs::rename origin destination (..any_callback write!) + node_fs)))))))))) + + @.python + (as_is (type: (Tuple/2 left right) + (Primitive "python_tuple[2]" [left right])) + + (ffi.import: PyFile + "[1]::[0]" + (read [] "io" "try" Binary) + (write [Binary] "io" "try" "?" Any) + (close [] "io" "try" "?" Any)) + + (ffi.import: (open [ffi.String ffi.String] "io" "try" PyFile)) + (ffi.import: (tuple [[ffi.Integer ffi.Integer]] (Tuple/2 ffi.Integer ffi.Integer))) + + (ffi.import: os + "[1]::[0]" + ("static" F_OK ffi.Integer) + ("static" R_OK ffi.Integer) + ("static" W_OK ffi.Integer) + ("static" X_OK ffi.Integer) + + ("static" mkdir [ffi.String] "io" "try" "?" Any) + ("static" access [ffi.String ffi.Integer] "io" "try" ffi.Boolean) + ("static" remove [ffi.String] "io" "try" "?" Any) + ("static" rmdir [ffi.String] "io" "try" "?" Any) + ("static" rename [ffi.String ffi.String] "io" "try" "?" Any) + ("static" utime [ffi.String (Tuple/2 ffi.Integer ffi.Integer)] "io" "try" "?" Any) + ("static" listdir [ffi.String] "io" "try" (Array ffi.String))) + + (ffi.import: os/path + "[1]::[0]" + ("static" isfile [ffi.String] "io" "try" ffi.Boolean) + ("static" isdir [ffi.String] "io" "try" ffi.Boolean) + ("static" sep ffi.String) + ("static" getsize [ffi.String] "io" "try" ffi.Integer) + ("static" getmtime [ffi.String] "io" "try" ffi.Float)) + + (def: python_separator + (os/path::sep)) + + (`` (implementation: .public default + (System IO) + + (def: separator + ..python_separator) + + (~~ (template [<name> <method>] + [(def: <name> + (|>> <method> + (io#each (|>> (try.else false)))))] + + [file? os/path::isfile] + [directory? os/path::isdir] + )) + + (def: make_directory + os::mkdir) + + (~~ (template [<name> <method>] + [(def: (<name> path) + (let [! (try.with io.monad)] + (|> path + os::listdir + (# ! each (|>> (array.list {.#None}) + (list#each (|>> (format path ..python_separator))) + (monad.each ! (function (_ sub) + (# ! each (|>> [sub]) (<method> sub)))) + (# ! each (|>> (list.only product.right) + (list#each product.left))))) + (# ! conjoint))))] + + [directory_files os/path::isfile] + [sub_directories os/path::isdir] + )) + + (def: file_size + (|>> os/path::getsize + (# (try.with io.monad) each (|>> .nat)))) + + (def: last_modified + (|>> os/path::getmtime + (# (try.with io.monad) each (|>> f.int + (i.* +1,000) + duration.of_millis + instant.absolute)))) + + (def: (can_execute? path) + (os::access path (os::X_OK))) + + (def: (read path) + (do (try.with io.monad) + [file (..open path "rb") + data (PyFile::read file) + _ (PyFile::close file)] + (in data))) + + (def: (delete path) + (do (try.with io.monad) + [? (os/path::isfile path)] + (if ? + (os::remove path) + (os::rmdir path)))) + + (def: (modify time_stamp path) + (let [when (|> time_stamp instant.relative duration.millis (i./ +1,000))] + (os::utime path (..tuple [when when])))) + + (~~ (template [<name> <mode>] + [(def: (<name> data path) + (do (try.with io.monad) + [file (..open path <mode>) + _ (PyFile::write data file)] + (PyFile::close file)))] + + [write "w+b"] + [append "ab"] + )) + + (def: (move destination origin) + (os::rename origin destination)) + ))) + + @.ruby + (as_is (ffi.import: Time + "[1]::[0]" + ("static" at [Frac] Time) + (to_f [] Frac)) + + (ffi.import: Stat + "[1]::[0]" + (executable? [] Bit) + (size Int) + (mtime [] Time)) + + (ffi.import: File "as" RubyFile + "[1]::[0]" + ("static" SEPARATOR ffi.String) + ("static" open [Path ffi.String] "io" "try" RubyFile) + ("static" stat [Path] "io" "try" Stat) + ("static" delete [Path] "io" "try" Int) + ("static" file? [Path] "io" "try" Bit) + ("static" directory? [Path] "io" "try" Bit) + ("static" utime [Time Time Path] "io" "try" Int) + + (read [] "io" "try" Binary) + (write [Binary] "io" "try" Int) + (flush [] "io" "try" "?" Any) + (close [] "io" "try" "?" Any)) + + (ffi.import: Dir + "[1]::[0]" + ("static" open [Path] "io" "try" Dir) + + (children [] "io" "try" (Array Path)) + (close [] "io" "try" "?" Any)) + + (ffi.import: "fileutils" FileUtils + "[1]::[0]" + ("static" move [Path Path] "io" "try" "?" Any) + ("static" rmdir [Path] "io" "try" "?" Any) + ("static" mkdir [Path] "io" "try" "?" Any)) + + (def: ruby_separator + Text + (..RubyFile::SEPARATOR)) + + (`` (implementation: .public default + (System IO) + + (def: separator + ..ruby_separator) + + (~~ (template [<name> <test>] + [(def: <name> + (|>> <test> + (io#each (|>> (try.else false)))))] + + [file? RubyFile::file?] + [directory? RubyFile::directory?] + )) + + (def: make_directory + FileUtils::mkdir) + + (~~ (template [<name> <test>] + [(def: (<name> path) + (do [! (try.with io.monad)] + [self (Dir::open path) + children (Dir::children self) + output (loop [input (|> children + (array.list {.#None}) + (list#each (|>> (format path ..ruby_separator)))) + output (: (List ..Path) + (list))] + (case input + {.#End} + (in output) + + {.#Item head tail} + (do ! + [verdict (<test> head)] + (again tail (if verdict + {.#Item head output} + output))))) + _ (Dir::close self)] + (in output)))] + + [directory_files RubyFile::file?] + [sub_directories RubyFile::directory?] + )) + + (~~ (template [<name> <pipeline>] + [(def: <name> + (let [! (try.with io.monad)] + (|>> RubyFile::stat + (# ! each (`` (|>> (~~ (template.spliced <pipeline>))))))))] + + [file_size [Stat::size .nat]] + [last_modified [Stat::mtime + Time::to_f + (f.* +1,000.0) + f.int + duration.of_millis + instant.absolute]] + [can_execute? [Stat::executable?]] + )) + + (def: (read path) + (do (try.with io.monad) + [file (RubyFile::open path "rb") + data (RubyFile::read file) + _ (RubyFile::close file)] + (in data))) + + (def: (delete path) + (do (try.with io.monad) + [? (RubyFile::file? path)] + (if ? + (RubyFile::delete path) + (FileUtils::rmdir path)))) + + (def: (modify moment path) + (let [moment (|> moment + instant.relative + duration.millis + i.frac + (f./ +1,000.0) + Time::at)] + (RubyFile::utime moment moment path))) + + (~~ (template [<mode> <name>] + [(def: (<name> data path) + (do [! (try.with io.monad)] + [file (RubyFile::open path <mode>) + data (RubyFile::write data file) + _ (RubyFile::flush file) + _ (RubyFile::close file)] + (in [])))] + + ["wb" write] + ["ab" append] + )) + + (def: (move destination origin) + (do (try.with io.monad) + [_ (FileUtils::move origin destination)] + (in []))) + ))) + + ... @.php + ... (as_is (ffi.import: (FILE_APPEND Int)) + ... ... https://www.php.net/manual/en/dir.constants.php + ... (ffi.import: (DIRECTORY_SEPARATOR ffi.String)) + ... ... https://www.php.net/manual/en/function.pack.php + ... ... https://www.php.net/manual/en/function.unpack.php + ... (ffi.import: (unpack [ffi.String ffi.String] Binary)) + ... ... https://www.php.net/manual/en/ref.filesystem.php + ... ... https://www.php.net/manual/en/function.file-get-contents.php + ... (ffi.import: (file_get_contents [Path] "io" "try" ffi.String)) + ... ... https://www.php.net/manual/en/function.file-put-contents.php + ... (ffi.import: (file_put_contents [Path ffi.String Int] "io" "try" ffi.Integer)) + ... (ffi.import: (filemtime [Path] "io" "try" ffi.Integer)) + ... (ffi.import: (filesize [Path] "io" "try" ffi.Integer)) + ... (ffi.import: (is_executable [Path] "io" "try" ffi.Boolean)) + ... (ffi.import: (touch [Path ffi.Integer] "io" "try" ffi.Boolean)) + ... (ffi.import: (rename [Path Path] "io" "try" ffi.Boolean)) + ... (ffi.import: (unlink [Path] "io" "try" ffi.Boolean)) + + ... ... https://www.php.net/manual/en/function.rmdir.php + ... (ffi.import: (rmdir [Path] "io" "try" ffi.Boolean)) + ... ... https://www.php.net/manual/en/function.scandir.php + ... (ffi.import: (scandir [Path] "io" "try" (Array Path))) + ... ... https://www.php.net/manual/en/function.is-file.php + ... (ffi.import: (is_file [Path] "io" "try" ffi.Boolean)) + ... ... https://www.php.net/manual/en/function.is-dir.php + ... (ffi.import: (is_dir [Path] "io" "try" ffi.Boolean)) + ... ... https://www.php.net/manual/en/function.mkdir.php + ... (ffi.import: (mkdir [Path] "io" "try" ffi.Boolean)) + + ... (def: byte_array_format "C*") + ... (def: default_separator (..DIRECTORY_SEPARATOR)) + + ... (template [<name>] + ... [(exception: .public (<name> [file Path]) + ... (exception.report + ... ["Path" file]))] + + ... [cannot_write_to_file] + ... ) + + ... (`` (implementation: (file path) + ... (-> Path (File IO)) + + ... (~~ (template [<name> <mode>] + ... [(def: (<name> data) + ... (do [! (try.with io.monad)] + ... [outcome (..file_put_contents [path ("php pack" ..byte_array_format data) <mode>])] + ... (if (bit#= false (:as Bit outcome)) + ... (# io.monad in (exception.except ..cannot_write_to_file [path])) + ... (in []))))] + + ... [over_write +0] + ... [append (..FILE_APPEND)] + ... )) + + ... (def: (content _) + ... (do [! (try.with io.monad)] + ... [data (..file_get_contents [path])] + ... (if (bit#= false (:as Bit data)) + ... (# io.monad in (exception.except ..cannot_find_file [path])) + ... (in (..unpack [..byte_array_format data]))))) + + ... (def: path + ... path) + + ... (~~ (template [<name> <ffi> <pipeline>] + ... [(def: (<name> _) + ... (do [! (try.with io.monad)] + ... [value (<ffi> [path])] + ... (if (bit#= false (:as Bit value)) + ... (# io.monad in (exception.except ..cannot_find_file [path])) + ... (in (`` (|> value (~~ (template.spliced <pipeline>))))))))] + + ... [size ..filesize [.nat]] + ... [last_modified ..filemtime [(i.* +1,000) duration.of_millis instant.absolute]] + ... )) + + ... (def: (can_execute? _) + ... (..is_executable [path])) + + ... (def: (modify moment) + ... (do [! (try.with io.monad)] + ... [verdict (..touch [path (|> moment instant.relative duration.millis (i./ +1,000))])] + ... (if (bit#= false (:as Bit verdict)) + ... (# io.monad in (exception.except ..cannot_find_file [path])) + ... (in [])))) + + ... (def: (move destination) + ... (do [! (try.with io.monad)] + ... [verdict (..rename [path destination])] + ... (if (bit#= false (:as Bit verdict)) + ... (# io.monad in (exception.except ..cannot_find_file [path])) + ... (in (file destination))))) + + ... (def: (delete _) + ... (do (try.with io.monad) + ... [verdict (..unlink [path])] + ... (if (bit#= false (:as Bit verdict)) + ... (# io.monad in (exception.except ..cannot_find_file [path])) + ... (in [])))) + ... )) + + ... (`` (implementation: (directory path) + ... (-> Path (Directory IO)) + + ... (def: scope + ... path) + + ... (~~ (template [<name> <test> <constructor> <capability>] + ... [(def: (<name> _) + ... (do [! (try.with io.monad)] + ... [children (..scandir [path])] + ... (loop [input (|> children + ... (array.list {.#None}) + ... (list.only (function (_ child) + ... (not (or (text#= "." child) + ... (text#= ".." child)))))) + ... output (: (List (<capability> IO)) + ... (list))] + ... (case input + ... {.#End} + ... (in output) + + ... {.#Item head tail} + ... (do ! + ... [verdict (<test> head)] + ... (if verdict + ... (again tail {.#Item (<constructor> head) output}) + ... (again tail output)))))))] + + ... [files ..is_file ..file File] + ... [directories ..is_dir directory Directory] + ... )) + + ... (def: (discard _) + ... (do (try.with io.monad) + ... [verdict (..rmdir [path])] + ... (if (bit#= false (:as Bit verdict)) + ... (# io.monad in (exception.except ..cannot_find_directory [path])) + ... (in [])))) + ... )) + + ... (`` (implementation: .public default + ... (System IO) + + ... (~~ (template [<name> <test> <constructor> <exception>] + ... [(def: (<name> path) + ... (do [! (try.with io.monad)] + ... [verdict (<test> path)] + ... (# io.monad in + ... (if verdict + ... {try.#Success (<constructor> path)} + ... (exception.except <exception> [path])))))] + + ... [file ..is_file ..file ..cannot_find_file] + ... [directory ..is_dir ..directory ..cannot_find_directory] + ... )) + + ... (def: (make_file path) + ... (do [! (try.with io.monad)] + ... [verdict (..touch [path (|> instant.now io.run! instant.relative duration.millis (i./ +1,000))])] + ... (# io.monad in + ... (if verdict + ... {try.#Success (..file path)} + ... (exception.except ..cannot_make_file [path]))))) + + ... (def: (make_directory path) + ... (do [! (try.with io.monad)] + ... [verdict (..mkdir path)] + ... (# io.monad in + ... (if verdict + ... {try.#Success (..directory path)} + ... (exception.except ..cannot_make_directory [path]))))) + + ... (def: separator + ... ..default_separator) + ... )) + ... ) + (as_is))) (def: .public (exists? monad fs path) |