Shells in OCaml
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Handle function IO correctly

+94 -26
+2 -1
src/bin/main.ml
··· 19 19 executor; 20 20 fs = env#fs; 21 21 options = Merry.Built_ins.Options.default; 22 - stdout = None; 22 + stdin = env#stdin; 23 + stdout = env#stdout; 23 24 async_switch; 24 25 background_jobs = []; 25 26 last_background_process = "";
+53 -25
src/lib/eval.ml
··· 35 35 executor : E.t; 36 36 fs : Eio.Fs.dir_ty Eio.Path.t; 37 37 options : Built_ins.Options.t; 38 - stdout : Eio_unix.sink_ty Eio.Flow.sink option; 38 + stdin : Eio_unix.source_ty Eio.Flow.source; 39 + stdout : Eio_unix.sink_ty Eio.Flow.sink; 39 40 background_jobs : J.t list; 40 41 last_background_process : string; 41 42 async_switch : Eio.Switch.t; ··· 115 116 (ctx, expand) 116 117 117 118 let stdout_for_pipeline ~sw ctx = function 118 - | [] -> (None, ctx.stdout) 119 + | [] -> (None, `Global ctx.stdout) 119 120 | _ -> 120 121 let r, w = Eio_unix.pipe sw in 121 - (Some r, Some (w :> Eio_unix.sink_ty Eio.Flow.sink)) 122 + (Some r, `Local (w :> Eio_unix.sink_ty Eio.Flow.sink)) 122 123 123 124 let fd_of_int ?(close_unix = true) ~sw n = 124 125 Eio_unix.Fd.of_unix ~close_unix ~sw (Obj.magic n : Unix.file_descr) ··· 158 159 | Io_op_greatand -> ( 159 160 match file with 160 161 | [ WordLiteral "-" ] -> 161 - if n = 0 then Some (Types.Close Eio_unix.Fd.stdin) 162 + if n = 0 then Some (Types.Close Eio_unix.Fd.stdout) 162 163 else 163 164 let fd = fd_of_int ~sw n in 164 165 Some (Types.Close fd) ··· 242 243 | Some j, `Built_in p -> Option.some @@ J.add_built_in p j 243 244 | Some j, `Error p -> Option.some @@ J.add_error p j 244 245 in 245 - let exec_process ctx job ?fds ?stdin ?stdout ~pgid args = 246 + let close_stdout ~is_global some_write = 247 + if not is_global then begin 248 + Eio.Flow.close some_write 249 + end 250 + in 251 + let exec_process ctx job ?fds ?stdin ~stdout ~pgid args = 246 252 let process = 247 - E.exec ctx.executor ?fds ?stdin ?stdout ~pgid ~mode 253 + E.exec ctx.executor ?fds ?stdin ~stdout ~pgid ~mode 248 254 ~cwd:(cwd_of_ctx ctx) 249 255 ~env:(get_env ~extra:ctx.local_state ()) 250 256 args ··· 274 280 | Ast.SimpleCommand (Named (executable, None)) :: rest -> ( 275 281 let ctx, executable = expand_cst ctx executable in 276 282 let executable = handle_word_components_to_string ctx executable in 283 + let some_read, some_write = 284 + stdout_for_pipeline ctx ~sw:pipeline_switch rest 285 + in 286 + let is_global, some_write = 287 + match some_write with 288 + | `Global p -> (true, p) 289 + | `Local p -> (false, p) 290 + in 277 291 match Built_ins.of_args [ executable ] with 278 292 | Some (Ok bi) -> 279 293 let ctx = handle_built_in ctx bi in ··· 283 297 | Some (Error _) -> 284 298 (ctx, handle_job ~pgid job (`Built_in (Exit.nonzero () 1))) 285 299 | None -> ( 300 + let saved_ctx = ctx in 286 301 match 302 + let ctx = { ctx with stdout = some_write } in 287 303 handle_function_application ctx ~name:executable [ executable ] 288 304 with 289 305 | Some ctx -> 306 + close_stdout ~is_global some_write; 290 307 (* TODO: Proper job stuff and redirects etc. *) 291 - loop (Exit.value ctx) job (pgid, stdout_of_previous) rest 308 + let job = 309 + handle_job ~pgid job (`Built_in (ctx >|= fun _ -> ())) 310 + in 311 + loop saved_ctx job (pgid, some_read) rest 292 312 | None -> ( 293 - let some_read, some_write = 294 - stdout_for_pipeline ctx ~sw:pipeline_switch rest 295 - in 296 313 match stdout_of_previous with 297 314 | None -> 298 315 let ctx, job = 299 - exec_process ctx job ?stdout:some_write ~pgid 316 + exec_process ctx job ~stdout:some_write ~pgid 300 317 [ executable ] 301 318 in 302 - Option.iter Eio.Flow.close some_write; 319 + close_stdout ~is_global some_write; 303 320 loop ctx job (pgid, some_read) rest 304 321 | Some stdout -> 305 322 let ctx, job = 306 - exec_process ctx job ~stdin:stdout ?stdout:some_write 323 + exec_process ctx job ~stdin:stdout ~stdout:some_write 307 324 ~pgid [ executable ] 308 325 in 309 - Option.iter Eio.Flow.close some_write; 326 + close_stdout ~is_global some_write; 310 327 loop ctx job (pgid, some_read) rest))) 311 328 | Ast.SimpleCommand (Named (executable, Some suffix)) :: rest -> ( 312 329 let ctx, executable = expand_cst ctx executable in 313 330 let executable = handle_word_components_to_string ctx executable in 314 331 let ctx, suffix = expand_redirects (ctx, []) suffix in 315 332 let args = args ctx suffix in 333 + let some_read, some_write = 334 + stdout_for_pipeline ~sw:pipeline_switch ctx rest 335 + in 336 + let is_global, some_write = 337 + match some_write with 338 + | `Global p -> (true, p) 339 + | `Local p -> (false, p) 340 + in 316 341 match Built_ins.of_args (executable :: args) with 317 342 | Some (Ok bi) -> 318 343 let ctx = handle_built_in ctx bi in ··· 322 347 | Some (Error _) -> 323 348 (ctx, handle_job ~pgid job (`Built_in (Exit.nonzero () 1))) 324 349 | None -> ( 350 + let saved_ctx = ctx in 325 351 match 352 + let ctx = { ctx with stdout = some_write } in 326 353 handle_function_application ctx ~name:executable 327 354 (ctx.program :: args) 328 355 with 329 356 | Some ctx -> 357 + close_stdout ~is_global some_write; 330 358 (* TODO: Proper job stuff and redirects etc. *) 331 - loop (Exit.value ctx) job (pgid, stdout_of_previous) rest 359 + let job = 360 + handle_job ~pgid job (`Built_in (ctx >|= fun _ -> ())) 361 + in 362 + loop saved_ctx job (pgid, some_read) rest 332 363 | None -> ( 333 364 let redirect = 334 365 List.fold_left ··· 340 371 [] suffix 341 372 |> List.rev |> List.filter_map Fun.id 342 373 in 343 - let some_read, some_write = 344 - stdout_for_pipeline ~sw:pipeline_switch ctx rest 345 - in 346 374 match stdout_of_previous with 347 375 | None -> 348 376 let ctx, job = 349 - exec_process ctx job ~fds:redirect ?stdout:some_write 377 + exec_process ctx job ~fds:redirect ~stdout:some_write 350 378 ~pgid (executable :: args) 351 379 in 352 - Option.iter Eio.Flow.close some_write; 380 + close_stdout ~is_global some_write; 353 381 loop ctx job (pgid, some_read) rest 354 382 | Some stdout -> 355 383 let ctx, job = 356 384 exec_process ctx job ~fds:redirect ~stdin:stdout 357 - ?stdout:some_write ~pgid (executable :: args) 385 + ~stdout:some_write ~pgid (executable :: args) 358 386 in 359 - Option.iter Eio.Flow.close some_write; 387 + close_stdout ~is_global some_write; 360 388 loop ctx job (pgid, some_read) rest))) 361 389 | CompoundCommand (c, rdrs) :: rest -> 362 390 let _rdrs = ··· 375 403 safely delay execution of a process. So instead we create a ghost 376 404 process that last just until all of the processes are setup. *) 377 405 let ctx, job = 378 - Eio.Switch.run @@ fun ghost_switch -> 379 406 let ghost_process = 380 - E.exec ~mode:(Types.Switched ghost_switch) ~pgid:0 407 + E.exec ~mode:(Types.Switched pipeline_switch) ~pgid:0 381 408 ~cwd:(cwd_of_ctx initial_ctx) initial_ctx.executor 382 409 [ "sleep"; "99999999" ] 383 410 |> function ··· 526 553 let stdout = Eio.Flow.buffer_sink buf in 527 554 let r, w = Eio_unix.pipe sw in 528 555 Eio.Fiber.fork ~sw (fun () -> Eio.Flow.copy r stdout); 529 - let subshell_ctx = { ctx with stdout = Some w } in 556 + let subshell_ctx = { ctx with stdout = w } in 530 557 let _ = run (Exit.zero subshell_ctx) s in 558 + Eio.Flow.close w; 531 559 (ctx, Buffer.contents buf) 532 560 in 533 561 let rec run_subshells ~sw ran_subshell = function
+14
test/forloops.t
··· 46 46 test.sh 47 47 world.txt 48 48 49 + 1.5 TODO Pipelines 50 + 51 + $ cat >test.sh << EOF 52 + > for i in "olleh" "dlrow"; do 53 + > echo \$i 54 + > done | rev 55 + > EOF 56 + 57 + $ sh test.sh 58 + hello 59 + world 60 + $ msh test.sh 61 + olleh 62 + dlrow
+25
test/functions.t
··· 27 27 $ msh test.sh 28 28 test.sh 29 29 HI THERE 30 + 31 + Redirection and exit codes should be preserved to just like any other command. 32 + 33 + $ cat > test.sh << EOF 34 + > goodbye () { 35 + > echo "eybdoog" 36 + > exit \$1 37 + > } 38 + > goodbye 0 | rev 39 + > goodbye 1 | rev 40 + > goodbye 128 41 + > EOF 42 + 43 + $ sh test.sh 44 + goodbye 45 + goodbye 46 + eybdoog 47 + [128] 48 + 49 + $ msh test.sh 50 + goodbye 51 + goodbye 52 + eybdoog 53 + exit 54 + [128]