diff --git a/certificate/authorization/service.go b/certificate/authorization/service.go index fa9df6dfa..02b0bc9a5 100644 --- a/certificate/authorization/service.go +++ b/certificate/authorization/service.go @@ -46,11 +46,9 @@ func (service *Service) GetOrCreate(ctx context.Context, userID string) (_ *Toke return nil, err } - if existingGroup != nil && len(existingGroup) > 0 { - for _, authorization := range existingGroup { - if authorization.Claim == nil { - return &authorization.Token, nil - } + for _, authorization := range existingGroup { + if authorization.Claim == nil { + return &authorization.Token, nil } } diff --git a/cmd/uplink/external.go b/cmd/uplink/external.go index f38040290..94f022a34 100644 --- a/cmd/uplink/external.go +++ b/cmd/uplink/external.go @@ -65,12 +65,12 @@ func (ex *external) Setup(f clingy.Flags) { ex.dirs.current = f.Flag( "config-dir", "Directory that stores the configuration", - appDir(false, "storj", "uplink"), + appDir(false, defaultUplinkSubdir()...), ).(string) ex.dirs.legacy = f.Flag( "legacy-config-dir", "Directory that stores legacy configuration. Only used during migration", - appDir(true, "storj", "uplink"), + appDir(true, defaultUplinkSubdir()...), clingy.Advanced, ).(string) @@ -187,17 +187,19 @@ func (ex *external) PromptSecret(ctx clingy.Context, prompt string) (secret stri } } +func defaultUplinkSubdir() []string { + switch runtime.GOOS { + case "windows", "darwin": + return []string{"Storj", "Uplink"} + default: + return []string{"storj", "uplink"} + } +} + // appDir returns best base directory for the currently running operating system. It // has a legacy bool to have it return the same values that storj.io/common/fpath.ApplicationDir // would have returned. func appDir(legacy bool, subdir ...string) string { - for i := range subdir { - if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { - subdir[i] = strings.Title(subdir[i]) - } else { - subdir[i] = strings.ToLower(subdir[i]) - } - } var appdir string home := os.Getenv("HOME") diff --git a/go.mod b/go.mod index 0a3546b03..3a6f22a1e 100644 --- a/go.mod +++ b/go.mod @@ -47,6 +47,7 @@ require ( golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 + golang.org/x/text v0.3.6 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e gopkg.in/segmentio/analytics-go.v3 v3.1.0 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 @@ -119,7 +120,6 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/mod v0.4.2 // indirect - golang.org/x/text v0.3.6 // indirect golang.org/x/tools v0.1.1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/api v0.20.0 // indirect diff --git a/private/apigen/api.go b/private/apigen/api.go index d4a06caac..68f2e0cad 100644 --- a/private/apigen/api.go +++ b/private/apigen/api.go @@ -12,6 +12,8 @@ import ( "time" "github.com/zeebo/errs" + "golang.org/x/text/cases" + "golang.org/x/text/language" "storj.io/common/uuid" "storj.io/storj/private/api" @@ -111,7 +113,7 @@ func (a *API) generateGo() ([]byte, error) { p(")") p("") - p("var Err%sAPI = errs.Class(\"%s %s api\")", strings.Title(group.Prefix), a.PackageName, group.Prefix) + p("var Err%sAPI = errs.Class(\"%s %s api\")", cases.Title(language.Und).String(group.Prefix), a.PackageName, group.Prefix) p("") p("type %sService interface {", group.Name) @@ -223,7 +225,7 @@ func (a *API) generateGo() ([]byte, error) { p("err = json.NewEncoder(w).Encode(retVal)") p("if err != nil {") - p("h.log.Debug(\"failed to write json %s response\", zap.Error(Err%sAPI.Wrap(err)))", endpoint.MethodName, strings.Title(group.Prefix)) + p("h.log.Debug(\"failed to write json %s response\", zap.Error(Err%sAPI.Wrap(err)))", endpoint.MethodName, cases.Title(language.Und).String(group.Prefix)) p("}") p("}") p("") diff --git a/private/version/checker/client.go b/private/version/checker/client.go index 23c974cc6..4d8ad73f8 100644 --- a/private/version/checker/client.go +++ b/private/version/checker/client.go @@ -12,6 +12,7 @@ import ( "reflect" "strings" "time" + "unicode" "github.com/spacemonkeygo/monkit/v3" "github.com/zeebo/errs" @@ -125,5 +126,46 @@ func (client *Client) Process(ctx context.Context, processName string) (process } func kebabToPascal(str string) string { - return strings.ReplaceAll(strings.Title(str), "-", "") + return strings.ReplaceAll(stringsTitle(str), "-", "") +} + +func stringsTitle(s string) string { + // strings.Title and cases.Title(language.Und) do different things. + // For example: + // s := `StoragenodeUpdater` + // strings.Title(s) == `StoragenodeUpdater` + // cases.Title(language.Und).String(s) == `Storagenodeupdater` + + // This reimplements strings.Title to bypass Deprecated notice. + prev := ' ' + return strings.Map( + func(r rune) rune { + if isSeparator(prev) { + prev = r + return unicode.ToTitle(r) + } + prev = r + return r + }, s) +} + +func isSeparator(r rune) bool { + // ASCII alphanumerics and underscore are not separators + if r <= 0x7F { + switch { + case '0' <= r && r <= '9': + return false + case 'a' <= r && r <= 'z': + return false + case 'A' <= r && r <= 'Z': + return false + case r == '_': + return false + } + return true + } + if unicode.IsLetter(r) || unicode.IsDigit(r) { + return false + } + return unicode.IsSpace(r) }