github.com/nats-io/nsc@v0.0.0-20221206222106-35db9400b257/cmd/action.go (about)

     1  /*
     2   * Copyright 2018 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/nats-io/nsc/cmd/store"
    23  	"github.com/spf13/cobra"
    24  )
    25  
    26  type ActionCtx interface {
    27  	StoreCtx() *store.Context
    28  	CurrentCmd() *cobra.Command
    29  	Args() []string
    30  	NothingToDo(flagNames ...string) bool
    31  	AllSet(flagNames ...string) bool
    32  	AnySet(flagNames ...string) bool
    33  	CountSet(flagNames ...string) int
    34  }
    35  
    36  type ActionFn func(ctx ActionCtx) error
    37  type ActionRunFn func(ctx ActionCtx) (store.Status, error)
    38  
    39  type Action interface {
    40  	// SetDefaults that can be derived from cmd flags
    41  	SetDefaults(ctx ActionCtx) error
    42  	// PreInteractive ask user for values
    43  	PreInteractive(ctx ActionCtx) error
    44  	// Load any data needed for the Run
    45  	Load(ctx ActionCtx) error
    46  	// PostInteractive ask user for values related to the action
    47  	PostInteractive(ctx ActionCtx) error
    48  	// Validate the action
    49  	Validate(ctx ActionCtx) error
    50  	// Run the action
    51  	Run(ctx ActionCtx) (store.Status, error)
    52  }
    53  
    54  type Actx struct {
    55  	ctx  *store.Context
    56  	cmd  *cobra.Command
    57  	args []string
    58  }
    59  
    60  func NewActx(cmd *cobra.Command, args []string) (ActionCtx, error) {
    61  	s, err := GetStore()
    62  	// in the case of add operator, there might not be a store
    63  	if err == ErrNoOperator {
    64  		if cmd.Name() == "operator" && cmd.Parent().Name() == "add" {
    65  			return nil, nil
    66  		}
    67  	}
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	ctx, err := s.GetContext()
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	return &Actx{cmd: cmd, ctx: ctx, args: args}, nil
    77  }
    78  
    79  func NewStoreLessActx(cmd *cobra.Command, args []string) (ActionCtx, error) {
    80  	var ctx Actx
    81  	ctx.cmd = cmd
    82  	ctx.args = args
    83  	ctx.ctx = &store.Context{}
    84  	return &ctx, nil
    85  }
    86  
    87  func RunMaybeStorelessAction(cmd *cobra.Command, args []string, action interface{}) error {
    88  	ctx, err := NewActx(cmd, args)
    89  	if err != nil {
    90  		ctx, err = NewStoreLessActx(cmd, args)
    91  		if err != nil {
    92  			return err
    93  		}
    94  	}
    95  	return run(ctx, action)
    96  
    97  }
    98  
    99  func RunStoreLessAction(cmd *cobra.Command, args []string, action interface{}) error {
   100  	ctx, err := NewStoreLessActx(cmd, args)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	return run(ctx, action)
   105  }
   106  
   107  func RunAction(cmd *cobra.Command, args []string, action interface{}) error {
   108  	ctx, err := NewActx(cmd, args)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	return run(ctx, action)
   113  }
   114  
   115  func run(ctx ActionCtx, action interface{}) error {
   116  	e, ok := action.(Action)
   117  	if !ok {
   118  		return fmt.Errorf("action provided is not an Action")
   119  	}
   120  	if err := e.SetDefaults(ctx); err != nil {
   121  		return err
   122  	}
   123  
   124  	if InteractiveFlag {
   125  		if err := e.PreInteractive(ctx); err != nil {
   126  			return err
   127  		}
   128  	}
   129  
   130  	if err := e.Load(ctx); err != nil {
   131  		return err
   132  	}
   133  
   134  	if InteractiveFlag {
   135  		if err := e.PostInteractive(ctx); err != nil {
   136  			return err
   137  		}
   138  	}
   139  
   140  	if err := e.Validate(ctx); err != nil {
   141  		return err
   142  	}
   143  
   144  	rs, err := e.Run(ctx)
   145  	if rs != nil {
   146  		ctx.CurrentCmd().Println(rs.Message())
   147  		sum, ok := rs.(store.Summarizer)
   148  		if ok {
   149  			m, err := sum.Summary()
   150  			if err != nil {
   151  				return err
   152  			}
   153  			if m != "" {
   154  				ctx.CurrentCmd().Println(strings.TrimSuffix(m, "\n"))
   155  			}
   156  		}
   157  	}
   158  	return err
   159  }
   160  
   161  func (c *Actx) StoreCtx() *store.Context {
   162  	return c.ctx
   163  }
   164  
   165  func (c *Actx) CurrentCmd() *cobra.Command {
   166  	return c.cmd
   167  }
   168  
   169  func (c *Actx) Args() []string {
   170  	return c.args
   171  }
   172  
   173  func (c *Actx) NothingToDo(flagNames ...string) bool {
   174  	for _, n := range flagNames {
   175  		if c.cmd.Flag(n).Changed {
   176  			return false
   177  		}
   178  	}
   179  	return true
   180  }
   181  
   182  // AnySet returns true if any of the flags are set
   183  func (c *Actx) AnySet(flagNames ...string) bool {
   184  	for _, n := range flagNames {
   185  		if c.cmd.Flag(n).Changed {
   186  			return true
   187  		}
   188  	}
   189  	return false
   190  }
   191  
   192  // AllSet returns true if all flags are set
   193  func (c *Actx) AllSet(flagNames ...string) bool {
   194  	count := 0
   195  	for _, n := range flagNames {
   196  		if c.cmd.Flag(n).Changed {
   197  			count++
   198  		}
   199  	}
   200  	return len(flagNames) == count
   201  }
   202  
   203  func (c *Actx) CountSet(flagNames ...string) int {
   204  	count := 0
   205  	for _, n := range flagNames {
   206  		if c.cmd.Flag(n).Changed {
   207  			count++
   208  		}
   209  	}
   210  	return count
   211  }