@@ -11,6 +11,7 @@ use std::ffi::{OsStr, OsString};
11
11
use std:: fs:: { read, read_link, File } ;
12
12
use std:: io:: { Read , Write } ;
13
13
use std:: os:: unix:: ffi:: OsStrExt ;
14
+ use std:: os:: unix:: prelude:: OsStringExt ;
14
15
use std:: os:: unix:: process:: CommandExt ;
15
16
use std:: os:: unix:: process:: ExitStatusExt ;
16
17
use std:: path:: { Path , PathBuf } ;
@@ -28,6 +29,12 @@ mod trace;
28
29
29
30
type EnvMap = BTreeMap < OsString , OsString > ;
30
31
32
+ struct EnvOptions {
33
+ env : EnvMap ,
34
+ bashopts : OsString ,
35
+ shellopts : OsString ,
36
+ }
37
+
31
38
static XDG_DIRS : Lazy < xdg:: BaseDirectories > = Lazy :: new ( || {
32
39
xdg:: BaseDirectories :: with_prefix ( "cached-nix-shell" )
33
40
. expect ( "Can't get find base cache directory" )
@@ -216,7 +223,7 @@ fn run_nix_shell(inp: &NixShellInput) -> NixShellOutput {
216
223
217
224
let env_file = NamedTempFile :: new ( ) . expect ( "can't create temporary file" ) ;
218
225
let env_cmd = [
219
- b"env -0 > " ,
226
+ b"{ printf \" BASHOPTS=%s \\ 0SHELLOPTS=%s \\ 0 \" \" ${BASHOPTS-} \" \" ${SHELLOPTS-} \" ; env -0; } > " ,
220
227
bash:: quote ( env_file. path ( ) . as_os_str ( ) . as_bytes ( ) ) . as_slice ( ) ,
221
228
]
222
229
. concat ( ) ;
@@ -327,7 +334,7 @@ fn run_script(
327
334
. arg ( fname)
328
335
. args ( script_args)
329
336
. env_clear ( )
330
- . envs ( & env)
337
+ . envs ( & env. env )
331
338
. exec ( )
332
339
} else {
333
340
// eprintln!("Interpreter is bash command, executing 'bash -c'");
@@ -342,7 +349,7 @@ fn run_script(
342
349
. arg ( fname)
343
350
. args ( script_args)
344
351
. env_clear ( )
345
- . envs ( & env)
352
+ . envs ( & env. env )
346
353
. exec ( )
347
354
} ;
348
355
@@ -409,25 +416,57 @@ fn run_from_args(args: Vec<OsString>) {
409
416
let inp = args_to_inp ( nix_shell_pwd, & args) ;
410
417
let env = cached_shell_env ( args. pure , & inp) ;
411
418
419
+ let mut bash_args = Vec :: new ( ) ;
420
+ // XXX: only check for options that are set by current stdenv and nix-shell.
421
+ env. bashopts
422
+ . as_bytes ( )
423
+ . split ( |& b| b == b':' )
424
+ . filter ( |opt| {
425
+ [ b"execfail" . as_ref ( ) , b"inherit_errexit" , b"nullglob" ]
426
+ . contains ( opt)
427
+ } )
428
+ . for_each ( |opt| {
429
+ bash_args. extend_from_slice ( & [
430
+ "-O" . into ( ) ,
431
+ OsString :: from_vec ( opt. to_vec ( ) ) ,
432
+ ] )
433
+ } ) ;
434
+ env. shellopts
435
+ . as_bytes ( )
436
+ . split ( |& b| b == b':' )
437
+ . filter ( |opt| [ b"pipefail" . as_ref ( ) ] . contains ( opt) )
438
+ . for_each ( |opt| {
439
+ bash_args. extend_from_slice ( & [
440
+ "-o" . into ( ) ,
441
+ OsString :: from_vec ( opt. to_vec ( ) ) ,
442
+ ] )
443
+ } ) ;
444
+
412
445
let ( cmd, cmd_args) = match args. run {
413
- args:: RunMode :: InteractiveShell => (
414
- "bash" . into ( ) ,
415
- vec ! [ "--rcfile" . into( ) , env!( "CNS_RCFILE" ) . into( ) ] ,
416
- ) ,
417
- args:: RunMode :: Shell ( cmd) => ( "bash" . into ( ) , vec ! [ "-c" . into( ) , cmd] ) ,
446
+ args:: RunMode :: InteractiveShell => {
447
+ bash_args. extend_from_slice ( & [
448
+ "--rcfile" . into ( ) ,
449
+ env ! ( "CNS_RCFILE" ) . into ( ) ,
450
+ ] ) ;
451
+ ( "bash" . into ( ) , bash_args)
452
+ }
453
+ args:: RunMode :: Shell ( cmd) => {
454
+ bash_args. extend_from_slice ( & [ "-c" . into ( ) , cmd] ) ;
455
+ ( "bash" . into ( ) , bash_args)
456
+ }
418
457
args:: RunMode :: Exec ( cmd, cmd_args) => ( cmd, cmd_args) ,
419
458
} ;
420
459
421
460
let exec = Command :: new ( cmd)
422
461
. args ( cmd_args)
423
462
. env_clear ( )
424
- . envs ( & env)
463
+ . envs ( & env. env )
425
464
. exec ( ) ;
426
465
eprintln ! ( "cached-nix-shell: couldn't run: {:?}" , exec) ;
427
466
exit ( 1 ) ;
428
467
}
429
468
430
- fn cached_shell_env ( pure : bool , inp : & NixShellInput ) -> EnvMap {
469
+ fn cached_shell_env ( pure : bool , inp : & NixShellInput ) -> EnvOptions {
431
470
let inputs = serialize_vecs ( & [
432
471
& serialize_env ( & inp. env ) ,
433
472
& serialize_args ( & inp. args ) ,
@@ -453,12 +492,14 @@ fn cached_shell_env(pure: bool, inp: &NixShellInput) -> EnvMap {
453
492
outp. env
454
493
} ;
455
494
495
+ let shellopts = env. remove ( OsStr :: new ( "SHELLOPTS" ) ) . unwrap_or_default ( ) ;
496
+ let bashopts = env. remove ( OsStr :: new ( "BASHOPTS" ) ) . unwrap_or_default ( ) ;
456
497
env. insert ( OsString :: from ( "IN_CACHED_NIX_SHELL" ) , OsString :: from ( "1" ) ) ;
457
498
458
- if pure {
459
- env
460
- } else {
461
- merge_env ( env )
499
+ EnvOptions {
500
+ env : if pure { env } else { merge_env ( env ) } ,
501
+ shellopts ,
502
+ bashopts ,
462
503
}
463
504
}
464
505
0 commit comments