summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornytpu <alex@nytpu.com>2021-03-16 10:20:31 -0600
committernytpu <alex@nytpu.com>2021-03-16 10:24:36 -0600
commit91e663c0f0ec4e1e61a2493f6ab08850cd2e5a2e (patch)
treecfc8f3e4db20d48085be41485ffcf411b9441920
parentf82e0905779c9d88140403778f7b3b35a1d03420 (diff)
add command parsing
-rw-r--r--comitium.go118
-rw-r--r--comitium_test.go31
-rw-r--r--flags.go49
-rw-r--r--go.mod8
-rw-r--r--go.sum4
-rw-r--r--version.go11
6 files changed, 221 insertions, 0 deletions
diff --git a/comitium.go b/comitium.go
new file mode 100644
index 0000000..6cc069b
--- /dev/null
+++ b/comitium.go
@@ -0,0 +1,118 @@
+// Copyright (C) 2021 nytpu
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// For more license details, see LICENSE or <https://www.gnu.org/licenses/agpl-3.0.html>.
+
+// comitium is a feed aggregator for gemini. see README.md for more details and
+// doc/comitium.1.scd for a manual page.
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+
+ "github.com/mitchellh/go-homedir"
+)
+
+func main() {
+ if len(os.Args) < 2 {
+ fmt.Fprint(os.Stderr, "Please provide a command.\n\n")
+ usage()
+ os.Exit(1)
+ }
+
+ // these are special cases where we shouldn't bother to do anything else
+ if os.Args[1] == "help" {
+ usage()
+ os.Exit(0)
+ }
+ if os.Args[1] == "version" {
+ fmt.Printf("comitium v%v, commit %v\n", Version, Commit)
+ os.Exit(0)
+ }
+
+ c, ok := commands[os.Args[1]]
+ if !ok {
+ fmt.Fprint(os.Stderr, "Unrecognized Command.\n\n")
+ usage()
+ os.Exit(1)
+ }
+
+ c.AddFlagSet(globalFs)
+ c.Parse(os.Args[2:])
+
+ // dataPath is the location where all the data (list of subs, cached hashes,
+ // etcetera) are stored
+ dataPath := getDataPath()
+
+ switch os.Args[1] {
+ case "refresh":
+ fmt.Println("Refresh")
+ case "list":
+ fmt.Println("List")
+ case "add":
+ fmt.Println("Add")
+ fmt.Printf("Format: %v\n", *addTypeFlag)
+ case "remove":
+ fmt.Println("Remove")
+ }
+
+ fmt.Printf("Detected data path: %v\n", dataPath)
+}
+
+// verifyPath will expand ~ if neccessary and will clean the path.
+func verifyPath(p string) string {
+ if n, err := homedir.Expand(p); err != nil {
+ return filepath.Clean(p)
+ } else {
+ return filepath.Clean(n)
+ }
+}
+
+// getDataPath will return a data path in a gracefully degrading tree, picking
+// the first that exists:
+// --data flag, $COMITIUM_DATA, $XDG_DATA_HOME/comitium,
+// $HOME/.local/share/comitium, $HOME/.comitium, $PWD (last resort)
+func getDataPath() string {
+ if *dataFlag != "" {
+ return verifyPath(*dataFlag)
+ }
+
+ if env := os.Getenv("COMITIUM_DATA"); env != "" {
+ return verifyPath(env)
+ }
+ if env := os.Getenv("XDG_DATA_HOME"); env != "" {
+ return verifyPath(env + "/comitium")
+ }
+
+ home, err := homedir.Dir()
+ if err == nil {
+ if _, err := os.Stat(verifyPath(home + "/.local")); !os.IsNotExist(err) {
+ return verifyPath(home + "/.local/share/comitium")
+ }
+ return verifyPath(home + "/.comitium")
+ }
+
+ log.Printf("Error finding a suitable directory! Falling back to the current working directory. See \"comitium help\" or comitium(1) for more information.")
+ return verifyPath("comitium")
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "Usage:\n")
+ fmt.Fprintf(os.Stderr, " %v <command> [FLAGS] [ARGUMENTS]\n\n", os.Args[0])
+
+ fmt.Fprint(os.Stderr, "Commands:\n")
+ for _, v := range commandInfo {
+ // FIXME: find a way to dynamically match the spacing that
+ // flag.PrintDefaults() outputs (instead of hardcoding "-20")
+ fmt.Fprintf(os.Stderr, " %-20s%s\n", v.Name, v.Usage)
+ }
+
+ fmt.Fprintf(os.Stderr, "\nGlobal Flags:\n%v", globalFs.FlagUsages())
+ // command-specific flags should be printed here
+ fmt.Fprintf(os.Stderr, "Flags for \"add\":\n%v\n", commands["add"].FlagUsages())
+
+ //fmt.Fprintf(os.Stderr, "To see specific details for a command, run \"%v <command> -h\"\n", os.Args[0])
+ fmt.Fprint(os.Stderr, "For more help, see comitium(1).\n")
+}
diff --git a/comitium_test.go b/comitium_test.go
new file mode 100644
index 0000000..287975a
--- /dev/null
+++ b/comitium_test.go
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 nytpu
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// For more license details, see LICENSE or <https://www.gnu.org/licenses/agpl-3.0.html>.
+
+package main
+
+import (
+ "testing"
+)
+
+func TestVerifyPath(t *testing.T) {
+ given := []string{
+ "~////../hello-world////",
+ "/home/~/../test/../..",
+ "/test/torture/../../../../test/./././torture/./0011/",
+ ".local/share/comitium/",
+ "/home/test/.local/share/comitium",
+ }
+ want := []string{
+ "/home/hello-world",
+ "/",
+ "/test/torture/0011",
+ ".local/share/comitium",
+ "/home/test/.local/share/comitium",
+ }
+ for i, v := range given {
+ if result := verifyPath(v); result != want[i] {
+ t.Fatalf(`verifyPath("%v") = %v, want %v`, v, result, want[i])
+ }
+ }
+}
diff --git a/flags.go b/flags.go
new file mode 100644
index 0000000..7f28bed
--- /dev/null
+++ b/flags.go
@@ -0,0 +1,49 @@
+// Copyright (C) 2021 nytpu
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// For more license details, see LICENSE or <https://www.gnu.org/licenses/agpl-3.0.html>.
+
+package main
+
+import flag "github.com/spf13/pflag"
+
+// globalFs contains the flags that are used in every command.
+var (
+ globalFs = flag.NewFlagSet("global", flag.ContinueOnError)
+
+ dataFlag = globalFs.StringP("data", "d", "", "The data directory where comitium will store its files")
+)
+
+// command holds fields used for printing information about a command.
+type command struct {
+ Name string
+ Usage string
+}
+
+// info about all the accepted commands
+var commandInfo = []command{
+ {"refresh", "Check for new updates to subscriptions"},
+ {"list", "List all subscriptions"},
+ {"add", "Add a new subscription"},
+ {"remove", "Remove a subscription"},
+ {"help", "Print usage information"},
+ {"version", "Print version information"},
+}
+
+var commands = map[string]*flag.FlagSet{
+ "refresh": flag.NewFlagSet("refresh", flag.ExitOnError),
+ "list": flag.NewFlagSet("list", flag.ExitOnError),
+ "add": flag.NewFlagSet("add", flag.ExitOnError),
+ "remove": flag.NewFlagSet("remove", flag.ExitOnError),
+}
+
+// set up various flags for each individual command
+var (
+ // add
+ addTypeFlag = commands["add"].StringP(
+ "type", "t", // long and shorthand flag
+ "g", // default
+ `Select which type a subscription is. Can be "g" for a
+Gemini feed; "a" for Atom, RSS, & JSON; or "c" to watch
+the page for changes.`,
+ )
+)
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..337d9c1
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,8 @@
+module golang.nytpu.com/comitium
+
+go 1.16
+
+require (
+ github.com/mitchellh/go-homedir v1.1.0
+ github.com/spf13/pflag v1.0.5
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..8635e51
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,4 @@
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
diff --git a/version.go b/version.go
new file mode 100644
index 0000000..7ea6fa6
--- /dev/null
+++ b/version.go
@@ -0,0 +1,11 @@
+// Copyright (C) 2021 nytpu
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// For more license details, see LICENSE or <https://www.gnu.org/licenses/agpl-3.0.html>.
+
+package main
+
+// These variables are set by the linker. They can be modified in the Makefile.
+var (
+ Version = "Unknown"
+ Commit = "Unknown"
+)