fix: customised usage messages
Add functionality to display the default help message when running spruce without any arguments or when the help flag is used. Customise the help message for the subcommands. Additional changes: - Refactor: move the Runner interface to the internal cmd package - Fix: Add a summary for each of the subcommands. - Refactor: Use string builder to replace string literals. - Perf: Use a switch statement to only create the subcommand that the user calls.
This commit is contained in:
parent
050748d8cd
commit
90638f5569
6 changed files with 118 additions and 35 deletions
|
@ -89,6 +89,29 @@ go install .
|
||||||
|
|
||||||
=== Verifying the installation
|
=== Verifying the installation
|
||||||
|
|
||||||
|
Run `spruce` to verify your installation. You should see the usage printed onto your screen.
|
||||||
|
|
||||||
|
[source,console]
|
||||||
|
----
|
||||||
|
$ spruce
|
||||||
|
A tool for building CVs
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
spruce [flags]
|
||||||
|
spruce [command]
|
||||||
|
|
||||||
|
Available Commands:
|
||||||
|
create create a new CV JSON file
|
||||||
|
generate generate a PDF file from an existing CV JSON file
|
||||||
|
version print the application's build information
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
-h, --help
|
||||||
|
print the help message for spruce
|
||||||
|
|
||||||
|
Use "spruce [command] --help" for more information about a command.
|
||||||
|
----
|
||||||
|
|
||||||
If you have installed spruce with Mage, you can get the build information to confirm that you have installed the correct version.
|
If you have installed spruce with Mage, you can get the build information to confirm that you have installed the correct version.
|
||||||
[source,console]
|
[source,console]
|
||||||
----
|
----
|
||||||
|
|
51
internal/cmd/cmd.go
Normal file
51
internal/cmd/cmd.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Runner interface {
|
||||||
|
Parse([]string) error
|
||||||
|
Name() string
|
||||||
|
Run() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func SpruceUsage() {
|
||||||
|
usage := `A tool for building CVs
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
spruce [flags]
|
||||||
|
spruce [command]
|
||||||
|
|
||||||
|
Available Commands:
|
||||||
|
create create a new CV JSON file
|
||||||
|
generate generate a PDF file from an existing CV JSON file
|
||||||
|
version print the application's build information
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
-h, --help
|
||||||
|
print the help message for spruce
|
||||||
|
|
||||||
|
Use "spruce [command] --help" for more information about a command.
|
||||||
|
`
|
||||||
|
|
||||||
|
fmt.Print(usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func usageFunc(name, summary string, flagset *flag.FlagSet) func() {
|
||||||
|
return func() {
|
||||||
|
var b strings.Builder
|
||||||
|
|
||||||
|
w := flag.CommandLine.Output()
|
||||||
|
|
||||||
|
fmt.Fprintf(&b, "%s\n\nUsage:\n spruce %s [flags]\n\nFlags:", summary, name)
|
||||||
|
|
||||||
|
flagset.VisitAll(func(f *flag.Flag) {
|
||||||
|
fmt.Fprintf(&b, "\n --%s\n %s\n", f.Name, f.Usage)
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Fprint(w, b.String())
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
type CreateCommand struct {
|
type CreateCommand struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
summary string
|
||||||
firstName string
|
firstName string
|
||||||
lastName string
|
lastName string
|
||||||
jobTitle string
|
jobTitle string
|
||||||
|
@ -22,12 +23,15 @@ type CreateCommand struct {
|
||||||
func NewCreateCommand() *CreateCommand {
|
func NewCreateCommand() *CreateCommand {
|
||||||
cc := CreateCommand{
|
cc := CreateCommand{
|
||||||
FlagSet: flag.NewFlagSet("create", flag.ExitOnError),
|
FlagSet: flag.NewFlagSet("create", flag.ExitOnError),
|
||||||
|
summary: "Create a new CV JSON file.",
|
||||||
}
|
}
|
||||||
|
|
||||||
cc.StringVar(&cc.firstName, "first-name", "", "specify your first name")
|
cc.StringVar(&cc.filename, "filepath", "cv.json", "specify the path where the CV JSON document should be created.")
|
||||||
cc.StringVar(&cc.lastName, "last-name", "", "specify your last name")
|
cc.StringVar(&cc.firstName, "first-name", "", "specify your first name.")
|
||||||
cc.StringVar(&cc.jobTitle, "job-title", "", "specify your preferred job title")
|
cc.StringVar(&cc.jobTitle, "job-title", "", "specify your current job title.")
|
||||||
cc.StringVar(&cc.filename, "filename", "cv.json", "specify the filename of the created JSON document")
|
cc.StringVar(&cc.lastName, "last-name", "", "specify your last name.")
|
||||||
|
|
||||||
|
cc.Usage = usageFunc(cc.Name(), cc.summary, cc.FlagSet)
|
||||||
|
|
||||||
return &cc
|
return &cc
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ var templates embed.FS
|
||||||
|
|
||||||
type GenerateCommand struct {
|
type GenerateCommand struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
summary string
|
||||||
input string
|
input string
|
||||||
output string
|
output string
|
||||||
employmentHistory int
|
employmentHistory int
|
||||||
|
@ -30,12 +31,15 @@ type GenerateCommand struct {
|
||||||
func NewGenerateCommand() *GenerateCommand {
|
func NewGenerateCommand() *GenerateCommand {
|
||||||
gc := GenerateCommand{
|
gc := GenerateCommand{
|
||||||
FlagSet: flag.NewFlagSet("generate", flag.ExitOnError),
|
FlagSet: flag.NewFlagSet("generate", flag.ExitOnError),
|
||||||
|
summary: "Generate a PDF file from an existing CV JSON file.",
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.StringVar(&gc.input, "input", "", "specify the CV JSON file that you want to input to the builder.")
|
gc.StringVar(&gc.input, "input", "", "specify the CV JSON file that you want to input to the builder.")
|
||||||
gc.StringVar(&gc.output, "output", "", "specify the name of the output CV file.")
|
gc.StringVar(&gc.output, "output", "", "specify the name of the output CV file.")
|
||||||
gc.IntVar(&gc.employmentHistory, "employment-history", 10, "show employment history within these number of years.")
|
gc.IntVar(&gc.employmentHistory, "employment-history", 10, "show employment history within these number of years.")
|
||||||
gc.BoolVar(&gc.verbose, "verbose", false, "set to true to enable verbose logging")
|
gc.BoolVar(&gc.verbose, "verbose", false, "set to true to enable verbose logging.")
|
||||||
|
|
||||||
|
gc.Usage = usageFunc(gc.Name(), gc.summary, gc.FlagSet)
|
||||||
|
|
||||||
return &gc
|
return &gc
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,12 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VersionCommand struct {
|
type VersionCommand struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
|
summary string
|
||||||
fullVersion bool
|
fullVersion bool
|
||||||
binaryVersion string
|
binaryVersion string
|
||||||
buildTime string
|
buildTime string
|
||||||
|
@ -21,28 +23,24 @@ func NewVersionCommand(binaryVersion, buildTime, goVersion, gitCommit string) *V
|
||||||
buildTime: buildTime,
|
buildTime: buildTime,
|
||||||
goVersion: goVersion,
|
goVersion: goVersion,
|
||||||
gitCommit: gitCommit,
|
gitCommit: gitCommit,
|
||||||
|
summary: "Print the application's build information.",
|
||||||
}
|
}
|
||||||
|
|
||||||
vc.BoolVar(&vc.fullVersion, "full", false, "prints the full version")
|
vc.BoolVar(&vc.fullVersion, "full", false, "prints the full build information")
|
||||||
|
|
||||||
|
vc.Usage = usageFunc(vc.Name(), vc.summary, vc.FlagSet)
|
||||||
|
|
||||||
return &vc
|
return &vc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VersionCommand) Run() error {
|
func (v *VersionCommand) Run() error {
|
||||||
var version string
|
var b strings.Builder
|
||||||
if v.fullVersion {
|
if v.fullVersion {
|
||||||
fullVersionFmt := `Spruce
|
fmt.Fprintf(&b, "Spruce\n Version: %s\n Git commit: %s\n Go version: %s\n Build date: %s\n", v.binaryVersion, v.gitCommit, v.goVersion, v.buildTime)
|
||||||
Version: %s
|
|
||||||
Git commit: %s
|
|
||||||
Go version: %s
|
|
||||||
Build date: %s
|
|
||||||
`
|
|
||||||
|
|
||||||
version = fmt.Sprintf(fullVersionFmt, v.binaryVersion, v.gitCommit, v.goVersion, v.buildTime)
|
|
||||||
} else {
|
} else {
|
||||||
version = v.binaryVersion + "\n"
|
fmt.Fprintln(&b, v.binaryVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print(version)
|
fmt.Print(b.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
39
main.go
39
main.go
|
@ -8,12 +8,6 @@ import (
|
||||||
"codeflow.dananglin.me.uk/apollo/spruce/internal/cmd"
|
"codeflow.dananglin.me.uk/apollo/spruce/internal/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Runner interface {
|
|
||||||
Parse([]string) error
|
|
||||||
Name() string
|
|
||||||
Run() error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
binaryVersion string
|
binaryVersion string
|
||||||
buildTime string
|
buildTime string
|
||||||
|
@ -22,6 +16,13 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
args := os.Args[1:]
|
||||||
|
|
||||||
|
if len(args) < 1 || args[0] == "--help" || args[0] == "-h" || args[0] == "help" || args[0] == "-help" {
|
||||||
|
cmd.SpruceUsage()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
logOptions := slog.HandlerOptions{
|
logOptions := slog.HandlerOptions{
|
||||||
AddSource: false,
|
AddSource: false,
|
||||||
}
|
}
|
||||||
|
@ -30,23 +31,25 @@ func main() {
|
||||||
|
|
||||||
slog.SetDefault(logger)
|
slog.SetDefault(logger)
|
||||||
|
|
||||||
commandMap := map[string]Runner{
|
subcommand := args[0]
|
||||||
"version": cmd.NewVersionCommand(
|
|
||||||
|
var runner cmd.Runner
|
||||||
|
|
||||||
|
switch subcommand {
|
||||||
|
case "version":
|
||||||
|
runner = cmd.NewVersionCommand(
|
||||||
binaryVersion,
|
binaryVersion,
|
||||||
buildTime,
|
buildTime,
|
||||||
goVersion,
|
goVersion,
|
||||||
gitCommit,
|
gitCommit,
|
||||||
),
|
)
|
||||||
"generate": cmd.NewGenerateCommand(),
|
case "generate":
|
||||||
"create": cmd.NewCreateCommand(),
|
runner = cmd.NewGenerateCommand()
|
||||||
}
|
case "create":
|
||||||
|
runner = cmd.NewCreateCommand()
|
||||||
subcommand := os.Args[1]
|
default:
|
||||||
|
|
||||||
runner, ok := commandMap[subcommand]
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
slog.Error("unknown subcommand", "subcommand", subcommand)
|
slog.Error("unknown subcommand", "subcommand", subcommand)
|
||||||
|
cmd.SpruceUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue