-
Notifications
You must be signed in to change notification settings - Fork 218
/
preparers.go
138 lines (117 loc) · 4.17 KB
/
preparers.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
package preparers
import (
"context"
"fmt"
"net/http"
"path/filepath"
"strings"
"github.com/spf13/pflag"
fly "github.com/superfly/fly-go"
"github.com/superfly/flyctl/helpers"
"github.com/superfly/flyctl/internal/config"
"github.com/superfly/flyctl/internal/flag/flagctx"
"github.com/superfly/flyctl/internal/flyutil"
"github.com/superfly/flyctl/internal/instrument"
"github.com/superfly/flyctl/internal/logger"
"github.com/superfly/flyctl/internal/state"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
// Preparers are split between here and `command/command.go` because
// tab-completion needs to run *some* of them, and importing the command package from there
// would create a circular dependency. Likewise, if *all* the preparers were in this module,
// that would also cause a circular dependency.
// I don't like this, but it's shippable until someone else fixes it
type Preparer func(context.Context) (context.Context, error)
func LoadConfig(ctx context.Context) (context.Context, error) {
logger := logger.FromContext(ctx)
cfg, err := config.Load(ctx, filepath.Join(state.ConfigDirectory(ctx), config.FileName))
if err != nil {
return nil, err
}
logger.Debug("config initialized.")
return config.NewContext(ctx, cfg), nil
}
func InitClient(ctx context.Context) (context.Context, error) {
logger := logger.FromContext(ctx)
cfg := config.FromContext(ctx)
// TODO: refactor so that api package does NOT depend on global state
fly.SetBaseURL(cfg.APIBaseURL)
fly.SetErrorLog(cfg.LogGQLErrors)
fly.SetInstrumenter(instrument.ApiAdapter)
fly.SetTransport(otelhttp.NewTransport(http.DefaultTransport))
c := flyutil.NewClientFromOptions(ctx, fly.ClientOptions{Tokens: cfg.Tokens})
logger.Debug("client initialized.")
return fly.NewContextWithClient(ctx, c), nil
}
func DetermineConfigDir(ctx context.Context) (context.Context, error) {
dir, err := helpers.GetConfigDirectory()
if err != nil {
return ctx, err
}
logger.FromContext(ctx).
Debugf("determined config directory: %q", dir)
return state.WithConfigDirectory(ctx, dir), nil
}
// ApplyAliases consolidates flags with aliases into a single source-of-truth flag.
// After calling this, the main flags will have their values set as follows:
// - If the main flag was already set, it will keep its value.
// - If it was not set, but an alias was, it will take the value of the first specified alias flag.
// This will set flag.Changed to true, as if it were specified manually.
// - If none of the flags were set, the main flag will remain its default value.
func ApplyAliases(ctx context.Context) (context.Context, error) {
var (
invalidFlagNames []string
invalidTypes []string
flags = flagctx.FromContext(ctx)
)
flags.VisitAll(func(f *pflag.Flag) {
aliases, ok := f.Annotations["flyctl_alias"]
if !ok {
return
}
name := f.Name
gotValue := false
origFlag := flags.Lookup(name)
if origFlag == nil {
invalidFlagNames = append(invalidFlagNames, name)
} else {
gotValue = origFlag.Changed
}
for _, alias := range aliases {
aliasFlag := flags.Lookup(alias)
if aliasFlag == nil {
invalidFlagNames = append(invalidFlagNames, alias)
continue
}
if origFlag == nil {
continue // nothing left to do here if we have no root flag
}
if aliasFlag.Value.Type() != origFlag.Value.Type() {
invalidTypes = append(invalidTypes, fmt.Sprintf("%s (%s) and %s (%s)", name, origFlag.Value.Type(), alias, aliasFlag.Value.Type()))
}
if !gotValue && aliasFlag.Changed {
err := origFlag.Value.Set(aliasFlag.Value.String())
if err != nil {
panic(err)
}
origFlag.Changed = true
}
}
})
var err error
{
var errorMessages []string
if len(invalidFlagNames) > 0 {
errorMessages = append(errorMessages, fmt.Sprintf("flags '%v' are not valid flags", invalidFlagNames))
}
if len(invalidTypes) > 0 {
errorMessages = append(errorMessages, fmt.Sprintf("flags '%v' have different types", invalidTypes))
}
if len(errorMessages) > 1 {
err = fmt.Errorf("multiple errors occured:\n > %s\n", strings.Join(errorMessages, "\n > "))
} else if len(errorMessages) == 1 {
err = fmt.Errorf("%s", errorMessages[0])
}
}
return ctx, err
}