@@ -394,7 +394,11 @@ func (e *Env) Test(l *ui.UI, pkg *manifest.Package) error {
394
394
return errors .Errorf ("couldn't find test executable %q in package %s" , args [0 ], pkg )
395
395
}
396
396
cmd , _ := util .Command (task , args ... )
397
- cmd .Env = e .allEnvarsForPackages (true , pkg )
397
+ deps , err := e .ensureRuntimeDepsPresent (l , pkg )
398
+ if err != nil {
399
+ return errors .WithStack (err )
400
+ }
401
+ cmd .Env = e .allEnvarsForPackages (true , deps , pkg )
398
402
return cmd .Run ()
399
403
}
400
404
@@ -441,27 +445,83 @@ func (e *Env) Install(l *ui.UI, pkg *manifest.Package) (*shell.Changes, error) {
441
445
}
442
446
}
443
447
444
- changes , err := e .install (task , pkg )
448
+ changes , err := e .install (l , pkg )
445
449
if err != nil {
446
450
return nil , errors .WithStack (err )
447
451
}
448
452
449
453
return allChanges .Merge (changes ), nil
450
454
}
451
455
456
+ // resolveRuntimeDependencies checks all runtime dependencies for a package are available.
457
+ // aggregate and bin collect the package names and binaries of all runtime dependencies to avoid collisions.
458
+ func (e * Env ) resolveRuntimeDependencies (l * ui.UI , p * manifest.Package , aggregate map [string ]* manifest.Package , bins map [string ]bool ) error {
459
+ for _ , ref := range p .RuntimeDeps {
460
+ previous := aggregate [ref .Name ]
461
+ if previous != nil && previous .Reference .Compare (ref ) != 0 {
462
+ return errors .Errorf ("two conflicting runtime-dependencies: %s vs %s" , ref , previous .Reference )
463
+ }
464
+
465
+ depPkg , err := e .Resolve (l , manifest .ExactSelector (ref ), true )
466
+ if err != nil {
467
+ return errors .WithStack (err )
468
+ }
469
+
470
+ for _ , bin := range depPkg .Binaries {
471
+ base := filepath .Base (bin )
472
+ if bins [base ] {
473
+ return errors .Errorf ("conflicting binary in multiple runtime dependencies: %s" , base )
474
+ }
475
+ bins [base ] = true
476
+ }
477
+
478
+ aggregate [depPkg .Reference .Name ] = depPkg
479
+ if err := e .resolveRuntimeDependencies (l , depPkg , aggregate , bins ); err != nil {
480
+ return err
481
+ }
482
+ }
483
+
484
+ return nil
485
+ }
486
+
487
+ func (e * Env ) ensureRuntimeDepsPresent (l * ui.UI , p * manifest.Package ) ([]* manifest.Package , error ) {
488
+ deps := map [string ]* manifest.Package {}
489
+ err := e .resolveRuntimeDependencies (l , p , deps , map [string ]bool {})
490
+ if err != nil {
491
+ return nil , errors .WithStack (err )
492
+ }
493
+ result := make ([]* manifest.Package , 0 , len (deps ))
494
+ for _ , pkg := range deps {
495
+ if err := e .state .CacheAndUnpack (l .Task (p .Reference .String ()), pkg ); err != nil {
496
+ return nil , errors .WithStack (err )
497
+ }
498
+ // Update usage for runtime dependencies so they wont get GC'd
499
+ if err := e .state .WritePackageState (pkg , e .binDir ); err != nil {
500
+ return nil , errors .WithStack (err )
501
+ }
502
+ result = append (result , pkg )
503
+ }
504
+ return result , nil
505
+ }
506
+
452
507
// install a package
453
- func (e * Env ) install (l * ui.Task , p * manifest.Package ) (* shell.Changes , error ) {
508
+ func (e * Env ) install (l * ui.UI , p * manifest.Package ) (* shell.Changes , error ) {
509
+ task := l .Task (p .Reference .String ())
510
+
511
+ if _ , err := e .ensureRuntimeDepsPresent (l , p ); err != nil {
512
+ return nil , errors .WithStack (err )
513
+ }
454
514
p .UpdatedAt = time .Now ()
455
- log := l .SubTask ("install" )
515
+ log := task .SubTask ("install" )
456
516
log .Infof ("Installing %s" , p )
457
517
log .Debugf ("From %s" , p .Source )
458
518
log .Debugf ("To %s" , p .Dest )
459
- err := e .state .CacheAndUnpack (l , p )
519
+ err := e .state .CacheAndUnpack (task , p )
460
520
if err != nil {
461
521
return nil , errors .WithStack (err )
462
522
}
463
523
if _ , err := os .Stat (e .pkgLink (p )); os .IsNotExist (err ) {
464
- if err = e .linkPackage (l , p ); err != nil {
524
+ if err = e .linkPackage (task , p ); err != nil {
465
525
return nil , errors .WithStack (err )
466
526
}
467
527
if err = e .state .WritePackageState (p , e .binDir ); err != nil {
@@ -544,15 +604,24 @@ func (e *Env) Exec(l *ui.UI, pkg *manifest.Package, binary string, args []string
544
604
if err != nil {
545
605
return errors .WithStack (err )
546
606
}
547
- err = e .EnsureChannelIsUpToDate (l , pkg )
607
+ if err := e .EnsureChannelIsUpToDate (l , pkg ); err != nil {
608
+ return errors .WithStack (err )
609
+ }
610
+ runtimeDeps , err := e .ensureRuntimeDepsPresent (l , pkg )
548
611
if err != nil {
549
612
return errors .WithStack (err )
550
613
}
551
614
binaries , err := pkg .ResolveBinaries ()
552
615
if err != nil {
553
616
return errors .WithStack (err )
554
617
}
555
- env , err := e .Envars (l , true )
618
+
619
+ installed , err := e .ListInstalled (l )
620
+ if err != nil {
621
+ return errors .WithStack (err )
622
+ }
623
+ env := e .allEnvarsForPackages (true , runtimeDeps , installed ... )
624
+
556
625
if err != nil {
557
626
return errors .WithStack (err )
558
627
}
@@ -740,7 +809,7 @@ func (e *Env) Envars(l *ui.UI, inherit bool) ([]string, error) {
740
809
if err != nil {
741
810
return nil , err
742
811
}
743
- return e .allEnvarsForPackages (inherit , pkgs ... ), nil
812
+ return e .allEnvarsForPackages (inherit , nil , pkgs ... ), nil
744
813
}
745
814
746
815
// EnvOps returns the envar mutation operations for this environment.
@@ -890,7 +959,7 @@ func (e *Env) upgradeVersion(l *ui.UI, pkg *manifest.Package) (*shell.Changes, e
890
959
if err != nil {
891
960
return nil , errors .WithStack (err )
892
961
}
893
- ic , err := e .install (l . Task ( resolved . Reference . String ()) , resolved )
962
+ ic , err := e .install (l , resolved )
894
963
if err != nil {
895
964
return nil , errors .WithStack (err )
896
965
}
@@ -985,9 +1054,10 @@ func (e *Env) pkgLink(pkg *manifest.Package) string {
985
1054
// Returns combined system + Hermit + package environment variables, fully expanded.
986
1055
//
987
1056
// If "inherit" is true, system envars will be included.
988
- func (e * Env ) allEnvarsForPackages (inherit bool , pkgs ... * manifest.Package ) []string {
1057
+ func (e * Env ) allEnvarsForPackages (inherit bool , runtimeDeps [] * manifest. Package , pkgs ... * manifest.Package ) []string {
989
1058
var ops envars.Ops
990
1059
system := envars .Parse (os .Environ ())
1060
+ ops = append (ops , e .hermitRuntimeDepOps (runtimeDeps )... )
991
1061
ops = append (ops , e .envarsForPackages (pkgs ... )... )
992
1062
ops = append (ops , e .localEnvarOps ()... )
993
1063
ops = append (ops , e .hermitEnvarOps ()... )
@@ -1013,7 +1083,7 @@ func (e *Env) localEnvarOps() envars.Ops {
1013
1083
return envars .Infer (e .config .Envars .System ())
1014
1084
}
1015
1085
1016
- // hermitEnvarOps returns the environment variables created and reuqired by hermit itself
1086
+ // hermitEnvarOps returns the environment variables created and required by hermit itself
1017
1087
func (e * Env ) hermitEnvarOps () envars.Ops {
1018
1088
return envars.Ops {
1019
1089
& envars.Prepend {Name : "PATH" , Value : e .binDir },
@@ -1022,6 +1092,15 @@ func (e *Env) hermitEnvarOps() envars.Ops {
1022
1092
}
1023
1093
}
1024
1094
1095
+ // hermitRuntimeDepOps returns the environment variables for runtime dependencies
1096
+ func (e * Env ) hermitRuntimeDepOps (pkgs []* manifest.Package ) envars.Ops {
1097
+ ops := e .envarsForPackages (pkgs ... )
1098
+ for _ , pkg := range pkgs {
1099
+ ops = append (ops , & envars.Prepend {Name : "PATH" , Value : filepath .Join (e .state .BinaryDir (), pkg .Reference .String ())})
1100
+ }
1101
+ return ops
1102
+ }
1103
+
1025
1104
func (e * Env ) linkApp (app string ) error {
1026
1105
root := filepath .Join (e .binDir , filepath .Base (app ))
1027
1106
for _ , dir := range []string {"Contents/MacOS" , "Contents/Resources" } {
0 commit comments