Skip to content

Commit dd20601

Browse files
authored
feat: package install/uninstall hooks (#184)
Fixes #177
1 parent c4c0aa9 commit dd20601

File tree

2 files changed

+61
-18
lines changed

2 files changed

+61
-18
lines changed

pkgmgr/package.go

+55-12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"io/fs"
2222
"log/slog"
2323
"os"
24+
"os/exec"
2425
"path/filepath"
2526
"regexp"
2627
"strings"
@@ -30,16 +31,20 @@ import (
3031
)
3132

3233
type Package struct {
33-
Name string `yaml:"name,omitempty"`
34-
Version string `yaml:"version,omitempty"`
35-
Description string `yaml:"description,omitempty"`
36-
InstallSteps []PackageInstallStep `yaml:"installSteps,omitempty"`
37-
Dependencies []string `yaml:"dependencies,omitempty"`
38-
Tags []string `yaml:"tags,omitempty"`
39-
PostInstallNotes string `yaml:"postInstallNotes,omitempty"`
40-
Options []PackageOption `yaml:"options,omitempty"`
41-
Outputs []PackageOutput `yaml:"outputs,omitempty"`
42-
filePath string
34+
Name string `yaml:"name,omitempty"`
35+
Version string `yaml:"version,omitempty"`
36+
Description string `yaml:"description,omitempty"`
37+
InstallSteps []PackageInstallStep `yaml:"installSteps,omitempty"`
38+
Dependencies []string `yaml:"dependencies,omitempty"`
39+
Tags []string `yaml:"tags,omitempty"`
40+
PreInstallScript string `yaml:"preInstallScript,omitempty"`
41+
PostInstallScript string `yaml:"postInstallScript,omitempty"`
42+
PreUninstallScript string `yaml:"preUninstallScript,omitempty"`
43+
PostUninstallScript string `yaml:"postUninstallScript,omitempty"`
44+
PostInstallNotes string `yaml:"postInstallNotes,omitempty"`
45+
Options []PackageOption `yaml:"options,omitempty"`
46+
Outputs []PackageOutput `yaml:"outputs,omitempty"`
47+
filePath string
4348
}
4449

4550
type PackageOption struct {
@@ -101,7 +106,7 @@ func (p Package) hasTags(tags []string) bool {
101106
return true
102107
}
103108

104-
func (p Package) install(cfg Config, context string, opts map[string]bool) (string, map[string]string, error) {
109+
func (p Package) install(cfg Config, context string, opts map[string]bool, runHooks bool) (string, map[string]string, error) {
105110
// Update template vars
106111
pkgName := fmt.Sprintf("%s-%s-%s", p.Name, p.Version, context)
107112
pkgCacheDir := filepath.Join(
@@ -154,6 +159,12 @@ func (p Package) install(cfg Config, context string, opts map[string]bool) (stri
154159
if err := os.MkdirAll(pkgDataDir, fs.ModePerm); err != nil {
155160
return "", nil, err
156161
}
162+
// Run pre-install script
163+
if runHooks && p.PreInstallScript != "" {
164+
if err := p.runHookScript(cfg, p.PreInstallScript); err != nil {
165+
return "", nil, err
166+
}
167+
}
157168
// Perform install
158169
for _, installStep := range p.InstallSteps {
159170
// Evaluate condition if defined
@@ -235,6 +246,12 @@ func (p Package) install(cfg Config, context string, opts map[string]bool) (stri
235246
}
236247
retOutputs[key] = val
237248
}
249+
// Run post-install script
250+
if runHooks && p.PostInstallScript != "" {
251+
if err := p.runHookScript(cfg, p.PostInstallScript); err != nil {
252+
return "", nil, err
253+
}
254+
}
238255
// Render notes and return
239256
var retNotes string
240257
if p.PostInstallNotes != "" {
@@ -247,8 +264,14 @@ func (p Package) install(cfg Config, context string, opts map[string]bool) (stri
247264
return retNotes, retOutputs, nil
248265
}
249266

250-
func (p Package) uninstall(cfg Config, context string, keepData bool) error {
267+
func (p Package) uninstall(cfg Config, context string, keepData bool, runHooks bool) error {
251268
pkgName := fmt.Sprintf("%s-%s-%s", p.Name, p.Version, context)
269+
// Run pre-uninstall script
270+
if runHooks && p.PreUninstallScript != "" {
271+
if err := p.runHookScript(cfg, p.PreUninstallScript); err != nil {
272+
return err
273+
}
274+
}
252275
// Iterate over install steps in reverse
253276
for idx := len(p.InstallSteps) - 1; idx >= 0; idx-- {
254277
installStep := p.InstallSteps[idx]
@@ -331,6 +354,12 @@ func (p Package) uninstall(cfg Config, context string, keepData bool) error {
331354
)
332355
}
333356
}
357+
// Run post-uninstall script
358+
if runHooks && p.PostUninstallScript != "" {
359+
if err := p.runHookScript(cfg, p.PostUninstallScript); err != nil {
360+
return err
361+
}
362+
}
334363
return nil
335364
}
336365

@@ -535,6 +564,20 @@ func (p Package) services(cfg Config, context string) ([]*DockerService, error)
535564
return ret, nil
536565
}
537566

567+
func (p Package) runHookScript(cfg Config, hookScript string) error {
568+
renderedScript, err := cfg.Template.Render(hookScript, nil)
569+
if err != nil {
570+
return fmt.Errorf("failed to render hook script template: %s", err)
571+
}
572+
cmd := exec.Command("/bin/sh", "-c", renderedScript)
573+
cmd.Stdout = os.Stdout
574+
cmd.Stderr = os.Stderr
575+
if err := cmd.Run(); err != nil {
576+
return fmt.Errorf("failed to run hook script: %s", err)
577+
}
578+
return nil
579+
}
580+
538581
type PackageInstallStep struct {
539582
Condition string `yaml:"condition,omitempty"`
540583
Docker *PackageInstallStepDocker `yaml:"docker,omitempty"`

pkgmgr/pkgmgr.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func (p *PackageManager) Install(pkgs ...string) error {
188188
tmpPkgOpts[k] = v
189189
}
190190
// Install package
191-
notes, outputs, err := installPkg.Install.install(p.config, activeContextName, tmpPkgOpts)
191+
notes, outputs, err := installPkg.Install.install(p.config, activeContextName, tmpPkgOpts, true)
192192
if err != nil {
193193
return err
194194
}
@@ -262,11 +262,11 @@ func (p *PackageManager) Upgrade(pkgs ...string) error {
262262
)
263263
}
264264
// Uninstall old version
265-
if err := p.uninstallPackage(upgradePkg.Installed, true); err != nil {
265+
if err := p.uninstallPackage(upgradePkg.Installed, true, false); err != nil {
266266
return err
267267
}
268268
// Install new version
269-
notes, outputs, err := upgradePkg.Upgrade.install(p.config, activeContextName, pkgOpts)
269+
notes, outputs, err := upgradePkg.Upgrade.install(p.config, activeContextName, pkgOpts, false)
270270
if err != nil {
271271
return err
272272
}
@@ -349,7 +349,7 @@ func (p *PackageManager) Uninstall(pkgName string, keepData bool, force bool) er
349349
fmt.Sprintf("failed to deactivate package: %s", err),
350350
)
351351
}
352-
if err := p.uninstallPackage(uninstallPkg, keepData); err != nil {
352+
if err := p.uninstallPackage(uninstallPkg, keepData, true); err != nil {
353353
return err
354354
}
355355
if err := p.state.Save(); err != nil {
@@ -498,9 +498,9 @@ func (p *PackageManager) Info(pkgs ...string) error {
498498
return nil
499499
}
500500

501-
func (p *PackageManager) uninstallPackage(uninstallPkg InstalledPackage, keepData bool) error {
501+
func (p *PackageManager) uninstallPackage(uninstallPkg InstalledPackage, keepData bool, runHooks bool) error {
502502
// Uninstall package
503-
if err := uninstallPkg.Package.uninstall(p.config, uninstallPkg.Context, keepData); err != nil {
503+
if err := uninstallPkg.Package.uninstall(p.config, uninstallPkg.Context, keepData, runHooks); err != nil {
504504
return err
505505
}
506506
// Remove package from installed packages

0 commit comments

Comments
 (0)