From a99317b650fa402ea602842ed759fb1ff8a95e50 Mon Sep 17 00:00:00 2001 From: James Behr Date: Sat, 6 Aug 2022 21:06:32 +0200 Subject: [PATCH] feat: set environment variables for hooks Provide the package root, source files and the target directory as environment variables to the package hooks. This is makes hooks that run prior to installation or after uninstallation when no package state exists more useful, as the package state path was previously the only value provided to the hook (as an argument). --- README.md | 10 ++++++++++ pkg/main.go | 7 +++++++ pkg/main_test.go | 41 ++++++++++++++++++++++++++++------------- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b153457..8301b42 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,16 @@ the packages installation state directory passed as their only argument. See the [section on package state](#package-state). The name of the hook specifies the life cycle event that will cause it to run. +The hooks also get called with the following environment variables set. This is +more useful for hooks that run prior to installation, when no package state has +been created. + +- `STOWAWAY_SOURCE` is set the the absolute path containing the package's + source files. +- `STOWAWAY_TARGET` is set the the absolute path where the package will be + installed. +- `STOWAWAY_PACKAGE_ROOT` is set the the absolute path of package root. + The following hoooks are currently available, in the order they are run: - `before_uninstall_all`: Run for each selected package in a `stow --delete` diff --git a/pkg/main.go b/pkg/main.go index bd8606c..3e55c87 100644 --- a/pkg/main.go +++ b/pkg/main.go @@ -2,6 +2,7 @@ package pkg import ( "errors" + "fmt" "io/fs" "os" "os/exec" @@ -145,6 +146,12 @@ func (pkg localPackage) RunHookIfExists(name string) error { } cmd := exec.Command(executable.String(), pkg.State.String()) + + cmd.Env = []string{ + fmt.Sprintf("STOWAWAY_SOURCE=%s", pkg.Source.String()), + fmt.Sprintf("STOWAWAY_TARGET=%s", pkg.Target.String()), + fmt.Sprintf("STOWAWAY_PACKAGE_ROOT=%s", pkg.PackageRoot.String()), + } return cmd.Run() } diff --git a/pkg/main_test.go b/pkg/main_test.go index f079c3f..7fcab06 100644 --- a/pkg/main_test.go +++ b/pkg/main_test.go @@ -149,8 +149,7 @@ func TestRunHook(t *testing.T) { p, err := loader.Load() require.NoError(t, err) - script := `#!/bin/sh -touch "$1/hookran"` + script := "#!/bin/sh\nprintenv > $1/env" writeFile(t, tmp, "bash/hooks/broken", "not executable", 0655) writeFile(t, tmp, "bash/hooks/working", script, 0755) @@ -159,7 +158,19 @@ touch "$1/hookran"` require.NoError(t, p.RunHookIfExists("working")) require.Error(t, p.RunHookIfExists("broken")) - require.FileExists(t, tmp.Join("data/hookran").String()) + contents, err := os.ReadFile(tmp.Join("data/env").String()) + + env := map[string]string{} + for _, line := range strings.Split(string(contents), "\n") { + fields := strings.SplitN(line, "=", 2) + if len(fields) == 2 { + env[fields[0]] = fields[1] + } + } + + require.Equal(t, tmp.Join("bash/src").String(), env["STOWAWAY_SOURCE"]) + require.Equal(t, tmp.Join("bash").String(), env["STOWAWAY_PACKAGE_ROOT"]) + require.Equal(t, tmp.Join("home/user").String(), env["STOWAWAY_TARGET"]) } type InstallTestCase struct { @@ -358,12 +369,16 @@ type MockPackage struct { IsInstalled bool InstallCalled func(string, bool) HookCalled func(string, string) - Name string + PackageName string +} + +func (m *MockPackage) Name() string { + return m.PackageName } func (m *MockPackage) Install() error { if m.InstallCalled != nil { - m.InstallCalled(m.Name, false) + m.InstallCalled(m.PackageName, false) } return nil @@ -371,7 +386,7 @@ func (m *MockPackage) Install() error { func (m *MockPackage) Uninstall() error { if m.InstallCalled != nil { - m.InstallCalled(m.Name, true) + m.InstallCalled(m.PackageName, true) } return nil @@ -383,7 +398,7 @@ func (m *MockPackage) Installed() (bool, error) { func (m *MockPackage) RunHookIfExists(name string) error { if m.HookCalled != nil { - m.HookCalled(m.Name, name) + m.HookCalled(m.PackageName, name) } return nil @@ -448,9 +463,9 @@ func TestStow(t *testing.T) { } pkgs := []Package{ - &MockPackage{Name: "a", IsInstalled: true, HookCalled: hook, InstallCalled: ins}, - &MockPackage{Name: "b", IsInstalled: false, HookCalled: hook, InstallCalled: ins}, - &MockPackage{Name: "c", IsInstalled: true, HookCalled: hook, InstallCalled: ins}, + &MockPackage{PackageName: "a", IsInstalled: true, HookCalled: hook, InstallCalled: ins}, + &MockPackage{PackageName: "b", IsInstalled: false, HookCalled: hook, InstallCalled: ins}, + &MockPackage{PackageName: "c", IsInstalled: true, HookCalled: hook, InstallCalled: ins}, } options := StowOptions{ @@ -492,9 +507,9 @@ func TestStow(t *testing.T) { } pkgs := []Package{ - &MockPackage{Name: "a", IsInstalled: false, HookCalled: hook, InstallCalled: ins}, - &MockPackage{Name: "b", IsInstalled: true, HookCalled: hook, InstallCalled: ins}, - &MockPackage{Name: "c", IsInstalled: false, HookCalled: hook, InstallCalled: ins}, + &MockPackage{PackageName: "a", IsInstalled: false, HookCalled: hook, InstallCalled: ins}, + &MockPackage{PackageName: "b", IsInstalled: true, HookCalled: hook, InstallCalled: ins}, + &MockPackage{PackageName: "c", IsInstalled: false, HookCalled: hook, InstallCalled: ins}, } options := StowOptions{