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