Skip to content

Commit

Permalink
Wire templates into mkuimage
Browse files Browse the repository at this point in the history
mkuimage defaults for init & shell are removed. Templates can be used
instead.

Signed-off-by: Chris Koch <[email protected]>
  • Loading branch information
hugelgupf committed Feb 18, 2024
1 parent 75bf238 commit 322a26a
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 25 deletions.
52 changes: 41 additions & 11 deletions cmd/mkuimage/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/dustin/go-humanize"
"github.com/u-root/gobusybox/src/pkg/golang"
"github.com/u-root/mkuimage/uimage"
"github.com/u-root/mkuimage/uimage/templates"
"github.com/u-root/mkuimage/uimage/uflags"
"github.com/u-root/uio/llog"
)
Expand All @@ -26,6 +27,11 @@ var (
errEmptyFilesArg = errors.New("empty argument to -files")
)

var (
config = flag.String("config", "", "Config to pick from templates")
configFile = flag.String("config-file", "", "Config file to read from (default: finds .mkuimage.yaml in cwd or parents)")
)

// checkArgs checks for common mistakes that cause confusion.
// 1. -files as the last argument
// 2. -files followed by any switch, indicating a shell expansion problem
Expand Down Expand Up @@ -61,19 +67,12 @@ func main() {
log.Fatal(err)
}

var sh string
if golang.Default().GOOS != "plan9" {
sh = "gosh"
}

env := golang.Default(golang.DisableCGO())
f := &uflags.Flags{
Commands: uflags.CommandFlags{
Builder: "bb",
BuildOpts: &golang.BuildOpts{},
},
Init: "init",
Shell: sh,
ArchiveFormat: "cpio",
OutputFile: defaultFile(env),
}
Expand All @@ -83,15 +82,32 @@ func main() {
l.RegisterVerboseFlag(flag.CommandLine, "v", slog.LevelDebug)
flag.Parse()

var tpl *templates.Templates
var err error
if *configFile != "" {
tpl, err = templates.TemplateFromFile(*configFile)
if err != nil {
l.Errorf("Failed to read template: %v", err)
os.Exit(1)
}
} else {
tpl, err = templates.Template()
// Only complain about not finding a template if user requested a templated config.
if err != nil && *config != "" {
l.Errorf("Could not find template file: %v", err)
os.Exit(1)
}
}

l.Infof("Build environment: %s", env)
if env.GOOS != "linux" {
l.Warnf("GOOS is not linux. Did you mean to set GOOS=linux?")
}

// Main is in a separate functions so defers run on return.
if err := Main(l, env, f); err != nil {
if err := Main(l, env, tpl, f); err != nil {
l.Errorf("Build error: %v", err)
return
os.Exit(1)
}

if stat, err := os.Stat(f.OutputFile); err == nil && f.ArchiveFormat == "cpio" {
Expand Down Expand Up @@ -123,7 +139,7 @@ func defaultFile(env *golang.Environ) string {

// Main is a separate function so defers are run on return, which they wouldn't
// on exit.
func Main(l *llog.Logger, env *golang.Environ, f *uflags.Flags) error {
func Main(l *llog.Logger, env *golang.Environ, tpl *templates.Templates, f *uflags.Flags) error {
v, err := env.Version()
if err != nil {
l.Infof("Could not get environment's Go version, using runtime's version: %v", err)
Expand Down Expand Up @@ -162,7 +178,21 @@ func Main(l *llog.Logger, env *golang.Environ, f *uflags.Flags) error {
uimage.WithBaseArchive(uimage.DefaultRamfs()),
uimage.WithCPIOOutput(defaultFile(env)),
}
more, err := f.Modifiers(flag.Args()...)
// Evaluate template first -- template settings may always be
// appended/overridden by further flag-based settings.
if *config != "" {
mods, err := tpl.Uimage(*config)
if err != nil {
return err
}
m = append(m, mods...)
}
pkgs := flag.Args()
// Expand command templates.
if tpl != nil {
pkgs = tpl.CommandsFor(pkgs...)
}
more, err := f.Modifiers(pkgs...)
if err != nil {
return err
}
Expand Down
81 changes: 67 additions & 14 deletions cmd/mkuimage/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"os/exec"
"path/filepath"
"strings"
"syscall"
"testing"

"github.com/u-root/gobusybox/src/pkg/golang"
Expand Down Expand Up @@ -65,7 +66,7 @@ func TestUrootCmdline(t *testing.T) {
name string
env []string
args []string
err error
exitCode int
validators []itest.ArchiveValidator
}

Expand All @@ -74,7 +75,6 @@ func TestUrootCmdline(t *testing.T) {
name: "include one extra file",
args: []string{"-nocmd", "-files=/bin/bash"},
env: []string{"GO111MODULE=off"},
err: nil,
validators: []itest.ArchiveValidator{
itest.HasFile{Path: "bin/bash"},
},
Expand All @@ -83,7 +83,6 @@ func TestUrootCmdline(t *testing.T) {
name: "fix usage of an absolute path",
args: []string{"-nocmd", fmt.Sprintf("-files=%s:/bin", sampledir)},
env: []string{"GO111MODULE=off"},
err: nil,
validators: []itest.ArchiveValidator{
itest.HasFile{Path: "/bin/foo"},
itest.HasFile{Path: "/bin/bar"},
Expand Down Expand Up @@ -122,7 +121,6 @@ func TestUrootCmdline(t *testing.T) {
{
name: "uinitcmd",
args: []string{"-uinitcmd=echo foobar fuzz", "-defaultsh=", "github.com/u-root/u-root/cmds/core/init", "github.com/u-root/u-root/cmds/core/echo"},
err: nil,
validators: []itest.ArchiveValidator{
itest.HasRecord{R: cpio.Symlink("bin/uinit", "../bbin/echo")},
itest.HasContent{
Expand All @@ -134,7 +132,6 @@ func TestUrootCmdline(t *testing.T) {
{
name: "binary build",
args: []string{"-build=binary", "-defaultsh=", "github.com/u-root/u-root/cmds/core/init", "github.com/u-root/u-root/cmds/core/echo"},
err: nil,
validators: []itest.ArchiveValidator{
itest.HasFile{Path: "bin/init"},
itest.HasFile{Path: "bin/echo"},
Expand Down Expand Up @@ -181,6 +178,56 @@ func TestUrootCmdline(t *testing.T) {
"github.com/u-root/u-root/cmds/core/echo",
},
},
{
name: "template config",
args: []string{"-config-file=./testdata/test-config.yaml", "-v", "-config=coreconf"},
validators: []itest.ArchiveValidator{
itest.HasRecord{R: cpio.CharDev("dev/tty", 0o666, 5, 0)},
itest.HasFile{Path: "bbin/bb"},
itest.HasRecord{R: cpio.Symlink("bbin/echo", "bb")},
itest.HasRecord{R: cpio.Symlink("bbin/ip", "bb")},
itest.HasRecord{R: cpio.Symlink("bbin/init", "bb")},
itest.HasRecord{R: cpio.Symlink("init", "bbin/init")},
itest.HasRecord{R: cpio.Symlink("bin/sh", "../bbin/echo")},
itest.HasRecord{R: cpio.Symlink("bin/uinit", "../bbin/echo")},
itest.HasRecord{R: cpio.Symlink("bin/defaultsh", "../bbin/echo")},
itest.HasContent{
Path: "etc/uinit.flags",
Content: "\"script.sh\"",
},
},
},
{
name: "template command",
args: []string{"-config-file=./testdata/test-config.yaml", "-v", "core"},
validators: []itest.ArchiveValidator{
itest.HasRecord{R: cpio.CharDev("dev/tty", 0o666, 5, 0)},
itest.HasFile{Path: "bbin/bb"},
itest.HasRecord{R: cpio.Symlink("bbin/echo", "bb")},
itest.HasRecord{R: cpio.Symlink("bbin/ip", "bb")},
itest.HasRecord{R: cpio.Symlink("bbin/init", "bb")},
},
},
{
name: "template config not found",
args: []string{"-config-file=./testdata/test-config.yaml", "-v", "-config=foobar"},
exitCode: 1,
},
{
name: "builder not found",
args: []string{"-v", "build=source"},
exitCode: 1,
},
{
name: "template file not found",
args: []string{"-v", "-config-file=./testdata/doesnotexist"},
exitCode: 1,
},
{
name: "config not found with no default template",
args: []string{"-v", "-config=foo"},
exitCode: 1,
},
}

for _, tt := range append(noCmdTests, bareTests...) {
Expand All @@ -192,18 +239,24 @@ func TestUrootCmdline(t *testing.T) {

g.Go(func() error {
var err error
f1, sum1, err = buildIt(t, execPath, tt.args, tt.env, tt.err, gocoverdir)
f1, sum1, err = buildIt(t, execPath, tt.args, tt.env, gocoverdir)
return err
})

g.Go(func() error {
var err error
f2, sum2, err = buildIt(t, execPath, tt.args, tt.env, tt.err, gocoverdir)
f2, sum2, err = buildIt(t, execPath, tt.args, tt.env, gocoverdir)
return err
})

if err := g.Wait(); err != nil {
t.Fatal(err)
var exitErr *exec.ExitError
if err := g.Wait(); errors.As(err, &exitErr) {
if ec := exitErr.Sys().(syscall.WaitStatus).ExitStatus(); ec != tt.exitCode {
t.Errorf("mkuimage exit code = %d, want %d", ec, tt.exitCode)
}
return
} else if err != nil {
return
}

a, err := itest.ReadArchive(f1.Name())
Expand All @@ -225,7 +278,7 @@ func TestUrootCmdline(t *testing.T) {
}
}

func buildIt(t *testing.T, execPath string, args, env []string, want error, gocoverdir string) (*os.File, []byte, error) {
func buildIt(t *testing.T, execPath string, args, env []string, gocoverdir string) (*os.File, []byte, error) {
t.Helper()
initramfs, err := os.CreateTemp(t.TempDir(), "u-root-")
if err != nil {
Expand All @@ -241,10 +294,10 @@ func buildIt(t *testing.T, execPath string, args, env []string, want error, goco
c.Env = append(os.Environ(), env...)
c.Env = append(c.Env, golang.Default().Env()...)
c.Env = append(c.Env, "GOCOVERDIR="+gocoverdir)
if out, err := c.CombinedOutput(); err != want {
return nil, nil, fmt.Errorf("Error: %v\nOutput:\n%s", err, out)
} else if err != nil {
return initramfs, nil, err
out, err := c.CombinedOutput()
t.Logf("output for %s:\n%s", t.Name(), out)
if err != nil {
return nil, nil, err
}

h1 := sha256.New()
Expand Down
37 changes: 37 additions & 0 deletions cmd/mkuimage/testdata/test-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
commands:
core:
- github.com/u-root/u-root/cmds/core/ip
- github.com/u-root/u-root/cmds/core/init
- github.com/u-root/u-root/cmds/core/echo

minimal:
- github.com/u-root/u-root/cmds/core/ls
- github.com/u-root/u-root/cmds/core/init

plan9:
- github.com/u-root/u-root/cmds/core/ls
- github.com/u-root/u-root/cmds/core/init
- github.com/u-root/u-root/cmds/core/cat

configs:
plan9:
goarch: amd64
goos: plan9
build_tags: [grpcnotrace]
files:
- /bin/bash
init: init
uinit: cat script.sh
shell: cat
commands:
- builder: bb
commands: [plan9]

coreconf:
build_tags: [grpcnotrace]
init: init
uinit: echo script.sh
shell: echo
commands:
- builder: bb
commands: [core, minimal]
9 changes: 9 additions & 0 deletions uimage/uimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,9 @@ func WithUinitCommand(cmd string) Modifier {
// and append arguments from both the kernel command-line
// (uroot.uinitargs) as well as those specified in cmd.
func WithUinit(arg0 string, args ...string) Modifier {
if arg0 == "" && len(args) == 0 {
return nil

Check warning on line 546 in uimage/uimage.go

View check run for this annotation

Codecov / codecov/patch

uimage/uimage.go#L546

Added line #L546 was not covered by tests
}
return func(opts *Opts) error {
opts.UinitCmd = arg0
opts.UinitArgs = args
Expand All @@ -554,6 +557,9 @@ func WithUinit(arg0 string, args ...string) Modifier {
// This can be an absolute path or the name of a command included in
// Commands.
func WithInit(arg0 string) Modifier {
if arg0 == "" {
return nil
}
return func(opts *Opts) error {
opts.InitCmd = arg0
return nil
Expand All @@ -566,6 +572,9 @@ func WithInit(arg0 string) Modifier {
// This can be an absolute path or the name of a command included in
// Commands.
func WithShell(arg0 string) Modifier {
if arg0 == "" {
return nil
}
return func(opts *Opts) error {
opts.DefaultShell = arg0
return nil
Expand Down

0 comments on commit 322a26a

Please sign in to comment.