diff --git a/README.asciidoc b/README.asciidoc index c7205a4..a1e6942 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -89,6 +89,29 @@ go install . === 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. [source,console] ---- diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go new file mode 100644 index 0000000..626459b --- /dev/null +++ b/internal/cmd/cmd.go @@ -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()) + } +} diff --git a/internal/cmd/create.go b/internal/cmd/create.go index f3c5aa5..d4c5e99 100644 --- a/internal/cmd/create.go +++ b/internal/cmd/create.go @@ -13,6 +13,7 @@ import ( type CreateCommand struct { *flag.FlagSet + summary string firstName string lastName string jobTitle string @@ -22,12 +23,15 @@ type CreateCommand struct { func NewCreateCommand() *CreateCommand { cc := CreateCommand{ 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.lastName, "last-name", "", "specify your last name") - cc.StringVar(&cc.jobTitle, "job-title", "", "specify your preferred job title") - cc.StringVar(&cc.filename, "filename", "cv.json", "specify the filename of the created JSON document") + cc.StringVar(&cc.filename, "filepath", "cv.json", "specify the path where the CV JSON document should be created.") + cc.StringVar(&cc.firstName, "first-name", "", "specify your first name.") + cc.StringVar(&cc.jobTitle, "job-title", "", "specify your current job title.") + cc.StringVar(&cc.lastName, "last-name", "", "specify your last name.") + + cc.Usage = usageFunc(cc.Name(), cc.summary, cc.FlagSet) return &cc } diff --git a/internal/cmd/generate.go b/internal/cmd/generate.go index 95cb6d7..7084339 100644 --- a/internal/cmd/generate.go +++ b/internal/cmd/generate.go @@ -21,6 +21,7 @@ var templates embed.FS type GenerateCommand struct { *flag.FlagSet + summary string input string output string employmentHistory int @@ -30,12 +31,15 @@ type GenerateCommand struct { func NewGenerateCommand() *GenerateCommand { gc := GenerateCommand{ 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.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.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 } diff --git a/internal/cmd/version.go b/internal/cmd/version.go index fb59aac..51eb80d 100644 --- a/internal/cmd/version.go +++ b/internal/cmd/version.go @@ -3,10 +3,12 @@ package cmd import ( "flag" "fmt" + "strings" ) type VersionCommand struct { *flag.FlagSet + summary string fullVersion bool binaryVersion string buildTime string @@ -21,28 +23,24 @@ func NewVersionCommand(binaryVersion, buildTime, goVersion, gitCommit string) *V buildTime: buildTime, goVersion: goVersion, 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 } func (v *VersionCommand) Run() error { - var version string + var b strings.Builder if v.fullVersion { - fullVersionFmt := `Spruce - Version: %s - Git commit: %s - Go version: %s - Build date: %s -` - - version = fmt.Sprintf(fullVersionFmt, v.binaryVersion, v.gitCommit, v.goVersion, v.buildTime) + 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) } else { - version = v.binaryVersion + "\n" + fmt.Fprintln(&b, v.binaryVersion) } - fmt.Print(version) + fmt.Print(b.String()) return nil } diff --git a/main.go b/main.go index 29cf4bc..6023086 100644 --- a/main.go +++ b/main.go @@ -8,12 +8,6 @@ import ( "codeflow.dananglin.me.uk/apollo/spruce/internal/cmd" ) -type Runner interface { - Parse([]string) error - Name() string - Run() error -} - var ( binaryVersion string buildTime string @@ -22,6 +16,13 @@ var ( ) 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{ AddSource: false, } @@ -30,23 +31,25 @@ func main() { slog.SetDefault(logger) - commandMap := map[string]Runner{ - "version": cmd.NewVersionCommand( + subcommand := args[0] + + var runner cmd.Runner + + switch subcommand { + case "version": + runner = cmd.NewVersionCommand( binaryVersion, buildTime, goVersion, gitCommit, - ), - "generate": cmd.NewGenerateCommand(), - "create": cmd.NewCreateCommand(), - } - - subcommand := os.Args[1] - - runner, ok := commandMap[subcommand] - - if !ok { + ) + case "generate": + runner = cmd.NewGenerateCommand() + case "create": + runner = cmd.NewCreateCommand() + default: slog.Error("unknown subcommand", "subcommand", subcommand) + cmd.SpruceUsage() os.Exit(1) }