Skip to content

Commit 5ddceca

Browse files
committed
refactor(cli): rename and move root validation
1 parent a5c4373 commit 5ddceca

2 files changed

Lines changed: 36 additions & 15 deletions

File tree

internal/cli/root.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import (
55
"errors"
66
"fmt"
77
"os"
8-
"os/exec"
98

109
"github.com/urfave/cli/v3"
1110

11+
"github.com/89luca89/distrobox/internal/rootful"
1212
"github.com/89luca89/distrobox/pkg/config"
1313
"github.com/89luca89/distrobox/pkg/containermanager"
1414
"github.com/89luca89/distrobox/pkg/containermanager/providers"
@@ -55,19 +55,6 @@ func printInvalidContainerManager(p *ui.Printer, containerManagerType string) {
5555
p.Println("The available choices are: 'autodetect', 'podman', 'podman-launcher', 'docker'")
5656
}
5757

58-
func validateSudo(ctx context.Context) error {
59-
cmd := exec.CommandContext(ctx, "sudo", "-v")
60-
cmd.Stdin = os.Stdin
61-
cmd.Stdout = os.Stdout
62-
cmd.Stderr = os.Stderr
63-
64-
if err := cmd.Run(); err != nil {
65-
return fmt.Errorf("failed to validate sudo: %w", err)
66-
}
67-
68-
return nil
69-
}
70-
7158
func subcommands(cfg *config.Values) []*cli.Command {
7259
return []*cli.Command{
7360
composeCommand(
@@ -152,7 +139,7 @@ func withRoot(_ *config.Values, cmd *cli.Command) *cli.Command {
152139
}
153140
}
154141
if c.Bool("root") {
155-
if err := validateSudo(ctx); err != nil {
142+
if err := rootful.Validate(ctx); err != nil {
156143
return nil, fmt.Errorf("cannot run in root mode: %w", err)
157144
}
158145
}

internal/rootful/rootful.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Package rootful provides utilities for running operations that require
2+
// root privileges via sudo.
3+
package rootful
4+
5+
import (
6+
"context"
7+
"fmt"
8+
"os"
9+
"os/exec"
10+
"sync"
11+
)
12+
13+
//nolint:gochecknoglobals // singleton: process-wide memoization is the intent
14+
var (
15+
validateOnce sync.Once
16+
errValidate error
17+
)
18+
19+
// Validate ensures that sudo is available and the user can elevate.
20+
// It runs `sudo -v` at most once per process: the first call performs the
21+
// check and caches the result; subsequent calls return the cached result
22+
// without re-running the command.
23+
func Validate(ctx context.Context) error {
24+
validateOnce.Do(func() {
25+
cmd := exec.CommandContext(ctx, "sudo", "-v")
26+
cmd.Stdin = os.Stdin
27+
cmd.Stdout = os.Stdout
28+
cmd.Stderr = os.Stderr
29+
if err := cmd.Run(); err != nil {
30+
errValidate = fmt.Errorf("failed to validate sudo: %w", err)
31+
}
32+
})
33+
return errValidate
34+
}

0 commit comments

Comments
 (0)