Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
phm07 committed Apr 26, 2024
1 parent bdcfa39 commit f895daf
Show file tree
Hide file tree
Showing 26 changed files with 943 additions and 152 deletions.
2 changes: 1 addition & 1 deletion cmd/hcloud/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func main() {

cfg := config.NewConfig()
if err := config.ReadConfig(cfg); err != nil {
log.Fatalf("unable to read config file %s\n", err)
log.Fatalf("unable to read config file: %s\n", err)
}

s, err := state.New(cfg)
Expand Down
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ module github.com/hetznercloud/cli

go 1.21

replace github.com/spf13/viper => github.com/phm07/viper v0.0.0-20240424133512-73ebad00c669

require (
github.com/BurntSushi/toml v1.3.2
github.com/boumenot/gocover-cobertura v1.2.0
github.com/cheggaaa/pb/v3 v3.1.5
github.com/dustin/go-humanize v1.0.1
Expand All @@ -12,7 +15,6 @@ require (
github.com/google/go-cmp v0.6.0
github.com/guptarohit/asciigraph v0.7.1
github.com/hetznercloud/hcloud-go/v2 v2.7.2
github.com/pelletier/go-toml/v2 v2.2.1
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.18.2
Expand All @@ -35,6 +37,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.19.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
Expand All @@ -56,7 +59,7 @@ require (
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/protobuf v1.32.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down Expand Up @@ -39,8 +41,6 @@ github.com/guptarohit/asciigraph v0.7.1 h1:K+JWbRc04XEfv8BSZgNuvhCmpbvX4+9NYd/Ux
github.com/guptarohit/asciigraph v0.7.1/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hetznercloud/hcloud-go/v2 v2.7.1 h1:D4domwRSLOyBL/bwzd1O7hunBbKmeEHZTa7GmCYrniY=
github.com/hetznercloud/hcloud-go/v2 v2.7.1/go.mod h1:49tIV+pXRJTUC7fbFZ03s45LKqSQdOPP5y91eOnJo/k=
github.com/hetznercloud/hcloud-go/v2 v2.7.2 h1:UlE7n1GQZacCfyjv9tDVUN7HZfOXErPIfM/M039u9A0=
github.com/hetznercloud/hcloud-go/v2 v2.7.2/go.mod h1:49tIV+pXRJTUC7fbFZ03s45LKqSQdOPP5y91eOnJo/k=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
Expand All @@ -64,6 +64,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg=
github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/phm07/viper v0.0.0-20240424133512-73ebad00c669 h1:/RkERYB9EOE1AkgDmGheEbPkDt8usI0EGryLsQGvG2c=
github.com/phm07/viper v0.0.0-20240424133512-73ebad00c669/go.mod h1:Hqr8J4/Q1O00v/4zIIggDIidAoD4w8Oqtzc+Ew8QO+I=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down Expand Up @@ -94,8 +96,6 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand Down Expand Up @@ -164,8 +164,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
Expand Down
1 change: 0 additions & 1 deletion internal/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ func NewRootCommand(s state.State) *cobra.Command {
var err error
out := os.Stdout
if quiet := config.OptionQuiet.Value(); quiet {
//if quiet := viper.GetBool("quiet"); quiet {
out, err = os.Open(os.DevNull)
if err != nil {
return err
Expand Down
11 changes: 11 additions & 0 deletions internal/cmd/cmpl/suggestions.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,14 @@ func SuggestArgs(
return f(cmd, args, toComplete)
}
}

// NoFileCompletion returns a function that provides completion suggestions without
// file completion.
func NoFileCompletion(f func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)) func(
*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {

return func(command *cobra.Command, i []string, s string) ([]string, cobra.ShellCompDirective) {
candidates, _ := f(command, i, s)
return candidates, cobra.ShellCompDirectiveNoFileComp
}
}
69 changes: 69 additions & 0 deletions internal/cmd/config/add.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package config

import (
"fmt"
"os"
"reflect"

"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/cmpl"
"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/state"
"github.com/hetznercloud/cli/internal/state/config"
)

func NewAddCommand(s state.State) *cobra.Command {
cmd := &cobra.Command{
Use: "add <key> <value>...",
Short: "Set a configuration value",
Args: util.Validate,
TraverseChildren: true,
DisableFlagsInUseLine: true,
RunE: state.Wrap(s, runAdd),
ValidArgsFunction: cmpl.NoFileCompletion(cmpl.SuggestArgs(
cmpl.SuggestCandidatesF(func() []string {
var keys []string
for key, opt := range config.Options {
if opt.HasFlag(config.OptionFlagPreference) {
keys = append(keys, key)
}
}
return keys
}),
cmpl.SuggestCandidatesCtx(func(_ *cobra.Command, args []string) []string {
var comps []string
if opt, ok := config.Options[args[0]]; ok {
comps = opt.Completions()
}
return comps
}),
)),
}
cmd.Flags().Bool("global", false, "Set the value globally (for all contexts)")
return cmd
}

func runAdd(s state.State, cmd *cobra.Command, args []string) error {
global, _ := cmd.Flags().GetBool("global")

var prefs config.Preferences

if global {
prefs = s.Config().Preferences()
} else {
ctx := s.Config().ActiveContext()
if reflect.ValueOf(ctx).IsNil() {
return fmt.Errorf("no active context (use --global flag to set a global option)")
}
prefs = ctx.Preferences()
}

key, values := args[0], args[1:]
if err := prefs.Add(key, values); err != nil {
return err
}

_ = s.Config().Write(nil)
return s.Config().Write(os.Stdout)
}
7 changes: 6 additions & 1 deletion internal/cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ func NewCommand(s state.State) *cobra.Command {
DisableFlagsInUseLine: true,
}
cmd.AddCommand(
newSetCommand(s),
NewSetCommand(s),
NewGetCommand(s),
NewListCommand(s),
NewUnsetCommand(s),
NewAddCommand(s),
NewRemoveCommand(s),
)
return cmd
}
59 changes: 59 additions & 0 deletions internal/cmd/config/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package config

import (
"fmt"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/state"
"github.com/hetznercloud/cli/internal/state/config"
)

func NewGetCommand(s state.State) *cobra.Command {
cmd := &cobra.Command{
Use: "get <key>",
Short: "Get a configuration value",
Args: util.Validate,
TraverseChildren: true,
DisableFlagsInUseLine: true,
RunE: state.Wrap(s, runGet),
}
cmd.Flags().Bool("global", false, "Get the value globally")
cmd.Flags().Bool("allow-sensitive", false, "Allow showing sensitive values")
return cmd
}

func runGet(s state.State, cmd *cobra.Command, args []string) error {
global, _ := cmd.Flags().GetBool("global")
allowSensitive, _ := cmd.Flags().GetBool("allow-sensitive")

if global {
viper.Reset()
config.ResetFlags()
viper.Set("context", nil)
if err := s.Config().ParseConfig(); err != nil {
return err
}
}

key := args[0]
var opt config.IOption
for name, o := range config.Options {
if name == key {
opt = o
break
}
}
if opt == nil {
return fmt.Errorf("unknown key: %s", key)
}

val := opt.ValueAny()
if opt.HasFlag(config.OptionFlagSensitive) && !allowSensitive {
return fmt.Errorf("'%s' is sensitive. use --allow-sensitive to show the value", key)
}
cmd.Println(val)
return nil
}
54 changes: 54 additions & 0 deletions internal/cmd/config/get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package config_test

import (
"testing"

"github.com/stretchr/testify/assert"

configCmd "github.com/hetznercloud/cli/internal/cmd/config"
"github.com/hetznercloud/cli/internal/testutil"
)

func TestGet(t *testing.T) {
type testCase struct {
key string
args []string
expOut string
expErr string
}

testCases := []testCase{
{
key: "context",
expOut: "test_context\n",
},
{
key: "debug",
expOut: "true\n",
},
{
key: "endpoint",
expOut: "https://test-endpoint.com\n",
},
{
key: "poll-interval",
expOut: "1.234s\n",
},
}

for _, tt := range testCases {
t.Run(tt.key, func(t *testing.T) {
fx := testutil.NewFixture(t)
defer fx.Finish()

cmd := configCmd.NewGetCommand(fx.State())

setTestValues()
out, errOut, err := fx.Run(cmd, append(tt.args, tt.key))

assert.NoError(t, err)
assert.Equal(t, tt.expErr, errOut)
assert.Equal(t, tt.expOut, out)
})
}
}
Loading

0 comments on commit f895daf

Please sign in to comment.