From 01b25ebd8e21692bddf724b5c02a9849c2a5427c Mon Sep 17 00:00:00 2001 From: sterni Date: Sun, 13 Feb 2022 19:30:29 +0100 Subject: [PATCH] feat(tools/magrathea): implement run command This command builds the desired target and runs the executable produced by it. If a directory is produced, it looks for a single (!) executable in the bin directory. Dot files are ignored, so wrappers should generally work. In the future we could provide a flag to select one of multiple executables. All arguments following the target are passed to the executable as is. Examples: mg run ops/mq_cli ls mg run web/bubblegum:examples Change-Id: I6490668af68e028520973196d9daa5f1d58969ee Reviewed-on: https://cl.tvl.fyi/c/depot/+/5277 Tested-by: BuildkiteCI Reviewed-by: tazjin --- tools/magrathea/mg.scm | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tools/magrathea/mg.scm b/tools/magrathea/mg.scm index 86fed6fc2..a453da2cc 100644 --- a/tools/magrathea/mg.scm +++ b/tools/magrathea/mg.scm @@ -11,6 +11,8 @@ (chicken format) (chicken irregex) (chicken port) + (chicken file) + (chicken file posix) (chicken process) (chicken process-context) (chicken string) @@ -37,6 +39,7 @@ commands: build - build a target shell - enter a shell with the target's build dependencies path - print source folder for the target + run - build a target and execute its output file all feedback on b.tvl.fyi USAGE @@ -243,6 +246,50 @@ USAGE (guarantee-success (parse-target arg)))] [other (print "not yet implemented")])) +(define (execute-run t #!optional cmd-args) + (fprintf (current-error-port) "[mg] building target ~A~%" t) + (let* ((expr (nix-expr-for t)) + (out (call-with-input-pipe + (apply string-append + ;; TODO(sterni): temporary gc root + (intersperse `("nix-build" "-E" ,(qs expr) "--no-out-link") + " ")) + (lambda (p) + (string-chomp (let ((s (read-string #f p))) + (if (eq? s #!eof) "" s))))))) + + ;; TODO(sterni): can we get the exit code of nix-build somehow? + (when (= (string-length out) 0) + (mg-error (string-append "Couldn't build target " (format "~A" t))) + (exit 1)) + + (fprintf (current-error-port) "[mg] running target ~A~%" t) + (process-execute + ;; If the output is a file, we assume it's an executable à la writeExecline, + ;; otherwise we look in the bin subdirectory and pick the only executable. + ;; Handling multiple executables is not possible at the moment, the choice + ;; could be made via a command line flag in the future. + (if (regular-file? out) + out + (let* ((dir-path (string-append out "/bin")) + (dir-contents (if (directory-exists? dir-path) + (directory dir-path #f) + '()))) + (case (length dir-contents) + ((0) (mg-error "no executables in build output") + (exit 1)) + ((1) (string-append dir-path "/" (car dir-contents))) + (else (mg-error "more than one executable in build output") + (exit 1))))) + cmd-args))) + +(define (run args) + (match args + [() (execute-run (empty-target))] + ;; TODO(sterni): flag for selecting binary name + [other (execute-run (guarantee-success (parse-target (car args))) + (cdr args))])) + (define (path args) (match args [(arg) @@ -262,6 +309,7 @@ USAGE [("build" . _) (build (cdr args))] [("shell" . _) (shell (cdr args))] [("path" . _) (path (cdr args))] + [("run" . _) (run (cdr args))] [other (begin (print "unknown command: mg " args) (print usage))]))