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 }