udpdate main program | simplify loaders (no more meta table for distro/package) | add default loader (pkg, ser) values | manage context creation : instruction.CreateContext() | fix tests | no more -distro parameter, only -package
This commit is contained in:
parent
f7d930b588
commit
ff06cccb89
|
@ -0,0 +1,55 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/instruction"
|
||||
)
|
||||
|
||||
func GetArgs() (*instruction.ExecutionContext, string, error) {
|
||||
setupFlags(flag.CommandLine)
|
||||
|
||||
longPack := flag.String("package", "", "")
|
||||
longServ := flag.String("service", "", "")
|
||||
pack := flag.String("p", "", "")
|
||||
serv := flag.String("s", "", "")
|
||||
flag.Parse()
|
||||
|
||||
// 1. fail on missing build file
|
||||
if len(flag.Args()) < 1 {
|
||||
return nil, "", fmt.Errorf("missing buildfile")
|
||||
}
|
||||
buildfile := flag.Arg(0)
|
||||
|
||||
// 2. override short version with long
|
||||
if longPack != nil && len(*longPack) > 0 {
|
||||
pack = longPack
|
||||
}
|
||||
if longServ != nil && len(*longServ) > 0 {
|
||||
serv = longServ
|
||||
}
|
||||
|
||||
// 3. fail on missing mandatory fields
|
||||
if pack == nil || len(*pack) < 1 {
|
||||
return nil, "", fmt.Errorf("missing -package")
|
||||
}
|
||||
// if serv == nil || len(*serv) < 1 { // default service
|
||||
// return nil, "", fmt.Errorf("missing -service")
|
||||
// }
|
||||
|
||||
// 3. Load context
|
||||
ctx, err := instruction.CreateContext(*pack, *serv)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
/*DEBUG*/ //fmt.Printf("package: '%s' | '%s'\n", fpackage, lpackage)
|
||||
/*DEBUG*/ //fmt.Printf("service: '%s' | '%s'\n", fservice, lservice)
|
||||
|
||||
return ctx, buildfile, nil
|
||||
}
|
||||
|
||||
func setupFlags(f *flag.FlagSet) {
|
||||
f.Usage = func() {
|
||||
help()
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ func help() {
|
|||
fmt.Printf("\tnix-amer - the automatic setup tool you need\n")
|
||||
|
||||
fmt.Printf("\n%s\n", clifmt.Color(1, "SYNOPSIS", true))
|
||||
fmt.Printf("\tnix-amer [-d <linux-distro> [-p <package-manager>] [-s <service-manager>] <buildfile>\n")
|
||||
fmt.Printf("\tnix-amer [-p <package-manager>] [-s <service-manager>] <buildfile>\n")
|
||||
fmt.Printf("\tnix-amer -help\n")
|
||||
fmt.Printf("\tnix-amer -h\n")
|
||||
fmt.Printf("\n")
|
||||
|
@ -28,11 +28,6 @@ func help() {
|
|||
|
||||
fmt.Printf("\n%s\n", clifmt.Color(1, "OPTIONS", true))
|
||||
|
||||
fmt.Printf("\t-d, -distro\n\t Define which linux distribution the target will run on.\n")
|
||||
fmt.Printf("\t Available values are 'debian', 'ubuntu', 'alpine', 'solus',\n")
|
||||
fmt.Printf("\t 'arch', 'centos' and 'fedora'.\n")
|
||||
fmt.Printf("\n")
|
||||
|
||||
fmt.Printf("\t-p, -package\n\t Define which package manager to use ; normally it is\n")
|
||||
fmt.Printf("\t automatically guessed if you define the -distro. Available\n")
|
||||
fmt.Printf("\t values are 'apt-get', 'eopkg', 'apk', 'yum', 'dnf' and 'pacman'.\n")
|
||||
|
|
|
@ -1,5 +1,37 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/buildfile"
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/clifmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
help()
|
||||
|
||||
// Manage arguments
|
||||
ctx, bf, err := GetArgs()
|
||||
if err != nil {
|
||||
fmt.Printf("%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 1. get buildfile reader
|
||||
bfreader, err := os.Open(bf)
|
||||
if err != nil {
|
||||
fmt.Printf("cannot open buildfile | %s\n", err)
|
||||
return
|
||||
}
|
||||
defer bfreader.Close()
|
||||
|
||||
// 2. parse buildfile
|
||||
_, err = buildfile.NewReader(ctx, bfreader)
|
||||
if err != nil {
|
||||
fmt.Printf("%s%s\n", bf, err)
|
||||
return
|
||||
}
|
||||
|
||||
clifmt.Align("build file")
|
||||
fmt.Printf("%s\n", clifmt.Color(32, "parsed"))
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package buildfile
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/clifmt"
|
||||
)
|
||||
|
||||
type LineError struct {
|
||||
|
@ -10,5 +11,5 @@ type LineError struct {
|
|||
}
|
||||
|
||||
func (le LineError) Error() string {
|
||||
return fmt.Sprintf("line %d | %s", le.Line, le.Err.Error())
|
||||
return fmt.Sprintf(":%d %s", le.Line, clifmt.Color(31, le.Err.Error()))
|
||||
}
|
||||
|
|
|
@ -2,23 +2,33 @@ package buildfile
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/instruction"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ErrNullContext = errors.New("null context")
|
||||
|
||||
// Reader is the buildfile reader
|
||||
type Reader struct {
|
||||
// linux distribution to run on
|
||||
distribution string
|
||||
Content []instruction.T
|
||||
// Context is the linux distribution-specified execution context (package manager, service manager, etc)
|
||||
Context *instruction.ExecutionContext
|
||||
// Content is the instruction list
|
||||
Content []instruction.T
|
||||
}
|
||||
|
||||
// NewReader creates a new reader for the specified build file and linux distribution
|
||||
func NewReader(distro string, buildfile io.Reader) (*Reader, error) {
|
||||
func NewReader(ctx *instruction.ExecutionContext, buildfile io.Reader) (*Reader, error) {
|
||||
|
||||
// fail on null context
|
||||
if ctx == nil {
|
||||
return nil, ErrNullContext
|
||||
}
|
||||
|
||||
r := &Reader{
|
||||
distribution: distro,
|
||||
Content: make([]instruction.T, 0),
|
||||
Context: ctx,
|
||||
Content: make([]instruction.T, 0),
|
||||
}
|
||||
|
||||
// add each line as instruction
|
||||
|
@ -33,6 +43,12 @@ func NewReader(distro string, buildfile io.Reader) (*Reader, error) {
|
|||
} else if err != nil {
|
||||
return nil, LineError{l, err}
|
||||
}
|
||||
line = strings.Trim(line, " \t\r\n")
|
||||
|
||||
// ignore newline & comments
|
||||
if len(line) < 1 || line[0] == '[' {
|
||||
continue
|
||||
}
|
||||
|
||||
// turn into instruction
|
||||
inst, err := instruction.Parse(line)
|
||||
|
|
|
@ -34,11 +34,13 @@ func TestInstructionSyntax(t *testing.T) {
|
|||
{"ins args\ncm args\n", 2, instruction.ErrInvalidSyntax},
|
||||
}
|
||||
|
||||
ctx, _ := instruction.CreateContext("apt-get", "")
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
// create reader
|
||||
buffer := bytes.NewBufferString(test.File)
|
||||
_, err := NewReader("ubuntu", buffer)
|
||||
_, err := NewReader(ctx, buffer)
|
||||
|
||||
// no error expected
|
||||
if test.Err == nil {
|
||||
|
|
|
@ -2,6 +2,7 @@ package instruction
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/cnf"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -12,20 +13,24 @@ type config struct {
|
|||
Path []string
|
||||
// Value if the value to add or update
|
||||
Value string
|
||||
// Format is the configuration format in use
|
||||
Format *cnf.ConfigurationFormat
|
||||
}
|
||||
|
||||
func (d *config) Build(_args string) error {
|
||||
|
||||
// 1. extract action (sub command)
|
||||
split := strings.SplitN(_args, " ", 2)
|
||||
split := strings.Fields(_args)
|
||||
|
||||
// 2. check path
|
||||
if len(split) < 2 {
|
||||
return fmt.Errorf("missing configuration path")
|
||||
}
|
||||
path := split[0]
|
||||
value := strings.Join(split[1:], "")
|
||||
|
||||
// 3. check path separator
|
||||
splitPath := strings.Split(split[0], "@")
|
||||
splitPath := strings.Split(path, "@")
|
||||
if len(splitPath) > 2 {
|
||||
return fmt.Errorf("invalid path (additional '@'?)")
|
||||
}
|
||||
|
@ -36,7 +41,7 @@ func (d *config) Build(_args string) error {
|
|||
}
|
||||
|
||||
// add value
|
||||
d.Value = split[1]
|
||||
d.Value = value
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package instruction
|
||||
|
||||
import (
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/cnf"
|
||||
"fmt"
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/pkg"
|
||||
"git.xdrm.io/xdrm-brackets/nix-amer/internal/ser"
|
||||
)
|
||||
|
@ -16,6 +16,43 @@ type T interface {
|
|||
|
||||
type ExecutionContext struct {
|
||||
PackageManager pkg.PackageManager
|
||||
Configuration cnf.ConfigurationFormat
|
||||
ServiceManager ser.ServiceManager
|
||||
}
|
||||
|
||||
// CreateContext creates an execution contet with the given package-manager and service-manager
|
||||
// default values are taken from each go package (pkg, ser)
|
||||
func CreateContext(_pkg, _ser string) (*ExecutionContext, error) {
|
||||
|
||||
// 1. fail if no value and no defaults
|
||||
if len(_pkg)+len(pkg.DefaultManager) < 1 {
|
||||
return nil, fmt.Errorf("missing package manager")
|
||||
}
|
||||
if len(_ser)+len(ser.DefaultManager) < 1 {
|
||||
return nil, fmt.Errorf("missing service manager")
|
||||
}
|
||||
|
||||
// 2. set default
|
||||
if len(_pkg) < 1 {
|
||||
_pkg = pkg.DefaultManager
|
||||
}
|
||||
if len(_ser) < 1 {
|
||||
_ser = ser.DefaultManager
|
||||
}
|
||||
|
||||
// 3. load managers
|
||||
pkg, err := pkg.Load(_pkg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("package manager: %s", err)
|
||||
}
|
||||
ser, err := ser.Load(_ser)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("service manager: %s", err)
|
||||
}
|
||||
|
||||
// 4. build context
|
||||
return &ExecutionContext{
|
||||
PackageManager: pkg,
|
||||
ServiceManager: ser,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
|
|
@ -8,16 +8,15 @@ import (
|
|||
func Parse(raw string) (T, error) {
|
||||
|
||||
// 1. format (trim + split first space)
|
||||
raw = strings.Trim(raw, " \t\n")
|
||||
cmd := strings.SplitN(raw, " ", 2)
|
||||
cmd[0] = strings.Trim(cmd[0], " \t")
|
||||
cmd[1] = strings.Trim(cmd[1], " \t")
|
||||
|
||||
// 2. fail if invalid base syntax 'cmd args...'
|
||||
// where command is 3 letters
|
||||
if len(cmd) < 2 || len(cmd[0]) < 3 || cmd[0][1] == ' ' {
|
||||
return nil, ErrInvalidSyntax
|
||||
}
|
||||
cmd[1] = strings.Trim(cmd[1], " \t")
|
||||
|
||||
// 3. Extract instruction type
|
||||
switch cmd[0] {
|
||||
|
@ -29,10 +28,6 @@ func Parse(raw string) (T, error) {
|
|||
i := &delete{}
|
||||
err := i.Build(cmd[1])
|
||||
return i, err
|
||||
case "upd":
|
||||
i := &update{}
|
||||
err := i.Build(cmd[1])
|
||||
return i, err
|
||||
case "ser":
|
||||
i := &service{}
|
||||
err := i.Build(cmd[1])
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package pkg
|
||||
|
||||
var DefaultManager = ""
|
||||
|
||||
// PackageManager is the common interface for all package-manager drivers (e.g. `dpkg` for debian-based, `pacman` for arch)
|
||||
type PackageManager interface {
|
||||
// Name of executable (to check if installed and for debug)
|
||||
|
|
|
@ -1,71 +1,38 @@
|
|||
package pkg
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var ErrUnknownDistribution = errors.New("unknown linux distribution")
|
||||
var ErrNoCandidateInstalled = errors.New("no package-manager candidate installed")
|
||||
var ErrNoDriverFound = errors.New("no driver found for the package manager")
|
||||
var ErrUnknownManager = errors.New("unknown package manager")
|
||||
var ErrNotInstalled = errors.New("no candidate installed")
|
||||
|
||||
func Load(_distro string) (PackageManager, error) {
|
||||
func Load(_manager string) (PackageManager, error) {
|
||||
|
||||
// 1. load config file
|
||||
driverTable := filepath.Join(os.Getenv("GOPATH"), "src/git.xdrm.io/xdrm-brackets/nix-amer/meta/pkg-drivers.json")
|
||||
file, err := os.Open(driverTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 2. Parse json
|
||||
table := make(map[string][]string)
|
||||
decoder := json.NewDecoder(file)
|
||||
if err := decoder.Decode(&table); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decoder = nil
|
||||
|
||||
// 3. Get available package-manager list for distro
|
||||
available, exists := table[_distro]
|
||||
if !exists || len(available) < 1 {
|
||||
return nil, ErrUnknownDistribution
|
||||
}
|
||||
|
||||
// 4. Check each available package-manager in order
|
||||
selected := ""
|
||||
for _, current := range available {
|
||||
if exec.Command("which", current).Run() == nil {
|
||||
selected = current
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// no candidate installed
|
||||
if len(selected) < 1 {
|
||||
return nil, ErrNoCandidateInstalled
|
||||
}
|
||||
|
||||
// 5. Instanciate
|
||||
switch selected {
|
||||
// 1. create manager (fail if unknown)
|
||||
var manager PackageManager
|
||||
switch _manager {
|
||||
case "apt-get":
|
||||
return new(Apt), nil
|
||||
manager = new(Apt)
|
||||
case "apk":
|
||||
return new(Apk), nil
|
||||
manager = new(Apk)
|
||||
case "eopkg":
|
||||
return new(Eopkg), nil
|
||||
manager = new(Eopkg)
|
||||
case "pacman":
|
||||
return new(Pacman), nil
|
||||
manager = new(Pacman)
|
||||
case "dnf":
|
||||
return new(Dnf), nil
|
||||
manager = new(Dnf)
|
||||
case "yum":
|
||||
return new(Yum), nil
|
||||
manager = new(Yum)
|
||||
default:
|
||||
return nil, ErrUnknownManager
|
||||
}
|
||||
|
||||
return nil, ErrNoDriverFound
|
||||
// 2. fail if not installed
|
||||
// if exec.Command("which", manager.Name()).Run() != nil {
|
||||
// return nil, ErrNotInstalled
|
||||
// }
|
||||
|
||||
return manager, nil
|
||||
|
||||
}
|
||||
|
|
|
@ -1,46 +1,23 @@
|
|||
package pkg
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnknownDistribution(t *testing.T) {
|
||||
func TestUnknownManager(t *testing.T) {
|
||||
|
||||
_, err := Load("invalid-distro-xxx")
|
||||
if err != ErrUnknownDistribution {
|
||||
t.Errorf("expected <%s>, got <%s>", ErrUnknownDistribution, err)
|
||||
_, err := Load("apt-put")
|
||||
if err != ErrUnknownManager {
|
||||
t.Errorf("expected <%s>, got <%s>", ErrUnknownManager, err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
||||
func TestNoCandidateInstalled(t *testing.T) {
|
||||
func TestKnownManager(t *testing.T) {
|
||||
|
||||
// get host distro
|
||||
out, err := exec.Command("lsb_release", "-is").Output()
|
||||
_, err := Load("apt-get")
|
||||
if err != nil {
|
||||
t.Errorf("cannot get host linux distribution")
|
||||
t.Fail()
|
||||
}
|
||||
hostDistro := strings.ToLower(strings.Trim(string(out), " \n\t"))
|
||||
|
||||
// valid candidate
|
||||
_, err = Load(hostDistro)
|
||||
if err != nil {
|
||||
t.Errorf("expected <nil>, got <%s>", err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// invalid candidate
|
||||
distro := "solus"
|
||||
if hostDistro == distro {
|
||||
distro = "ubuntu"
|
||||
}
|
||||
|
||||
_, err = Load(distro)
|
||||
if err != ErrNoCandidateInstalled {
|
||||
t.Errorf("expected <%s>, got <%s>", ErrNoCandidateInstalled, err)
|
||||
t.Errorf("unexpected error <%s>", err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ser
|
||||
|
||||
var DefaultManager = "systemd"
|
||||
|
||||
// ServiceManager is the common interface for service managers (systemd, init.d)
|
||||
type ServiceManager interface {
|
||||
// Name of executable (to check if installed and for debug)
|
||||
|
|
|
@ -2,31 +2,14 @@ package ser
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
var ErrUnknownManager = errors.New("unknown service manager")
|
||||
var ErrNoCandidateInstalled = errors.New("no package-manager candidate installed")
|
||||
|
||||
// available service managers
|
||||
// var available = []string{"systemd", "init"}
|
||||
var available = []string{"systemd"}
|
||||
var ErrNotInstalled = errors.New("not candidate installed")
|
||||
|
||||
func Load(_manager string) (ServiceManager, error) {
|
||||
|
||||
// 1. fail if unknown manager
|
||||
known := false
|
||||
for _, mgr := range available {
|
||||
if _manager == mgr {
|
||||
known = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !known {
|
||||
return nil, ErrUnknownManager
|
||||
}
|
||||
|
||||
// 2. Create manager accordingly
|
||||
// 1. create manager (fail if unknown)
|
||||
var manager ServiceManager
|
||||
switch _manager {
|
||||
case "systemd":
|
||||
|
@ -36,9 +19,9 @@ func Load(_manager string) (ServiceManager, error) {
|
|||
}
|
||||
|
||||
// 2. fail if not installed
|
||||
if exec.Command("which", manager.Name()).Run() == nil {
|
||||
return nil, ErrNoCandidateInstalled
|
||||
}
|
||||
// if exec.Command("which", manager.Name()).Run() != nil {
|
||||
// return nil, ErrNotInstalled
|
||||
// }
|
||||
|
||||
return manager, nil
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ubuntu": [ "apt-get" ],
|
||||
"debian": [ "apt-get" ],
|
||||
|
||||
"alpine": [ "apk" ],
|
||||
|
||||
"solus": [ "eopkg" ],
|
||||
|
||||
"arch": [ "pacman" ],
|
||||
|
||||
"centos": [ "dnf", "yum" ],
|
||||
"fedora": [ "dnf", "yum" ]
|
||||
}
|
Loading…
Reference in New Issue