diff --git a/README.adoc b/README.adoc index d82ec09..d1bbfa7 100644 --- a/README.adoc +++ b/README.adoc @@ -4,7 +4,7 @@ image:https://img.shields.io/github/go-mod/go-version/jlanzarotta/khronos[Go Ver = Khronos :toc: preamble -:toclevels: 6 +:toclevels: 7 :icons: font :sectnums: :numbered: @@ -561,7 +561,7 @@ $ k report --yesterday ===== --date -By specifying the option `--date`, this tells Khronos you would the report specifically for the given date. The date MUST be in the following format `YYYY-mm-dd`. +By specifying the option `--date`, this tells Khronos you would like the report specifically for the given date. The date MUST be in the following format `YYYY-mm-dd`. [source, shell] ---- @@ -570,9 +570,9 @@ $ k report --date 2024-10-11 ===== --no-rounding -By specifying the option `--no-rounding`, this tells Khronos you would -the all the duration to be their original, unrounded values. This option is good it you have durations that are -less than the value you have configured for rounding. +By specifying the option `--no-rounding`, this tells Khronos you would the all +the duration to be their original, unrounded values. This option is good it you +have durations that are less than the value you have configured for rounding. [source, shell] ---- @@ -580,6 +580,19 @@ $ k report --from 2019-04-01 --to 2019-04-13 --no-rounding $ k report --previous-week --no-rounding ---- +==== --export type + +By specifying the option '--export', this tells Khronos you would like export the report to one three types, CSV, HTML, and Mark Down. The default is CSV. + +[source, shell] +---- +$ k report --current-week --export --type csv +$ k report --previous-week --export --type html +$ k report --export --type md +---- + +These commands will create a unique report file with the extension associated with the type you specified. CSV produces a file ending in .csv, HTML produces a file ending in .html, and MD produces a file ending in .md. + === stretch Stretches the last entry to the current or specified date/time. diff --git a/cmd/add.go b/cmd/add.go index f1ee3e1..a983847 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -56,9 +56,8 @@ import ( var addCmd = &cobra.Command{ Use: "add [project+task...]", Args: cobra.MaximumNArgs(1), - Short: "Add a completed entry", - Long: `Once you have completed a entry (project+task), use this command to add that newly -completed task to the database with an optional note.`, + Short: constants.ADD_SHORT_DESCRIPTION, + Long: constants.ADD_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runAdd(cmd, args) }, diff --git a/cmd/amend.go b/cmd/amend.go index f5abf6d..369f536 100644 --- a/cmd/amend.go +++ b/cmd/amend.go @@ -56,9 +56,8 @@ import ( var amendCmd = &cobra.Command{ Use: "amend", Args: cobra.MaximumNArgs(1), - Short: "Amend an entry", - Long: `Amend is a convenient way to modify an entry, default is the last -entry. It lets you modify the project, task, and/or datetime.`, + Short: constants.AMEND_SHORT_DESCRIPTION, + Long: constants.AMEND_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runAmend(cmd, args) }, diff --git a/cmd/backend.go b/cmd/backend.go index bcab252..0ea0298 100644 --- a/cmd/backend.go +++ b/cmd/backend.go @@ -45,8 +45,8 @@ var backendCmd = &cobra.Command{ Use: "backend", Aliases: []string{"b", "back"}, Args: cobra.ExactArgs(0), - Short: "Open a sqlite shell to the database", - Long: "Open a sqlite shell to the database.", + Short: constants.BACKEND_SHORT_DESCRIPTION, + Long: constants.BACKEND_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runBackend(args) }, diff --git a/cmd/break.go b/cmd/break.go index cb7b39b..c6056e5 100644 --- a/cmd/break.go +++ b/cmd/break.go @@ -49,9 +49,8 @@ import ( // breakCmd represents the break command var breakCmd = &cobra.Command{ Use: "break", - Short: "Add a break", - Long: `If you just spent time on break, use this command to add that time -to the database.`, + Short: constants.BREAK_SHORT_DESCRIPTION, + Long: constants.BREAK_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runBreak(cmd, args) }, diff --git a/cmd/configure.go b/cmd/configure.go index a74f988..f6e27e0 100644 --- a/cmd/configure.go +++ b/cmd/configure.go @@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. package cmd import ( + "khronos/constants" "log" "os" @@ -41,8 +42,8 @@ import ( var configureCmd = &cobra.Command{ Use: "configure", Aliases: []string{"c", "config", "conf"}, - Short: "Write out a YAML config file", - Long: "Write out a YAML config file. Print path to config file.", + Short: constants.CONFIGURE_SHORT_DESCRIPTION, + Long: constants.CONFIGURE_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runConfigure(args) }, diff --git a/cmd/edit.go b/cmd/edit.go index 75e3cc9..c09ccb4 100644 --- a/cmd/edit.go +++ b/cmd/edit.go @@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. package cmd import ( + "khronos/constants" "log" "os/exec" @@ -41,8 +42,8 @@ import ( // editCmd represents the edit command. var editCmd = &cobra.Command{ Use: "edit", - Short: "Open the Khronos configuration file in your default editor", - Long: "Open the Khronos configuration file in your default editor.", + Short: constants.EDIT_SHORT_DESCRIPTION, + Long: constants.EDIT_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runEdit(cmd, args) }, diff --git a/cmd/hello.go b/cmd/hello.go index fda809f..a428d98 100644 --- a/cmd/hello.go +++ b/cmd/hello.go @@ -53,10 +53,8 @@ var at string // helloCmd represents the hello command var helloCmd = &cobra.Command{ Use: "hello", - Short: "Start time tracking for the day", - Long: `In order to have khronos start tracking time is to run this -command. It informs khronos that you would like it to start tracking -your time.`, + Short: constants.HELLO_SHORT_DESCRIPTION, + Long: constants.HELLO_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runHello(cmd, args) }, diff --git a/cmd/nuke.go b/cmd/nuke.go index cb2c9f7..8612902 100644 --- a/cmd/nuke.go +++ b/cmd/nuke.go @@ -49,8 +49,8 @@ import ( var nukeCmd = &cobra.Command{ Use: "nuke", - Short: "Nukes entries from the sqlite database", - Long: `As you continuously add completed entries, the database continues to grow unbounded. The nuke command allows you to manage the size of your database.`, + Short: constants.NUKE_SHORT_DESCRIPTION, + Long: constants.NUKE_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runNuke(cmd, args) }, diff --git a/cmd/report.go b/cmd/report.go index 7de2203..22037c7 100644 --- a/cmd/report.go +++ b/cmd/report.go @@ -55,9 +55,12 @@ import ( var from string var to string var givenDate string - var daysOfWeek = map[string]string{} var roundToMinutes int64 +var exportFilename string = constants.EMPTY +var _cmd *cobra.Command + +var exportType = models.ExportTypeCSV // reportCmd represents the report command. var reportCmd = &cobra.Command{ @@ -86,6 +89,55 @@ func dateRange(date carbon.Carbon) (start carbon.Carbon, end carbon.Carbon) { return start, end } +func export(title string, t table.Writer) { + exporting, _ := _cmd.Flags().GetBool(constants.EXPORT) + if exporting { + typeStr, _ := _cmd.Flags().GetString(constants.EXPORT_TYPE) + if len(strings.TrimSpace(exportFilename)) == 0 { + // Create our new export file. + exportFilename = constants.APPLICATION_NAME_LOWERCASE + "_report_" + carbon.Now().ToShortDateTimeString() + if typeStr == string(models.ExportTypeCSV) { + exportFilename += ".csv" + } else if typeStr == string(models.ExportTypeHTML) { + exportFilename += ".html" + } else { + exportFilename += ".md" + } + + _, err := os.OpenFile(exportFilename, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.Fatal(err) + } + } + + // Open the file for appending. + file, err := os.OpenFile(exportFilename, os.O_APPEND|os.O_WRONLY, 0) + if err != nil { + log.Fatal(err) + } + + // Remember to close the file. + defer file.Close() + + file.WriteString(title + "\n") + + // Render the table to the file. + if typeStr == string(models.ExportTypeCSV) { + _, err = file.WriteString(t.RenderCSV()) + } else if typeStr == string(models.ExportTypeHTML) { + _, err = file.WriteString(t.RenderHTML()) + } else { + _, err = file.WriteString(t.RenderMarkdown()) + } + + if err != nil { + log.Fatal(err) + } + + file.WriteString("\n") + } +} + func init() { reportCmd.Flags().BoolP(constants.FLAG_NO_ROUNDING, constants.EMPTY, false, "Reports all durations in their unrounded form.") reportCmd.Flags().BoolP(constants.FLAG_CURRENT_WEEK, constants.EMPTY, false, "Report on the current week's entries.") @@ -97,6 +149,9 @@ func init() { reportCmd.Flags().StringVarP(&from, constants.FLAG_FROM, constants.EMPTY, constants.EMPTY, "Specify an inclusive start date to report in "+constants.DATE_FORMAT+" format.") reportCmd.Flags().StringVarP(&to, constants.FLAG_TO, constants.EMPTY, constants.EMPTY, "Specify an inclusive end date to report in "+constants.DATE_FORMAT+" format. If this is a day of the week, then it is the next occurrence from the start date of the report, including the start date itself.") reportCmd.MarkFlagsRequiredTogether(constants.FLAG_FROM, constants.FLAG_TO) + reportCmd.Flags().BoolP(constants.EXPORT, constants.EMPTY, false, "Export to file.") + reportCmd.Flags().Var(&exportType, constants.EXPORT_TYPE, `Type of export file. Allowed values: "csv", "html" or "md"`) + reportCmd.MarkFlagsRequiredTogether(constants.EXPORT, constants.EXPORT_TYPE) rootCmd.AddCommand(reportCmd) // Here you will define your flags and configuration settings. @@ -213,6 +268,9 @@ func reportByDay(entries []models.Entry) { // Render the table. log.Println(t.Render()) + + // Export table if needed. + export("report by day", t) } func reportByEntry(entries []models.Entry) { @@ -237,6 +295,9 @@ func reportByEntry(entries []models.Entry) { // Render the table. log.Println(t.Render()) + + // Export table if needed. + export("report by entry", t) } func reportByLastEntry() { @@ -302,6 +363,9 @@ func reportByProject(entries []models.Entry) { // Render the table. log.Println(t.Render()) + + // Export table if needed. + export("report by project", t) } func reportByTask(entries []models.Entry) { @@ -354,6 +418,9 @@ func reportByTask(entries []models.Entry) { // Render the table. log.Println(t.Render()) + + // Export table if needed. + export("report by task", t) } func reportTotalWorkAndBreakTime(entries []models.Entry) { @@ -415,6 +482,9 @@ func runReport(cmd *cobra.Command, _ []string) { var start carbon.Carbon var end carbon.Carbon + // Save this so we can use it in other methods. + _cmd = cmd + // See if the user asked to override round. If no, use the rounding value // from the configuration file. Otherwise, set the rounding value to 0. noRounding, _ := cmd.Flags().GetBool(constants.FLAG_NO_ROUNDING) diff --git a/cmd/root.go b/cmd/root.go index f7cb52d..03f9adf 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -51,10 +51,8 @@ var note string // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "khronos", - Short: "Simple program used to track time spent on projects and tasks.", - Long: `Khronos is a simple command line tool use to track the time you spend -on a specific project and the one or more tasks associated with that project. -It was inspired by the concepts of utt (Ultimate Time Tracker) and timetrap.`, + Short: constants.ROOT_SHORT_DESCRIPTION, + Long: constants.ROOT_LONG_DESCRIPTION, } // Execute adds all child commands to the root command and sets flags appropriately. diff --git a/cmd/show.go b/cmd/show.go index 536e884..4acdbba 100644 --- a/cmd/show.go +++ b/cmd/show.go @@ -49,8 +49,8 @@ import ( // showCmd represents the show command var showCmd = &cobra.Command{ Use: "show", - Short: "Show various information", - Long: "Show various information.", + Short: constants.SHOW_SHORT_DESCRIPTION, + Long: constants.SHOW_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runShow(cmd, args) }, diff --git a/cmd/stretch.go b/cmd/stretch.go index 269ef07..eb70e13 100644 --- a/cmd/stretch.go +++ b/cmd/stretch.go @@ -53,8 +53,8 @@ import ( // stretchCmd represents the stretch command var stretchCmd = &cobra.Command{ Use: "stretch last project", - Short: "Stretch the latest entry", - Long: "Stretch the latest entry to 'now' or the whatever is specified using the 'at' flag command.", + Short: constants.STRETCH_SHORT_DESCRIPTION, + Long: constants.STRETCH_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runStretch(cmd, args) }, diff --git a/cmd/version.go b/cmd/version.go index 20c09e8..1e547b8 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -45,8 +45,8 @@ var BuildDateTime string // versionCmd represents the version command var versionCmd = &cobra.Command{ Use: "version", - Short: "Show the version information", - Long: "Show the version information.", + Short: constants.VERSION_SHORT_DESCRIPTION, + Long: constants.VERSION_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runVersion(cmd, args) }, diff --git a/cmd/web.go b/cmd/web.go index 36e8faa..384d367 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -41,8 +41,8 @@ import ( // webCmd represents the web command. var webCmd = &cobra.Command{ Use: "web", - Short: "Open the Khronos website in your default browser", - Long: "Open the Khronos website in your default browser.", + Short: constants.WEB_SHORT_DESCRIPTION, + Long: constants.WEB_LONG_DESCRIPTION, Run: func(cmd *cobra.Command, args []string) { runWeb(cmd, args) }, diff --git a/constants/constants.go b/constants/constants.go index 7ac2f07..05cf726 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -30,22 +30,41 @@ POSSIBILITY OF SUCH DAMAGE. */ package constants +const ADD_LONG_DESCRIPTION = "Once you have completed a entry (project+task), use this command to add that newly completed task to the database with an optional note." +const ADD_SHORT_DESCRIPTION = "Add a completed entry." const ADDING string = "Adding" const ALL string = "all" +const AMEND_LONG_DESCRIPTION = "Amend is a convenient way to modify an entry, default is the last entry. It lets you modify the project, task, and/or datetime." +const AMEND_SHORT_DESCRIPTION = "Amend an entry." const AMENDING string = "Amending" const APPLICATION_NAME = "Khronos" +const APPLICATION_NAME_LOWERCASE = "khronos" const AT string = "at" +const BACKEND_LONG_DESCRIPTION = "Open a sqlite shell to the database." +const BACKEND_SHORT_DESCRIPTION = "Open a sqlite shell to the database." const BREAK string = "***break" +const BREAK_LONG_DESCRIPTION = "If you just spent time on break, use this command to add that time to the database." +const BREAK_SHORT_DESCRIPTION = "Add a break." const CARBON_DATE_FORMAT string = "Y-m-d" const CARBON_START_END_TIME_FORMAT string = "h:ia" const CONFIGURATION_FILE string = ".khronos.yaml" +const CONFIGURE_LONG_DESCRIPTION = "Write out a YAML config file. Print path to config file." +const CONFIGURE_SHORT_DESCRIPTION = "Write out a YAML config file." +const CSV = "csv" const DATABASE_FILE string = "database_file" const DATE_FORMAT string = "2006-01-02" // WTF golang? Why this date format? const DATE_NORMAL_CASE = "Date" const DATE_TIME_NORMAL_CASE = "Date Time" -const DURATION_NORMAL_CASE = "Duration" const DRY_RUN = "dry-run" +const DURATION_NORMAL_CASE = "Duration" +const EDIT_LONG_DESCRIPTION = "Open the Khronos configuration file in your default editor." +const EDIT_SHORT_DESCRIPTION = "Open the Khronos configuration file in your default editor." const EMPTY string = "" +const EXPORT = "export" +const EXPORT_TYPE = "type" +const FATAL_NORMAL_CASE string = "Fatal" +const FAVORITE string = "favorite" +const FAVORITES string = "favorites" const FLAG_CURRENT_WEEK = "current-week" const FLAG_DATE = "date" const FLAG_FROM = "from" @@ -55,15 +74,16 @@ const FLAG_PREVIOUS_WEEK = "previous-week" const FLAG_TO = "to" const FLAG_TODAY = "today" const FLAG_YESTERDAY = "yesterday" -const FATAL_NORMAL_CASE string = "Fatal" -const FAVORITE string = "favorite" -const FAVORITES string = "favorites" const HELLO string = "***hello" +const HELLO_LONG_DESCRIPTION = "In order to have khronos start tracking time is to run this command. It informs khronos that you would like it to start tracking your time." +const HELLO_SHORT_DESCRIPTION = "Start time tracking for the day." const INDENT_AMOUNT int = 4 const NATURAL_LANGUAGE_DESCRIPTION string = "Natural Language Time, e.g., '18 minutes ago' or '9:45am'" const NOTE string = "note" const NOTE_DESCRIPTION string = "A note associated with this entry" const NOTE_NORMAL_CASE = "Note" +const NUKE_LONG_DESCRIPTION = "As you continuously add completed entries, the database continues to grow unbounded. The nuke command allows you to manage the size of your database." +const NUKE_SHORT_DESCRIPTION = "Nukes entries from the sqlite database." const PRINT_DATE_WIDTH int = 10 const PRINT_DURATION_WIDTH int = 38 const PRINT_NOTE_WIDTH int = 40 @@ -83,13 +103,19 @@ const REPORT_BY_PROJECT_FORMAT string = "%-38s %-20s %-20s" const REPORT_BY_TASK = "report.by_task" const REPORT_CARBON_TO_FROM_FORMAT string = "Y-M-d" const REQUIRE_NOTE string = "require_note" +const ROOT_LONG_DESCRIPTION = "Khronos is a simple command line tool use to track the time you spend on a specific project and the one or more tasks associated with that project. It was inspired by the concepts of utt (Ultimate Time Tracker) and timetrap." +const ROOT_SHORT_DESCRIPTION = "Simple program used to track time spent on projects and tasks." const ROUND_TO_MINUTES string = "round_to_minutes" const SECONDS_PER_DAY = 86400 const SHOW_BY_DAY_TOTALS string = "show_by_day_totals" +const SHOW_LONG_DESCRIPTION = "Show various information." +const SHOW_SHORT_DESCRIPTION = "Show various information." const SPACE_CHARACTER string = " " const SPLIT_WORK_FROM_BREAK_TIME string = "split_work_from_break_time" const START_END_NORMAL_CASE = "Start-End" const STATISTICS string = "statistics" +const STRETCH_LONG_DESCRIPTION = "Stretch the latest entry to 'now' or the whatever is specified using the 'at' flag command." +const STRETCH_SHORT_DESCRIPTION = "Stretch the latest entry." const TASK string = "task" const TASK_DELIMITER string = "+" const TASK_NORMAL_CASE = "Task" @@ -98,5 +124,9 @@ const TOTAL = "TOTAL" const UNKNOWN_UID int64 = -1 const URL = "url" const URL_NORMAL_CASE = "URL" +const VERSION_LONG_DESCRIPTION = "Show the version information." +const VERSION_SHORT_DESCRIPTION = "Show the version information." +const WEB_LONG_DESCRIPTION = "Open the Khronos website in your default browser." +const WEB_SHORT_DESCRIPTION = "Open the Khronos website in your default browser." const WEB_SITE string = "https://github.com/jlanzarotta/khronos/" -const WEEK_START string = "week_start" +const WEEK_START string = "week_start" \ No newline at end of file diff --git a/go.mod b/go.mod index 0545c5f..3dc61b4 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/dromara/carbon/v2 v2.5.2 github.com/ijt/go-anytime v1.9.2 github.com/mattn/go-sqlite3 v1.14.24 - golang.org/x/term v0.27.0 + golang.org/x/term v0.28.0 ) require ( @@ -15,7 +15,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/rivo/uniseg v0.4.7 // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.32.0 // indirect ) require ( @@ -40,8 +40,8 @@ require ( github.com/spf13/viper v1.19.0 github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index 712982b..69bbe16 100644 --- a/go.sum +++ b/go.sum @@ -81,15 +81,23 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/models/exportType.go b/internal/models/exportType.go new file mode 100644 index 0000000..61618e0 --- /dev/null +++ b/internal/models/exportType.go @@ -0,0 +1,32 @@ +package models + +import "errors" + +type ExportType string + +const ( + ExportTypeCSV ExportType = "csv" + ExportTypeHTML ExportType = "html" + ExportTypeMarkDown ExportType = "md" +) + +// String is used both by fmt.Print and by Cobra in help text. +func (e *ExportType) String() string { + return string(*e) +} + +// Set must have pointer receiver so it doesn't change the value of a copy. +func (e *ExportType) Set(v string) error { + switch v { + case string(ExportTypeCSV), string(ExportTypeHTML), string(ExportTypeMarkDown): + *e = ExportType(v) + return nil + default: + return errors.New(`must be one of "csv", "html", or "md"`) + } +} + +// Type is only used in help text +func (e *ExportType) Type() string { + return "string" +}