Skip to content

Commit 4a3346f

Browse files
pieternclaude
andauthored
Use env.UserHomeDir(ctx) instead of os.UserHomeDir() (#4654)
## Summary - Convert `os.UserHomeDir()` to `env.UserHomeDir(ctx)` at callsites where context is available - Makes home directory resolution context-aware, enabling test overrides - Covers `cmd/completion`, `libs/databrickscfg`, `experimental/aitools`, `experimental/ssh/internal/server`, and internal test utilities - Thread ctx through `InstallMCP` and agent `ConfigDir` function signatures - Add `forbidigo` linter rule to reject new `os.UserHomeDir()` calls - Remaining callsites in `libs/git` and `experimental/ssh` (public API changes) are annotated with `nolint` and left for separate PRs ## Test plan - [x] All modified packages compile - [x] `experimental/aitools` tests pass - [x] `make lintfull` passes with zero issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 85f43e9 commit 4a3346f

File tree

25 files changed

+91
-82
lines changed

25 files changed

+91
-82
lines changed

.golangci.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ linters:
2828
msg: Use cmdio.IsPromptSupported(ctx) to check for a TTY.
2929
- pattern: 'isatty\.IsCygwinTerminal'
3030
msg: Use cmdio.IsPromptSupported(ctx) to check for a TTY.
31+
- pattern: 'os\.UserHomeDir'
32+
msg: Use env.UserHomeDir(ctx) from libs/env instead.
3133
analyze-types: true
3234
copyloopvar:
3335
check-alias: true

cmd/apps/init.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ func runCreate(ctx context.Context, opts createOptions) error {
871871
// Recommend skills installation if coding agents are detected without skills.
872872
// In flags mode, only print a hint — never prompt interactively.
873873
if flagsMode {
874-
if !agents.HasDatabricksSkillsInstalled() {
874+
if !agents.HasDatabricksSkillsInstalled(ctx) {
875875
cmdio.LogString(ctx, "Tip: coding agents detected without Databricks skills. Run 'databricks experimental aitools skills install' to install them.")
876876
}
877877
} else if err := agents.RecommendSkillsInstall(ctx, installer.InstallAllSkills); err != nil {

cmd/completion/install.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package completion
33
import (
44
"errors"
55
"fmt"
6-
"os"
76
"path/filepath"
87

98
"github.com/databricks/cli/libs/cmdio"
109
libcompletion "github.com/databricks/cli/libs/completion"
10+
"github.com/databricks/cli/libs/env"
1111
"github.com/spf13/cobra"
1212
)
1313

@@ -28,7 +28,7 @@ func newInstallCmd() *cobra.Command {
2828
return err
2929
}
3030

31-
home, err := os.UserHomeDir()
31+
home, err := env.UserHomeDir(ctx)
3232
if err != nil {
3333
return err
3434
}

cmd/completion/status.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package completion
22

33
import (
44
"fmt"
5-
"os"
65
"path/filepath"
76

87
"github.com/databricks/cli/libs/cmdio"
98
libcompletion "github.com/databricks/cli/libs/completion"
9+
"github.com/databricks/cli/libs/env"
1010
"github.com/spf13/cobra"
1111
)
1212

@@ -26,7 +26,7 @@ func newStatusCmd() *cobra.Command {
2626
return err
2727
}
2828

29-
home, err := os.UserHomeDir()
29+
home, err := env.UserHomeDir(ctx)
3030
if err != nil {
3131
return err
3232
}

cmd/completion/uninstall.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package completion
33
import (
44
"errors"
55
"fmt"
6-
"os"
76
"path/filepath"
87

98
"github.com/databricks/cli/libs/cmdio"
109
libcompletion "github.com/databricks/cli/libs/completion"
10+
"github.com/databricks/cli/libs/env"
1111
"github.com/spf13/cobra"
1212
)
1313

@@ -28,7 +28,7 @@ func newUninstallCmd() *cobra.Command {
2828
return err
2929
}
3030

31-
home, err := os.UserHomeDir()
31+
home, err := env.UserHomeDir(ctx)
3232
if err != nil {
3333
return err
3434
}

experimental/aitools/cmd/install.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func runInstall(ctx context.Context) error {
3939
}
4040

4141
if targetAgent != nil && targetAgent.InstallMCP != nil {
42-
if err := targetAgent.InstallMCP(); err != nil {
42+
if err := targetAgent.InstallMCP(ctx); err != nil {
4343
return err
4444
}
4545
cmdio.LogString(ctx, color.GreenString("✓ Installed Databricks MCP server for %s", targetAgent.DisplayName))
@@ -81,7 +81,7 @@ func runInstall(ctx context.Context) error {
8181
}
8282
if ans == "yes" {
8383
fmt.Fprintf(os.Stderr, "Installing MCP server for %s...", a.DisplayName)
84-
if err := a.InstallMCP(); err != nil {
84+
if err := a.InstallMCP(ctx); err != nil {
8585
fmt.Fprint(os.Stderr, "\r"+color.YellowString("⊘ Skipped %s: %s", a.DisplayName, err.Error())+"\n")
8686
} else {
8787
// Brief delay so users see the "Installing..." message before it's replaced

experimental/aitools/lib/agents/agents.go

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package agents
22

33
import (
4+
"context"
45
"os"
56
"path/filepath"
6-
"runtime"
7+
8+
"github.com/databricks/cli/libs/env"
79
)
810

911
// Agent defines a coding agent that can have skills installed and optionally MCP server.
@@ -12,17 +14,17 @@ type Agent struct {
1214
DisplayName string
1315
// ConfigDir returns the agent's config directory (e.g., ~/.claude).
1416
// Used for detection and as base for skills directory.
15-
ConfigDir func() (string, error)
17+
ConfigDir func(ctx context.Context) (string, error)
1618
// SkillsSubdir is the subdirectory within ConfigDir for skills (default: "skills").
1719
SkillsSubdir string
1820
// InstallMCP installs the Databricks MCP server for this agent.
1921
// Nil if agent doesn't support MCP or we haven't implemented it.
20-
InstallMCP func() error
22+
InstallMCP func(ctx context.Context) error
2123
}
2224

2325
// Detected returns true if the agent is installed on the system.
24-
func (a *Agent) Detected() bool {
25-
dir, err := a.ConfigDir()
26+
func (a *Agent) Detected(ctx context.Context) bool {
27+
dir, err := a.ConfigDir(ctx)
2628
if err != nil {
2729
return false
2830
}
@@ -31,8 +33,8 @@ func (a *Agent) Detected() bool {
3133
}
3234

3335
// SkillsDir returns the full path to the agent's skills directory.
34-
func (a *Agent) SkillsDir() (string, error) {
35-
configDir, err := a.ConfigDir()
36+
func (a *Agent) SkillsDir(ctx context.Context) (string, error) {
37+
configDir, err := a.ConfigDir(ctx)
3638
if err != nil {
3739
return "", err
3840
}
@@ -43,20 +45,10 @@ func (a *Agent) SkillsDir() (string, error) {
4345
return filepath.Join(configDir, subdir), nil
4446
}
4547

46-
// getHomeDir returns home directory, handling Windows USERPROFILE.
47-
func getHomeDir() (string, error) {
48-
if runtime.GOOS == "windows" {
49-
if userProfile := os.Getenv("USERPROFILE"); userProfile != "" {
50-
return userProfile, nil
51-
}
52-
}
53-
return os.UserHomeDir()
54-
}
55-
5648
// homeSubdir returns a function that computes ~/subpath.
57-
func homeSubdir(subpath ...string) func() (string, error) {
58-
return func() (string, error) {
59-
home, err := getHomeDir()
49+
func homeSubdir(subpath ...string) func(ctx context.Context) (string, error) {
50+
return func(ctx context.Context) (string, error) {
51+
home, err := env.UserHomeDir(ctx)
6052
if err != nil {
6153
return "", err
6254
}
@@ -103,10 +95,10 @@ var Registry = []Agent{
10395
}
10496

10597
// DetectInstalled returns all agents that are installed on the system.
106-
func DetectInstalled() []*Agent {
98+
func DetectInstalled(ctx context.Context) []*Agent {
10799
var installed []*Agent
108100
for i := range Registry {
109-
if Registry[i].Detected() {
101+
if Registry[i].Detected(ctx) {
110102
installed = append(installed, &Registry[i])
111103
}
112104
}

experimental/aitools/lib/agents/claude.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package agents
22

33
import (
4+
"context"
45
"errors"
56
"fmt"
67
"os"
78
"os/exec"
89
)
910

1011
// InstallClaude installs the Databricks AI Tools MCP server in Claude Code.
11-
func InstallClaude() error {
12+
func InstallClaude(_ context.Context) error {
1213
// Check if claude CLI is available
1314
if _, err := exec.LookPath("claude"); err != nil {
1415
return errors.New("'claude' CLI is not installed or not on PATH\n\nPlease install Claude Code and ensure 'claude' is available on your system PATH.\nFor installation instructions, visit: https://docs.anthropic.com/en/docs/claude-code")

experimental/aitools/lib/agents/cursor.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package agents
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"os"
78
"path/filepath"
9+
10+
"github.com/databricks/cli/libs/env"
811
)
912

1013
type cursorConfig struct {
@@ -18,11 +21,12 @@ type mcpServer struct {
1821
}
1922

2023
// InstallCursor installs the Databricks AI Tools MCP server in Cursor.
21-
func InstallCursor() error {
22-
configDir, err := homeSubdir(".cursor")()
24+
func InstallCursor(ctx context.Context) error {
25+
home, err := env.UserHomeDir(ctx)
2326
if err != nil {
2427
return fmt.Errorf("failed to determine Cursor config path: %w", err)
2528
}
29+
configDir := filepath.Join(home, ".cursor")
2630

2731
// Check if .cursor directory exists
2832
if _, err := os.Stat(configDir); err != nil {

experimental/aitools/lib/agents/recommend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
// RecommendSkillsInstall checks if coding agents are detected but have no skills installed.
1111
// In interactive mode, prompts the user to install now using installFn. In non-interactive mode, prints a hint.
1212
func RecommendSkillsInstall(ctx context.Context, installFn func(context.Context) error) error {
13-
if HasDatabricksSkillsInstalled() {
13+
if HasDatabricksSkillsInstalled(ctx) {
1414
return nil
1515
}
1616

0 commit comments

Comments
 (0)