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 . + +// 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 [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 -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 . + +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 . + +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 . + +package main + +// These variables are set by the linker. They can be modified in the Makefile. +var ( + Version = "Unknown" + Commit = "Unknown" +)