(defmodule nemoptera_fossil
(export all))
(defun default-timeout-ms () 120000)
(defun clone-timeout-ms () 300000)
(defun run (args)
(run args (default-timeout-ms)))
(defun run (args timeout-ms)
(let ((bin (nemoptera_config:fossil-bin)))
(if (is_list bin)
(run-bin bin args timeout-ms)
`#(error #(enoent "fossil executable was not found")))))
(defun run-bin (bin args timeout-ms)
(let ((cmd-args (lists:map #'to-charlist/1 args))
(home (to-charlist (filename:absname (nemoptera_config:get 'fossil_home "data/fossil-home")))))
(filelib:ensure_dir (filename:join (binary_to_list (list_to_binary home)) "x"))
(case (catch
(open_port (tuple 'spawn_executable (to-charlist bin))
(list 'stream 'in 'binary 'exit_status 'hide 'stderr_to_stdout
(tuple 'env (list (tuple "FOSSIL_HOME" home)
(tuple "HOME" home)
(tuple "USER" (os:getenv "USER" "nemoptera"))))
(tuple 'args cmd-args))))
(`#(EXIT ,reason) (open-error reason))
(port (collect port #"" timeout-ms)))))
(defun collect (port acc timeout-ms)
(receive
(`#(,port #(data ,data))
(collect port (iolist_to_binary (list acc data)) timeout-ms))
(`#(,port #(exit_status 0))
`#(ok ,(binary_to_list acc)))
(`#(,port #(exit_status ,code))
`#(error #(exit_status ,code ,(binary_to_list acc))))
(after timeout-ms
(catch (port_close port))
`#(error timeout))))
(defun open-error (reason)
(let ((text (lists:flatten (io_lib:format "~p" (list reason)))))
(cond
((or (=:= reason 'enoent) (lists:member "enoent" (string:lexemes text "{} ,")))
`#(error #(enoent ,text)))
((or (=:= reason 'eacces) (lists:member "eacces" (string:lexemes text "{} ,")))
`#(error #(eacces ,text)))
('true `#(error #(enoent ,text))))))
(defun error-message (reason)
(case reason
(`#(enoent ,_) "fossil executable or target path was not found")
(`#(eacces ,_) "fossil could not access the target path")
(`#(exit_status ,code ,out)
(lists:flatten (io_lib:format "fossil exited ~p: ~s" (list code (nemoptera_text:clip out 500)))))
('timeout "fossil command timed out")
(`#(timeout ,out)
(lists:flatten (io_lib:format "fossil server did not start: ~s" (list (nemoptera_text:clip out 300)))))
(_ (lists:flatten (io_lib:format "fossil command failed: ~p" (list reason))))))
(defun to-charlist (value)
(cond
((is_binary value) (binary_to_list value))
((is_list value) value)
('true (lists:flatten (io_lib:format "~p" (list value))))))