Implement action {add,delete,edit,list}

This commit is contained in:
Tim Van Baak 2025-01-23 08:22:50 -08:00
parent 14df3cac03
commit 7b8d3796bd
9 changed files with 228 additions and 16 deletions

View File

@ -7,8 +7,19 @@ import (
var actionCmd = &cobra.Command{
Use: "action",
Short: "Manage and run source actions",
Long: `
`,
Long: `Add, edit, delete, and run source actions on items.
A feed source is updated by the "fetch" action, which receives no input and
returns one JSON item per line on stdout. Other source actions are run on a
specific item, receiving that item on stdin and expecting that item, with any
modifications made by the action, on stdout.
Items declare support for an action by having an "action" key containing an
object with a key for every supported action. The value of that key may be
any arbitrary JSON value. Use --force to execute an unsupported action anyway,
though the action may fail if it operated on the item's action data.
To execute the "fetch" action, use "intake source fetch".`,
}
func init() {

View File

@ -3,19 +3,50 @@ package cmd
import (
"log"
"github.com/Jaculabilis/intake/core"
"github.com/spf13/cobra"
)
var actionAddCmd = &cobra.Command{
Use: "add",
Use: "add [flags] -- argv...",
Short: "Add an action to a source",
Long: `
Long: `Add an action to a source.
`,
Run: func(cmd *cobra.Command, args []string) {
log.Fatal("not implemented")
actionAdd(getArgv(cmd, args))
},
}
var actionAddSource string
var actionAddAction string
func init() {
actionCmd.AddCommand(actionAddCmd)
actionAddCmd.Flags().StringVarP(&actionAddSource, "source", "s", "", "Source to add action")
actionAddCmd.MarkFlagRequired("source")
actionAddCmd.Flags().StringVarP(&actionAddAction, "action", "a", "", "Action name")
actionAddCmd.MarkFlagRequired("action")
}
func actionAdd(argv []string) {
if actionAddSource == "" {
log.Fatal("error: --source is empty")
}
if actionAddAction == "" {
log.Fatal("error: --action is empty")
}
if len(argv) == 0 {
log.Fatal("error: no argv provided")
}
db := openAndMigrateDb()
err := core.AddAction(db, actionAddSource, actionAddAction, argv)
if err != nil {
log.Fatalf("error: %v", err)
}
log.Printf("Added action %s to source %s", actionAddAction, actionAddSource)
}

View File

@ -3,19 +3,48 @@ package cmd
import (
"log"
"github.com/Jaculabilis/intake/core"
"github.com/spf13/cobra"
)
var actionDeleteCmd = &cobra.Command{
Use: "delete",
Short: "Delete an action from a source",
Long: `
Use: "delete",
Aliases: []string{"rm"},
Short: "Delete an action from a source",
Long: `Delete an action from a source.
`,
Run: func(cmd *cobra.Command, args []string) {
log.Fatal("not implemented")
actionDelete()
},
}
var actionDeleteSource string
var actionDeleteAction string
func init() {
actionCmd.AddCommand(actionDeleteCmd)
actionDeleteCmd.Flags().StringVarP(&actionDeleteSource, "source", "s", "", "Source to add action")
actionDeleteCmd.MarkFlagRequired("source")
actionDeleteCmd.Flags().StringVarP(&actionDeleteAction, "action", "a", "", "Action name")
actionDeleteCmd.MarkFlagRequired("action")
}
func actionDelete() {
if actionDeleteSource == "" {
log.Fatal("error: --source is empty")
}
if actionDeleteAction == "" {
log.Fatal("error: --action is empty")
}
db := openAndMigrateDb()
err := core.DeleteAction(db, actionDeleteSource, actionDeleteAction)
if err != nil {
log.Fatalf("error: %v", err)
}
log.Printf("Deleted action %s from source %s", actionDeleteAction, actionDeleteSource)
}

View File

@ -3,19 +3,50 @@ package cmd
import (
"log"
"github.com/Jaculabilis/intake/core"
"github.com/spf13/cobra"
)
var actionEditCmd = &cobra.Command{
Use: "edit",
Short: "Edit an action",
Long: `
Short: "Edit an action on a source",
Long: `Edit an action on a source.
`,
Run: func(cmd *cobra.Command, args []string) {
log.Fatal("not implemented")
actionEdit(getArgv(cmd, args))
},
}
var actionEditSource string
var actionEditAction string
func init() {
actionCmd.AddCommand(actionEditCmd)
actionEditCmd.Flags().StringVarP(&actionEditSource, "source", "s", "", "Source to edit action")
actionEditCmd.MarkFlagRequired("source")
actionEditCmd.Flags().StringVarP(&actionEditAction, "action", "a", "", "Action name")
actionEditCmd.MarkFlagRequired("action")
}
func actionEdit(argv []string) {
if actionEditSource == "" {
log.Fatal("error: --source is empty")
}
if actionEditAction == "" {
log.Fatal("error: --action is empty")
}
if len(argv) == 0 {
log.Fatal("error: no argv provided")
}
db := openAndMigrateDb()
err := core.UpdateAction(db, actionEditSource, actionEditAction, argv)
if err != nil {
log.Fatalf("error: %v", err)
}
log.Printf("Updated action %s on source %s", actionEditAction, actionEditSource)
}

66
cmd/actionList.go Normal file
View File

@ -0,0 +1,66 @@
package cmd
import (
"fmt"
"log"
"slices"
"github.com/Jaculabilis/intake/core"
"github.com/spf13/cobra"
)
var actionListCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "List actions on a source",
Long: `List actions on a source.
`,
Run: func(cmd *cobra.Command, args []string) {
actionList()
},
}
var actionListSource string
var actionListArgv bool
func init() {
actionCmd.AddCommand(actionListCmd)
actionListCmd.Flags().StringVarP(&actionListSource, "source", "s", "", "Source to list actions")
actionListCmd.MarkFlagRequired("source")
actionListCmd.Flags().BoolVarP(&actionListArgv, "argv", "a", false, "Include action command")
}
func actionList() {
if actionListSource == "" {
log.Fatal("error: --source is empty")
}
db := openAndMigrateDb()
actions, err := core.GetActionsForSource(db, actionListSource)
if err != nil {
log.Fatal(err)
}
slices.SortFunc(actions, actionSort)
if actionListArgv {
actionArgv := make(map[string][]string)
for _, name := range actions {
argv, err := core.GetArgvForAction(db, actionListSource, name)
if err != nil {
log.Fatalf("error: could not get argv for source %s action %s: %v", actionListSource, name, err)
}
actionArgv[name] = argv
}
for _, name := range actions {
fmt.Printf("%s %v\n", name, actionArgv[name])
}
} else {
for _, action := range actions {
fmt.Println(action)
}
}
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"log"
"os"
"strings"
"github.com/Jaculabilis/intake/core"
"github.com/spf13/cobra"
@ -65,3 +66,23 @@ func openAndMigrateDb() *core.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
func actionSort(a string, b string) int {
if a == "fetch" {
return -1
}
if b == "fetch" {
return 1
}
return strings.Compare(a, b)
}

View File

@ -20,8 +20,12 @@ var sourceListCmd = &cobra.Command{
},
}
var sourceListShowActions bool
func init() {
sourceCmd.AddCommand(sourceListCmd)
sourceListCmd.Flags().BoolVarP(&sourceListShowActions, "actions", "a", false, "Include source actions")
}
func sourceList() {
@ -31,10 +35,24 @@ func sourceList() {
if err != nil {
log.Fatalf("error: %v", err)
}
slices.Sort(names)
for _, name := range names {
fmt.Println(name)
if sourceListShowActions {
sourceActions := make(map[string][]string)
for _, name := range names {
actions, err := core.GetActionsForSource(db, name)
if err != nil {
log.Fatalf("error: could not get actions for source %s: %v", name, err)
}
slices.SortFunc(actions, actionSort)
sourceActions[name] = actions
}
for _, name := range names {
fmt.Printf("%s %v\n", name, sourceActions[name])
}
} else {
for _, name := range names {
fmt.Println(name)
}
}
}

View File

@ -81,7 +81,7 @@ func DeleteAction(db *DB, source string, name string) error {
_, err := db.Exec(`
delete from actions
where source = ? and name = ?
`)
`, source, name)
return err
}

View File

@ -48,6 +48,11 @@ func TestActionCreate(t *testing.T) {
if len(argv) != 2 || argv[0] != "echo" || argv[1] != "goodbye" {
t.Fatalf("expected [echo goodbye], got: %v", argv)
}
err = DeleteAction(db, "test", "hello")
if err != nil {
t.Fatal(err)
}
}
func TestExecute(t *testing.T) {