aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorAlexander Kiryukhin <a.kiryukhin@mail.ru>2021-12-05 17:46:53 +0300
committerAlexander Kiryukhin <a.kiryukhin@mail.ru>2021-12-05 17:46:53 +0300
commitbcdbe68ecde049ef62343584bcc26840322c4864 (patch)
tree4a02b4da5db29ab3f3526ff475db859293a97646 /cmd
Initial commit
Diffstat (limited to 'cmd')
-rw-r--r--cmd/add.go48
-rw-r--r--cmd/ls.go66
-rw-r--r--cmd/root.go68
-rw-r--r--cmd/start.go37
-rw-r--r--cmd/stop.go38
5 files changed, 257 insertions, 0 deletions
diff --git a/cmd/add.go b/cmd/add.go
new file mode 100644
index 0000000..b8979b0
--- /dev/null
+++ b/cmd/add.go
@@ -0,0 +1,48 @@
+package cmd
+
+import (
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+// addCmd represents the add command
+var addCmd = &cobra.Command{
+ Use: "add",
+ Short: "Add activity",
+ Long: `Add new activity that we can track`,
+ Run: func(cmd *cobra.Command, args []string) {
+ titles := []string{}
+ tags := []string{}
+ contexts := []string{}
+ for _, s := range args {
+ if len(s) == 0 {
+ continue
+ }
+ if s[0:1] == "#" {
+ if len(s[1:]) >= 1 {
+ tags = append(tags, s[1:])
+ continue
+ }
+ }
+ if s[0:1] == "@" {
+ if len(s[1:]) >= 1 {
+ contexts = append(contexts, s[1:])
+ continue
+ }
+ }
+ titles = append(titles, s)
+ }
+ title := strings.Join(titles, " ")
+ activityID, err := tr.Add(title, tags, contexts)
+ if err != nil {
+ cmd.PrintErr(err)
+ return
+ }
+ cmd.Printf("Activity #%d added! Now you can start it.\n", activityID)
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(addCmd)
+}
diff --git a/cmd/ls.go b/cmd/ls.go
new file mode 100644
index 0000000..3fe7244
--- /dev/null
+++ b/cmd/ls.go
@@ -0,0 +1,66 @@
+package cmd
+
+import (
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+// lsCmd represents the ls command
+var lsCmd = &cobra.Command{
+ Use: "ls",
+ Short: "List activities",
+ Long: `List started (or all by -a flag) activities`,
+ Run: func(cmd *cobra.Command, args []string) {
+ all, err := cmd.Flags().GetBool("all")
+ if err != nil {
+ cmd.PrintErr(err)
+ return
+ }
+ verbose, err := cmd.Flags().GetBool("verbose")
+ if err != nil {
+ cmd.PrintErr(err)
+ return
+ }
+ activities := tr.List(all)
+ if len(activities) == 0 {
+ cmd.Printf("There is no activities.\n")
+ return
+ }
+ if all {
+ cmd.Printf("Activities:\n")
+ } else {
+ cmd.Printf("Started activities:\n")
+ }
+ for _, activity := range activities {
+ cmd.Printf("%d. %s\n", activity.ID, activity.Title)
+ if len(activity.Tags) > 0 {
+ cmd.Printf("\tTags: %v\n", activity.Tags)
+ }
+ if len(activity.Context) > 0 {
+ cmd.Printf("\tContexts: %v\n", activity.Context)
+ }
+ cmd.Printf("\t%d timespans\n", len(activity.Spans))
+ for i, span := range activity.Spans {
+ if !verbose && i < len(activity.Spans)-1 {
+ continue
+ }
+ stop := "now"
+ if span.Stop != nil {
+ stop = span.Stop.Format("15:04:05 2.1.2006")
+ }
+ if strings.Trim(span.Comment, " ") != "" {
+ cmd.Printf("\t%s — %s: \"%s\"\n", span.Start.Format("15:04:05 2.1.2006"), stop, span.Comment)
+ } else {
+ cmd.Printf("\t%s — %s\n", span.Start.Format("15:04:05 2.1.2006"), stop)
+ }
+ }
+ }
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(lsCmd)
+ lsCmd.Flags().BoolP("all", "a", false, "List all activities. Only started by default")
+ lsCmd.Flags().BoolP("verbose", "v", false, "List all timespans. Only last by default")
+}
diff --git a/cmd/root.go b/cmd/root.go
new file mode 100644
index 0000000..ad372c1
--- /dev/null
+++ b/cmd/root.go
@@ -0,0 +1,68 @@
+package cmd
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/spf13/afero"
+ "github.com/spf13/cobra"
+
+ "github.com/spf13/viper"
+
+ "github.com/neonxp/track/internal/tracker"
+)
+
+var cfgFile string
+
+// rootCmd represents the base command when called without any subcommands
+var rootCmd = &cobra.Command{
+ Use: "track",
+ Short: "Track your work or personal activities",
+ Long: `Track time spent for any work or personal activities`,
+}
+
+var tr *tracker.Tracker
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the rootCmd.
+func Execute() {
+ fs := afero.NewOsFs()
+ var err error
+ tr, err = tracker.New(fs)
+ if err != nil {
+ panic(err)
+ return
+ }
+ cobra.CheckErr(rootCmd.Execute())
+}
+
+func init() {
+ cobra.OnInitialize(initConfig)
+ rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.track.yaml)")
+ rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+}
+
+// initConfig reads in config file and ENV variables if set.
+func initConfig() {
+ if cfgFile != "" {
+ // Use config file from the flag.
+ viper.SetConfigFile(cfgFile)
+ } else {
+ // Find home directory.
+ home, err := os.UserHomeDir()
+ cobra.CheckErr(err)
+
+ // Search config in home directory with name ".track" (without extension).
+ viper.AddConfigPath(home)
+ viper.SetConfigType("yaml")
+ viper.SetConfigName(".track")
+ }
+
+ viper.AutomaticEnv() // read in environment variables that match
+
+ // If a config file is found, read it in.
+ if err := viper.ReadInConfig(); err == nil {
+ fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
+ }
+}
+
diff --git a/cmd/start.go b/cmd/start.go
new file mode 100644
index 0000000..a0ae4f1
--- /dev/null
+++ b/cmd/start.go
@@ -0,0 +1,37 @@
+package cmd
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+// startCmd represents the start command
+var startCmd = &cobra.Command{
+ Use: "start",
+ Short: "Start activity",
+ Long: `Start new timespan on activity`,
+ Run: func(cmd *cobra.Command, args []string) {
+ if len(args) == 0 {
+ cmd.PrintErr("First argument must be activity id\n")
+ return
+ }
+ id, err := strconv.Atoi(args[0])
+ if err != nil {
+ cmd.PrintErr("First argument must be activity id, got %s\n", args[0])
+ return
+ }
+ comment := strings.Join(args[1:], " ")
+ if err := tr.Start(id, comment); err != nil {
+ cmd.PrintErr(err)
+ return
+ }
+ activity := tr.Activity(id)
+ cmd.Printf("Started new span for activity \"%s\".\n", activity.Title)
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(startCmd)
+}
diff --git a/cmd/stop.go b/cmd/stop.go
new file mode 100644
index 0000000..ac472cd
--- /dev/null
+++ b/cmd/stop.go
@@ -0,0 +1,38 @@
+package cmd
+
+import (
+ "strconv"
+
+ "github.com/spf13/cobra"
+
+ "github.com/neonxp/track/internal/tracker"
+)
+
+// stopCmd represents the stop command
+var stopCmd = &cobra.Command{
+ Use: "stop",
+ Short: "Stop activity",
+ Long: `Stop working on activity`,
+ Run: func(cmd *cobra.Command, args []string) {
+ activities := tr.List(false)
+ if len(args) != 0 {
+ id, err := strconv.Atoi(args[0])
+ if err != nil {
+ cmd.PrintErr("First argument must be activity id, got %s.\n", args[0])
+ return
+ }
+ activities = []*tracker.Activity{tr.Activity(id)}
+ }
+ for _, activity := range activities {
+ if err := tr.Stop(activity.ID); err != nil {
+ cmd.PrintErr(err)
+ return
+ }
+ cmd.Printf("Stopped activity \"%s\".\n", activity.Title)
+ }
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(stopCmd)
+}