Skip to content

Commit acc5f40

Browse files
committed
build: Use urfave/cli for CLI wiring
Signed-off-by: Paulo Gomes <[email protected]>
1 parent f2b5a8e commit acc5f40

31 files changed

+430
-1560
lines changed

.goreleaser.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ builds:
77
- -trimpath
88
ldflags:
99
- -s -w
10-
- -X github.com/qubesome/cli/cmd/version.version={{.Version}}
10+
- -X github.com/qubesome/cli/cmd/cli.version={{.Version}}
1111
goos:
1212
- linux
1313
goarch:

Makefile

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1+
include hack/base.mk
2+
13
TARGET_BIN ?= build/bin/qubesome
24

3-
include hack/base.mk
5+
GO_TAGS = -tags 'netgo,osusergo,static_build'
6+
LDFLAGS = -ldflags '-extldflags -static -s -w -X \
7+
github.com/qubesome/cli/cmd/cli.version=$(VERSION)'
48

59
.PHONY: help
610
help: ## display Makefile's help.
711
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
812

913
.PHONY: build
10-
build: ## build qubesome to the path set on TARGET_BIN.
11-
go build -trimpath -tags 'netgo,osusergo,static_build' -ldflags '-extldflags -static -s -w' -o $(TARGET_BIN) cmd/qubesome/main.go
14+
build: ## build qubesome to the path set by TARGET_BIN.
15+
go build -trimpath $(GO_TAGS) $(LDFLAGS) -o $(TARGET_BIN) cmd/qubesome/main.go
1216

1317
.PHONY: test
1418
test: ## run golang tests.

cmd/cli/clipboard.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/qubesome/cli/internal/clipboard"
8+
"github.com/qubesome/cli/internal/command"
9+
"github.com/urfave/cli/v3"
10+
)
11+
12+
func clipboardCommand() *cli.Command {
13+
clipType := &cli.StringFlag{
14+
Name: "type",
15+
Aliases: []string{"t"},
16+
Validator: func(s string) error {
17+
switch s {
18+
case "image/png":
19+
return nil
20+
}
21+
return fmt.Errorf("unsupported type %q", s)
22+
},
23+
}
24+
25+
cmd := &cli.Command{
26+
Name: "clipboard",
27+
Aliases: []string{"clip"},
28+
Usage: "enable sharing of clipboard across profiles and the host",
29+
Commands: []*cli.Command{
30+
{
31+
Name: "from-host",
32+
Arguments: []cli.Argument{
33+
&cli.StringArg{
34+
Name: "target_profile",
35+
Min: 1,
36+
Max: 1,
37+
Destination: &targetProfile,
38+
},
39+
},
40+
Flags: []cli.Flag{
41+
clipType,
42+
},
43+
Action: func(ctx context.Context, c *cli.Command) error {
44+
cfg := profileConfigOrDefault(targetProfile)
45+
46+
target, ok := cfg.Profiles[targetProfile]
47+
if !ok {
48+
return fmt.Errorf("no active profile %q found", targetProfile)
49+
}
50+
51+
opts := []command.Option[clipboard.Options]{
52+
clipboard.WithFromHost(),
53+
clipboard.WithTargetProfile(target),
54+
}
55+
56+
if typ := c.String("type"); typ != "" {
57+
fmt.Println(typ)
58+
opts = append(opts, clipboard.WithContentType(typ))
59+
}
60+
61+
return clipboard.Run(
62+
opts...,
63+
)
64+
},
65+
},
66+
{
67+
Name: "from-profile",
68+
Arguments: []cli.Argument{
69+
&cli.StringArg{
70+
Name: "source_profile",
71+
Min: 1,
72+
Max: 1,
73+
Destination: &sourceProfile,
74+
},
75+
&cli.StringArg{
76+
Name: "target_profile",
77+
Min: 1,
78+
Max: 1,
79+
Destination: &targetProfile,
80+
},
81+
},
82+
Flags: []cli.Flag{
83+
clipType,
84+
},
85+
Action: func(ctx context.Context, c *cli.Command) error {
86+
cfg := profileConfigOrDefault(targetProfile)
87+
88+
source, ok := cfg.Profiles[sourceProfile]
89+
if !ok {
90+
return fmt.Errorf("no active profile %q found", sourceProfile)
91+
}
92+
93+
target, ok := cfg.Profiles[targetProfile]
94+
if !ok {
95+
return fmt.Errorf("no active profile %q found", targetProfile)
96+
}
97+
98+
opts := []command.Option[clipboard.Options]{
99+
clipboard.WithSourceProfile(source),
100+
clipboard.WithTargetProfile(target),
101+
}
102+
103+
if typ := c.String("type"); typ != "" {
104+
fmt.Println(typ)
105+
opts = append(opts, clipboard.WithContentType(typ))
106+
}
107+
108+
return clipboard.Run(
109+
opts...,
110+
)
111+
},
112+
},
113+
},
114+
}
115+
return cmd
116+
}

cmd/cli/deps.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
6+
"github.com/qubesome/cli/internal/deps"
7+
"github.com/urfave/cli/v3"
8+
)
9+
10+
func depsCommand() *cli.Command {
11+
cmd := &cli.Command{
12+
Name: "deps",
13+
Usage: "shows status of external dependencies",
14+
Action: func(ctx context.Context, cmd *cli.Command) error {
15+
return deps.Run()
16+
},
17+
}
18+
return cmd
19+
}

cmd/cli/images.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
6+
"github.com/qubesome/cli/internal/images"
7+
"github.com/urfave/cli/v3"
8+
)
9+
10+
func imagesCommand() *cli.Command {
11+
cmd := &cli.Command{
12+
Name: "images",
13+
Aliases: []string{"i"},
14+
Usage: "manage workload images",
15+
Commands: []*cli.Command{
16+
{
17+
Name: "pull",
18+
Flags: []cli.Flag{
19+
&cli.StringFlag{
20+
Name: "profile",
21+
Destination: &targetProfile,
22+
},
23+
},
24+
Action: func(ctx context.Context, cmd *cli.Command) error {
25+
cfg := profileConfigOrDefault(targetProfile)
26+
27+
return images.Run(images.WithConfig(cfg))
28+
},
29+
},
30+
},
31+
}
32+
return cmd
33+
}

cmd/cli/root.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"os"
6+
"path/filepath"
7+
8+
"github.com/qubesome/cli/internal/files"
9+
"github.com/qubesome/cli/internal/log"
10+
"github.com/qubesome/cli/internal/types"
11+
"github.com/urfave/cli/v3"
12+
)
13+
14+
var (
15+
targetProfile string
16+
sourceProfile string
17+
gitURL string
18+
workload string
19+
path string
20+
local string
21+
debug bool
22+
)
23+
24+
func RootCommand() *cli.Command {
25+
cmd := &cli.Command{
26+
Commands: []*cli.Command{
27+
startCommand(),
28+
runCommand(),
29+
imagesCommand(),
30+
clipboardCommand(),
31+
xdgCommand(),
32+
depsCommand(),
33+
versionCommand(),
34+
},
35+
}
36+
37+
cmd.Flags = append(cmd.Flags, &cli.BoolFlag{
38+
Name: "debug",
39+
Value: false,
40+
Destination: &debug,
41+
Sources: cli.EnvVars("QS_DEBUG"),
42+
Action: func(ctx context.Context, c *cli.Command, b bool) error {
43+
if debug {
44+
return log.Configure("DEBUG", true, false, false)
45+
}
46+
return nil
47+
},
48+
})
49+
cmd.Version = shortVersion()
50+
cmd.Usage = "A cli to GitOps your dotfiles"
51+
cmd.Suggest = true
52+
cmd.EnableShellCompletion = true
53+
54+
return cmd
55+
}
56+
57+
func config(path string) *types.Config {
58+
if _, err := os.Stat(path); err != nil {
59+
return nil
60+
}
61+
cfg, err := types.LoadConfig(path)
62+
if err != nil {
63+
return nil
64+
}
65+
cfg.RootDir = filepath.Dir(path)
66+
67+
return cfg
68+
}
69+
70+
func profileConfigOrDefault(profile string) *types.Config {
71+
path := files.ProfileConfig(profile)
72+
target, err := os.Readlink(path)
73+
74+
var c *types.Config
75+
if err == nil {
76+
c = config(target)
77+
}
78+
79+
if c != nil {
80+
return c
81+
}
82+
83+
path = files.QubesomeConfig()
84+
return config(path)
85+
}

cmd/cli/run.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
6+
"github.com/qubesome/cli/internal/qubesome"
7+
"github.com/urfave/cli/v3"
8+
)
9+
10+
func runCommand() *cli.Command {
11+
cmd := &cli.Command{
12+
Name: "run",
13+
Aliases: []string{"r"},
14+
Arguments: []cli.Argument{
15+
&cli.StringArg{
16+
Name: "workload",
17+
Min: 1,
18+
Max: 1,
19+
Destination: &workload,
20+
},
21+
},
22+
Flags: []cli.Flag{
23+
&cli.StringFlag{
24+
Name: "profile",
25+
Destination: &targetProfile,
26+
},
27+
},
28+
Usage: "execute workloads",
29+
Action: func(ctx context.Context, cmd *cli.Command) error {
30+
cfg := profileConfigOrDefault(targetProfile)
31+
32+
return qubesome.Run(
33+
qubesome.WithWorkload(workload),
34+
qubesome.WithProfile(targetProfile),
35+
qubesome.WithConfig(cfg),
36+
qubesome.WithExtraArgs(cmd.Args().Slice()),
37+
)
38+
},
39+
}
40+
return cmd
41+
}

cmd/cli/start.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
6+
"github.com/qubesome/cli/internal/profiles"
7+
"github.com/urfave/cli/v3"
8+
)
9+
10+
func startCommand() *cli.Command {
11+
cmd := &cli.Command{
12+
Name: "start",
13+
Aliases: []string{"s"},
14+
Flags: []cli.Flag{
15+
&cli.StringFlag{
16+
Name: "git",
17+
Usage: "git repository URL",
18+
Destination: &gitURL,
19+
},
20+
&cli.StringFlag{
21+
Name: "path",
22+
Usage: "rel path (based on -git / -path) to the dir containing the qubesome.config",
23+
Destination: &path,
24+
},
25+
&cli.StringFlag{
26+
Name: "local",
27+
Usage: "local is the local path for a git repository. This is to be used in combination with --git.",
28+
Destination: &local,
29+
},
30+
},
31+
Arguments: []cli.Argument{
32+
&cli.StringArg{
33+
Name: "profile",
34+
Min: 1,
35+
Max: 1,
36+
Destination: &targetProfile,
37+
},
38+
},
39+
Usage: "start qubesome profiles",
40+
Action: func(ctx context.Context, cmd *cli.Command) error {
41+
cfg := profileConfigOrDefault(targetProfile)
42+
43+
return profiles.Run(
44+
profiles.WithConfig(cfg),
45+
profiles.WithProfile(targetProfile),
46+
profiles.WithGitURL(gitURL),
47+
profiles.WithPath(path),
48+
profiles.WithLocal(local),
49+
)
50+
},
51+
}
52+
return cmd
53+
}

0 commit comments

Comments
 (0)