diff options
| author | Joe Richey joerichey@google.com <joerichey@google.com> | 2017-10-12 17:59:45 -0700 |
|---|---|---|
| committer | Joseph Richey <joerichey94@gmail.com> | 2017-10-19 02:22:25 -0700 |
| commit | b4299090c3e503ba0c49a6086b1a46c218ca45f4 (patch) | |
| tree | 889adbf3da9616a5c6eaa783291e5f94c01955a2 | |
| parent | 921f1c977c4e0704f61e3a7c092d3a4317ab278c (diff) | |
Command, Context, command line splitting setup
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | cmd/cmd.go | 146 | ||||
| -rw-r--r-- | cmd/flag.go | 104 | ||||
| -rw-r--r-- | cmd/info.go | 88 | ||||
| -rw-r--r-- | cmd/output.go | 4 | ||||
| -rw-r--r-- | cmd/strings.go | 14 | ||||
| -rw-r--r-- | cmd/version.go | 57 | ||||
| -rw-r--r-- | ext4/ext4.go | 155 | ||||
| -rw-r--r-- | ext4/feature_flag.go | 6 |
9 files changed, 304 insertions, 274 deletions
@@ -87,10 +87,10 @@ GO_LINK_FLAGS ?= -s -w # Pass the version to the command line program (pulled from tags). TAG_VERSION = $(shell git describe --tags) VERSION = $(if $(TAG_VERSION),$(TAG_VERSION),$(RELEASE_VERSION)) -VERSION_FLAG = -X "main.version=$(VERSION)" +VERSION_FLAG = -X "$(PKG_DIR)/cmd.VersionTag=$(VERSION)" # Pass the current date and time to the command line program. -DATE_FLAG = -X "main.buildTime=$(shell date)" +DATE_FLAG = -X "$(PKG_DIR)/cmd.BuildTimeTag=$(shell date)" # Add the version, date, and any specified LDFLAGS to any user-specified flags. override GO_LINK_FLAGS += $(VERSION_FLAG) $(DATE_FLAG) -extldflags "$(LDFLAGS)" # Add the link flags to any user-specified flags. @@ -27,18 +27,69 @@ // to use for other commands. package cmd -import "os" +import ( + "fmt" + "io" + "os" + "text/template" + "time" -// Command represents a command with many potential top-level commands. This is -// transformed into a cli.Command in Run(). -type Command struct { - Name string - UsageLines []string - SubCmds []*Command - Arguments []*Argument - Flags []Flag - ManPage *ManEntry - Action CommandFunc + "github.com/blang/semver" +) + +// Context represents the state of a running application, and is the only thing +// passed to a CommandFunc. +type Context struct { + Command *Command + Parent *Context + Info *Info + Args []string + flagArgs []string +} + +// FullName returns the space-separated name of the command and all parents. +func (ctx *Context) FullName() string { + if ctx.Parent == nil { + return ctx.Command.Name + } + return fmt.Sprintf("%s %s", ctx.Parent.FullName(), ctx.Command.Name) +} + +// ManPage returns the man page entry for this context. It is either the ManPage +// for the the current command or the closet Parent. +func (ctx *Context) ManPage() *ManPage { + if ctx.Command.ManPage.Section != 0 || ctx.Parent == nil { + return ctx.Command.ManPage + } + return ctx.Parent.ManPage() +} + +// Creates an anonymous template from the text, and runs it with the provided +// Context and writer. Panics if text has a bad format or execution fails. +func (ctx *Context) executeTemplate(w io.Writer, text string) { + tmpl := template.Must(template.New("").Parse(text)) + if err := tmpl.Execute(w, ctx); err != nil { + panic(err) + } +} + +func (ctx *Context) execute() { + fmt.Printf("%+v\n", ctx) + return +} + +// Info is a parsed view of the corresponding global variables. +type Info struct { + Version semver.Version + BuildTime time.Time + Authors []Author + Copyright string +} + +// Author contains the contact information for a contributor. +type Author struct { + Name string + Email string } // Argument represents a parameter passed to a function. It has an optional @@ -48,19 +99,35 @@ type Argument struct { Usage string } -// ManEntry represents an entry in a man page with a name, section, and title. -type ManEntry struct { - Name string - Section int +func (a *Argument) String() string { return fmt.Sprintf("<%s>", a.ArgName) } + +// ManPage a man page with a title and section. +type ManPage struct { Title string + Section int } -// CommandFunc contains the implementation of a command. The provided args have -// the flags and leading command names removed. If a normal error is returned, -// it is printed out (with an optional explanation) and exits with FailureCode. -// If a usage error is returned, it is printed out with the command's usage and -// exits with UsageFailureCode. Returning nil causes an exit with success. -type CommandFunc func(args []string) error +// CommandFunc contains the implementation of a command. If a normal error is +// returned, the error will be printed out (with an optional explanation) and +// Run will exit with FailureCode. If a usage error is returned, the error and +// the commnd's usage are printed out and Run will exit with UsageFailureCode. +// Returning nil causes Run to return. +type CommandFunc func(ctx *Context) error + +// Command represents a command with many potential top-level commands. This is +// transformed into a cli.Command in Run(). +type Command struct { + Name string + Title string + UsageLines []string + SubCommands []*Command + InheritArguments bool + Arguments []*Argument + InheritFlags bool + Flags []Flag + ManPage *ManPage + Action CommandFunc +} // Run executes the command with os.Args, equivalent to c.RunArgs(os.Args). func (c *Command) Run() { @@ -71,5 +138,40 @@ func (c *Command) Run() { // empty, args[0]'s basename is used instead. If the command fails, this method // will not return. func (c *Command) RunArgs(args []string) { - // TODO(joerichey): Implement conversion to cli.Command + binaryName, args := args[0], args[1:] + if c.Name == "" { + c.Name = binaryName + } + + // Create our initial context by sorting the args and parsing the tags. + ctx := &Context{ + Command: c, + Info: parseInfo(), + } + ctx.Args, ctx.flagArgs = sortArgs(args) + + ctx.execute() +} + +// Divide the arguments into flag arguments (those starting with "-") and normal +// arguments. If "--" appears in the list, it will classified as a normal +// argument as well as all arguments following it. Also removes empty args. +func sortArgs(args []string) (normalArgs, flagArgs []string) { + var arg string + for len(args) > 0 { + arg, args = args[0], args[1:] + if arg == "" { + continue + } + if arg == "--" { + normalArgs = append(normalArgs, arg) + normalArgs = append(normalArgs, args...) + return + } else if arg[0] == '-' { + flagArgs = append(flagArgs, arg) + } else { + normalArgs = append(normalArgs, arg) + } + } + return } diff --git a/cmd/flag.go b/cmd/flag.go index 18b2a4c..5f864b9 100644 --- a/cmd/flag.go +++ b/cmd/flag.go @@ -26,48 +26,31 @@ import ( "time"
)
-// Flag represents a command line flag that can be passed to a command. Note
-// that Flag also conforms to the cli.Flag interface. The Name, ArgName, and
-// Usage of the Flag can be used to format it in a short form with ShortFormat,
-// or in it's full format with the String method.
+// Flag represents a flag that can be passed to a command. The Name, ArgName,
+// and Usage are used to format and display the flag.
type Flag interface {
+ // String formats the flag as either "--name" or "--name=<argName>".
fmt.Stringer
+ // FullUsage is the usage for this flag with an optional default note.
+ FullUsage() string
+ // Apply sets up this flag on a flag set.
Apply(*flag.FlagSet)
- GetName() string
- GetArgName() string
- GetUsage() string
}
-// How the first usage line for a Flag should appear. We have two formats:
-// --name
-// --name=<argName>
-// The <argName> appears if the prettyFlag's GetArgName() method returns a
-// non-empty string. The returned string from shortFormat() does not include
-// any leading or trailing whitespace.
-func ShortFormat(f Flag) string {
- if argName := f.GetArgName(); argName != "" {
- return fmt.Sprintf("--%s=%s", f.GetName(), argName)
+// Formats as "--name" or as "--name=<argName>" if argName is present.
+func formatHelper(name, argName string) string {
+ if argName != "" {
+ return fmt.Sprintf("--%s=<%s>", name, argName)
}
- return fmt.Sprintf("--%s", f.GetName())
+ return fmt.Sprintf("--%s", name)
}
-// How our flags should appear when displaying their usage. An example would be:
-// --help
-// Prints help screen for commands and subcommands.
-//
-// If defaultString is specified, this if appended to the usage. Example:
-//
-// --legacy
-// Allow for support of older kernels with ext4 (before v4.8) and
-// F2FS (before v4.6) filesystems. (default: true)
-func longFormat(f Flag, defaultString ...string) string {
- usage := f.GetUsage()
- if len(defaultString) > 0 {
- usage += fmt.Sprintf(" (default: %v)", defaultString[0])
+// Appends (default: <default>) to the usage if defaultString is present.
+func usageHelper(usage, defaultString string) string {
+ if defaultString != "" {
+ usage += fmt.Sprintf(" (default: %s)", defaultString)
}
-
- usage = wrapText(usage, 2)
- return fmt.Sprintf("\t%s\n%s", ShortFormat(f), usage)
+ return usage
}
// BoolFlag is a Flag of type bool.
@@ -78,25 +61,20 @@ type BoolFlag struct { Value bool
}
-func (f *BoolFlag) String() string {
+// String always uses the smaller format, as it has no ArgName.
+func (f *BoolFlag) String() string { return formatHelper(f.Name, "") }
+
+// FullUsage shows the default if it's true (flag is implicitly passed).
+func (f *BoolFlag) FullUsage() string {
if !f.Default {
- return longFormat(f)
+ return usageHelper(f.Usage, "")
}
- return longFormat(f, strconv.FormatBool(f.Default))
+ return usageHelper(f.Usage, "true")
}
// Apply uses BoolFlag's value to set a flag.BoolVar on the FlagSet.
func (f *BoolFlag) Apply(s *flag.FlagSet) { s.BoolVar(&f.Value, f.Name, f.Default, f.Usage) }
-// GetName just returns BoolFlag's name.
-func (f *BoolFlag) GetName() string { return f.Name }
-
-// GetArgName returns nothing as BoolFlags don't have an argument name.
-func (f *BoolFlag) GetArgName() string { return "" }
-
-// GetUsage returns BoolFlag's usage.
-func (f *BoolFlag) GetUsage() string { return f.Usage }
-
// StringFlag is a Flag of type string.
type StringFlag struct {
Name string
@@ -106,25 +84,19 @@ type StringFlag struct { Value string
}
-func (f *StringFlag) String() string {
+func (f *StringFlag) String() string { return formatHelper(f.Name, f.ArgName) }
+
+// FullUsage shows the deafult if the string is non-empty.
+func (f *StringFlag) FullUsage() string {
if f.Default == "" {
- return longFormat(f)
+ return usageHelper(f.Usage, "")
}
- return longFormat(f, strconv.Quote(f.Default))
+ return usageHelper(f.Usage, strconv.Quote(f.Default))
}
// Apply uses StringFlag's value to set a flag.StringVar on the FlagSet.
func (f *StringFlag) Apply(s *flag.FlagSet) { s.StringVar(&f.Value, f.Name, f.Default, f.Usage) }
-// GetName just returns StringFlag's name.
-func (f *StringFlag) GetName() string { return f.Name }
-
-// GetArgName returns StringFlag's argument name.
-func (f *StringFlag) GetArgName() string { return f.ArgName }
-
-// GetUsage returns StringFlag's usage.
-func (f *StringFlag) GetUsage() string { return f.Usage }
-
// DurationFlag is a Flag of type time.Duration.
type DurationFlag struct {
Name string
@@ -134,21 +106,15 @@ type DurationFlag struct { Value time.Duration
}
-func (f *DurationFlag) String() string {
+func (f *DurationFlag) String() string { return formatHelper(f.Name, f.ArgName) }
+
+// FullUsage shows the default if the duration is non-zero.
+func (f *DurationFlag) FullUsage() string {
if f.Default == 0 {
- return longFormat(f)
+ return usageHelper(f.Usage, "")
}
- return longFormat(f, f.Default.String())
+ return usageHelper(f.Usage, f.Default.String())
}
// Apply uses DurationFlag's value to set a flag.DurationVar on the FlagSet.
func (f *DurationFlag) Apply(s *flag.FlagSet) { s.DurationVar(&f.Value, f.Name, f.Default, f.Usage) }
-
-// GetName just returns DurationFlag's name.
-func (f *DurationFlag) GetName() string { return f.Name }
-
-// GetArgName returns DurationFlag's argument name.
-func (f *DurationFlag) GetArgName() string { return f.ArgName }
-
-// GetUsage returns DurationFlag's usage.
-func (f *DurationFlag) GetUsage() string { return f.Usage }
diff --git a/cmd/info.go b/cmd/info.go index 6257ec1..96079ea 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -22,51 +22,75 @@ package cmd import ( "time" - "github.com/urfave/cli" + "github.com/blang/semver" + "github.com/pkg/errors" ) -// Info contains the global info for the functions. -var Info struct { - // Program is the name of the top-level program being executed. If not - // set it is set in cmd.RunArgs(). - Program string +var ( // VersionTag (if set) will be displayed in both the short and long - // version output. VersionTag is not parsed, so any string will work. + // version output and can be accessed though Context.Info.Version. + // VersionTag must be formatted using Semver (http://semver.org/). + // + // Often set in Makefile with "-X cmd.VersionTag=$(VERSION)" VersionTag string - // BuildTime (if set) will be displayed in the long version output. - BuildTime time.Time - // Authors (if non-empty) are displayed in the long version output. - Authors []cli.Author - // Copyright (if set) is displayed in the long version output. + // BuildTimeTag (if set) will be displayed in the long version + // output and can be accessed thought Context.Info.BuildTime. This + // string must be formatted as the output of UNIX `date`. + // + // Often set in Makefile with "-X cmd.BuildTimeTag=$(shell date)" + BuildTimeTag string + // Authors (if non-empty) are displayed in the long version output and + // can be accessed though Context.Info.Authors. + Authors []Author + // Copyright (if set) is displayed in the long version output and can + // be accessed through Context.Info.Copyright. Copyright string -} - -// Linker flags of the form "-X cmd.Info.VersionTag=1.0" do not work, so we use -// these separate files so variables can be set from the Makefile. -var ( - versionTag string - buildTime string ) // fscrypt specific initialization func init() { - Info.VersionTag = versionTag - Info.BuildTime = buildTime - Info.Authors = []cli.Author{{ + Authors = []Author{{ Name: "Joe Richey", Email: "joerichey@google.com", }} - Info.Copyright = `Copyright 2017 Google, Inc. + Copyright = `Copyright 2017 Google, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.` +} + +// Creates the Info structure by parsing the above global variables. Panics if +// the variables to parse are in the incorrect format. +func parseInfo() *Info { + var err error - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + var t time.Time + if BuildTimeTag != "" { + if t, err = time.Parse(time.UnixDate, BuildTimeTag); err != nil { + panic(err) + } + } - http://www.apache.org/licenses/LICENSE-2.0 + var v semver.Version + if VersionTag != "" { + if v, err = semver.ParseTolerant(VersionTag); err != nil { + panic(errors.Wrapf(err, "semver: parsing %q", VersionTag)) + } + } - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.` + return &Info{ + Version: v, + BuildTime: t, + Authors: Authors, + Copyright: Copyright, + } } diff --git a/cmd/output.go b/cmd/output.go index 024705d..c3a79a4 100644 --- a/cmd/output.go +++ b/cmd/output.go @@ -51,7 +51,7 @@ var ( // HelpFlag writes help to Stdout HelpFlag = &BoolFlag{ Name: "help", - Usage: "Prints this 🧗help text for commands and subcommands", + Usage: "Prints this help text for commands and subcommands", } // VerboseFlag indicates that all logging output should be printed. VerboseFlag = &BoolFlag{ @@ -101,7 +101,7 @@ func wrapText(text string, numTabs int) string { spaceLeft := 0 maxTextLen := LineLength - numTabs*TabWidth delimiter := strings.Repeat("\t", numTabs) - for i, word := range strings.Fields(text) { + for _, word := range strings.Fields(text) { wordLen := utf8.RuneCountInString(word) if wordLen >= spaceLeft { // If no room left, write the word on the next line. diff --git a/cmd/strings.go b/cmd/strings.go index 559c60c..16c80f2 100644 --- a/cmd/strings.go +++ b/cmd/strings.go @@ -18,17 +18,3 @@ */ package cmd - -import ( - "io" - "text/template" -) - -// ExecuteTemplate creates an anonymous template the text, and runs it with the -// provided writer and data. Panics if text has bad format or execution fails. -func ExecuteTemplate(w io.Writer, text string, data interface{}) { - tmpl := template.Must(template.New("").Parse(text)) - if err := tmpl.Execute(w, data); err != nil { - panic(err) - } -} diff --git a/cmd/version.go b/cmd/version.go index 787e2cd..99097b5 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -19,44 +19,61 @@ package cmd +import ( + "fmt" + + "github.com/blang/semver" +) + // Templates for use with the version command, which both parse the Info var. var ( - VersionShortTemplate = "{{.Command}} version {{.VersionTag}}\n" - VersionLongTemplate = VersionShortTemplate + `{{if .Compiled}} + VersionTemplate = "{{.FullName}} {{.Info.Version}}\n" + VersionLongTemplate = `{{if .Info.BuildTime}} Compiled: - {{.Compiled}} -{{end}}{{if len .Authors}} -Author{{with $length := len .Authors}}{{if ne 1 $length}}s{{end}}{{end}}:{{range .Authors}} - {{.}}{{end}} -{{end}}{{if .Copyright}} + {{.Info.BuildTime}} +{{end}} + +{{with $length := len .Info.Authors}} +{{if $length}} +Author{{if ne 1 $length}}s{{end}}: +{{range .Info.Authors}} + {{.Name}}{{if .Email}} <{{.Email}}>{{end}} +{{end}} +{{end}} +{{end}} + +{{if .Info.Copyright}} Copyright: - {{.Copyright}} +{{.Info.Copyright}} {{end}}` ) -// Version is a command which will display either the VersionTag (by default) or -// the full version information (version, copyright, authors). -var Version = &Command{ +// VersionCommand is a command which will display either the VersionTag (by +// default) or the full version information: version, copyright, authors, etc... +var VersionCommand = &Command{ Name: "version", - UsageLines: []string{""}, - Flags: []Flag{longFlag}, + Title: "display this program's version information", + UsageLines: []string{fmt.Sprintf("[%v]", longFlag)}, + Flags: []Flag{longFlag, HelpFlag}, Action: versionAction, } -// Using longFlag with the version command displays the longer version info. +// VersionUsage is a UsageLine to add to a Command with a version Subcommand. +var VersionUsage = VersionCommand.Name + " " + VersionCommand.UsageLines[0] + +// longFlag tells the version command to display the longer version info. var longFlag = &BoolFlag{ Name: "long", - Usage: "Print the detailed version and copyright information.", + Usage: "Print the detailed version, build, and copyright information.", } -func versionAction(_ []string) error { - if Info.VersionTag == "" { +func versionAction(ctx *Context) error { + if ctx.Info.Version.Equals(semver.Version{}) { return ErrUnknownVersion } + ctx.executeTemplate(Output, VersionTemplate) if longFlag.Value { - - } else { - + ctx.executeTemplate(Output, VersionLongTemplate) } return nil } diff --git a/ext4/ext4.go b/ext4/ext4.go index 063d68c..80d229d 100644 --- a/ext4/ext4.go +++ b/ext4/ext4.go @@ -20,124 +20,63 @@ package main import ( - "flag" "fmt" - "io" - "io/ioutil" - "os" - "time" - "github.com/urfave/cli" + "github.com/google/fscrypt/cmd" ) +// Arguments used with the ext4 enable/disable commands. var ( - // Setup command parsing - cmdName = os.Args[0] - set = flag.NewFlagSet(cmdName, flag.ContinueOnError) - // Flags for our command - forceFlag = set.Bool("force", false, "Suppress all warnings and do not prompt") - versionFlag = set.Bool("version", false, "Print the fscrypt version.") - helpFlag = set.Bool("help", false, "Print this help text.") - // fscrypt's version (set by Makefile) - version string -) - -const ( - manPage = "fscrypt-ext4(8)" - manBrief = "enable or disable encryption on an ext4 filesystem" - usageFmt = ` -Usage: - %[1]s [enable | disable] <mountpoint> [--force] - %[1]s --help - %[1]s --version - -Arguments: - <mountpoint> - path to an ext4 filesystem -` -) - -func printAndExit(err error, printUsage bool) { - var w io.Writer - var rc int - if err == nil { - w = os.Stdout - rc = 0 - fmt.Fprintf(w, "%s - %s\n", cmdName, manBrief) - } else { - w = os.Stderr - rc = 1 - fmt.Fprintf(w, "%s: %v\n", cmdName, err) + MountpointArg = &cmd.Argument{ + ArgName: "mountpoint", + Usage: "the path to an ext4 filesystem's mountpoint", } - if printUsage { - fmt.Fprintf(w, usageFmt, cmdName) - fmt.Fprintln(w, "\nOptions:") - set.VisitAll(func(f *flag.Flag) { - fmt.Fprintf(w, "\t--%s\n\t\t%s\n", f.Name, f.Usage) - }) - fmt.Fprintf(w, "\nSee the %s man page for more info.\n", manPage) + DeviceArg = &cmd.Argument{ + ArgName: "device", + Usage: "the path to a device containing an ext4 filesystem", } - os.Exit(rc) -} - -func main() { - // Create our command line application - app := cli.NewApp() - app.Usage = shortUsage - app.Authors = Authors - app.Copyright = apache2GoogleCopyright - - // Grab the version and compilation time passed in from the Makefile. - app.Version = version - app.Compiled, _ = time.Parse(time.UnixDate, buildTime) - app.OnUsageError = onUsageError - - // Setup global flags - cli.HelpFlag = helpFlag - cli.VersionFlag = versionFlag - cli.VersionPrinter = func(c *cli.Context) { - cli.HelpPrinter(c.App.Writer, versionInfoTemplate, c.App) - } - app.Flags = universalFlags - - // We hide the help subcommand so that "fscrypt <command> --help" works - // and "fscrypt <command> help" does not. - app.HideHelp = true + Ext4Usage = fmt.Sprintf("(%s | %s) [options]", MountpointArg, DeviceArg) +) - // Initialize command list and setup all of the commands. - app.Action = defaultAction - app.Commands = []cli.Command{Setup, Encrypt, Unlock, Purge, Status, Metadata} - for i := range app.Commands { - setupCommand(&app.Commands[i]) - } +// Commands for running the ext4 enable/disable commands. +var () + +var Ext4Command = &cmd.Command{ + Title: "toggle ext4 filesystem encryption flag", + UsageLines: []string{ + fmt.Sprintf("(enable | disable) %s", Ext4Usage), + cmd.VersionUsage, + }, + SubCommands: []*cmd.Command{EnableCommand, DisableCommand, cmd.VersionCommand}, + Arguments: []*cmd.Argument{MountpointArg, DeviceArg}, + Flags: []cmd.Flag{cmd.ForceFlag, cmd.VerboseFlag, cmd.HelpFlag}, + ManPage: &cmd.ManPage{ + Title: "fscrypt-ext4", + Section: 8, + }, +} - app.Run(os.Args) +var EnableCommand = &cmd.Command{ + Name: "enable", + Title: "turn on encryption for an ext4 filesystem", + UsageLines: []string{Ext4Usage}, + InheritArguments: true, + InheritFlags: true, + Action: func(ctx *cmd.Context) error { return toggleState(ctx, true) }, +} - set.SetOutput(ioutil.Discard) - if err := set.Parse(os.Args[1:]); err != nil { - printAndExit(err, true) - } - if *helpFlag { - printAndExit(nil, true) - } - if *versionFlag { - fmt.Println(version) - return - } - if set.NArg() != 2 { - printAndExit(fmt.Errorf("expected 2 arguments (got %d)", set.NArg()), true) - } +var DisableCommand = &cmd.Command{ + Name: "disable", + Title: "turn off encryption for an ext4 filesystem", + UsageLines: []string{Ext4Usage}, + InheritArguments: true, + InheritFlags: true, + Action: func(ctx *cmd.Context) error { return toggleState(ctx, false) }, +} - _, err := NewExt4Filesystem(set.Arg(1)) - if err != nil { - printAndExit(err, false) - } +func main() { Ext4Command.Run() } - switch command := set.Arg(0); command { - case "enable": - fmt.Println("Enabling encryption not implemented") - case "disable": - fmt.Println("Disabling encryption not implemented") - default: - printAndExit(fmt.Errorf("invalid command %q", command), true) - } +func toggleState(ctx *cmd.Context, enable bool) error { + fmt.Fprintf(cmd.Output, "Toggle value = %v", enable) + return nil } diff --git a/ext4/feature_flag.go b/ext4/feature_flag.go index 4b588d6..ab618e2 100644 --- a/ext4/feature_flag.go +++ b/ext4/feature_flag.go @@ -42,11 +42,7 @@ type Ext4Filesystem struct { // NewExt4Filesystem creates a new Ext4Filesystem from a mountpoint path. Fail // if the path is not the mountpoint of an ext4 filesystem or cannot be opened. -func NewExt4Filesystem(mountpoint string) (*Ext4Filesystem, error) { - mount, err := filesystem.FindMount(set.Arg(1)) - if err != nil { - return nil, err - } +func NewExt4Filesystem(mount *filesystem.Mount) (*Ext4Filesystem, error) { if mount.Filesystem != "ext4" { err := fmt.Errorf("%q is not an ext4 filesystem (type %q)", mount.Path, mount.Filesystem) return nil, err |