diff --git a/go.mod b/go.mod
index 1b0478035052bc994bb56c84ab222d9ff7e5f2bd..75e5be586496a16aa20375ef7557d4d000349a26 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.14
 require (
 	github.com/blevesearch/bleve v1.0.14
 	github.com/glycerine/go-unsnap-stream v0.0.0-20190730064659-98d31706395a // indirect
-	github.com/google/subcommands v1.0.1
+	github.com/google/subcommands v1.2.0
 	github.com/gorilla/mux v1.6.3-0.20181030152528-3d80bc801bb0
 	github.com/meskio/epubgo v0.0.0-20160213181628-90dd5d78197f
 	github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
diff --git a/go.sum b/go.sum
index 18d8077be60dc97bae6ae544494313d61588f74e..ccf4467068fc7b19686990a1bcdfa38e440c1bac 100644
--- a/go.sum
+++ b/go.sum
@@ -62,8 +62,8 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k=
-github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
+github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
+github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
 github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/mux v1.6.3-0.20181030152528-3d80bc801bb0 h1:lkoCFKD1IVH+yARHTUkCerTOqKkwVVO+IyGWld86voc=
diff --git a/vendor/github.com/google/subcommands/subcommands.go b/vendor/github.com/google/subcommands/subcommands.go
index 9cb98e5cce7595789e5df569148596e977cd707d..39268f7362faf5b85bdeb764be91a91a0f806f5d 100644
--- a/vendor/github.com/google/subcommands/subcommands.go
+++ b/vendor/github.com/google/subcommands/subcommands.go
@@ -50,21 +50,30 @@ type Command interface {
 
 // A Commander represents a set of commands.
 type Commander struct {
-	commands  []*commandGroup
+	commands  []*CommandGroup
 	topFlags  *flag.FlagSet // top-level flags
 	important []string      // important top-level flags
 	name      string        // normally path.Base(os.Args[0])
 
+	Explain        func(io.Writer)                // A function to print a top level usage explanation. Can be overridden.
+	ExplainGroup   func(io.Writer, *CommandGroup) // A function to print a command group's usage explanation. Can be overridden.
+	ExplainCommand func(io.Writer, Command)       // A function to print a command usage explanation. Can be overridden.
+
 	Output io.Writer // Output specifies where the commander should write its output (default: os.Stdout).
 	Error  io.Writer // Error specifies where the commander should write its error (default: os.Stderr).
 }
 
-// A commandGroup represents a set of commands about a common topic.
-type commandGroup struct {
+// A CommandGroup represents a set of commands about a common topic.
+type CommandGroup struct {
 	name     string
 	commands []Command
 }
 
+// Name returns the group name
+func (g *CommandGroup) Name() string {
+	return g.name
+}
+
 // An ExitStatus represents a Posix exit status that a subcommand
 // expects to be returned to the shell.
 type ExitStatus int
@@ -85,10 +94,19 @@ func NewCommander(topLevelFlags *flag.FlagSet, name string) *Commander {
 		Output:   os.Stdout,
 		Error:    os.Stderr,
 	}
-	topLevelFlags.Usage = func() { cdr.explain(cdr.Error) }
+
+	cdr.Explain = cdr.explain
+	cdr.ExplainGroup = explainGroup
+	cdr.ExplainCommand = explain
+	topLevelFlags.Usage = func() { cdr.Explain(cdr.Error) }
 	return cdr
 }
 
+// Name returns the commander's name
+func (cdr *Commander) Name() string {
+	return cdr.name
+}
+
 // Register adds a subcommand to the supported subcommands in the
 // specified group. (Help output is sorted and arranged by group name.)
 // The empty string is an acceptable group name; such subcommands are
@@ -100,7 +118,7 @@ func (cdr *Commander) Register(cmd Command, group string) {
 			return
 		}
 	}
-	cdr.commands = append(cdr.commands, &commandGroup{
+	cdr.commands = append(cdr.commands, &CommandGroup{
 		name:     group,
 		commands: []Command{cmd},
 	})
@@ -114,6 +132,55 @@ func (cdr *Commander) ImportantFlag(name string) {
 	cdr.important = append(cdr.important, name)
 }
 
+// VisitGroups visits each command group in lexicographical order, calling
+// fn for each.
+func (cdr *Commander) VisitGroups(fn func(*CommandGroup)) {
+	sort.Sort(byGroupName(cdr.commands))
+	for _, g := range cdr.commands {
+		fn(g)
+	}
+}
+
+// VisitCommands visits each command in registered order grouped by
+// command group in lexicographical order, calling fn for each.
+func (cdr *Commander) VisitCommands(fn func(*CommandGroup, Command)) {
+	cdr.VisitGroups(func(g *CommandGroup) {
+		for _, cmd := range g.commands {
+			fn(g, cmd)
+		}
+	})
+}
+
+// VisitAllImportant visits the important top level flags in lexicographical
+// order, calling fn for each. It visits all flags, even those not set.
+func (cdr *Commander) VisitAllImportant(fn func(*flag.Flag)) {
+	sort.Strings(cdr.important)
+	for _, name := range cdr.important {
+		f := cdr.topFlags.Lookup(name)
+		if f == nil {
+			panic(fmt.Sprintf("Important flag (%s) is not defined", name))
+		}
+		fn(f)
+	}
+}
+
+// VisitAll visits the top level flags in lexicographical order, calling fn
+// for each. It visits all flags, even those not set.
+func (cdr *Commander) VisitAll(fn func(*flag.Flag)) {
+	if cdr.topFlags != nil {
+		cdr.topFlags.VisitAll(fn)
+	}
+}
+
+// countFlags returns the number of top-level flags defined, even those not set.
+func (cdr *Commander) countTopFlags() int {
+	count := 0
+	cdr.VisitAll(func(*flag.Flag) {
+		count++
+	})
+	return count
+}
+
 // Execute should be called once the top-level-flags on a Commander
 // have been initialized. It finds the correct subcommand and executes
 // it, and returns an ExitStatus with the result. On a usage error, an
@@ -134,7 +201,7 @@ func (cdr *Commander) Execute(ctx context.Context, args ...interface{}) ExitStat
 				continue
 			}
 			f := flag.NewFlagSet(name, flag.ContinueOnError)
-			f.Usage = func() { explain(cdr.Error, cmd) }
+			f.Usage = func() { cdr.ExplainCommand(cdr.Error, cmd) }
 			cmd.SetFlags(f)
 			if f.Parse(cdr.topFlags.Args()[1:]) != nil {
 				return ExitUsageError
@@ -149,8 +216,9 @@ func (cdr *Commander) Execute(ctx context.Context, args ...interface{}) ExitStat
 }
 
 // Sorting of a slice of command groups.
-type byGroupName []*commandGroup
+type byGroupName []*CommandGroup
 
+// TODO Sort by function rather than implement sortable?
 func (p byGroupName) Len() int           { return len(p) }
 func (p byGroupName) Less(i, j int) bool { return p[i].name < p[j].name }
 func (p byGroupName) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
@@ -161,14 +229,18 @@ func (cdr *Commander) explain(w io.Writer) {
 	fmt.Fprintf(w, "Usage: %s <flags> <subcommand> <subcommand args>\n\n", cdr.name)
 	sort.Sort(byGroupName(cdr.commands))
 	for _, group := range cdr.commands {
-		explainGroup(w, group)
+		cdr.ExplainGroup(w, group)
 	}
 	if cdr.topFlags == nil {
 		fmt.Fprintln(w, "\nNo top level flags.")
 		return
 	}
+
+	sort.Strings(cdr.important)
 	if len(cdr.important) == 0 {
-		fmt.Fprintf(w, "\nUse \"%s flags\" for a list of top-level flags\n", cdr.name)
+		if cdr.countTopFlags() > 0 {
+			fmt.Fprintf(w, "\nUse \"%s flags\" for a list of top-level flags\n", cdr.name)
+		}
 		return
 	}
 
@@ -183,12 +255,12 @@ func (cdr *Commander) explain(w io.Writer) {
 }
 
 // Sorting of the commands within a group.
-func (g commandGroup) Len() int           { return len(g.commands) }
-func (g commandGroup) Less(i, j int) bool { return g.commands[i].Name() < g.commands[j].Name() }
-func (g commandGroup) Swap(i, j int)      { g.commands[i], g.commands[j] = g.commands[j], g.commands[i] }
+func (g CommandGroup) Len() int           { return len(g.commands) }
+func (g CommandGroup) Less(i, j int) bool { return g.commands[i].Name() < g.commands[j].Name() }
+func (g CommandGroup) Swap(i, j int)      { g.commands[i], g.commands[j] = g.commands[j], g.commands[i] }
 
 // explainGroup explains all the subcommands for a particular group.
-func explainGroup(w io.Writer, group *commandGroup) {
+func explainGroup(w io.Writer, group *CommandGroup) {
 	if len(group.commands) == 0 {
 		return
 	}
@@ -254,7 +326,7 @@ func (h *helper) Usage() string {
 func (h *helper) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) ExitStatus {
 	switch f.NArg() {
 	case 0:
-		(*Commander)(h).explain(h.Output)
+		(*Commander)(h).Explain(h.Output)
 		return ExitSuccess
 
 	case 1:
@@ -263,7 +335,7 @@ func (h *helper) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}
 				if f.Arg(0) != cmd.Name() {
 					continue
 				}
-				explain(h.Output, cmd)
+				(*Commander)(h).ExplainCommand(h.Output, cmd)
 				return ExitSuccess
 			}
 		}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 62c6d898b95d50d4cdc1eff8337a105e8d2d9d3a..da68b523ac661e1d6c6cffbeac3fca7e716078a0 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -76,7 +76,7 @@ github.com/glycerine/go-unsnap-stream
 github.com/golang/protobuf/proto
 # github.com/golang/snappy v0.0.1
 github.com/golang/snappy
-# github.com/google/subcommands v1.0.1
+# github.com/google/subcommands v1.2.0
 ## explicit
 github.com/google/subcommands
 # github.com/gorilla/mux v1.6.3-0.20181030152528-3d80bc801bb0