github.com/kbehouse/nsc@v0.0.6/cmd/contextconfig.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  	"io/ioutil"
    21  	"os"
    22  	"path/filepath"
    23  	"sort"
    24  
    25  	"github.com/kbehouse/nsc/cmd/store"
    26  )
    27  
    28  type ContextConfig struct {
    29  	StoreRoot string `json:"store_root"` // where the projects are
    30  	Operator  string `json:"operator"`
    31  	Account   string `json:"account"`
    32  }
    33  
    34  func NewContextConfig(storeRoot string) (*ContextConfig, error) {
    35  	ctx := ContextConfig{}
    36  	dc := GetCwdCtx()
    37  	if dc != nil {
    38  		ctx = *dc
    39  		config.SetDefaults()
    40  		ctx.setStoreRoot(ctx.StoreRoot)
    41  		return &ctx, nil
    42  	}
    43  
    44  	if err := ctx.setStoreRoot(storeRoot); err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	return &ctx, nil
    49  }
    50  
    51  func (c *ContextConfig) setStoreRoot(storeRoot string) error {
    52  	var err error
    53  	if storeRoot != "" {
    54  		c.StoreRoot, err = filepath.Abs(storeRoot)
    55  		if err != nil {
    56  			return err
    57  		}
    58  		c.SetDefaults()
    59  	}
    60  	return nil
    61  }
    62  
    63  func (c *ContextConfig) Update(root string, operator string, account string) error {
    64  	if err := c.setStoreRoot(root); err != nil {
    65  		return err
    66  	}
    67  	if operator != "" {
    68  		if err := c.SetOperator(operator); err != nil {
    69  			return err
    70  		}
    71  	}
    72  	if account != "" {
    73  		if err := c.SetAccount(account); err != nil {
    74  			return err
    75  		}
    76  	}
    77  	c.SetDefaults()
    78  	return nil
    79  }
    80  
    81  // deduce as much context as possible
    82  func (c *ContextConfig) SetDefaults() {
    83  	if err := IsValidDir(c.StoreRoot); err == nil {
    84  		operators := c.ListOperators()
    85  		c.Operator = c.saneDefault(c.Operator, operators)
    86  		if c.Operator == "" {
    87  			// reset everything
    88  			c.Account = ""
    89  			return
    90  		}
    91  
    92  		s, err := c.LoadStore(c.Operator)
    93  		if err != nil {
    94  			return
    95  		}
    96  		accounts, err := s.ListSubContainers(store.Accounts)
    97  		if err == nil {
    98  			c.Account = c.saneDefault(c.Account, accounts)
    99  		}
   100  	}
   101  }
   102  
   103  // saneDefault keeps the current choice if it exists, or returns ""
   104  func (c *ContextConfig) saneDefault(current string, choices []string) string {
   105  	switch len(choices) {
   106  	case 0:
   107  		return ""
   108  	case 1:
   109  		return choices[0]
   110  	default:
   111  		for _, v := range choices {
   112  			if v == current {
   113  				return current
   114  			}
   115  		}
   116  		return ""
   117  	}
   118  }
   119  
   120  func (c *ContextConfig) LoadStore(operatorName string) (*store.Store, error) {
   121  	return store.LoadStore(filepath.Join(c.StoreRoot, operatorName))
   122  }
   123  
   124  func (c *ContextConfig) ListOperators() []string {
   125  	infos, err := ioutil.ReadDir(c.StoreRoot)
   126  	if err != nil {
   127  		return nil
   128  	}
   129  	var operators []string
   130  	for _, v := range infos {
   131  		name := store.SafeName(filepath.Base(v.Name()))
   132  		fp := filepath.Join(c.StoreRoot, name, store.NSCFile)
   133  		info, err := os.Stat(fp)
   134  		if err == nil && info != nil {
   135  			operators = append(operators, v.Name())
   136  		}
   137  	}
   138  	sort.Strings(operators)
   139  	return operators
   140  }
   141  
   142  func (c *ContextConfig) SetOperator(operator string) error {
   143  	ok := true
   144  	if operator != "" {
   145  		ok = false
   146  		for _, v := range c.ListOperators() {
   147  			if v == operator {
   148  				ok = true
   149  				break
   150  			}
   151  		}
   152  	}
   153  	if !ok {
   154  		return fmt.Errorf("operator %q not in %#q", operator, c.StoreRoot)
   155  	}
   156  
   157  	c.Operator = operator
   158  	return GetConfig().Save()
   159  }
   160  
   161  func (c *ContextConfig) SetAccount(account string) error {
   162  	if err := c.SetAccountTemp(account); err != nil {
   163  		return err
   164  	}
   165  	return GetConfig().Save()
   166  }
   167  
   168  func (c *ContextConfig) SetAccountTemp(account string) error {
   169  	if account != "" {
   170  		if err := c.hasSubContainer(store.Accounts, account); err != nil {
   171  			return err
   172  		}
   173  	}
   174  	c.Account = account
   175  
   176  	return nil
   177  }
   178  
   179  func (c *ContextConfig) ListAccounts() ([]string, error) {
   180  	return c.getSubContainers(store.Accounts)
   181  }
   182  
   183  func (c *ContextConfig) getSubContainers(kind string) ([]string, error) {
   184  	s, err := store.LoadStore(filepath.Join(c.StoreRoot, c.Operator))
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	names, err := s.ListSubContainers(kind)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	return names, nil
   193  }
   194  
   195  func (c *ContextConfig) hasSubContainer(kind string, name string) error {
   196  	names, err := c.getSubContainers(kind)
   197  	if err != nil {
   198  		return err
   199  	}
   200  	for _, v := range names {
   201  		if name == v {
   202  			return nil
   203  		}
   204  	}
   205  	return fmt.Errorf("%q not in %s for operator %q in %#q", name, kind, c.Operator, c.StoreRoot)
   206  }