summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2023-12-26 05:58:19 +0100
committerPřemysl Eric Janouch <p@janouch.name>2023-12-26 06:39:28 +0100
commit74a6dd0233bd0c983e191b9708e0ed257e78b0ff (patch)
tree2a09d73f247d8f72c06fb88d0f190badf9f25ee9
parent615860362a39b769f75cf45a8d0e58d3e218e72a (diff)
downloadgallery-74a6dd0233bd0c983e191b9708e0ed257e78b0ff.tar.gz
gallery-74a6dd0233bd0c983e191b9708e0ed257e78b0ff.tar.xz
gallery-74a6dd0233bd0c983e191b9708e0ed257e78b0ff.zip
WIP: Command arguments
-rw-r--r--main.go81
1 files changed, 53 insertions, 28 deletions
diff --git a/main.go b/main.go
index 0d89b06..67c0850 100644
--- a/main.go
+++ b/main.go
@@ -9,6 +9,7 @@ import (
"encoding/hex"
"encoding/json"
"errors"
+ "flag"
"fmt"
"html/template"
"image"
@@ -260,9 +261,9 @@ func parallelize(strings []string, callback parallelFunc) error {
// cmdInit initializes a "gallery directory" that contains gallery.sqlite,
// images, thumbs.
-func cmdInit(args []string) error {
+func cmdInit(fs *flag.FlagSet, args []string) error {
if len(args) != 1 {
- return errors.New("usage: GD")
+ return errWrongUsage
}
if err := openDB(args[0]); err != nil {
@@ -1074,9 +1075,9 @@ func handleAPISearch(w http.ResponseWriter, r *http.Request) {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// cmdWeb runs a web UI against GD on ADDRESS.
-func cmdWeb(args []string) error {
+func cmdWeb(fs *flag.FlagSet, args []string) error {
if len(args) != 2 {
- return errors.New("usage: GD ADDRESS")
+ return errWrongUsage
}
if err := openDB(args[0]); err != nil {
return err
@@ -1681,11 +1682,17 @@ func syncRun(ctx context.Context, tx *sql.Tx, roots []string) error {
// cmdSync ensures the given (sub)roots are accurately reflected
// in the database.
-func cmdSync(args []string) error {
- if len(args) < 2 {
- return errors.New("usage: GD ROOT...")
+func cmdSync(fs *flag.FlagSet, args []string) error {
+ // TODO: Convert the other commands as well.
+ fullpaths := fs.Bool("fullpaths", false, "don't basename the arguments")
+ if err := fs.Parse(args); err != nil {
+ return err
}
- if err := openDB(args[0]); err != nil {
+ if fs.NArg() < 2 {
+ return errWrongUsage
+ }
+
+ if err := openDB(fs.Arg(0)); err != nil {
return err
}
@@ -1709,9 +1716,12 @@ func cmdSync(args []string) error {
return err
}
+ // TODO: Handle sensibly.
+ _ = fullpaths
+
// Normalize arguments.
// At least for now, turn all roots into absolute paths.
- roots := args[1:]
+ roots := fs.Args()[1:]
for i := range roots {
roots[i], err = filepath.Abs(filepath.Clean(roots[i]))
if err != nil {
@@ -1739,9 +1749,9 @@ func cmdSync(args []string) error {
// cmdRemove is for manual removal of subtrees from the database.
// Beware that inputs are database, not filesystem paths.
-func cmdRemove(args []string) error {
+func cmdRemove(fs *flag.FlagSet, args []string) error {
if len(args) < 2 {
- return errors.New("usage: GD PATH...")
+ return errWrongUsage
}
if err := openDB(args[0]); err != nil {
return err
@@ -1784,7 +1794,7 @@ func cmdRemove(args []string) error {
// cmdTag mass imports tags from data passed on stdin as a TSV
// of SHA1 TAG WEIGHT entries.
-func cmdTag(args []string) error {
+func cmdTag(fs *flag.FlagSet, args []string) error {
if len(args) < 2 || len(args) > 3 {
return errors.New("usage: GD SPACE [DESCRIPTION]")
}
@@ -1935,7 +1945,7 @@ func checkFiles(root, suffix string, hashes []string) (bool, []string, error) {
}
// cmdCheck carries out various database consistency checks.
-func cmdCheck(args []string) error {
+func cmdCheck(fs *flag.FlagSet, args []string) error {
if len(args) != 1 {
return errors.New("usage: GD")
}
@@ -2052,9 +2062,9 @@ func makeThumbnailFor(sha1 string) (message string, err error) {
}
// cmdThumbnail generates missing thumbnails, in parallel.
-func cmdThumbnail(args []string) error {
+func cmdThumbnail(fs *flag.FlagSet, args []string) error {
if len(args) < 1 {
- return errors.New("usage: GD [SHA1...]")
+ return errWrongUsage
}
if err := openDB(args[0]); err != nil {
return err
@@ -2207,9 +2217,9 @@ func makeDhashFor(sha1 string) (message string, err error) {
}
// cmdDhash generates perceptual hash from thumbnails.
-func cmdDhash(args []string) error {
+func cmdDhash(fs *flag.FlagSet, args []string) error {
if len(args) < 1 {
- return errors.New("usage: GD [SHA1...]")
+ return errWrongUsage
}
if err := openDB(args[0]); err != nil {
return err
@@ -2229,20 +2239,25 @@ func cmdDhash(args []string) error {
// --- Main --------------------------------------------------------------------
+var errWrongUsage = errors.New("wrong usage")
+
var commands = map[string]struct {
- handler func(args []string) error
+ handler func(*flag.FlagSet, []string) error
+ usage string
}{
- "init": {cmdInit},
- "web": {cmdWeb},
- "tag": {cmdTag},
- "sync": {cmdSync},
- "remove": {cmdRemove},
- "check": {cmdCheck},
- "thumbnail": {cmdThumbnail},
- "dhash": {cmdDhash},
+ "init": {cmdInit, "GD"},
+ "web": {cmdWeb, "GD ADDRESS"},
+ "tag": {cmdTag, "GD SPACE [DESCRIPTION]"},
+ "sync": {cmdSync, "GD ROOT..."},
+ "remove": {cmdRemove, "GD PATH..."},
+ "check": {cmdCheck, "GD"},
+ "thumbnail": {cmdThumbnail, "GD [SHA1...]"},
+ "dhash": {cmdDhash, "GD [SHA1...]"},
}
func main() {
+ // TODO: Implement a global -h command.
+ // The flag package doesn't reorder, unlike GNU, so it's fine.
if len(os.Args) <= 2 {
log.Fatalln("Missing arguments")
}
@@ -2252,8 +2267,15 @@ func main() {
log.Fatalln("Unknown command: " + os.Args[1])
}
+ fs := flag.NewFlagSet(os.Args[1], flag.ExitOnError)
+ fs.Usage = func() {
+ fmt.Fprintf(fs.Output(),
+ "Usage: %s [OPTION...] %s...\n", fs.Name(), cmd.usage)
+ fs.PrintDefaults()
+ }
+
taskSemaphore = newSemaphore(runtime.NumCPU())
- err := cmd.handler(os.Args[2:])
+ err := cmd.handler(fs, os.Args[2:])
// Note that the database object has a closing finalizer,
// we just additionally print any errors coming from there.
@@ -2263,7 +2285,10 @@ func main() {
}
}
- if err != nil {
+ if errors.Is(err, errWrongUsage) {
+ fs.Usage()
+ os.Exit(2)
+ } else if err != nil {
log.Fatalln(err)
}
}