forked from viamrobotics/rdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprofile.go
156 lines (128 loc) · 3.98 KB
/
profile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package cli
import (
"encoding/json"
"fmt"
"os"
"github.com/urfave/cli/v2"
)
// CLI profiles allow a user to run commands with a specific API key without having to
// log out and log back in. A profile is added with `viam profiles add`, updated with
// `viam profiles udpate`, etc. Once a profile is added, a command can be run using a
// profile by using the `--profile {profile name}` global flag.
//
// If one wants to use a profile for an entire shell session without having to specify it
// each time, the user can set the `VIAM_CLI_PROFILE_NAME` env var. The CLI will then use
// that env var to find a profile, provided the global flag is not set. To override the env
// var without unsetting it, simply use the `--disable-profiles` flag.
const profileEnvVar = "VIAM_CLI_PROFILE_NAME"
type addOrUpdateProfileArgs struct {
ProfileName string
Key string
KeyID string
}
func getProfiles() (map[string]profile, error) {
rd, err := os.ReadFile(getCLIProfilesPath())
if err != nil {
if !os.IsNotExist(err) {
return nil, err
}
rd = make([]byte, 0)
}
profiles := make(map[string]profile)
if err := json.Unmarshal(rd, &profiles); err != nil {
return nil, err
}
return profiles, nil
}
func writeProfiles(profiles map[string]profile) error {
md, err := json.MarshalIndent(profiles, "", " ")
if err != nil {
return err
}
//nolint:gosec
return os.WriteFile(getCLIProfilesPath(), md, 0o640)
}
func addOrUpdateProfile(c *cli.Context, args addOrUpdateProfileArgs, isAdd bool) error {
profiles, err := getProfiles()
if err != nil {
if !os.IsNotExist(err) {
return err
}
profiles = make(map[string]profile)
}
profile, alreadyExists := profiles[args.ProfileName]
if isAdd && alreadyExists {
return fmt.Errorf("attempted to add new profile %s but it already existed", args.ProfileName)
}
profile.APIKey.KeyCrypto = args.Key
profile.APIKey.KeyID = args.KeyID
profile.Name = args.ProfileName
profiles[args.ProfileName] = profile
if err := writeProfiles(profiles); err != nil {
return err
}
var addOrUpdate string
if isAdd {
addOrUpdate = "added"
} else {
addOrUpdate = "updated"
}
printf(c.App.Writer, "Successfully %s profile %s", addOrUpdate, args.ProfileName)
return nil
}
// AddProfileAction adds a new CLI profile.
func AddProfileAction(c *cli.Context, args addOrUpdateProfileArgs) error {
return addOrUpdateProfile(c, args, true)
}
// UpdateProfileAction updates an existing CLI profile, or adds it if it doesn't already exist.
func UpdateProfileAction(c *cli.Context, args addOrUpdateProfileArgs) error {
return addOrUpdateProfile(c, args, false)
}
type removeProfileArgs struct {
ProfileName string
}
// bool return indicates whether a profile has been specified, as opposed to either not existing
// or existing as an env var. This is relevant because we want to fall back on default behavior
// if an env var profile isn't found, but return an error if a profile specified with the `--profile`
// flag isn't found.
func whichProfile(args *globalArgs) (*string, bool) {
// profile hasn't been specified for this command
if args.Profile != "" {
return &args.Profile, true
}
if envProfile := os.Getenv(profileEnvVar); envProfile != "" {
return &envProfile, false
}
return nil, false
}
// RemoveProfileAction removes a CLI profile.
func RemoveProfileAction(c *cli.Context, args removeProfileArgs) error {
profiles, err := getProfiles()
if err != nil {
return err
}
delete(profiles, args.ProfileName)
if err := os.Remove(getCLIProfilePath(args.ProfileName)); err != nil {
return err
}
if err := writeProfiles(profiles); err != nil {
return err
}
printf(c.App.Writer, "Successfully deleted profile %s", args.ProfileName)
return nil
}
// ListProfilesAction lists all currently supported profiles.
func ListProfilesAction(c *cli.Context, args emptyArgs) error {
profiles, err := getProfiles()
if err != nil {
return err
}
for p := range profiles {
printf(c.App.Writer, p)
}
return nil
}
type profile struct {
Name string
APIKey apiKey
}