go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/experiments/huectl/pkg/command/script.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package command
     9  
    10  import (
    11  	"flag"
    12  	"fmt"
    13  
    14  	"github.com/urfave/cli/v2"
    15  
    16  	"go.charczuk.com/experiments/huectl/pkg/hue"
    17  )
    18  
    19  // Script returns a command.
    20  func Script() *cli.Command {
    21  	const (
    22  		flagFile   = "file"
    23  		flagRepeat = "repeat"
    24  	)
    25  	return &cli.Command{
    26  		Name:  "script",
    27  		Usage: "Execute a script from a given json file.",
    28  		Flags: append(
    29  			DefaultFlags,
    30  			&cli.StringFlag{
    31  				Name:    flagFile,
    32  				Aliases: []string{"f"},
    33  				Usage:   "The script file path",
    34  			},
    35  			&cli.BoolFlag{
    36  				Name:  flagRepeat,
    37  				Usage: "If the script should repeat when complete",
    38  				Value: true,
    39  			},
    40  		),
    41  		Action: func(c *cli.Context) error {
    42  			c.Context = hue.WithVerbose(c.Context, c.Bool(flagVerbose))
    43  
    44  			scriptPath := c.String(flagFile)
    45  			var script []ScriptAction
    46  			if err := readJSON(&script, scriptPath); err != nil {
    47  				return fmt.Errorf("error reading script at path %s: %w", scriptPath, err)
    48  			}
    49  
    50  			cfg, ok, err := getConfig(c)
    51  			if err != nil {
    52  				return err
    53  			}
    54  			if ok {
    55  				c.Context = withConfig(c.Context, cfg)
    56  			}
    57  
    58  			b, err := getBridge(c)
    59  			if err != nil {
    60  				return err
    61  			}
    62  			c.Context = withBridge(c.Context, b)
    63  
    64  			if c.Bool(flagRepeat) {
    65  				var err error
    66  				for {
    67  					if err = runScript(c, script); err != nil {
    68  						return err
    69  					}
    70  				}
    71  			}
    72  			return runScript(c, script)
    73  		},
    74  	}
    75  }
    76  
    77  func runScript(c *cli.Context, script []ScriptAction) error {
    78  	var cmd *cli.Command
    79  	var err error
    80  	for _, scriptStep := range script {
    81  		cmd = c.App.Command(scriptStep.Name)
    82  		err = cmd.Action(cli.NewContext(c.App, flagSetFromMap(scriptStep.Flags), c))
    83  		if err != nil {
    84  			return err
    85  		}
    86  	}
    87  	return nil
    88  }
    89  
    90  func flagSetFromMap(flags map[string]string) *flag.FlagSet {
    91  	set := flag.NewFlagSet("", flag.ContinueOnError)
    92  	var arguments []string
    93  	for name, value := range flags {
    94  		set.String(name, value, "")
    95  		arguments = append(arguments, fmt.Sprintf("-%s=%s", name, value))
    96  	}
    97  	_ = set.Parse(arguments)
    98  	return set
    99  }
   100  
   101  // ScriptContents is a list of script actions
   102  type ScriptContents []ScriptAction
   103  
   104  // ScriptAction is a specific action in a script.
   105  type ScriptAction struct {
   106  	Name  string            `json:"name"`
   107  	Flags map[string]string `json:"flags"`
   108  }