Skip to content

Commit 0d0000e

Browse files
committed
Add connection aliases
Adds support for defining connection aliases in the user's $HOME/.config/usql/config.yaml file. See contrib/config.yaml for an example. Implements #443.
1 parent cefcc94 commit 0d0000e

File tree

2 files changed

+55
-38
lines changed

2 files changed

+55
-38
lines changed

handler/handler.go

+25-9
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,14 @@ type Handler struct {
7474
u *dburl.URL
7575
db *sql.DB
7676
tx *sql.Tx
77+
// conns are user defined connections.
78+
conns map[string]string
7779
// out file or pipe
7880
out io.WriteCloser
7981
}
8082

8183
// New creates a new input handler.
82-
func New(l rline.IO, user *user.User, wd string, nopw bool) *Handler {
84+
func New(l rline.IO, user *user.User, wd string, nopw bool, conns map[string]string) *Handler {
8385
f, iactive := l.Next, l.Interactive()
8486
if iactive {
8587
f = func() ([]rune, error) {
@@ -94,16 +96,20 @@ func New(l rline.IO, user *user.User, wd string, nopw bool) *Handler {
9496
}
9597
}
9698
h := &Handler{
97-
l: l,
98-
user: user,
99-
wd: wd,
100-
nopw: nopw,
101-
buf: stmt.New(f),
99+
l: l,
100+
user: user,
101+
wd: wd,
102+
nopw: nopw,
103+
buf: stmt.New(f),
104+
conns: conns,
102105
}
103106
if iactive {
104107
l.SetOutput(h.outputHighlighter)
105108
l.Completer(completer.NewDefaultCompleter(completer.WithConnStrings(h.connStrings())))
106109
}
110+
if h.conns == nil {
111+
h.conns = make(map[string]string)
112+
}
107113
return h
108114
}
109115

@@ -740,8 +746,12 @@ func (h *Handler) Open(ctx context.Context, params ...string) error {
740746
return text.ErrPreviousTransactionExists
741747
}
742748
if len(params) < 2 {
749+
dsn := params[0]
750+
if s, ok := h.conns[dsn]; ok {
751+
dsn = s
752+
}
743753
// parse dsn
744-
u, err := dburl.Parse(params[0])
754+
u, err := dburl.Parse(dsn)
745755
if err != nil {
746756
return err
747757
}
@@ -821,6 +831,9 @@ func (h *Handler) connStrings() []string {
821831
}
822832
names = append(names, fmt.Sprintf("%s://%s%s%s%s", entry.Protocol, user, host, port, dbname))
823833
}
834+
for name := range h.conns {
835+
names = append(names, name)
836+
}
824837
sort.Strings(names)
825838
return names
826839
}
@@ -847,8 +860,11 @@ func (h *Handler) forceParams(u *dburl.URL) {
847860
// Password collects a password from input, and returns a modified DSN
848861
// including the collected password.
849862
func (h *Handler) Password(dsn string) (string, error) {
850-
if dsn == "" {
863+
switch s, ok := h.conns[dsn]; {
864+
case dsn == "":
851865
return "", text.ErrMissingDSN
866+
case ok:
867+
dsn = s
852868
}
853869
u, err := dburl.Parse(dsn)
854870
if err != nil {
@@ -1387,7 +1403,7 @@ func (h *Handler) Include(path string, relative bool) error {
13871403
Err: h.l.Stderr(),
13881404
Pw: h.l.Password,
13891405
}
1390-
p := New(l, h.user, filepath.Dir(path), h.nopw)
1406+
p := New(l, h.user, filepath.Dir(path), h.nopw, h.conns)
13911407
p.db, p.u = h.db, h.u
13921408
drivers.ConfigStmt(p.u, p.buf)
13931409
err = p.Run()

run.go

+30-29
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func New(cliargs []string) ContextExecutor {
9999
return nil
100100
},
101101
RunE: func(cmd *cobra.Command, cliargs []string) error {
102-
// completions
102+
// completions and short circuits
103103
switch {
104104
case bashCompletion:
105105
return cmd.GenBashCompletionV2(os.Stdout, !noDescriptions)
@@ -118,6 +118,7 @@ func New(cliargs []string) ContextExecutor {
118118
case badHelp:
119119
return errors.New("unknown shorthand flag: 'h' in -h")
120120
}
121+
args.Conns = v.GetStringMapString("connections")
121122
// run
122123
if len(cliargs) > 0 {
123124
args.DSN = cliargs[0]
@@ -194,15 +195,6 @@ func New(cliargs []string) ContextExecutor {
194195
_ = flags.BoolP("help", "?", false, "show this help, then exit")
195196
_ = c.Flags().SetAnnotation("help", cobra.FlagSetByCobraAnnotation, []string{"true"})
196197

197-
// expose to metacmd
198-
metacmd.Usage = func(w io.Writer, banner bool) {
199-
s := c.UsageString()
200-
if banner {
201-
s = text.Short() + "\n\n" + s
202-
}
203-
_, _ = w.Write([]byte(s))
204-
}
205-
206198
// mark hidden
207199
for _, name := range []string{
208200
"no-psqlrc", "no-usqlrc", "var", "variable",
@@ -212,6 +204,15 @@ func New(cliargs []string) ContextExecutor {
212204
} {
213205
flags.Lookup(name).Hidden = true
214206
}
207+
208+
// expose to metacmd
209+
metacmd.Usage = func(w io.Writer, banner bool) {
210+
s := c.UsageString()
211+
if banner {
212+
s = text.Short() + "\n\n" + s
213+
}
214+
_, _ = w.Write([]byte(s))
215+
}
215216
return c
216217
}
217218

@@ -227,43 +228,42 @@ func Run(ctx context.Context, args *Args) error {
227228
if err != nil {
228229
return err
229230
}
231+
230232
// determine if interactive
231233
interactive := isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stdin.Fd())
232234
cygwin := isatty.IsCygwinTerminal(os.Stdout.Fd()) && isatty.IsCygwinTerminal(os.Stdin.Fd())
233235
forceNonInteractive := len(args.CommandOrFiles) != 0
236+
234237
// enable term graphics
235-
/*
236-
if !forceNonInteractive && interactive && !cygwin {
237-
// NOTE: this is done here and not in the env.init() package, because
238-
// NOTE: we need to determine if it is interactive first, otherwise it
239-
// NOTE: could mess up the non-interactive output with control characters
240-
var typ string
241-
if s, _ := env.Getenv(commandUpper+"_TERM_GRAPHICS", "TERM_GRAPHICS"); s != "" {
242-
typ = s
243-
}
244-
if err := env.Set("TERM_GRAPHICS", typ); err != nil {
245-
return err
246-
}
238+
if !forceNonInteractive && interactive && !cygwin {
239+
// NOTE: this is done here and not in the env.init() package, because
240+
// NOTE: we need to determine if it is interactive first, otherwise it
241+
// NOTE: could mess up the non-interactive output with control characters
242+
var typ string
243+
if s, _ := env.Getenv(text.CommandUpper()+"_TERM_GRAPHICS", "TERM_GRAPHICS"); s != "" {
244+
typ = s
247245
}
248-
*/
246+
if err := env.Set("TERM_GRAPHICS", typ); err != nil {
247+
return err
248+
}
249+
}
249250

250-
// fmt.Fprintf(os.Stdout, "\n\nVARS: %v\n\nPVARS: %v\n\n\n", args.Variables, args.PVariables)
251+
// fmt.Fprintf(os.Stdout, "VARS: %v\nPVARS: %v\n", args.Variables, args.PVariables)
251252

252-
// handle variables
253+
// set variables
253254
for _, v := range args.Variables {
254255
if i := strings.Index(v, "="); i != -1 {
255256
_ = env.Set(v[:i], v[i+1:])
256257
} else {
257258
_ = env.Unset(v)
258259
}
259260
}
261+
// set pvariables
260262
for _, v := range args.PVariables {
261263
if i := strings.Index(v, "="); i != -1 {
262264
vv := v[i+1:]
263265
if c := vv[0]; c == '\'' || c == '"' {
264-
var err error
265-
vv, err = env.Dequote(vv, c)
266-
if err != nil {
266+
if vv, err = env.Dequote(vv, c); err != nil {
267267
return err
268268
}
269269
}
@@ -283,7 +283,7 @@ func Run(ctx context.Context, args *Args) error {
283283
}
284284
defer l.Close()
285285
// create handler
286-
h := handler.New(l, u, wd, args.NoPassword)
286+
h := handler.New(l, u, wd, args.NoPassword, args.Conns)
287287
// force password
288288
dsn := args.DSN
289289
if args.ForcePassword {
@@ -337,6 +337,7 @@ type Args struct {
337337
SingleTransaction bool
338338
Variables []string
339339
PVariables []string
340+
Conns map[string]string
340341
}
341342

342343
// CommandOrFile is a special type to deal with interspersed -c, -f,

0 commit comments

Comments
 (0)