github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/cmd/snap/cmd_set.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package main 21 22 import ( 23 "fmt" 24 "strings" 25 26 "github.com/jessevdk/go-flags" 27 28 "github.com/snapcore/snapd/i18n" 29 "github.com/snapcore/snapd/jsonutil" 30 ) 31 32 var shortSetHelp = i18n.G("Change configuration options") 33 var longSetHelp = i18n.G(` 34 The set command changes the provided configuration options as requested. 35 36 $ snap set snap-name username=frank password=$PASSWORD 37 38 All configuration changes are persisted at once, and only after the 39 snap's configuration hook returns successfully. 40 41 Nested values may be modified via a dotted path: 42 43 $ snap set snap-name author.name=frank 44 45 Configuration option may be unset with exclamation mark: 46 $ snap set snap-name author! 47 `) 48 49 type cmdSet struct { 50 waitMixin 51 Positional struct { 52 Snap installedSnapName 53 ConfValues []string `required:"1"` 54 } `positional-args:"yes" required:"yes"` 55 } 56 57 func init() { 58 addCommand("set", shortSetHelp, longSetHelp, func() flags.Commander { return &cmdSet{} }, waitDescs, []argDesc{ 59 { 60 name: "<snap>", 61 // TRANSLATORS: This should not start with a lowercase letter. 62 desc: i18n.G("The snap to configure (e.g. hello-world)"), 63 }, { 64 // TRANSLATORS: This needs to begin with < and end with > 65 name: i18n.G("<conf value>"), 66 // TRANSLATORS: This should not start with a lowercase letter. 67 desc: i18n.G("Set (key=value) or unset (key!) configuration value"), 68 }, 69 }) 70 } 71 72 func (x *cmdSet) Execute(args []string) error { 73 patchValues := make(map[string]interface{}) 74 for _, patchValue := range x.Positional.ConfValues { 75 parts := strings.SplitN(patchValue, "=", 2) 76 if len(parts) == 1 && strings.HasSuffix(patchValue, "!") { 77 patchValues[strings.TrimSuffix(patchValue, "!")] = nil 78 continue 79 } 80 if len(parts) != 2 { 81 return fmt.Errorf(i18n.G("invalid configuration: %q (want key=value)"), patchValue) 82 } 83 var value interface{} 84 if err := jsonutil.DecodeWithNumber(strings.NewReader(parts[1]), &value); err != nil { 85 // Not valid JSON-- just save the string as-is. 86 patchValues[parts[0]] = parts[1] 87 } else { 88 patchValues[parts[0]] = value 89 } 90 } 91 92 snapName := string(x.Positional.Snap) 93 id, err := x.client.SetConf(snapName, patchValues) 94 if err != nil { 95 return err 96 } 97 98 if _, err := x.wait(id); err != nil { 99 if err == noWait { 100 return nil 101 } 102 return err 103 } 104 105 return nil 106 }