create os/exec generic interface (internal/exec) with 'Default' wrapping os/exec + make tests do not use it

This commit is contained in:
xdrm-brackets 2018-11-11 21:38:16 +01:00
parent 2901a4edd4
commit 1df8f9df9e
16 changed files with 175 additions and 60 deletions

View File

@ -6,6 +6,27 @@ import (
"testing" "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) { func TestInstructionSyntax(t *testing.T) {
tests := []struct { tests := []struct {
File string File string

12
internal/exec/common.go Normal file
View File

@ -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
}

11
internal/exec/os.go Normal file
View File

@ -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...)
}

View File

@ -2,6 +2,7 @@ package instruction
import ( import (
"fmt" "fmt"
"git.xdrm.io/go/nix-amer/internal/exec"
"git.xdrm.io/go/nix-amer/internal/pkg" "git.xdrm.io/go/nix-amer/internal/pkg"
"git.xdrm.io/go/nix-amer/internal/ser" "git.xdrm.io/go/nix-amer/internal/ser"
) )
@ -16,8 +17,14 @@ type T interface {
Exec(ExecutionContext) ([]byte, error) 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 // ExecutionContext contains system-specific drivers to manage the host
type ExecutionContext struct { type ExecutionContext struct {
ExecContext Executor
PackageManager pkg.PackageManager PackageManager pkg.PackageManager
ServiceManager ser.ServiceManager ServiceManager ser.ServiceManager
} }
@ -42,12 +49,14 @@ func CreateContext(_pkg, _ser string) (*ExecutionContext, error) {
_ser = ser.DefaultManager _ser = ser.DefaultManager
} }
executor := new(exec.Default)
// 3. load managers // 3. load managers
pkg, err := pkg.Load(_pkg) pkg, err := pkg.Load(_pkg, executor)
if err != nil { if err != nil {
return nil, fmt.Errorf("package manager: %s", err) return nil, fmt.Errorf("package manager: %s", err)
} }
ser, err := ser.Load(_ser) ser, err := ser.Load(_ser, executor)
if err != nil { if err != nil {
return nil, fmt.Errorf("service manager: %s", err) return nil, fmt.Errorf("service manager: %s", err)
} }

View File

@ -1,25 +1,27 @@
package pkg package pkg
import ( import "git.xdrm.io/go/nix-amer/internal/exec"
"os/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) Name() string { return "apk" }
func (d apk) Fetch() error { 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 { 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 { 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 { func (d apk) Remove(_pkg string) error {
return exec.Command(d.Name(), "del", _pkg).Run() return d.exec.Command(d.Name(), "del", _pkg).Run()
} }

View File

@ -1,40 +1,44 @@
package pkg package pkg
import ( 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) Name() string { return "apt-get" }
func (d aptGet) Fetch() error { func (d aptGet) Fetch() error {
err := exec.Command(d.Name(), "update").Run() err := d.exec.Command(d.Name(), "update").Run()
return err return err
} }
func (d aptGet) Upgrade() error { func (d aptGet) Upgrade() error {
err := exec.Command(d.Name(), "upgrade").Run() err := d.exec.Command(d.Name(), "upgrade").Run()
if err != nil { if err != nil {
return err return err
} }
err = exec.Command(d.Name(), "dist-upgrade").Run() err = d.exec.Command(d.Name(), "dist-upgrade").Run()
if err != nil { if err != nil {
return err return err
} }
exec.Command(d.Name(), "autoremove").Run() d.exec.Command(d.Name(), "autoremove").Run()
return nil return nil
} }
func (d aptGet) Install(_pkg string) error { 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 return err
} }
func (d aptGet) Remove(_pkg string) error { func (d aptGet) Remove(_pkg string) error {
err := exec.Command(d.Name(), "remove", _pkg).Run() err := d.exec.Command(d.Name(), "remove", _pkg).Run()
exec.Command(d.Name(), "autoremove").Run() d.exec.Command(d.Name(), "autoremove").Run()
return err return err
} }

View File

@ -1,10 +1,16 @@
package pkg package pkg
import (
"git.xdrm.io/go/nix-amer/internal/exec"
)
// DefaultManager if not empty is the default package-manager to use when missing // DefaultManager if not empty is the default package-manager to use when missing
var DefaultManager = "" var DefaultManager = ""
// PackageManager is the common interface for all package-manager drivers (e.g. `dpkg` for debian-based, `pacman` for arch) // PackageManager is the common interface for all package-manager drivers (e.g. `dpkg` for debian-based, `pacman` for arch)
type PackageManager interface { 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 of executable (to check if installed and for debug)
Name() string Name() string
// Fetch updates the package cache/databse // Fetch updates the package cache/databse

View File

@ -1,10 +1,12 @@
package pkg package pkg
import ( import "git.xdrm.io/go/nix-amer/internal/exec"
"os/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" } func (d dnf) Name() string { return "dnf" }
@ -13,17 +15,17 @@ func (d dnf) Fetch() error {
} }
func (d dnf) Upgrade() error { func (d dnf) Upgrade() error {
err := exec.Command(d.Name(), "upgrade").Run() err := d.exec.Command(d.Name(), "upgrade").Run()
exec.Command(d.Name(), "autoremove").Run() d.exec.Command(d.Name(), "autoremove").Run()
return err return err
} }
func (d dnf) Install(_pkg string) error { 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 { func (d dnf) Remove(_pkg string) error {
err := exec.Command(d.Name(), "remove", _pkg).Run() err := d.exec.Command(d.Name(), "remove", _pkg).Run()
exec.Command(d.Name(), "autoremove").Run() d.exec.Command(d.Name(), "autoremove").Run()
return err return err
} }

View File

@ -1,10 +1,12 @@
package pkg package pkg
import ( import "git.xdrm.io/go/nix-amer/internal/exec"
"os/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" } func (d eopkg) Name() string { return "eopkg" }
@ -13,18 +15,18 @@ func (d eopkg) Fetch() error {
} }
func (d eopkg) Upgrade() error { func (d eopkg) Upgrade() error {
err := exec.Command(d.Name(), "upgrade").Run() err := d.exec.Command(d.Name(), "upgrade").Run()
exec.Command(d.Name(), "remove-orphans").Run() d.exec.Command(d.Name(), "remove-orphans").Run()
return err return err
} }
func (d eopkg) Install(_pkg string) error { 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 return err
} }
func (d eopkg) Remove(_pkg string) error { func (d eopkg) Remove(_pkg string) error {
err := exec.Command(d.Name(), "remove", _pkg).Run() err := d.exec.Command(d.Name(), "remove", _pkg).Run()
exec.Command(d.Name(), "remove-orphans").Run() d.exec.Command(d.Name(), "remove-orphans").Run()
return err return err
} }

View File

@ -2,6 +2,7 @@ package pkg
import ( import (
"errors" "errors"
"git.xdrm.io/go/nix-amer/internal/exec"
) )
// ErrUnknownManager is raised when the asked manager does not exist // 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") var ErrNotInstalled = errors.New("no candidate installed")
// Load a specific package-manager by its name // 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) // 1. create manager (fail if unknown)
var manager PackageManager var manager PackageManager
@ -39,6 +40,7 @@ func Load(_manager string) (PackageManager, error) {
// return nil, ErrNotInstalled // return nil, ErrNotInstalled
// } // }
manager.SetExecutor(_exec)
return manager, nil return manager, nil
} }

View File

@ -1,12 +1,37 @@
package pkg package pkg
import ( import (
"git.xdrm.io/go/nix-amer/internal/exec"
"testing" "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) { 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 { if err != ErrUnknownManager {
t.Errorf("expected <%s>, got <%s>", ErrUnknownManager, err) t.Errorf("expected <%s>, got <%s>", ErrUnknownManager, err)
t.Fail() t.Fail()
@ -14,8 +39,11 @@ func TestUnknownManager(t *testing.T) {
} }
func TestKnownManager(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 { if err != nil {
t.Errorf("unexpected error <%s>", err) t.Errorf("unexpected error <%s>", err)
t.Fail() t.Fail()

View File

@ -1,10 +1,12 @@
package pkg package pkg
import ( import "git.xdrm.io/go/nix-amer/internal/exec"
"os/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" } func (d pacman) Name() string { return "pacman" }
@ -13,18 +15,18 @@ func (d pacman) Fetch() error {
} }
func (d pacman) Upgrade() error { func (d pacman) Upgrade() error {
err := exec.Command(d.Name(), "-Syu").Run() err := d.exec.Command(d.Name(), "-Syu").Run()
exec.Command(d.Name(), "-Ru").Run() d.exec.Command(d.Name(), "-Ru").Run()
return err return err
} }
func (d pacman) Install(_pkg string) error { 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 return err
} }
func (d pacman) Remove(_pkg string) error { func (d pacman) Remove(_pkg string) error {
err := exec.Command(d.Name(), "-R", _pkg).Run() err := d.exec.Command(d.Name(), "-R", _pkg).Run()
exec.Command(d.Name(), "-Ru").Run() d.exec.Command(d.Name(), "-Ru").Run()
return err return err
} }

View File

@ -1,10 +1,12 @@
package pkg package pkg
import ( import "git.xdrm.io/go/nix-amer/internal/exec"
"os/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" } func (d yum) Name() string { return "yum" }
@ -13,13 +15,13 @@ func (d yum) Fetch() error {
} }
func (d yum) Upgrade() 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 { 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 { func (d yum) Remove(_pkg string) error {
return exec.Command(d.Name(), "remove", _pkg).Run() return d.exec.Command(d.Name(), "remove", _pkg).Run()
} }

View File

@ -1,10 +1,16 @@
package ser package ser
import (
"git.xdrm.io/go/nix-amer/internal/exec"
)
// DefaultManager if not empty is the default service-manager to use when missing // DefaultManager if not empty is the default service-manager to use when missing
var DefaultManager = "systemd" var DefaultManager = "systemd"
// ServiceManager is the common interface for service managers (systemd, init.d) // ServiceManager is the common interface for service managers (systemd, init.d)
type ServiceManager interface { 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 of executable (to check if installed and for debug)
Name() string Name() string
// Exec a specific action on a service // Exec a specific action on a service

View File

@ -2,6 +2,7 @@ package ser
import ( import (
"errors" "errors"
"git.xdrm.io/go/nix-amer/internal/exec"
) )
// ErrUnknownManager is raised when the asked manager does not exist // 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") var ErrNotInstalled = errors.New("no candidate installed")
// Load a specific service-manager by its name // 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) // 1. create manager (fail if unknown)
var manager ServiceManager var manager ServiceManager
@ -29,6 +30,7 @@ func Load(_manager string) (ServiceManager, error) {
// return nil, ErrNotInstalled // return nil, ErrNotInstalled
// } // }
manager.SetExecutor(_exec)
return manager, nil return manager, nil
} }

View File

@ -1,14 +1,18 @@
package ser package ser
import ( import (
"os/exec" "git.xdrm.io/go/nix-amer/internal/exec"
) )
type systemd struct{} type systemd struct{ exec exec.Executor }
// available actions // available actions
var actions = []string{"enable", "disable", "start", "stop", "reload", "restart"} 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) Name() string { return "systemctl" }
func (d systemd) Exec(action, service string) error { func (d systemd) Exec(action, service string) error {
@ -26,6 +30,6 @@ func (d systemd) Exec(action, service string) error {
} }
// 2. execute command // 2. execute command
return exec.Command("systemctl", action, service).Run() return d.exec.Command("systemctl", action, service).Run()
} }