refactor go-flags initialization

This commit is contained in:
Motiejus Jakštys 2021-05-24 00:11:58 +03:00
parent 861f0d319a
commit d7fb5140e8
10 changed files with 46 additions and 84 deletions

View File

@ -1,8 +0,0 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["cmd.go"],
importpath = "github.com/motiejus/code/undocker/internal/cmd",
visibility = ["//src/undocker:__subpackages__"],
)

View File

@ -1,20 +0,0 @@
package cmd
import (
"io"
"os"
)
// BaseCommand provides common fields to all commands.
type BaseCommand struct {
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
}
// Init initializes BaseCommand with default arguments
func (b *BaseCommand) Init() {
b.Stdin = os.Stdin
b.Stdout = os.Stdout
b.Stderr = os.Stderr
}

View File

@ -6,7 +6,6 @@ go_library(
importpath = "github.com/motiejus/code/undocker/internal/cmdlxcconfig", importpath = "github.com/motiejus/code/undocker/internal/cmdlxcconfig",
visibility = ["//src/undocker:__subpackages__"], visibility = ["//src/undocker:__subpackages__"],
deps = [ deps = [
"//src/undocker/internal/cmd:go_default_library",
"//src/undocker/lxcconfig:go_default_library", "//src/undocker/lxcconfig:go_default_library",
"@com_github_jessevdk_go_flags//:go_default_library", "@com_github_jessevdk_go_flags//:go_default_library",
"@org_uber_go_multierr//:go_default_library", "@org_uber_go_multierr//:go_default_library",

View File

@ -2,10 +2,11 @@ package cmdlxcconfig
import ( import (
"errors" "errors"
"fmt"
"io"
"os" "os"
goflags "github.com/jessevdk/go-flags" goflags "github.com/jessevdk/go-flags"
"github.com/motiejus/code/undocker/internal/cmd"
"github.com/motiejus/code/undocker/lxcconfig" "github.com/motiejus/code/undocker/lxcconfig"
"go.uber.org/multierr" "go.uber.org/multierr"
) )
@ -13,7 +14,8 @@ import (
// Command is "lxcconfig" command // Command is "lxcconfig" command
type ( type (
Command struct { Command struct {
cmd.BaseCommand Stdout io.Writer
PositionalArgs struct { PositionalArgs struct {
Infile goflags.Filename `long:"infile" description:"Input tarball"` Infile goflags.Filename `long:"infile" description:"Input tarball"`
Outfile string `long:"outfile" description:"Output path, stdout is '-'"` Outfile string `long:"outfile" description:"Output path, stdout is '-'"`
@ -21,9 +23,17 @@ type (
} }
) )
func NewCommand() *Command {
return &Command{
Stdout: os.Stdout,
}
}
func (*Command) ShortDesc() string { return "Create an LXC-compatible container configuration" }
func (*Command) LongDesc() string { return "" }
// Execute executes lxcconfig Command // Execute executes lxcconfig Command
func (c *Command) Execute(args []string) (err error) { func (c *Command) Execute(args []string) (err error) {
c.BaseCommand.Init()
if len(args) != 0 { if len(args) != 0 {
return errors.New("too many args") return errors.New("too many args")
} }
@ -34,17 +44,18 @@ func (c *Command) Execute(args []string) (err error) {
} }
defer func() { err = multierr.Append(err, rd.Close()) }() defer func() { err = multierr.Append(err, rd.Close()) }()
var out *os.File var out io.Writer
outf := string(c.PositionalArgs.Outfile) outf := string(c.PositionalArgs.Outfile)
if outf == "-" { if fname := string(c.PositionalArgs.Outfile); fname == "-" {
out = os.Stdout out = c.Stdout
} else { } else {
out, err = os.Create(outf) outf, err := os.Create(outf)
if err != nil { if err != nil {
return err return fmt.Errorf("create: %w", err)
} }
defer func() { err = multierr.Append(err, outf.Close()) }()
out = outf
} }
defer func() { err = multierr.Append(err, out.Close()) }()
return lxcconfig.LXCConfig(rd, out) return lxcconfig.LXCConfig(rd, out)
} }

View File

@ -6,7 +6,6 @@ go_library(
importpath = "github.com/motiejus/code/undocker/internal/cmdrootfs", importpath = "github.com/motiejus/code/undocker/internal/cmdrootfs",
visibility = ["//src/undocker:__subpackages__"], visibility = ["//src/undocker:__subpackages__"],
deps = [ deps = [
"//src/undocker/internal/cmd:go_default_library",
"//src/undocker/rootfs:go_default_library", "//src/undocker/rootfs:go_default_library",
"@com_github_jessevdk_go_flags//:go_default_library", "@com_github_jessevdk_go_flags//:go_default_library",
"@org_uber_go_multierr//:go_default_library", "@org_uber_go_multierr//:go_default_library",
@ -18,7 +17,6 @@ go_test(
srcs = ["cmdrootfs_test.go"], srcs = ["cmdrootfs_test.go"],
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//src/undocker/internal/cmd:go_default_library",
"@com_github_jessevdk_go_flags//:go_default_library", "@com_github_jessevdk_go_flags//:go_default_library",
"@com_github_stretchr_testify//assert:go_default_library", "@com_github_stretchr_testify//assert:go_default_library",
"@com_github_stretchr_testify//require:go_default_library", "@com_github_stretchr_testify//require:go_default_library",

View File

@ -7,34 +7,37 @@ import (
"os" "os"
goflags "github.com/jessevdk/go-flags" goflags "github.com/jessevdk/go-flags"
"github.com/motiejus/code/undocker/internal/cmd"
"github.com/motiejus/code/undocker/rootfs" "github.com/motiejus/code/undocker/rootfs"
"go.uber.org/multierr" "go.uber.org/multierr"
) )
type ( type (
// Command is "rootfs" command
Command struct { Command struct {
cmd.BaseCommand flattener func(io.ReadSeeker, io.Writer) error
Stdout io.Writer
PositionalArgs struct { PositionalArgs struct {
Infile goflags.Filename `long:"infile" description:"Input tarball"` Infile goflags.Filename `long:"infile" desc:"Input tarball"`
Outfile string `long:"outfile" description:"Output path, stdout is '-'"` Outfile string `long:"outfile" desc:"Output path, stdout is '-'"`
} `positional-args:"yes" required:"yes"` } `positional-args:"yes" required:"yes"`
flattener func(io.ReadSeeker, io.Writer) error
} }
) )
func NewCommand() *Command {
return &Command{
flattener: rootfs.Flatten,
Stdout: os.Stdout,
}
}
func (*Command) ShortDesc() string { return "Flatten a docker container image to a tarball" }
func (*Command) LongDesc() string { return "" }
// Execute executes rootfs Command // Execute executes rootfs Command
func (c *Command) Execute(args []string) (err error) { func (c *Command) Execute(args []string) (err error) {
if len(args) != 0 { if len(args) != 0 {
return errors.New("too many args") return errors.New("too many args")
} }
if c.flattener == nil {
c.init()
}
rd, err := os.Open(string(c.PositionalArgs.Infile)) rd, err := os.Open(string(c.PositionalArgs.Infile))
if err != nil { if err != nil {
@ -56,12 +59,3 @@ func (c *Command) Execute(args []string) (err error) {
return c.flattener(rd, out) return c.flattener(rd, out)
} }
// init() initializes Command with the default options.
//
// Since constructors for sub-commands requires lots of boilerplate,
// command will initialize itself.
func (c *Command) init() {
c.BaseCommand.Init()
c.flattener = rootfs.Flatten
}

View File

@ -8,7 +8,6 @@ import (
"testing" "testing"
goflags "github.com/jessevdk/go-flags" goflags "github.com/jessevdk/go-flags"
"github.com/motiejus/code/undocker/internal/cmd"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -57,7 +56,7 @@ func TestExecute(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
dir := t.TempDir() dir := t.TempDir()
var stdout bytes.Buffer var stdout bytes.Buffer
c := &Command{BaseCommand: cmd.BaseCommand{Stdout: &stdout}} c := &Command{Stdout: &stdout}
if tt.fixture != nil { if tt.fixture != nil {
tt.fixture(t, dir) tt.fixture(t, dir)
} }

27
main.go
View File

@ -4,29 +4,22 @@ import (
"os" "os"
goflags "github.com/jessevdk/go-flags" goflags "github.com/jessevdk/go-flags"
"github.com/motiejus/code/undocker/internal/cmdlxcconfig" "github.com/motiejus/code/undocker/internal/cmdlxcconfig"
"github.com/motiejus/code/undocker/internal/cmdrootfs" "github.com/motiejus/code/undocker/internal/cmdrootfs"
) )
type (
params struct {
RootFS cmdrootfs.Command `command:"rootfs" description:"Unpack a docker container image to a single filesystem tarball"`
LXCConfig cmdlxcconfig.Command `command:"lxcconfig" description:"Create an LXC-compatible container configuration"`
}
)
func main() { func main() {
if err := run(os.Args); err != nil { flags := goflags.NewParser(nil, goflags.Default)
rootfs := cmdrootfs.NewCommand()
lxcconfig := cmdlxcconfig.NewCommand()
flags.AddCommand("rootfs", rootfs.ShortDesc(), rootfs.LongDesc(), rootfs)
flags.AddCommand("lxcconfig", lxcconfig.ShortDesc(), lxcconfig.LongDesc(), lxcconfig)
_, err := flags.Parse()
if err != nil {
os.Exit(1) os.Exit(1)
} }
os.Exit(0) os.Exit(0)
} }
func run(args []string) error {
var opts params
if _, err := goflags.ParseArgs(&opts, args[1:]); err != nil {
return err
}
return nil
}

View File

@ -9,10 +9,6 @@ go_library(
], ],
importpath = "github.com/motiejus/code/undocker/rootfs", importpath = "github.com/motiejus/code/undocker/rootfs",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [
"//src/undocker/internal/bytecounter:go_default_library",
"@org_uber_go_multierr//:go_default_library",
],
) )
go_test( go_test(

View File

@ -2,7 +2,7 @@
// tarball. It will go trough all layers in order and copy every file to the // tarball. It will go trough all layers in order and copy every file to the
// destination archive. // destination archive.
// //
// Except it will also reasonably process those files. // It will also reasonably process those files.
// //
// == Non-directory will be copied only once == // == Non-directory will be copied only once ==
// A non-directory will be copied only once, only from within it's past // A non-directory will be copied only once, only from within it's past