Skip to content

Commit 60507d5

Browse files
committed
use cobra
Signed-off-by: luyanbo <[email protected]>
1 parent f17506d commit 60507d5

File tree

16 files changed

+422
-380
lines changed

16 files changed

+422
-380
lines changed

cmd/lima-guestagent/daemon_linux.go

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,32 @@ import (
1212
"github.com/lima-vm/lima/pkg/guestagent"
1313
"github.com/lima-vm/lima/pkg/guestagent/api/server"
1414
"github.com/sirupsen/logrus"
15-
"github.com/urfave/cli/v2"
15+
"github.com/spf13/cobra"
1616
)
1717

18-
var daemonCommand = &cli.Command{
19-
Name: "daemon",
20-
Usage: "run the daemon",
21-
Flags: []cli.Flag{
22-
&cli.StringFlag{
23-
Name: "socket",
24-
Usage: "socket",
25-
Value: func() string {
26-
if xrd := os.Getenv("XDG_RUNTIME_DIR"); xrd != "" {
27-
return filepath.Join(xrd, "lima-guestagent.sock")
28-
}
29-
logrus.Warn("$XDG_RUNTIME_DIR is not set, cannot determine the socket name")
30-
return ""
31-
}(),
32-
},
33-
&cli.DurationFlag{
34-
Name: "tick",
35-
Usage: "tick for polling events",
36-
Value: 3 * time.Second,
37-
},
38-
},
39-
Action: daemonAction,
18+
func newDaemonCommand() *cobra.Command {
19+
daemonCommand := &cobra.Command{
20+
Use: "daemon",
21+
Short: "run the daemon",
22+
RunE: daemonAction,
23+
}
24+
daemonCommand.Flags().String("socket", socketDefaultValue(), "the unix socket to listen on")
25+
daemonCommand.Flags().Duration("tick", 3*time.Second, "tick for polling events")
26+
return daemonCommand
4027
}
4128

42-
func daemonAction(clicontext *cli.Context) error {
43-
socket := clicontext.String("socket")
29+
func daemonAction(cmd *cobra.Command, args []string) error {
30+
socket, err := cmd.Flags().GetString("socket")
31+
if err != nil {
32+
return err
33+
}
4434
if socket == "" {
4535
return errors.New("socket must be specified")
4636
}
47-
tick := clicontext.Duration("tick")
37+
tick, err := cmd.Flags().GetDuration("tick")
38+
if err != nil {
39+
return err
40+
}
4841
if tick == 0 {
4942
return errors.New("tick must be specified")
5043
}
@@ -68,7 +61,7 @@ func daemonAction(clicontext *cli.Context) error {
6861
r := mux.NewRouter()
6962
server.AddRoutes(r, backend)
7063
srv := &http.Server{Handler: r}
71-
err := os.RemoveAll(socket)
64+
err = os.RemoveAll(socket)
7265
if err != nil {
7366
return err
7467
}
@@ -79,3 +72,11 @@ func daemonAction(clicontext *cli.Context) error {
7972
logrus.Infof("serving the guest agent on %q", socket)
8073
return srv.Serve(l)
8174
}
75+
76+
func socketDefaultValue() string {
77+
if xrd := os.Getenv("XDG_RUNTIME_DIR"); xrd != "" {
78+
return filepath.Join(xrd, "lima-guestagent.sock")
79+
}
80+
logrus.Warn("$XDG_RUNTIME_DIR is not set, cannot determine the socket name")
81+
return ""
82+
}

cmd/lima-guestagent/install_systemd_linux.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@ import (
1010

1111
"github.com/lima-vm/lima/pkg/templateutil"
1212
"github.com/sirupsen/logrus"
13-
"github.com/urfave/cli/v2"
13+
"github.com/spf13/cobra"
1414
)
1515

16-
var installSystemdCommand = &cli.Command{
17-
Name: "install-systemd",
18-
Usage: "install a systemd unit (user)",
19-
Action: installSystemdAction,
16+
func newInstallSystemdCommand() *cobra.Command {
17+
var installSystemdCommand = &cobra.Command{
18+
Use: "install-systemd",
19+
Short: "install a systemd unit (user)",
20+
RunE: installSystemdAction,
21+
}
22+
return installSystemdCommand
2023
}
2124

22-
func installSystemdAction(clicontext *cli.Context) error {
25+
func installSystemdAction(cmd *cobra.Command, args []string) error {
2326
unit, err := generateSystemdUnit()
2427
if err != nil {
2528
return err

cmd/lima-guestagent/main_linux.go

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,35 @@ import (
77

88
"github.com/lima-vm/lima/pkg/version"
99
"github.com/sirupsen/logrus"
10-
"github.com/urfave/cli/v2"
10+
"github.com/spf13/cobra"
1111
)
1212

1313
func main() {
14-
if err := newApp().Run(os.Args); err != nil {
14+
if err := newApp().Execute(); err != nil {
1515
logrus.Fatal(err)
1616
}
1717
}
1818

19-
func newApp() *cli.App {
20-
app := cli.NewApp()
21-
app.Name = "lima-guestagent"
22-
app.Usage = "Do not launch manually"
23-
app.Version = strings.TrimPrefix(version.Version, "v")
24-
app.Flags = []cli.Flag{
25-
&cli.BoolFlag{
26-
Name: "debug",
27-
Usage: "debug mode",
28-
},
19+
func newApp() *cobra.Command {
20+
var rootCmd = &cobra.Command{
21+
Use: "lima-guestagent",
22+
Short: "Do not launch manually",
23+
Version: strings.TrimPrefix(version.Version, "v"),
2924
}
30-
app.Before = func(clicontext *cli.Context) error {
31-
if clicontext.Bool("debug") {
25+
rootCmd.PersistentFlags().Bool("debug", false, "debug mode")
26+
rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
27+
debug, _ := cmd.Flags().GetBool("debug")
28+
if debug {
3229
logrus.SetLevel(logrus.DebugLevel)
3330
}
3431
if os.Geteuid() == 0 {
3532
return errors.New("must not run as the root")
3633
}
3734
return nil
3835
}
39-
app.Commands = []*cli.Command{
40-
daemonCommand,
41-
installSystemdCommand,
42-
}
43-
return app
36+
rootCmd.AddCommand(
37+
newDaemonCommand(),
38+
newInstallSystemdCommand(),
39+
)
40+
return rootCmd
4441
}

cmd/limactl/completion.go

Lines changed: 4 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,14 @@
1-
// Forked from https://github.com/containerd/nerdctl/blob/v0.8.1/completion.go
2-
3-
/*
4-
Copyright The containerd Authors.
5-
6-
Licensed under the Apache License, Version 2.0 (the "License");
7-
you may not use this file except in compliance with the License.
8-
You may obtain a copy of the License at
9-
10-
http://www.apache.org/licenses/LICENSE-2.0
11-
12-
Unless required by applicable law or agreed to in writing, software
13-
distributed under the License is distributed on an "AS IS" BASIS,
14-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15-
See the License for the specific language governing permissions and
16-
limitations under the License.
17-
*/
18-
191
package main
202

213
import (
22-
"fmt"
23-
244
"github.com/lima-vm/lima/pkg/store"
25-
"github.com/urfave/cli/v2"
5+
"github.com/spf13/cobra"
266
)
277

28-
var completionCommand = &cli.Command{
29-
Name: "completion",
30-
Usage: "Show shell completion",
31-
Subcommands: []*cli.Command{
32-
completionBashCommand,
33-
},
34-
}
35-
36-
var completionBashCommand = &cli.Command{
37-
Name: "bash",
38-
Usage: "Show bash completion (use with `source <(limactl completion bash)`)",
39-
Description: "Usage: add `source <(limactl completion bash)` to ~/.bash_profile",
40-
Action: completionBashAction,
41-
}
42-
43-
func completionBashAction(clicontext *cli.Context) error {
44-
tmpl := `#!/bin/bash
45-
# Autocompletion enabler for limactl.
46-
# Usage: add 'source <(limactl completion bash)' to ~/.bash_profile
47-
48-
# _limactl_bash_autocomplete is forked from https://github.com/urfave/cli/blob/v2.3.0/autocomplete/bash_autocomplete (MIT License)
49-
_limactl_bash_autocomplete() {
50-
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
51-
local cur opts base
52-
COMPREPLY=()
53-
cur="${COMP_WORDS[COMP_CWORD]}"
54-
local args="${COMP_WORDS[@]:0:$COMP_CWORD}"
55-
# make {"limactl", "--foo", "=", "bar"} into {"limactl", "--foo=bar"}
56-
args="$(echo $args | sed -e 's/ = /=/g')"
57-
if [[ "$cur" == "-"* ]]; then
58-
opts=$( ${args} ${cur} --generate-bash-completion )
59-
else
60-
opts=$( ${args} --generate-bash-completion )
61-
fi
62-
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
63-
return 0
64-
fi
65-
}
66-
67-
complete -o bashdefault -o default -o nospace -F _limactl_bash_autocomplete limactl
68-
`
69-
_, err := fmt.Fprint(clicontext.App.Writer, tmpl)
70-
return err
71-
}
72-
73-
func bashCompleteInstanceNames(clicontext *cli.Context) {
74-
w := clicontext.App.Writer
8+
func bashCompleteInstanceNames(cmd *cobra.Command) ([]string, cobra.ShellCompDirective) {
759
instances, err := store.Instances()
7610
if err != nil {
77-
return
78-
}
79-
for _, name := range instances {
80-
fmt.Fprintln(w, name)
11+
return nil, cobra.ShellCompDirectiveDefault
8112
}
13+
return instances, cobra.ShellCompDirectiveNoFileComp
8214
}

cmd/limactl/copy.go

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,30 @@ import (
1111
"github.com/lima-vm/lima/pkg/sshutil"
1212
"github.com/lima-vm/lima/pkg/store"
1313
"github.com/sirupsen/logrus"
14-
"github.com/urfave/cli/v2"
14+
"github.com/spf13/cobra"
1515
)
1616

17-
var copyCommand = &cli.Command{
18-
Name: "copy",
19-
Aliases: []string{"cp"},
20-
Usage: "Copy files between host and guest",
21-
Description: "Prefix guest filenames with the instance name and a colon.\nExample: limactl copy default:/etc/os-release .",
22-
ArgsUsage: "SOURCE ... TARGET",
23-
Action: copyAction,
24-
}
17+
var copyHelp = `Copy files between host and guest
18+
19+
Prefix guest filenames with the instance name and a colon.
20+
21+
Example: limactl copy default:/etc/os-release .
22+
`
2523

26-
func copyAction(clicontext *cli.Context) error {
27-
if clicontext.NArg() < 2 {
28-
return fmt.Errorf("requires at least 2 arguments: SOURCE DEST")
24+
func newCopyCommand() *cobra.Command {
25+
var copyCommand = &cobra.Command{
26+
Use: "copy SOURCE ... TARGET",
27+
Aliases: []string{"cp"},
28+
Short: "Copy files between host and guest",
29+
Long: copyHelp,
30+
Args: cobra.MinimumNArgs(2),
31+
RunE: copyAction,
2932
}
33+
34+
return copyCommand
35+
}
36+
37+
func copyAction(cmd *cobra.Command, args []string) error {
3038
arg0, err := exec.LookPath("scp")
3139
if err != nil {
3240
return err
@@ -37,12 +45,20 @@ func copyAction(clicontext *cli.Context) error {
3745
}
3846

3947
instDirs := make(map[string]string)
40-
args := []string{"-3", "--"}
41-
for _, arg := range clicontext.Args().Slice() {
48+
scpArgs := []string{}
49+
debug, err := cmd.Flags().GetBool("debug")
50+
if err != nil {
51+
return err
52+
}
53+
if debug {
54+
scpArgs = append(scpArgs, "-v")
55+
}
56+
scpArgs = append(scpArgs, "-3", "--")
57+
for _, arg := range args {
4258
path := strings.Split(arg, ":")
4359
switch len(path) {
4460
case 1:
45-
args = append(args, arg)
61+
scpArgs = append(scpArgs, arg)
4662
case 2:
4763
instName := path[0]
4864
inst, err := store.Inspect(instName)
@@ -55,10 +71,10 @@ func copyAction(clicontext *cli.Context) error {
5571
if inst.Status == store.StatusStopped {
5672
return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName)
5773
}
58-
args = append(args, fmt.Sprintf("scp://%[email protected]:%d/%s", u.Username, inst.SSHLocalPort, path[1]))
74+
scpArgs = append(scpArgs, fmt.Sprintf("scp://%[email protected]:%d/%s", u.Username, inst.SSHLocalPort, path[1]))
5975
instDirs[instName] = inst.Dir
6076
default:
61-
return fmt.Errorf("Path %q contains multiple colons", arg)
77+
return fmt.Errorf("path %q contains multiple colons", arg)
6278
}
6379
}
6480

@@ -81,12 +97,12 @@ func copyAction(clicontext *cli.Context) error {
8197
}
8298
}
8399

84-
cmd := exec.Command(arg0, append(sshArgs, args...)...)
85-
cmd.Stdin = os.Stdin
86-
cmd.Stdout = os.Stdout
87-
cmd.Stderr = os.Stderr
88-
logrus.Debugf("executing scp (may take a long time)): %+v", cmd.Args)
100+
sshCmd := exec.Command(arg0, append(sshArgs, scpArgs...)...)
101+
sshCmd.Stdin = cmd.InOrStdin()
102+
sshCmd.Stdout = cmd.OutOrStdout()
103+
sshCmd.Stderr = cmd.ErrOrStderr()
104+
logrus.Debugf("executing scp (may take a long time)): %+v", sshCmd.Args)
89105

90106
// TODO: use syscall.Exec directly (results in losing tty?)
91-
return cmd.Run()
107+
return sshCmd.Run()
92108
}

0 commit comments

Comments
 (0)