From 46c400071af709753605cbd23f5836f40be55812 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 5 Sep 2024 12:00:03 -0600 Subject: [PATCH] address comments --- share/wake/lib/system/io.wake | 55 ++++++++++++++++++------------- share/wake/lib/system/job.wake | 21 +++++++++--- share/wake/lib/system/runner.wake | 28 +++++++++------- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/share/wake/lib/system/io.wake b/share/wake/lib/system/io.wake index 962a95bb0..d1bd2bb21 100644 --- a/share/wake/lib/system/io.wake +++ b/share/wake/lib/system/io.wake @@ -129,32 +129,43 @@ export def read (path: Path): Result String Error = Pass body -> Pass body Fail f -> Fail (makeError f) -target writeImp inputs mode path content = - # TODO: move this runner out of writeImp and don't directly depent on the parameters passed in to writeImp - # See mkdirRunner for example of proper implementation - def writeRunner = - def primWrite (mode: Integer) (path: String) (content: String): Result String String = - (\_ \_ \_ prim "write") mode path content +# writeRunner: A runner that processes special write jobs +# +# Allows for calls to the write prim to be tracked in the database as any other job. +# Ideally content would be part of RunnerInputCmd however this gets tracked exactly in the database +# which means all writes would cost 2x the total amount. +def writeRunner (content: String) = + def primWrite (mode: Integer) (path: String) (content: String): Result String String = + (\_ \_ \_ prim "write") mode path content - def run (job: Job) ((RunnerInput _ _ vis _ _ _ _ _ predict _): RunnerInput): Result RunnerOutput Error = - # Insert the job into the database - def _ = primJobVirtual job "" "" predict + def run (job: Job) ((RunnerInput _ cmd vis _ _ _ _ _ predict _): RunnerInput): Result RunnerOutput Error = + # Command must be ("", "-m", "{string mode}", "{string path}", Nil) + require "", "-m", smode, path, Nil = cmd + else panic "writeImp violated command-line contract" + + # Insert the job into the database + def _ = primJobVirtual job "" "" predict - # Wait for the virtual job to complete - require Pass reality = job.getJobReality + # Wait for the virtual job to complete + require Pass reality = job.getJobReality + + # Actually trigger the effects required by the job + def mode = + int smode + | getOrElse 0x200 - # Actually trigger the effects required by the job - require True = mode >= 0 && mode <= 0x1ff - else failWithError "write {path}: Invalid mode ({strOctal mode})" + require True = mode >= 0 && mode <= 0x1ff + else failWithError "write {path}: Invalid mode ({strOctal mode})" - match (primWrite mode path content) - Fail f -> failWithError f - Pass path -> - RunnerOutput (vis | map getPathName) (path,) reality - | Pass + match (primWrite mode path content) + Fail f -> failWithError f + Pass path -> + RunnerOutput (vis | map getPathName) (path,) reality + | Pass - makeRunner "write" run + makeRunner "write" run +target writeImp inputs mode path content = # There are a couple likely bad paths that we don't want the user writing to # so we give good error messages for these cases require False = path ==* "" @@ -184,11 +195,11 @@ target writeImp inputs mode path content = # If all those checks pass we go ahead and perform the write. The write will # overwrite single files but it will not overwrite a whole directory with a file. - makeExecPlan ("", "0{strOctal mode}", path, Nil) inputs + makeExecPlan ("", "-m", "0{strOctal mode}", path, Nil) inputs | setPlanLabel "write: {path} 0{strOctal mode}" | setPlanOnce False | setPlanEnvironment Nil - | runJobWith writeRunner + | runJobWith (writeRunner content) | setJobInspectVisibilityHidden | getJobOutput diff --git a/share/wake/lib/system/job.wake b/share/wake/lib/system/job.wake index 42724a91a..248206747 100644 --- a/share/wake/lib/system/job.wake +++ b/share/wake/lib/system/job.wake @@ -25,7 +25,9 @@ export tuple JobKey = export isatty: Integer # Create/reserve a job handle, parameters aren't necessarily finalized -export def primJobCreate (label: String) ((JobKey dir stdin env cmd signature visible isatty): JobKey) (keep: Integer) (echo: String) (stdout: String) (stderr: String): Job = +export def primJobCreate (label: String) (jobKey: JobKey) (keep: Integer) (echo: String) (stdout: String) (stderr: String): Job = + def JobKey dir stdin env cmd signature visible isatty = jobKey + (\_ \_ \_ \_ \_ \_ \_ \_ \_ \_ \_ \_ prim "job_create") label dir @@ -41,7 +43,9 @@ export def primJobCreate (label: String) ((JobKey dir stdin env cmd signature vi isatty # Imediatly complete a job with the provided ouputs without launching a process -export def primJobVirtual (job: Job) (stdout: String) (stderr: String) ((Usage status runtime cputime membytes ibytes obytes): Usage): Unit = +export def primJobVirtual (job: Job) (stdout: String) (stderr: String) (usage: Usage): Unit = + def Usage status runtime cputime membytes ibytes obytes = usage + (\_ \_ \_ \_ \_ \_ \_ \_ \_ prim "job_virtual") job stdout @@ -54,7 +58,10 @@ export def primJobVirtual (job: Job) (stdout: String) (stderr: String) ((Usage s obytes # Launch the job via a child process. Values such as command or environment can be freely changed from the initial reservation. -export def primJobLaunch (job: Job) ((JobKey dir stdin env cmd signature visible isatty): JobKey) ((Usage status runtime cputime membytes ibytes obytes): Usage): Unit = +export def primJobLaunch (job: Job) (jobKey: JobKey) (usage: Usage): Unit = + def JobKey dir stdin env cmd _signature _visible isatty = jobKey + def Usage status runtime cputime membytes ibytes obytes = usage + (\_ \_ \_ \_ \_ \_ \_ \_ \_ \_ \_ \_ prim "job_launch") job dir @@ -78,7 +85,9 @@ export def primJobFailFinish (job: Job) (error: Error): Unit = (\_ \_ prim "job_fail_finish") job error # Complete a job successfully by providing to the runtime the inputs/outputs/usage of the job -export def primJobFinish (job: Job) (inputs: String) (outputs: String) (all_outputs: String) ((Usage status runtime cputime membytes ibytes obytes): Usage): Unit = +export def primJobFinish (job: Job) (inputs: String) (outputs: String) (all_outputs: String) (usage: Usage): Unit = + def Usage status runtime cputime membytes ibytes obytes = usage + (\_ \_ \_ \_ \_ \_ \_ \_ \_ \_ prim "job_finish") job inputs @@ -92,7 +101,9 @@ export def primJobFinish (job: Job) (inputs: String) (outputs: String) (all_outp obytes # Look up a job in the local database. Returns a completed Job handle with outputs already resolved if it is already cached -export def primJobCache ((JobKey dir stdin env cmd signature visible isatty): JobKey): Pair (List Job) (List (Pair String String)) = +export def primJobCache (jobKey: JobKey): Pair (List Job) (List (Pair String String)) = + def JobKey dir stdin env cmd signature visible isatty = jobKey + (\_ \_ \_ \_ \_ \_ \_ prim "job_cache") dir stdin env cmd signature visible isatty # Creates a hash of 5 elements diff --git a/share/wake/lib/system/runner.wake b/share/wake/lib/system/runner.wake index 11c9f6544..2caf4b23a 100644 --- a/share/wake/lib/system/runner.wake +++ b/share/wake/lib/system/runner.wake @@ -60,11 +60,15 @@ export tuple Runner = # makeRunner: Hides some of the boiler plate required to create a runner # -# This function requires very advanced wake expierence and should be used with the greatest amount of caution. -# Callers must ensure at the very least than run calls primJobLaunch and one of the many job "wait" functions. -# Runners should not wrap other runners instead they should precisely do what they need to complete their task. +# This function requires very advanced wake experience and should be used with the greatest amount +# of caution. Callers must ensure at the very least that `run` calls primJobLaunch and one of the +# many job "wait" functions. Historically runners allowed dispatching to an arbirary "base" or +# "inner" runner. This significantly complicated the system and led to very unexpected interactions. +# It is recomennded that runners don't accept an "inner" runner and instead directly call the job +# primatives. If wrapping is unavoidable then the specific runner being wrapped should be named +# instead of accepting an arbitrary runner parameter. # -# localRunner is a good reference implementation. +# localRunner is a good reference implementation of the run function. export def makeRunner (name: String) (run: Job => RunnerInput => Result RunnerOutput Error): Runner = def do job maybeInput = match maybeInput Fail e -> @@ -84,9 +88,8 @@ export def localRunner: Runner = def jobKey = JobKey dir stdin env.implode cmd.implode 0 "" isatty.booleanToInteger def _ = primJobLaunch job jobKey predict - job - | getJobReality - |< (\reality RunnerOutput (vis | map getPathName) Nil reality) + job.getJobReality + |< RunnerOutput (vis | map getPathName) Nil makeRunner "local" run @@ -97,14 +100,15 @@ export def virtualRunner: Runner = def run (job: Job) ((RunnerInput _ _ vis _ _ _ _ _ predict _): RunnerInput): Result RunnerOutput Error = def _ = primJobVirtual job "" "" predict - job - | getJobReality - |< (\reality RunnerOutput (vis | map getPathName) Nil reality) + job.getJobReality + |< RunnerOutput (vis | map getPathName) Nil makeRunner "virtual" run -# depreMakeRunner: Deprecated. Do not use -export def depreMakeRunner name pre post (Runner _ run) = +# wrapRunner: Deprecated. Do not use this function. +# +# It will be deleted in the next release. See makeRunner for migration +export def wrapRunner name pre post (Runner _ run) = def doit job preInput = match (pre preInput) Pair runInput state -> def runOutput = run job runInput