Eliminate global variables in cmd

This commit is contained in:
Tim Van Baak 2025-01-30 07:54:13 -08:00
parent f5e9277e26
commit 9bf840fcec
17 changed files with 240 additions and 212 deletions

View File

@ -13,28 +13,25 @@ var actionAddCmd = &cobra.Command{
Long: `Add an action to a source. Long: `Add an action to a source.
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
actionAdd(getArgv(cmd, args)) actionAdd(stringArg(cmd, "source"), stringArg(cmd, "action"), getArgv(cmd, args))
}, },
} }
var actionAddSource string
var actionAddAction string
func init() { func init() {
actionCmd.AddCommand(actionAddCmd) actionCmd.AddCommand(actionAddCmd)
actionAddCmd.Flags().StringVarP(&actionAddSource, "source", "s", "", "Source to add action") actionAddCmd.Flags().StringP("source", "s", "", "Source to add action")
actionAddCmd.MarkFlagRequired("source") actionAddCmd.MarkFlagRequired("source")
actionAddCmd.Flags().StringVarP(&actionAddAction, "action", "a", "", "Action name") actionAddCmd.Flags().StringP("action", "a", "", "Action name")
actionAddCmd.MarkFlagRequired("action") actionAddCmd.MarkFlagRequired("action")
} }
func actionAdd(argv []string) { func actionAdd(source string, action string, argv []string) {
if actionAddSource == "" { if source == "" {
log.Fatal("error: --source is empty") log.Fatal("error: --source is empty")
} }
if actionAddAction == "" { if action == "" {
log.Fatal("error: --action is empty") log.Fatal("error: --action is empty")
} }
if len(argv) == 0 { if len(argv) == 0 {
@ -43,10 +40,10 @@ func actionAdd(argv []string) {
db := openAndMigrateDb() db := openAndMigrateDb()
err := core.AddAction(db, actionAddSource, actionAddAction, argv) err := core.AddAction(db, source, action, argv)
if err != nil { if err != nil {
log.Fatalf("error: failed to add action: %v", err) log.Fatalf("error: failed to add action: %v", err)
} }
log.Printf("Added action %s to source %s", actionAddAction, actionAddSource) log.Printf("Added action %s to source %s", action, source)
} }

View File

@ -14,37 +14,34 @@ var actionDeleteCmd = &cobra.Command{
Long: `Delete an action from a source. Long: `Delete an action from a source.
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
actionDelete() actionDelete(stringArg(cmd, "source"), stringArg(cmd, "action"))
}, },
} }
var actionDeleteSource string
var actionDeleteAction string
func init() { func init() {
actionCmd.AddCommand(actionDeleteCmd) actionCmd.AddCommand(actionDeleteCmd)
actionDeleteCmd.Flags().StringVarP(&actionDeleteSource, "source", "s", "", "Source to add action") actionDeleteCmd.Flags().StringP("source", "s", "", "Source to add action")
actionDeleteCmd.MarkFlagRequired("source") actionDeleteCmd.MarkFlagRequired("source")
actionDeleteCmd.Flags().StringVarP(&actionDeleteAction, "action", "a", "", "Action name") actionDeleteCmd.Flags().StringP("action", "a", "", "Action name")
actionDeleteCmd.MarkFlagRequired("action") actionDeleteCmd.MarkFlagRequired("action")
} }
func actionDelete() { func actionDelete(source string, action string) {
if actionDeleteSource == "" { if source == "" {
log.Fatal("error: --source is empty") log.Fatal("error: --source is empty")
} }
if actionDeleteAction == "" { if action == "" {
log.Fatal("error: --action is empty") log.Fatal("error: --action is empty")
} }
db := openAndMigrateDb() db := openAndMigrateDb()
err := core.DeleteAction(db, actionDeleteSource, actionDeleteAction) err := core.DeleteAction(db, source, action)
if err != nil { if err != nil {
log.Fatalf("error: failed to delete action: %v", err) log.Fatalf("error: failed to delete action: %v", err)
} }
log.Printf("Deleted action %s from source %s", actionDeleteAction, actionDeleteSource) log.Printf("Deleted action %s from source %s", action, source)
} }

View File

@ -13,28 +13,25 @@ var actionEditCmd = &cobra.Command{
Long: `Edit an action on a source. Long: `Edit an action on a source.
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
actionEdit(getArgv(cmd, args)) actionEdit(stringArg(cmd, "source"), stringArg(cmd, "action"), getArgv(cmd, args))
}, },
} }
var actionEditSource string
var actionEditAction string
func init() { func init() {
actionCmd.AddCommand(actionEditCmd) actionCmd.AddCommand(actionEditCmd)
actionEditCmd.Flags().StringVarP(&actionEditSource, "source", "s", "", "Source to edit action") actionEditCmd.Flags().StringP("source", "s", "", "Source to edit action")
actionEditCmd.MarkFlagRequired("source") actionEditCmd.MarkFlagRequired("source")
actionEditCmd.Flags().StringVarP(&actionEditAction, "action", "a", "", "Action name") actionEditCmd.Flags().StringP("action", "a", "", "Action name")
actionEditCmd.MarkFlagRequired("action") actionEditCmd.MarkFlagRequired("action")
} }
func actionEdit(argv []string) { func actionEdit(source string, action string, argv []string) {
if actionEditSource == "" { if source == "" {
log.Fatal("error: --source is empty") log.Fatal("error: --source is empty")
} }
if actionEditAction == "" { if action == "" {
log.Fatal("error: --action is empty") log.Fatal("error: --action is empty")
} }
if len(argv) == 0 { if len(argv) == 0 {
@ -43,10 +40,10 @@ func actionEdit(argv []string) {
db := openAndMigrateDb() db := openAndMigrateDb()
err := core.UpdateAction(db, actionEditSource, actionEditAction, argv) err := core.UpdateAction(db, source, action, argv)
if err != nil { if err != nil {
log.Fatalf("error: failed to update action: %v", err) log.Fatalf("error: failed to update action: %v", err)
} }
log.Printf("Updated action %s on source %s", actionEditAction, actionEditSource) log.Printf("Updated action %s on source %s", action, source)
} }

View File

@ -25,77 +25,85 @@ In a dry run, the item will be printed in the chosen format and not updated.
%s`, makeFormatHelpText()), %s`, makeFormatHelpText()),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
actionExecute() actionExecute(
stringArg(cmd, "source"),
stringArg(cmd, "action"),
stringArg(cmd, "item"),
stringArg(cmd, "format"),
boolArg(cmd, "dry-run"),
boolArg(cmd, "diff"),
boolArg(cmd, "force"),
)
}, },
} }
var actionExecuteSource string
var actionExecuteAction string
var actionExecuteItem string
var actionExecuteFormat string
var actionExecuteDryRun bool
var actionExecuteDiff bool
var actionExecuteForce bool
func init() { func init() {
actionCmd.AddCommand(actionExecuteCmd) actionCmd.AddCommand(actionExecuteCmd)
actionExecuteCmd.PersistentFlags().StringVarP(&actionExecuteSource, "source", "s", "", "Source of the item") actionExecuteCmd.PersistentFlags().StringP("source", "s", "", "Source of the item")
actionExecuteCmd.MarkFlagRequired("source") actionExecuteCmd.MarkFlagRequired("source")
actionExecuteCmd.PersistentFlags().StringVarP(&actionExecuteItem, "item", "i", "", "Item to run action on") actionExecuteCmd.PersistentFlags().StringP("item", "i", "", "Item to run action on")
actionExecuteCmd.MarkFlagRequired("item") actionExecuteCmd.MarkFlagRequired("item")
actionExecuteCmd.PersistentFlags().StringVarP(&actionExecuteAction, "action", "a", "", "Action to run") actionExecuteCmd.PersistentFlags().StringP("action", "a", "", "Action to run")
actionExecuteCmd.MarkFlagRequired("action") actionExecuteCmd.MarkFlagRequired("action")
actionExecuteCmd.Flags().StringVarP(&actionExecuteFormat, "format", "f", "headlines", "Feed format for returned items") actionExecuteCmd.Flags().StringP("format", "f", "headlines", "Feed format for returned items")
actionExecuteCmd.Flags().BoolVar(&actionExecuteDryRun, "dry-run", false, "Instead of updating the item, print it") actionExecuteCmd.Flags().Bool("dry-run", false, "Instead of updating the item, print it")
actionExecuteCmd.Flags().BoolVar(&actionExecuteDiff, "diff", false, "Show which fields of the item changed") actionExecuteCmd.Flags().Bool("diff", false, "Show which fields of the item changed")
actionExecuteCmd.Flags().BoolVar(&actionExecuteForce, "force", false, "Execute the action even if the item does not support it") actionExecuteCmd.Flags().Bool("force", false, "Execute the action even if the item does not support it")
} }
func actionExecute() { func actionExecute(
formatter := formatAs(actionExecuteFormat) source string,
action string,
itemId string,
format string,
dryRun bool,
diff bool,
force bool,
) {
formatter := formatAs(format)
if actionExecuteSource == "" { if source == "" {
log.Fatal("error: --source is empty") log.Fatal("error: --source is empty")
} }
if actionExecuteAction == "" { if action == "" {
log.Fatal("error: --action is empty") log.Fatal("error: --action is empty")
} }
if actionExecuteItem == "" { if itemId == "" {
log.Fatal("error: --item is empty") log.Fatal("error: --item is empty")
} }
db := openAndMigrateDb() db := openAndMigrateDb()
item, err := core.GetItem(db, actionExecuteSource, actionExecuteItem) item, err := core.GetItem(db, source, itemId)
if err != nil { if err != nil {
log.Fatalf("error: failed to get item: %v", err) log.Fatalf("error: failed to get item: %v", err)
} }
if item.Action[actionExecuteAction] == nil { if item.Action[action] == nil {
if actionExecuteForce { if force {
log.Printf("warning: force-executing %s on %s/%s", actionExecuteAction, actionExecuteSource, actionExecuteItem) log.Printf("warning: force-executing %s on %s/%s", action, source, itemId)
} else { } else {
log.Fatalf("error: %s/%s does not support %s", actionExecuteSource, actionExecuteItem, actionExecuteAction) log.Fatalf("error: %s/%s does not support %s", source, itemId, action)
} }
} }
argv, err := core.GetArgvForAction(db, actionExecuteSource, actionExecuteAction) argv, err := core.GetArgvForAction(db, source, action)
if err != nil { if err != nil {
log.Fatalf("error: failed to get action: %v", err) log.Fatalf("error: failed to get action: %v", err)
} }
newItem, err := core.ExecuteItemAction(item, actionExecuteSource, argv, nil, "", time.Minute) newItem, err := core.ExecuteItemAction(item, source, argv, nil, "", time.Minute)
if err != nil { if err != nil {
log.Fatalf("error executing action: %v", err) log.Fatalf("error executing action: %v", err)
} }
if actionExecuteDiff { if diff {
if item.Title != newItem.Title { if item.Title != newItem.Title {
log.Printf("title: %s => %s", item.Title, newItem.Title) log.Printf("title: %s => %s", item.Title, newItem.Title)
} }
@ -116,7 +124,7 @@ func actionExecute() {
} }
} }
if actionExecuteDryRun { if dryRun {
fmt.Println(formatter(newItem)) fmt.Println(formatter(newItem))
return return
} }

View File

@ -16,41 +16,38 @@ var actionListCmd = &cobra.Command{
Long: `List actions on a source. Long: `List actions on a source.
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
actionList() actionList(stringArg(cmd, "source"), boolArg(cmd, "argv"))
}, },
} }
var actionListSource string
var actionListArgv bool
func init() { func init() {
actionCmd.AddCommand(actionListCmd) actionCmd.AddCommand(actionListCmd)
actionListCmd.Flags().StringVarP(&actionListSource, "source", "s", "", "Source to list actions") actionListCmd.Flags().StringP("source", "s", "", "Source to list actions")
actionListCmd.MarkFlagRequired("source") actionListCmd.MarkFlagRequired("source")
actionListCmd.Flags().BoolVarP(&actionListArgv, "argv", "a", false, "Include action command") actionListCmd.Flags().BoolP("argv", "a", false, "Include action command")
} }
func actionList() { func actionList(source string, argv bool) {
if actionListSource == "" { if source == "" {
log.Fatal("error: --source is empty") log.Fatal("error: --source is empty")
} }
db := openAndMigrateDb() db := openAndMigrateDb()
actions, err := core.GetActionsForSource(db, actionListSource) actions, err := core.GetActionsForSource(db, source)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
slices.SortFunc(actions, actionSort) slices.SortFunc(actions, actionSort)
if actionListArgv { if argv {
actionArgv := make(map[string][]string) actionArgv := make(map[string][]string)
for _, name := range actions { for _, name := range actions {
argv, err := core.GetArgvForAction(db, actionListSource, name) argv, err := core.GetArgvForAction(db, source, name)
if err != nil { if err != nil {
log.Fatalf("error: could not get argv for source %s action %s: %v", actionListSource, name, err) log.Fatalf("error: could not get argv for source %s action %s: %v", source, name, err)
} }
actionArgv[name] = argv actionArgv[name] = argv
} }

53
cmd/args.go Normal file
View File

@ -0,0 +1,53 @@
package cmd
import (
"log"
"github.com/spf13/cobra"
)
// Get the value of a bool flag.
func boolArg(cmd *cobra.Command, name string) bool {
b, err := cmd.Flags().GetBool(name)
if err != nil {
log.Fatal(err)
}
return b
}
// Get the value of an int flag.
func intArg(cmd *cobra.Command, name string) int {
i, err := cmd.Flags().GetInt(name)
if err != nil {
log.Fatal(err)
}
return i
}
// Get the value of a string flag.
func stringArg(cmd *cobra.Command, name string) string {
str, err := cmd.Flags().GetString(name)
if err != nil {
log.Fatal(err)
}
return str
}
// Get the value of a string array flag.
func stringArrayArg(cmd *cobra.Command, name string) []string {
s, err := cmd.Flags().GetStringArray(name)
if err != nil {
log.Fatal(err)
}
return s
}
// Get the argv after the -- separator.
func getArgv(cmd *cobra.Command, args []string) []string {
lenAtDash := cmd.Flags().ArgsLenAtDash()
if lenAtDash == -1 {
return nil
} else {
return args[lenAtDash:]
}
}

View File

@ -16,45 +16,50 @@ The default format is "headlines".
%s`, makeFormatHelpText()), %s`, makeFormatHelpText()),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
feed() feed(
stringArg(cmd, "format"),
stringArg(cmd, "source"),
stringArg(cmd, "channel"),
boolArg(cmd, "all"),
)
}, },
} }
var feedFormat string
var feedSource string
var feedChannel string
var feedShowInactive bool
func init() { func init() {
rootCmd.AddCommand(feedCmd) rootCmd.AddCommand(feedCmd)
feedCmd.Flags().StringVarP(&feedFormat, "format", "f", "headlines", "Feed format") feedCmd.Flags().StringP("format", "f", "headlines", "Feed format")
feedCmd.Flags().StringVarP(&feedSource, "source", "s", "", "Limit to items from source") feedCmd.Flags().StringP("source", "s", "", "Limit to items from source")
feedCmd.Flags().StringVarP(&feedChannel, "channel", "c", "", "Limit to items from channel") feedCmd.Flags().StringP("channel", "c", "", "Limit to items from channel")
feedCmd.MarkFlagsMutuallyExclusive("source", "channel") feedCmd.MarkFlagsMutuallyExclusive("source", "channel")
feedCmd.Flags().BoolVar(&feedShowInactive, "all", false, "Show inactive items") feedCmd.Flags().Bool("all", false, "Show inactive items")
} }
func feed() { func feed(
formatter := formatAs(feedFormat) format string,
source string,
channel string,
showInactive bool,
) {
formatter := formatAs(format)
db := openAndMigrateDb() db := openAndMigrateDb()
var items []core.Item var items []core.Item
var err error var err error
if feedSource != "" { if source != "" {
if feedShowInactive { if showInactive {
items, err = core.GetAllItemsForSource(db, feedSource) items, err = core.GetAllItemsForSource(db, source)
} else { } else {
items, err = core.GetActiveItemsForSource(db, feedSource) items, err = core.GetActiveItemsForSource(db, source)
} }
if err != nil { if err != nil {
log.Fatalf("error: failed to fetch items from %s:, %v", feedSource, err) log.Fatalf("error: failed to fetch items from %s:, %v", source, err)
} }
} else if feedChannel != "" { } else if channel != "" {
log.Fatal("error: unimplemented") log.Fatal("error: unimplemented")
} else { } else {
if feedShowInactive { if showInactive {
items, err = core.GetAllItems(db) items, err = core.GetAllItems(db)
} else { } else {
items, err = core.GetAllActiveItems(db) items, err = core.GetAllActiveItems(db)

View File

@ -19,49 +19,58 @@ var itemAddCmd = &cobra.Command{
By default, the item is created in the "default" source, which is created By default, the item is created in the "default" source, which is created
if it doesn't exist, with a random id.`, if it doesn't exist, with a random id.`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
itemAdd() itemAdd(
stringArg(cmd, "source"),
stringArg(cmd, "id"),
stringArg(cmd, "title"),
stringArg(cmd, "author"),
stringArg(cmd, "body"),
stringArg(cmd, "link"),
intArg(cmd, "time"),
stringArg(cmd, "action"),
)
}, },
} }
var addItemSource string
var addItemId string
var addItemTitle string
var addItemAuthor string
var addItemBody string
var addItemLink string
var addItemTime int
var addItemActions string
func init() { func init() {
itemCmd.AddCommand(itemAddCmd) itemCmd.AddCommand(itemAddCmd)
itemAddCmd.Flags().StringVarP(&addItemSource, "source", "s", "", "Source in which to create the item (default: default)") itemAddCmd.Flags().StringP("source", "s", "", "Source in which to create the item (default: default)")
itemAddCmd.Flags().StringVarP(&addItemId, "id", "i", "", "Item id (default: random hex)") itemAddCmd.Flags().StringP("id", "i", "", "Item id (default: random hex)")
itemAddCmd.Flags().StringVarP(&addItemTitle, "title", "t", "", "Item title") itemAddCmd.Flags().StringP("title", "t", "", "Item title")
itemAddCmd.Flags().StringVarP(&addItemAuthor, "author", "a", "", "Item author") itemAddCmd.Flags().StringP("author", "a", "", "Item author")
itemAddCmd.Flags().StringVarP(&addItemBody, "body", "b", "", "Item body") itemAddCmd.Flags().StringP("body", "b", "", "Item body")
itemAddCmd.Flags().StringVarP(&addItemLink, "link", "l", "", "Item link") itemAddCmd.Flags().StringP("link", "l", "", "Item link")
itemAddCmd.Flags().IntVarP(&addItemTime, "time", "m", 0, "Item time as a Unix timestamp") itemAddCmd.Flags().IntP("time", "m", 0, "Item time as a Unix timestamp")
itemAddCmd.Flags().StringVarP(&addItemActions, "action", "x", "", "Item time as a Unix timestamp") itemAddCmd.Flags().StringP("action", "x", "", "Item action data as JSON")
} }
func itemAdd() { func itemAdd(
source string,
id string,
title string,
author string,
body string,
link string,
time int,
actions string,
) {
// Default to "default" source // Default to "default" source
if addItemSource == "" { if source == "" {
addItemSource = "default" source = "default"
} }
// Default id to random hex string // Default id to random hex string
if addItemId == "" { if id == "" {
bytes := make([]byte, 16) bytes := make([]byte, 16)
if _, err := rand.Read(bytes); err != nil { if _, err := rand.Read(bytes); err != nil {
log.Fatalf("error: failed to generate id: %v", err) log.Fatalf("error: failed to generate id: %v", err)
} }
addItemId = hex.EncodeToString(bytes) id = hex.EncodeToString(bytes)
} }
var actions core.Actions var itemActions core.Actions
if addItemActions != "" { if actions != "" {
if err := json.Unmarshal([]byte(addItemActions), &actions); err != nil { if err := json.Unmarshal([]byte(actions), &itemActions); err != nil {
log.Fatalf("error: could not parse actions: %v", err) log.Fatalf("error: could not parse actions: %v", err)
} }
} }
@ -69,17 +78,17 @@ func itemAdd() {
db := openAndMigrateDb() db := openAndMigrateDb()
if err := core.AddItems(db, []core.Item{{ if err := core.AddItems(db, []core.Item{{
Source: addItemSource, Source: source,
Id: addItemId, Id: id,
Title: addItemTitle, Title: title,
Author: addItemAuthor, Author: author,
Body: addItemBody, Body: body,
Link: addItemLink, Link: link,
Time: addItemTime, Time: time,
Action: actions, Action: itemActions,
}}); err != nil { }}); err != nil {
log.Fatalf("error: failed to add item: %s", err) log.Fatalf("error: failed to add item: %s", err)
} }
log.Printf("Added %s/%s\n", addItemSource, addItemId) log.Printf("Added %s/%s\n", source, id)
} }

View File

@ -17,30 +17,27 @@ var itemDeactivateCmd = &cobra.Command{
Deactivation is idempotent.`, Deactivation is idempotent.`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
itemDeactivate() itemDeactivate(stringArg(cmd, "source"), stringArg(cmd, "item"))
}, },
} }
var deacSource string
var deacItem string
func init() { func init() {
itemCmd.AddCommand(itemDeactivateCmd) itemCmd.AddCommand(itemDeactivateCmd)
itemDeactivateCmd.Flags().StringVarP(&deacSource, "source", "s", "", "Source of the item") itemDeactivateCmd.Flags().StringP("source", "s", "", "Source of the item")
itemDeactivateCmd.MarkFlagRequired("source") itemDeactivateCmd.MarkFlagRequired("source")
itemDeactivateCmd.Flags().StringVarP(&deacItem, "item", "i", "", "Item id") itemDeactivateCmd.Flags().StringP("item", "i", "", "Item id")
itemDeactivateCmd.MarkFlagRequired("item") itemDeactivateCmd.MarkFlagRequired("item")
} }
func itemDeactivate() { func itemDeactivate(source string, item string) {
db := openAndMigrateDb() db := openAndMigrateDb()
active, err := core.DeactivateItem(db, deacSource, deacItem) active, err := core.DeactivateItem(db, source, item)
if err != nil { if err != nil {
log.Fatalf("Failed to deactivate item: %s", err) log.Fatalf("Failed to deactivate item: %s", err)
} }
if active { if active {
fmt.Printf("Deactivated %s/%s\n", deacSource, deacItem) fmt.Printf("Deactivated %s/%s\n", source, item)
} }
} }

View File

@ -16,23 +16,21 @@ var migrateCmd = &cobra.Command{
Note that the database will be created if it does not exist, even with --list.`, Note that the database will be created if it does not exist, even with --list.`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
migrate() migrate(boolArg(cmd, "list"))
}, },
} }
var migrateListOnly bool
func init() { func init() {
rootCmd.AddCommand(migrateCmd) rootCmd.AddCommand(migrateCmd)
migrateCmd.Flags().BoolVarP(&migrateListOnly, "list", "l", false, "Show the list of migrations") migrateCmd.Flags().BoolP("list", "l", false, "Show the list of migrations")
} }
func migrate() { func migrate(listOnly bool) {
db := openDb() db := openDb()
core.InitDatabase(db) core.InitDatabase(db)
if migrateListOnly { if listOnly {
pending, err := core.GetPendingMigrations(db) pending, err := core.GetPendingMigrations(db)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -72,15 +72,6 @@ func openAndMigrateDb() *core.DB {
return db return db
} }
func getArgv(cmd *cobra.Command, args []string) []string {
lenAtDash := cmd.Flags().ArgsLenAtDash()
if lenAtDash == -1 {
return nil
} else {
return args[lenAtDash:]
}
}
// Sort "fetch" action ahead of other actions // Sort "fetch" action ahead of other actions
func actionSort(a string, b string) int { func actionSort(a string, b string) int {
if a == "fetch" { if a == "fetch" {

View File

@ -11,21 +11,18 @@ var serveCmd = &cobra.Command{
Long: `Serve the intake web interface. Long: `Serve the intake web interface.
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
serve() serve(stringArg(cmd, "addr"), stringArg(cmd, "port"))
}, },
} }
var serveAddr string
var servePort string
func init() { func init() {
rootCmd.AddCommand(serveCmd) rootCmd.AddCommand(serveCmd)
serveCmd.Flags().StringVarP(&serveAddr, "addr", "a", "localhost", "Address to bind to") serveCmd.Flags().StringP("addr", "a", "localhost", "Address to bind to")
serveCmd.Flags().StringVarP(&servePort, "port", "p", "8081", "Port to bind to") serveCmd.Flags().StringP("port", "p", "8081", "Port to bind to")
} }
func serve() { func serve(addr string, port string) {
db := openAndMigrateDb() db := openAndMigrateDb()
web.RunServer(db, serveAddr, servePort) web.RunServer(db, addr, port)
} }

View File

@ -13,29 +13,27 @@ var sourceAddCmd = &cobra.Command{
Long: `Create a source. Long: `Create a source.
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
sourceAdd() sourceAdd(stringArg(cmd, "source"))
}, },
} }
var sourceAddSource string
func init() { func init() {
sourceCmd.AddCommand(sourceAddCmd) sourceCmd.AddCommand(sourceAddCmd)
sourceAddCmd.Flags().StringVarP(&sourceAddSource, "source", "s", "", "Source name") sourceAddCmd.Flags().StringP("source", "s", "", "Source name")
sourceAddCmd.MarkFlagRequired("source") sourceAddCmd.MarkFlagRequired("source")
} }
func sourceAdd() { func sourceAdd(source string) {
if sourceAddSource == "" { if source == "" {
log.Fatal("error: --source is empty") log.Fatal("error: --source is empty")
} }
db := openAndMigrateDb() db := openAndMigrateDb()
if err := core.AddSource(db, sourceAddSource); err != nil { if err := core.AddSource(db, source); err != nil {
log.Fatalf("error: failed to add source: %v", err) log.Fatalf("error: failed to add source: %v", err)
} }
log.Printf("Added source %s", sourceAddSource) log.Printf("Added source %s", source)
} }

View File

@ -14,28 +14,26 @@ var sourceDeleteCmd = &cobra.Command{
Long: `Delete a source. Long: `Delete a source.
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
sourceDelete() sourceDelete(stringArg(cmd, "source"))
}, },
} }
var sourceDeleteSource string
func init() { func init() {
sourceCmd.AddCommand(sourceDeleteCmd) sourceCmd.AddCommand(sourceDeleteCmd)
sourceDeleteCmd.Flags().StringVarP(&sourceDeleteSource, "source", "s", "", "Source to delete") sourceDeleteCmd.Flags().StringP("source", "s", "", "Source to delete")
} }
func sourceDelete() { func sourceDelete(source string) {
if sourceDeleteSource == "" { if source == "" {
log.Fatal("error: --source is empty") log.Fatal("error: --source is empty")
} }
db := openAndMigrateDb() db := openAndMigrateDb()
if err := core.DeleteSource(db, sourceDeleteSource); err != nil { if err := core.DeleteSource(db, source); err != nil {
log.Fatalf("error: failed to delete source: %v", err) log.Fatalf("error: failed to delete source: %v", err)
} }
log.Printf("Deleted source %s", sourceDeleteSource) log.Printf("Deleted source %s", source)
} }

View File

@ -23,40 +23,36 @@ the source will not be updated with the fetch result.
%s`, makeFormatHelpText()), %s`, makeFormatHelpText()),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
sourceFetch() sourceFetch(stringArg(cmd, "source"), stringArg(cmd, "format"), boolArg(cmd, "dry-run"))
}, },
} }
var sourceFetchSource string
var sourceFetchFormat string
var sourceFetchDryRun bool
func init() { func init() {
sourceCmd.AddCommand(sourceFetchCmd) sourceCmd.AddCommand(sourceFetchCmd)
sourceFetchCmd.Flags().StringVarP(&sourceFetchSource, "source", "s", "", "Source name to fetch (required)") sourceFetchCmd.Flags().StringP("source", "s", "", "Source name to fetch (required)")
sourceFetchCmd.MarkFlagRequired("source") sourceFetchCmd.MarkFlagRequired("source")
sourceFetchCmd.Flags().StringVarP(&sourceFetchFormat, "format", "f", "headlines", "Feed format for returned items.") sourceFetchCmd.Flags().StringP("format", "f", "headlines", "Feed format for returned items.")
sourceFetchCmd.Flags().BoolVar(&sourceFetchDryRun, "dry-run", false, "Instead of updating the source, print the fetched items") sourceFetchCmd.Flags().Bool("dry-run", false, "Instead of updating the source, print the fetched items")
} }
func sourceFetch() { func sourceFetch(source string, format string, dryRun bool) {
formatter := formatAs(sourceFetchFormat) formatter := formatAs(format)
db := openAndMigrateDb() db := openAndMigrateDb()
argv, err := core.GetArgvForAction(db, sourceFetchSource, "fetch") argv, err := core.GetArgvForAction(db, source, "fetch")
if err != nil { if err != nil {
log.Fatalf("error: failed to get fetch action: %v", err) log.Fatalf("error: failed to get fetch action: %v", err)
} }
items, err := core.Execute(sourceFetchSource, argv, nil, "", "", time.Minute) items, err := core.Execute(source, argv, nil, "", "", time.Minute)
if err != nil { if err != nil {
log.Fatalf("error: failed to execute fetch: %v", err) log.Fatalf("error: failed to execute fetch: %v", err)
} }
if sourceFetchDryRun { if dryRun {
log.Printf("Fetch returned %d items", len(items)) log.Printf("Fetch returned %d items", len(items))
for _, item := range items { for _, item := range items {
fmt.Println(formatter(item)) fmt.Println(formatter(item))
@ -64,9 +60,9 @@ func sourceFetch() {
return return
} }
added, deleted, err := core.UpdateWithFetchedItems(db, sourceFetchSource, items) added, deleted, err := core.UpdateWithFetchedItems(db, source, items)
if err != nil { if err != nil {
log.Fatalf("error: failed to update: %v", err) log.Fatalf("error: failed to update: %v", err)
} }
log.Printf("%s added %d items, updated %d items, and deleted %d items", sourceFetchSource, added, len(items)-added, deleted) log.Printf("%s added %d items, updated %d items, and deleted %d items", source, added, len(items)-added, deleted)
} }

View File

@ -16,19 +16,17 @@ var sourceListCmd = &cobra.Command{
Long: `Print the list of sources. Long: `Print the list of sources.
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
sourceList() sourceList(boolArg(cmd, "actions"))
}, },
} }
var sourceListShowActions bool
func init() { func init() {
sourceCmd.AddCommand(sourceListCmd) sourceCmd.AddCommand(sourceListCmd)
sourceListCmd.Flags().BoolVarP(&sourceListShowActions, "actions", "a", false, "Include source actions") sourceListCmd.Flags().BoolP("actions", "a", false, "Include source actions")
} }
func sourceList() { func sourceList(showActions bool) {
db := openAndMigrateDb() db := openAndMigrateDb()
names, err := core.GetSources(db) names, err := core.GetSources(db)
@ -37,7 +35,7 @@ func sourceList() {
} }
slices.Sort(names) slices.Sort(names)
if sourceListShowActions { if showActions {
sourceActions := make(map[string][]string) sourceActions := make(map[string][]string)
for _, name := range names { for _, name := range names {
actions, err := core.GetActionsForSource(db, name) actions, err := core.GetActionsForSource(db, name)

View File

@ -16,29 +16,21 @@ var sourceTestCmd = &cobra.Command{
%s`, makeFormatHelpText()), %s`, makeFormatHelpText()),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
l := cmd.Flags().ArgsLenAtDash() sourceTest(stringArrayArg(cmd, "env"), stringArg(cmd, "format"), getArgv(cmd, args))
if l == -1 {
sourceTest(nil)
} else {
sourceTest(args[l:])
}
}, },
} }
var sourceTestEnv []string
var sourceTestFormat string
func init() { func init() {
sourceCmd.AddCommand(sourceTestCmd) sourceCmd.AddCommand(sourceTestCmd)
sourceTestCmd.Flags().StringArrayVarP(&sourceTestEnv, "env", "e", nil, "Environment variables to set, in the form KEY=VAL") sourceTestCmd.Flags().StringArrayP("env", "e", nil, "Environment variables to set, in the form KEY=VAL")
sourceTestCmd.Flags().StringVarP(&sourceTestFormat, "format", "f", "headlines", "Feed format for returned items.") sourceTestCmd.Flags().StringP("format", "f", "headlines", "Feed format for returned items.")
} }
func sourceTest(cmd []string) { func sourceTest(env []string, format string, cmd []string) {
formatter := formatAs(sourceTestFormat) formatter := formatAs(format)
items, err := core.Execute("", cmd, sourceTestEnv, "", "", time.Minute) items, err := core.Execute("test", cmd, env, "", "", time.Minute)
log.Printf("Returned %d items", len(items)) log.Printf("Returned %d items", len(items))
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)