X Tutup
Skip to content

Commit 2b9de23

Browse files
committed
Extract alias expansion into a separate package
1 parent 172ea2b commit 2b9de23

File tree

7 files changed

+329
-372
lines changed

7 files changed

+329
-372
lines changed

cmd/gen-docs/main.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import (
55
"os"
66
"strings"
77

8-
"github.com/cli/cli/command"
8+
"github.com/cli/cli/pkg/cmd/root"
9+
"github.com/cli/cli/pkg/cmdutil"
10+
"github.com/cli/cli/pkg/iostreams"
911
"github.com/spf13/cobra/doc"
1012
"github.com/spf13/pflag"
1113
)
@@ -35,13 +37,16 @@ func main() {
3537
fatal("no dir set")
3638
}
3739

40+
io, _, _, _ := iostreams.Test()
41+
rootCmd := root.NewCmdRoot(&cmdutil.Factory{IOStreams: io}, "", "")
42+
3843
err := os.MkdirAll(*dir, 0755)
3944
if err != nil {
4045
fatal(err)
4146
}
4247

4348
if *website {
44-
err = doc.GenMarkdownTreeCustom(command.RootCmd, *dir, filePrepender, linkHandler)
49+
err = doc.GenMarkdownTreeCustom(rootCmd, *dir, filePrepender, linkHandler)
4550
if err != nil {
4651
fatal(err)
4752
}
@@ -54,7 +59,7 @@ func main() {
5459
Source: "", //source and manual are just put at the top of the manpage, before name
5560
Manual: "", //if source is an empty string, it's set to "Auto generated by spf13/cobra"
5661
}
57-
err = doc.GenManTree(command.RootCmd, header, *dir)
62+
err = doc.GenManTree(rootCmd, header, *dir)
5863
if err != nil {
5964
fatal(err)
6065
}

cmd/gh/main.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import (
1212

1313
"github.com/cli/cli/command"
1414
"github.com/cli/cli/internal/config"
15+
"github.com/cli/cli/internal/run"
16+
"github.com/cli/cli/pkg/cmd/alias/expand"
17+
"github.com/cli/cli/pkg/cmd/factory"
1518
"github.com/cli/cli/pkg/cmd/root"
1619
"github.com/cli/cli/pkg/cmdutil"
1720
"github.com/cli/cli/update"
@@ -32,25 +35,44 @@ func main() {
3235

3336
hasDebug := os.Getenv("DEBUG") != ""
3437

35-
stderr := utils.NewColorable(os.Stderr)
38+
cmdFactory := factory.New(command.Version)
39+
stderr := cmdFactory.IOStreams.ErrOut
40+
rootCmd := root.NewCmdRoot(cmdFactory, command.Version, command.BuildDate)
3641

3742
expandedArgs := []string{}
3843
if len(os.Args) > 0 {
3944
expandedArgs = os.Args[1:]
4045
}
4146

42-
cmd, _, err := command.RootCmd.Traverse(expandedArgs)
43-
if err != nil || cmd == command.RootCmd {
47+
cmd, _, err := rootCmd.Traverse(expandedArgs)
48+
if err != nil || cmd == rootCmd {
4449
originalArgs := expandedArgs
4550
isShell := false
46-
expandedArgs, isShell, err = command.ExpandAlias(os.Args)
51+
52+
cfg, err := cmdFactory.Config()
53+
if err != nil {
54+
fmt.Fprintf(stderr, "failed to read configuration: %s\n", err)
55+
os.Exit(2)
56+
}
57+
58+
expandedArgs, isShell, err = expand.ExpandAlias(cfg, os.Args, nil)
4759
if err != nil {
4860
fmt.Fprintf(stderr, "failed to process aliases: %s\n", err)
4961
os.Exit(2)
5062
}
5163

64+
if hasDebug {
65+
fmt.Fprintf(stderr, "%v -> %v\n", originalArgs, expandedArgs)
66+
}
67+
5268
if isShell {
53-
err = command.ExecuteShellAlias(expandedArgs)
69+
externalCmd := exec.Command(expandedArgs[0], expandedArgs[1:]...)
70+
externalCmd.Stderr = os.Stderr
71+
externalCmd.Stdout = os.Stdout
72+
externalCmd.Stdin = os.Stdin
73+
preparedCmd := run.PrepareCmd(externalCmd)
74+
75+
err = preparedCmd.Run()
5476
if err != nil {
5577
if ee, ok := err.(*exec.ExitError); ok {
5678
os.Exit(ee.ExitCode())
@@ -62,16 +84,12 @@ func main() {
6284

6385
os.Exit(0)
6486
}
65-
66-
if hasDebug {
67-
fmt.Fprintf(stderr, "%v -> %v\n", originalArgs, expandedArgs)
68-
}
6987
}
7088

71-
command.RootCmd.SetArgs(expandedArgs)
89+
rootCmd.SetArgs(expandedArgs)
7290

73-
if cmd, err := command.RootCmd.ExecuteC(); err != nil {
74-
printError(os.Stderr, err, cmd, hasDebug)
91+
if cmd, err := rootCmd.ExecuteC(); err != nil {
92+
printError(stderr, err, cmd, hasDebug)
7593
os.Exit(1)
7694
}
7795
if root.HasFailed() {
@@ -86,7 +104,6 @@ func main() {
86104
ansi.Color(newRelease.Version, "cyan"),
87105
ansi.Color(newRelease.URL, "yellow"))
88106

89-
stderr := utils.NewColorable(os.Stderr)
90107
fmt.Fprintf(stderr, "\n\n%s\n\n", msg)
91108
}
92109
}

command/alias_test.go

Lines changed: 0 additions & 109 deletions
This file was deleted.

command/root.go

Lines changed: 0 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,15 @@
11
package command
22

33
import (
4-
"errors"
54
"fmt"
65
"os"
7-
"os/exec"
8-
"path/filepath"
9-
"regexp"
10-
"runtime"
116
"runtime/debug"
127
"strings"
138

149
"github.com/cli/cli/api"
15-
"github.com/cli/cli/context"
1610
"github.com/cli/cli/internal/config"
1711
"github.com/cli/cli/internal/ghinstance"
18-
"github.com/cli/cli/internal/run"
19-
"github.com/cli/cli/pkg/cmd/factory"
20-
"github.com/cli/cli/pkg/cmd/root"
2112
"github.com/cli/cli/utils"
22-
"github.com/google/shlex"
23-
"github.com/spf13/cobra"
2413
)
2514

2615
// Version is dynamically set by the toolchain or overridden by the Makefile.
@@ -29,22 +18,12 @@ var Version = "DEV"
2918
// BuildDate is dynamically set at build time in the Makefile.
3019
var BuildDate = "" // YYYY-MM-DD
3120

32-
var RootCmd *cobra.Command
33-
3421
func init() {
3522
if Version == "DEV" {
3623
if info, ok := debug.ReadBuildInfo(); ok && info.Main.Version != "(devel)" {
3724
Version = info.Main.Version
3825
}
3926
}
40-
41-
cmdFactory := factory.New(Version)
42-
RootCmd = root.NewCmdRoot(cmdFactory, Version, BuildDate)
43-
}
44-
45-
// overridden in tests
46-
var initContext = func() context.Context {
47-
return context.New()
4827
}
4928

5029
// BasicClient returns an API client for github.com only that borrows from but
@@ -73,110 +52,3 @@ func apiVerboseLog() api.ClientOption {
7352
colorize := utils.IsTerminal(os.Stderr)
7453
return api.VerboseLog(utils.NewColorable(os.Stderr), logTraffic, colorize)
7554
}
76-
77-
func ExecuteShellAlias(args []string) error {
78-
externalCmd := exec.Command(args[0], args[1:]...)
79-
externalCmd.Stderr = os.Stderr
80-
externalCmd.Stdout = os.Stdout
81-
externalCmd.Stdin = os.Stdin
82-
preparedCmd := run.PrepareCmd(externalCmd)
83-
84-
return preparedCmd.Run()
85-
}
86-
87-
var findSh = func() (string, error) {
88-
shPath, err := exec.LookPath("sh")
89-
if err == nil {
90-
return shPath, nil
91-
}
92-
93-
if runtime.GOOS == "windows" {
94-
winNotFoundErr := errors.New("unable to locate sh to execute the shell alias with. The sh.exe interpreter is typically distributed with Git for Windows.")
95-
// We can try and find a sh executable in a Git for Windows install
96-
gitPath, err := exec.LookPath("git")
97-
if err != nil {
98-
return "", winNotFoundErr
99-
}
100-
101-
shPath = filepath.Join(filepath.Dir(gitPath), "..", "bin", "sh.exe")
102-
_, err = os.Stat(shPath)
103-
if err != nil {
104-
return "", winNotFoundErr
105-
}
106-
107-
return shPath, nil
108-
}
109-
110-
return "", errors.New("unable to locate sh to execute shell alias with")
111-
}
112-
113-
// ExpandAlias processes argv to see if it should be rewritten according to a user's aliases. The
114-
// second return value indicates whether the alias should be executed in a new shell process instead
115-
// of running gh itself.
116-
func ExpandAlias(args []string) (expanded []string, isShell bool, err error) {
117-
err = nil
118-
isShell = false
119-
expanded = []string{}
120-
121-
if len(args) < 2 {
122-
// the command is lacking a subcommand
123-
return
124-
}
125-
126-
ctx := initContext()
127-
cfg, err := ctx.Config()
128-
if err != nil {
129-
return
130-
}
131-
aliases, err := cfg.Aliases()
132-
if err != nil {
133-
return
134-
}
135-
136-
expansion, ok := aliases.Get(args[1])
137-
if ok {
138-
if strings.HasPrefix(expansion, "!") {
139-
isShell = true
140-
shPath, shErr := findSh()
141-
if shErr != nil {
142-
err = shErr
143-
return
144-
}
145-
146-
expanded = []string{shPath, "-c", expansion[1:]}
147-
148-
if len(args[2:]) > 0 {
149-
expanded = append(expanded, "--")
150-
expanded = append(expanded, args[2:]...)
151-
}
152-
153-
return
154-
}
155-
156-
extraArgs := []string{}
157-
for i, a := range args[2:] {
158-
if !strings.Contains(expansion, "$") {
159-
extraArgs = append(extraArgs, a)
160-
} else {
161-
expansion = strings.ReplaceAll(expansion, fmt.Sprintf("$%d", i+1), a)
162-
}
163-
}
164-
lingeringRE := regexp.MustCompile(`\$\d`)
165-
if lingeringRE.MatchString(expansion) {
166-
err = fmt.Errorf("not enough arguments for alias: %s", expansion)
167-
return
168-
}
169-
170-
var newArgs []string
171-
newArgs, err = shlex.Split(expansion)
172-
if err != nil {
173-
return
174-
}
175-
176-
expanded = append(newArgs, extraArgs...)
177-
return
178-
}
179-
180-
expanded = args[1:]
181-
return
182-
}

0 commit comments

Comments
 (0)
X Tutup