diff --git a/internal/buildfile/reader_test.go b/internal/buildfile/reader_test.go index de71e4c..8c81e43 100644 --- a/internal/buildfile/reader_test.go +++ b/internal/buildfile/reader_test.go @@ -6,6 +6,27 @@ import ( "testing" ) +func TestNullContext(t *testing.T) { + buffer := bytes.NewBufferString("") + _, err := NewReader(nil, buffer) + if err != ErrNullContext { + t.Fatalf("expected <%s>, got <%v>", ErrNullContext, err) + } +} +func TestIgnoreCommentsAndEmptyLines(t *testing.T) { + ctx, _ := instruction.CreateContext("apt-get", "") + buffer := bytes.NewBufferString("[ some comment ]\n\n \t \n\t \t\n[ other comment after empty lines ]") + + r, err := NewReader(ctx, buffer) + if err != nil { + t.Fatalf("unexpected error <%v>", err) + } + + if len(r.Content) > 0 { + t.Fatalf("expected no content, got %d instructions", len(r.Content)) + } +} + func TestInstructionSyntax(t *testing.T) { tests := []struct { File string diff --git a/internal/exec/common.go b/internal/exec/common.go new file mode 100644 index 0000000..8c210ef --- /dev/null +++ b/internal/exec/common.go @@ -0,0 +1,12 @@ +package exec + +// Command is the common interface wrapping os/exec.Command() output +type Command interface { + Run() error + Output() ([]byte, error) +} + +// Executor is the common interface wrapping os/exec.Command() +type Executor interface { + Command(string, ...string) Command +} diff --git a/internal/exec/os.go b/internal/exec/os.go new file mode 100644 index 0000000..969385a --- /dev/null +++ b/internal/exec/os.go @@ -0,0 +1,11 @@ +package exec + +import ( + osexec "os/exec" +) + +type Default struct{} + +func (d *Default) Command(cmd string, args ...string) Command { + return osexec.Command(cmd, args...) +} diff --git a/internal/instruction/common.go b/internal/instruction/common.go index f0b6ccc..7106edd 100644 --- a/internal/instruction/common.go +++ b/internal/instruction/common.go @@ -2,6 +2,7 @@ package instruction import ( "fmt" + "git.xdrm.io/go/nix-amer/internal/exec" "git.xdrm.io/go/nix-amer/internal/pkg" "git.xdrm.io/go/nix-amer/internal/ser" ) @@ -16,8 +17,14 @@ type T interface { Exec(ExecutionContext) ([]byte, error) } +// Executor is the common interface to execute commands +type Executor interface { + Execute(...string) error +} + // ExecutionContext contains system-specific drivers to manage the host type ExecutionContext struct { + ExecContext Executor PackageManager pkg.PackageManager ServiceManager ser.ServiceManager } @@ -42,12 +49,14 @@ func CreateContext(_pkg, _ser string) (*ExecutionContext, error) { _ser = ser.DefaultManager } + executor := new(exec.Default) + // 3. load managers - pkg, err := pkg.Load(_pkg) + pkg, err := pkg.Load(_pkg, executor) if err != nil { return nil, fmt.Errorf("package manager: %s", err) } - ser, err := ser.Load(_ser) + ser, err := ser.Load(_ser, executor) if err != nil { return nil, fmt.Errorf("service manager: %s", err) } diff --git a/internal/pkg/apk.go b/internal/pkg/apk.go index ea332e5..c622620 100644 --- a/internal/pkg/apk.go +++ b/internal/pkg/apk.go @@ -1,25 +1,27 @@ package pkg -import ( - "os/exec" -) +import "git.xdrm.io/go/nix-amer/internal/exec" -type apk struct{} +type apk struct{ exec exec.Executor } + +func (d *apk) SetExecutor(_exec exec.Executor) { + d.exec = _exec +} func (d apk) Name() string { return "apk" } func (d apk) Fetch() error { - return exec.Command(d.Name(), "update").Run() + return d.exec.Command(d.Name(), "update").Run() } func (d apk) Upgrade() error { - return exec.Command(d.Name(), "upgrade").Run() + return d.exec.Command(d.Name(), "upgrade").Run() } func (d apk) Install(_pkg string) error { - return exec.Command(d.Name(), "add", _pkg).Run() + return d.exec.Command(d.Name(), "add", _pkg).Run() } func (d apk) Remove(_pkg string) error { - return exec.Command(d.Name(), "del", _pkg).Run() + return d.exec.Command(d.Name(), "del", _pkg).Run() } diff --git a/internal/pkg/apt.go b/internal/pkg/apt.go index 2f161ba..358cb61 100644 --- a/internal/pkg/apt.go +++ b/internal/pkg/apt.go @@ -1,40 +1,44 @@ package pkg import ( - "os/exec" + "git.xdrm.io/go/nix-amer/internal/exec" ) -type aptGet struct{} +type aptGet struct{ exec exec.Executor } + +func (d *aptGet) SetExecutor(_exec exec.Executor) { + d.exec = _exec +} func (d aptGet) Name() string { return "apt-get" } func (d aptGet) Fetch() error { - err := exec.Command(d.Name(), "update").Run() + err := d.exec.Command(d.Name(), "update").Run() return err } func (d aptGet) Upgrade() error { - err := exec.Command(d.Name(), "upgrade").Run() + err := d.exec.Command(d.Name(), "upgrade").Run() if err != nil { return err } - err = exec.Command(d.Name(), "dist-upgrade").Run() + err = d.exec.Command(d.Name(), "dist-upgrade").Run() if err != nil { return err } - exec.Command(d.Name(), "autoremove").Run() + d.exec.Command(d.Name(), "autoremove").Run() return nil } func (d aptGet) Install(_pkg string) error { - err := exec.Command(d.Name(), "install", _pkg).Run() + err := d.exec.Command(d.Name(), "install", _pkg).Run() return err } func (d aptGet) Remove(_pkg string) error { - err := exec.Command(d.Name(), "remove", _pkg).Run() - exec.Command(d.Name(), "autoremove").Run() + err := d.exec.Command(d.Name(), "remove", _pkg).Run() + d.exec.Command(d.Name(), "autoremove").Run() return err } diff --git a/internal/pkg/common.go b/internal/pkg/common.go index 54c6b27..b0ac043 100644 --- a/internal/pkg/common.go +++ b/internal/pkg/common.go @@ -1,10 +1,16 @@ package pkg +import ( + "git.xdrm.io/go/nix-amer/internal/exec" +) + // DefaultManager if not empty is the default package-manager to use when missing var DefaultManager = "" // PackageManager is the common interface for all package-manager drivers (e.g. `dpkg` for debian-based, `pacman` for arch) type PackageManager interface { + // SetExecContext sets the execution context, default is os/exec + SetExecutor(exec.Executor) // Name of executable (to check if installed and for debug) Name() string // Fetch updates the package cache/databse diff --git a/internal/pkg/dnf.go b/internal/pkg/dnf.go index d2f2da3..62d58e5 100644 --- a/internal/pkg/dnf.go +++ b/internal/pkg/dnf.go @@ -1,10 +1,12 @@ package pkg -import ( - "os/exec" -) +import "git.xdrm.io/go/nix-amer/internal/exec" -type dnf struct{} +type dnf struct{ exec exec.Executor } + +func (d *dnf) SetExecutor(_exec exec.Executor) { + d.exec = _exec +} func (d dnf) Name() string { return "dnf" } @@ -13,17 +15,17 @@ func (d dnf) Fetch() error { } func (d dnf) Upgrade() error { - err := exec.Command(d.Name(), "upgrade").Run() - exec.Command(d.Name(), "autoremove").Run() + err := d.exec.Command(d.Name(), "upgrade").Run() + d.exec.Command(d.Name(), "autoremove").Run() return err } func (d dnf) Install(_pkg string) error { - return exec.Command(d.Name(), "install", _pkg).Run() + return d.exec.Command(d.Name(), "install", _pkg).Run() } func (d dnf) Remove(_pkg string) error { - err := exec.Command(d.Name(), "remove", _pkg).Run() - exec.Command(d.Name(), "autoremove").Run() + err := d.exec.Command(d.Name(), "remove", _pkg).Run() + d.exec.Command(d.Name(), "autoremove").Run() return err } diff --git a/internal/pkg/eopkg.go b/internal/pkg/eopkg.go index 5be6bc6..d4a311a 100644 --- a/internal/pkg/eopkg.go +++ b/internal/pkg/eopkg.go @@ -1,10 +1,12 @@ package pkg -import ( - "os/exec" -) +import "git.xdrm.io/go/nix-amer/internal/exec" -type eopkg struct{} +type eopkg struct{ exec exec.Executor } + +func (d *eopkg) SetExecutor(_exec exec.Executor) { + d.exec = _exec +} func (d eopkg) Name() string { return "eopkg" } @@ -13,18 +15,18 @@ func (d eopkg) Fetch() error { } func (d eopkg) Upgrade() error { - err := exec.Command(d.Name(), "upgrade").Run() - exec.Command(d.Name(), "remove-orphans").Run() + err := d.exec.Command(d.Name(), "upgrade").Run() + d.exec.Command(d.Name(), "remove-orphans").Run() return err } func (d eopkg) Install(_pkg string) error { - err := exec.Command(d.Name(), "install", _pkg).Run() + err := d.exec.Command(d.Name(), "install", _pkg).Run() return err } func (d eopkg) Remove(_pkg string) error { - err := exec.Command(d.Name(), "remove", _pkg).Run() - exec.Command(d.Name(), "remove-orphans").Run() + err := d.exec.Command(d.Name(), "remove", _pkg).Run() + d.exec.Command(d.Name(), "remove-orphans").Run() return err } diff --git a/internal/pkg/loader.go b/internal/pkg/loader.go index 63e8b26..1d08753 100644 --- a/internal/pkg/loader.go +++ b/internal/pkg/loader.go @@ -2,6 +2,7 @@ package pkg import ( "errors" + "git.xdrm.io/go/nix-amer/internal/exec" ) // ErrUnknownManager is raised when the asked manager does not exist @@ -13,7 +14,7 @@ var ErrUnknownManager = errors.New("unknown package manager") var ErrNotInstalled = errors.New("no candidate installed") // Load a specific package-manager by its name -func Load(_manager string) (PackageManager, error) { +func Load(_manager string, _exec exec.Executor) (PackageManager, error) { // 1. create manager (fail if unknown) var manager PackageManager @@ -39,6 +40,7 @@ func Load(_manager string) (PackageManager, error) { // return nil, ErrNotInstalled // } + manager.SetExecutor(_exec) return manager, nil } diff --git a/internal/pkg/loader_test.go b/internal/pkg/loader_test.go index 2c5fb82..9617810 100644 --- a/internal/pkg/loader_test.go +++ b/internal/pkg/loader_test.go @@ -1,12 +1,37 @@ package pkg import ( + "git.xdrm.io/go/nix-amer/internal/exec" "testing" ) +/////////////////// MOCKUP START /////////////////// +type MockupCommand struct { + Out []byte + Err error +} + +func (c MockupCommand) Run() error { return c.Err } +func (c MockupCommand) Output() ([]byte, error) { return c.Out, c.Err } + +type MockupExecutor struct { + Out []byte + Err error +} + +func (d MockupExecutor) Command(cmd string, args ...string) exec.Command { + return &MockupCommand{Out: d.Out, Err: d.Err} +} + +/////////////////// MOCKUP END /////////////////// + func TestUnknownManager(t *testing.T) { - _, err := Load("apt-put") + execctx := new(MockupExecutor) + execctx.Err = nil + execctx.Out = []byte{} + + _, err := Load("apt-put", execctx) if err != ErrUnknownManager { t.Errorf("expected <%s>, got <%s>", ErrUnknownManager, err) t.Fail() @@ -14,8 +39,11 @@ func TestUnknownManager(t *testing.T) { } func TestKnownManager(t *testing.T) { + execctx := new(MockupExecutor) + execctx.Err = nil + execctx.Out = []byte{} - _, err := Load("apt-get") + _, err := Load("apt-get", execctx) if err != nil { t.Errorf("unexpected error <%s>", err) t.Fail() diff --git a/internal/pkg/pacman.go b/internal/pkg/pacman.go index 304bf67..01f97e1 100644 --- a/internal/pkg/pacman.go +++ b/internal/pkg/pacman.go @@ -1,10 +1,12 @@ package pkg -import ( - "os/exec" -) +import "git.xdrm.io/go/nix-amer/internal/exec" -type pacman struct{} +type pacman struct{ exec exec.Executor } + +func (d *pacman) SetExecutor(_exec exec.Executor) { + d.exec = _exec +} func (d pacman) Name() string { return "pacman" } @@ -13,18 +15,18 @@ func (d pacman) Fetch() error { } func (d pacman) Upgrade() error { - err := exec.Command(d.Name(), "-Syu").Run() - exec.Command(d.Name(), "-Ru").Run() + err := d.exec.Command(d.Name(), "-Syu").Run() + d.exec.Command(d.Name(), "-Ru").Run() return err } func (d pacman) Install(_pkg string) error { - err := exec.Command(d.Name(), "-S", _pkg).Run() + err := d.exec.Command(d.Name(), "-S", _pkg).Run() return err } func (d pacman) Remove(_pkg string) error { - err := exec.Command(d.Name(), "-R", _pkg).Run() - exec.Command(d.Name(), "-Ru").Run() + err := d.exec.Command(d.Name(), "-R", _pkg).Run() + d.exec.Command(d.Name(), "-Ru").Run() return err } diff --git a/internal/pkg/yum.go b/internal/pkg/yum.go index 8c05779..8001fc6 100644 --- a/internal/pkg/yum.go +++ b/internal/pkg/yum.go @@ -1,10 +1,12 @@ package pkg -import ( - "os/exec" -) +import "git.xdrm.io/go/nix-amer/internal/exec" -type yum struct{} +type yum struct{ exec exec.Executor } + +func (d *yum) SetExecutor(_exec exec.Executor) { + d.exec = _exec +} func (d yum) Name() string { return "yum" } @@ -13,13 +15,13 @@ func (d yum) Fetch() error { } func (d yum) Upgrade() error { - return exec.Command(d.Name(), "update").Run() + return d.exec.Command(d.Name(), "update").Run() } func (d yum) Install(_pkg string) error { - return exec.Command(d.Name(), "install", _pkg).Run() + return d.exec.Command(d.Name(), "install", _pkg).Run() } func (d yum) Remove(_pkg string) error { - return exec.Command(d.Name(), "remove", _pkg).Run() + return d.exec.Command(d.Name(), "remove", _pkg).Run() } diff --git a/internal/ser/common.go b/internal/ser/common.go index 5def149..23dbad9 100644 --- a/internal/ser/common.go +++ b/internal/ser/common.go @@ -1,10 +1,16 @@ package ser +import ( + "git.xdrm.io/go/nix-amer/internal/exec" +) + // DefaultManager if not empty is the default service-manager to use when missing var DefaultManager = "systemd" // ServiceManager is the common interface for service managers (systemd, init.d) type ServiceManager interface { + // SetExecContext sets the execution context, default is os/exec + SetExecutor(exec.Executor) // Name of executable (to check if installed and for debug) Name() string // Exec a specific action on a service diff --git a/internal/ser/loader.go b/internal/ser/loader.go index 99a15d7..9a7d261 100644 --- a/internal/ser/loader.go +++ b/internal/ser/loader.go @@ -2,6 +2,7 @@ package ser import ( "errors" + "git.xdrm.io/go/nix-amer/internal/exec" ) // ErrUnknownManager is raised when the asked manager does not exist @@ -13,7 +14,7 @@ var ErrUnknownManager = errors.New("unknown service manager") var ErrNotInstalled = errors.New("no candidate installed") // Load a specific service-manager by its name -func Load(_manager string) (ServiceManager, error) { +func Load(_manager string, _exec exec.Executor) (ServiceManager, error) { // 1. create manager (fail if unknown) var manager ServiceManager @@ -29,6 +30,7 @@ func Load(_manager string) (ServiceManager, error) { // return nil, ErrNotInstalled // } + manager.SetExecutor(_exec) return manager, nil } diff --git a/internal/ser/systemd.go b/internal/ser/systemd.go index c20ab04..feef320 100644 --- a/internal/ser/systemd.go +++ b/internal/ser/systemd.go @@ -1,14 +1,18 @@ package ser import ( - "os/exec" + "git.xdrm.io/go/nix-amer/internal/exec" ) -type systemd struct{} +type systemd struct{ exec exec.Executor } // available actions var actions = []string{"enable", "disable", "start", "stop", "reload", "restart"} +func (d *systemd) SetExecutor(_exec exec.Executor) { + d.exec = _exec +} + func (d systemd) Name() string { return "systemctl" } func (d systemd) Exec(action, service string) error { @@ -26,6 +30,6 @@ func (d systemd) Exec(action, service string) error { } // 2. execute command - return exec.Command("systemctl", action, service).Run() + return d.exec.Command("systemctl", action, service).Run() }