diff --git a/.gitignore b/.gitignore index cb33077..91e6eff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1 @@ /gitmirror -/gitmirror-clone -/gitmirror-help -/gitmirror-update -/gitmirror-version diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..d456cb3 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,11 @@ +# TODO + +## Clean up + +This works now as a single command, but there’s a lot of overlapping +responsibilities and cruft. + ++ How should I handle the command and subcommand names? (Store them in the app? + Store them as package constants? Something else?) ++ What is the responsibility of the app versus just a function call? ++ Maybe I can handle flags and flag-parsing better? diff --git a/internal/cli/app.go b/internal/cli/app.go index ed93677..3ec271e 100644 --- a/internal/cli/app.go +++ b/internal/cli/app.go @@ -12,7 +12,6 @@ import ( ) const ( - cmdName = "gitmirror" defaultConfig = ".gitmirror.json" defaultStorage = ".local/share/gitmirror" exitSuccess = 0 @@ -31,19 +30,19 @@ type App struct { // NoOp determines whether an App should bail out. func (app *App) NoOp() bool { - return app.ExitValue != exitSuccess || app.HelpWanted + return app.ExitValue != exitSuccess } // NewApp returns a new App pointer. func NewApp(cmdUsage string) *App { homeDir, err := os.UserHomeDir() if err != nil { - fmt.Fprintf(os.Stderr, "%s: %s\n", cmdName, err) + fmt.Fprintf(os.Stderr, "%s: %s\n", gitmirrorName, err) return &App{ExitValue: exitFailure} } return &App{ - CmdName: cmdName, - Usage: cmdUsage, + CmdName: gitmirrorName, + Usage: gitmirrorUsage, ExitValue: exitSuccess, HomeDir: homeDir, } @@ -77,7 +76,9 @@ func (app *App) Flags(args []string) (string, bool) { fmt.Fprintf(os.Stderr, "%s: %s\n%s", app.CmdName, err, app.Usage) app.ExitValue = exitFailure case app.HelpWanted: - fmt.Print(app.Usage) + fmt.Fprintf(os.Stderr, "%s: use 'help' not '-help' or '-h'\n", app.CmdName) + fmt.Fprint(os.Stderr, app.Usage) + app.ExitValue = exitFailure case configFile == "": configFile = defaultConfig configIsDefault = true diff --git a/internal/cli/gitmirror.go b/internal/cli/gitmirror.go index a89a607..f3d1ce1 100644 --- a/internal/cli/gitmirror.go +++ b/internal/cli/gitmirror.go @@ -5,6 +5,11 @@ import ( "os" ) +const ( + gitmirrorName = "gitmirror" + gitmirrorVersion = "v0.1.0" +) + // CmdWrapper turns, e.g., `gitmirror update -q` into `gitmirror-update -q`. func CmdGitmirror(args []string) int { if len(args) < 1 { @@ -27,6 +32,7 @@ func CmdGitmirror(args []string) int { // TODO: write the help in Asciidoc? exitValue = CmdHelp(args[1:]) default: + fmt.Fprintf(os.Stderr, "gitmirror: unrecognized subcommand: \"%s\"\n", args[0]) fmt.Fprint(os.Stderr, gitmirrorUsage) exitValue = exitFailure } diff --git a/internal/cli/help.go b/internal/cli/help.go index fc7c9e1..0e66d87 100644 --- a/internal/cli/help.go +++ b/internal/cli/help.go @@ -11,8 +11,14 @@ func (app *App) Help(args []string) { return } if len(args) < 1 { - fmt.Fprintf(os.Stderr, "%s: no command given\n", cmdName) - fmt.Fprint(os.Stderr, gitmirrorUsage) + fmt.Fprintf(os.Stderr, "%s help: no subcommand given\n", gitmirrorName) + fmt.Fprint(os.Stderr, helpUsage) + app.ExitValue = exitFailure + return + } + if len(args) > 1 { + fmt.Fprintf(os.Stderr, "%s help: too many arguments: %+v\n", gitmirrorName, args) + fmt.Fprint(os.Stderr, helpUsage) app.ExitValue = exitFailure return } @@ -21,17 +27,20 @@ func (app *App) Help(args []string) { fmt.Fprint(os.Stdout, cloneUsage) case "up", "update": fmt.Fprint(os.Stdout, updateUsage) + case "help": + fmt.Fprint(os.Stdout, helpUsage) case "version": fmt.Fprint(os.Stdout, versionUsage) default: - fmt.Fprint(os.Stderr, gitmirrorUsage) + fmt.Fprintf(os.Stderr, "%s help: unrecognized subcommand: \"%s\"\n", gitmirrorName, args[0]) + fmt.Fprint(os.Stderr, helpUsage) app.ExitValue = exitFailure } } // CmdHelp clones requested repos locally for mirroring. func CmdHelp(args []string) int { - app := NewApp(gitmirrorUsage) + app := NewApp(helpUsage) app.Help(args) return app.ExitValue } diff --git a/internal/cli/usage.go b/internal/cli/usage.go index 2e14d21..ebf9f93 100644 --- a/internal/cli/usage.go +++ b/internal/cli/usage.go @@ -2,39 +2,54 @@ package cli import "github.com/MakeNowJust/heredoc" -var gitmirrorUsage = heredoc.Doc(` - usage: gitmirror help +var gitmirrorUsage = heredoc.Docf(` + Usage: gitmirror [options] - Display help information for the specified command + Back up git repositories using git itself. - The commands are: + Subcommands: clone Clone repositories to mirror update|up Update mirrored repositories - version Print version and exit -`) + help Show detailed information about a subcommand + version Show version + + Run %[1]sgitmirror help %[1]s for more information about a subcommand. +`, "`") + +var helpUsage = heredoc.Docf(` + Usage: gitmirror help + + %[1]sgitmirror help%[1]s displays detailed information about a subcommand. + + Subcommands: + clone Clone repositories to mirror + update|up Update mirrored repositories + help Show detailed information about a subcommand + version Show version +`, "`") var cloneUsage = heredoc.Docf( - `usage: gitmirror clone [-config FILENAME] + `Usage: gitmirror clone [-config FILENAME] - Run %[1]sgit clone --mirror%[1]s on repos listed in a configuration file. + %[1]sgitmirror clone%[1]s runs %[1]sgit clone --mirror%[1]s on repos in a configuration file. - options: + Options: -config/-c FILENAME Specify configuration file (default ~/.gitmirror.json) -quiet/-q Suppress output unless an error occurs `, "`") var updateUsage = heredoc.Docf( - `usage: gitmirror-update [-config FILENAME] + `Usage: gitmirror update|up [-config FILENAME] - Run %[1]sgit remote update%[1]s on repos listed in a configuration file. + %[1]sgitmirror update%[1]s runs %[1]sgit remote update%[1]s on repos in a configuration file. - options: + Options: -config/-c FILENAME Specify configuration file (default ~/.gitmirror.json) -quiet/-q Suppress output unless an error occurs `, "`") -var versionUsage = heredoc.Doc(` - usage: gitmirror version +var versionUsage = heredoc.Docf(` + Usage: gitmirror version - Display version information about gitmirror -`) + %[1]sgitmirror version%[1]s displays version information for gitmirror. +`, "`") diff --git a/internal/cli/version.go b/internal/cli/version.go index 6d75c49..cd879d0 100644 --- a/internal/cli/version.go +++ b/internal/cli/version.go @@ -5,26 +5,22 @@ import ( "os" ) -const ( - gitmirrorVersion = "v0.1.0" -) - // Version displays gitmirror's version. func (app *App) Version(args []string) { if app.NoOp() { return } if len(args) != 0 { - fmt.Fprintf(os.Stderr, "%s: no arguments accepted\n", cmdName) + fmt.Fprintf(os.Stderr, "%s version: no arguments accepted\n", gitmirrorName) fmt.Fprint(os.Stderr, versionUsage) app.ExitValue = exitFailure return } - fmt.Fprintf(os.Stdout, "%s: %s\n", cmdName, gitmirrorVersion) + fmt.Fprintf(os.Stdout, "%s: %s\n", gitmirrorName, gitmirrorVersion) } func CmdVersion(args []string) int { - app := NewApp(gitmirrorVersion) + app := NewApp(gitmirrorUsage) app.Version(args) return app.ExitValue }