Skip to content

Commit d3f4133

Browse files
authored
fix(runtime): filter shims directory from PATH in DetectInstalled (#126)
1 parent 699a504 commit d3f4133

8 files changed

Lines changed: 348 additions & 205 deletions

File tree

.github/workflows/build.yml

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,14 @@ jobs:
6464
with:
6565
go-version: '1.23'
6666

67-
- name: Install golangci-lint
68-
run: |
69-
# Download and install golangci-lint v2.6.2
70-
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.6.2
71-
golangci-lint --version
72-
7367
- name: Run golangci-lint
74-
run: GOOS=${{ matrix.goos }} golangci-lint run --timeout=5m --config=../.golangci.yml
75-
working-directory: src
68+
uses: golangci/golangci-lint-action@v7
69+
with:
70+
version: v2.6.2
71+
working-directory: src
72+
args: --timeout=5m --config=../.golangci.yml
73+
env:
74+
GOOS: ${{ matrix.goos }}
7675

7776
- name: Verify no linting issues
7877
if: success()

.golangci.yml

Lines changed: 85 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,32 @@
11
# golangci-lint configuration for dtvem
2-
# Documentation: https://golangci-lint.run/usage/configuration/
2+
# Documentation: https://golangci-lint.run/docs/configuration/file/
33

4-
# Config version
5-
version: 2
4+
# Config version (must be a string for v2.x)
5+
version: "2"
66

77
run:
88
# Timeout for analysis
99
timeout: 5m
10-
1110
# Include test files in linting
1211
tests: true
1312

14-
# Output configuration
13+
# Output configuration (v2.x format)
1514
output:
16-
# Colored output
17-
format: colored-line-number
18-
19-
# Print lines of code with issue
20-
print-issued-lines: true
21-
22-
# Print linter name in the end of issue text
23-
print-linter-name: true
24-
25-
# Make issues output unique by line
26-
uniq-by-line: true
27-
28-
# Sort results by: filepath, line and column
29-
sort-results: true
30-
31-
# Linters configuration
15+
formats:
16+
text:
17+
path: stdout
18+
colors: true
19+
# Sort results by file, linter, severity
20+
sort-order:
21+
- file
22+
- linter
23+
# Show statistics
24+
show-stats: true
25+
26+
# Linters configuration (v2.x format)
3227
linters:
33-
# Disable all linters by default
34-
disable-all: true
35-
36-
# Explicitly disable warning-only linters
37-
disable:
38-
- staticcheck # Code improvement suggestions
39-
- revive # Style suggestions
40-
- prealloc # Performance hints
41-
- gosec # Security false positives
28+
# Start with no linters enabled
29+
default: none
4230

4331
# Enable specific linters
4432
enable:
@@ -62,115 +50,73 @@ linters:
6250
- nilerr # Find code that returns nil even if it checks that the error is not nil
6351
- nilnil # Checks that there is no simultaneous return of nil error and invalid value
6452

65-
# WARNINGS ONLY (disabled to prevent CI failure)
66-
# These are style/security suggestions that should not fail the build
67-
# Re-enable locally with: golangci-lint run --enable-all
68-
# - staticcheck # Code improvement suggestions (QF quick-fixes)
69-
# - revive # Style suggestions (comment formatting, etc.)
70-
# - prealloc # Performance hints
71-
# - gosec # Security warnings (often false positives)
72-
73-
linters-settings:
74-
# Settings for errcheck
75-
errcheck:
76-
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`
77-
check-type-assertions: true
78-
79-
# Report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`
80-
check-blank: false
81-
82-
# List of functions to exclude from checking
83-
exclude-functions:
84-
- (*os.File).Close
85-
- (*database/sql.Rows).Close
86-
87-
# Settings for govet
88-
govet:
89-
# Enable all analyzers
90-
enable-all: true
91-
# Disable specific analyzers
92-
disable:
93-
- shadow # Reports variables that shadow other variables (can be too noisy)
94-
95-
# Settings for gocyclo (cyclomatic complexity)
96-
gocyclo:
97-
# Minimal code complexity to report
98-
min-complexity: 15
99-
100-
# Settings for dupl (code duplication)
101-
dupl:
102-
# Threshold for duplicate code detection
103-
threshold: 100
104-
105-
# Settings for goconst
106-
goconst:
107-
# Minimal length of string constant
108-
min-len: 3
109-
# Minimum occurrences count to trigger issue
110-
min-occurrences: 3
111-
# Ignore test files
112-
ignore-tests: true
113-
114-
# Settings for misspell
115-
misspell:
116-
# Correct spellings using locale preferences
117-
locale: US
118-
119-
# DISABLED LINTER SETTINGS (commented out since linters are disabled above)
120-
# Uncomment these when re-enabling the corresponding linters
121-
122-
# # Settings for revive (replacement for golint)
123-
# revive:
124-
# enable-all-rules: false
125-
# rules:
126-
# # ... (keep original rules for reference)
127-
128-
# # Settings for gosec (security)
129-
# gosec:
130-
# tests: true
131-
# excludes:
132-
# - G304 # File path provided as taint input
133-
134-
# # Settings for staticcheck
135-
# staticcheck:
136-
# checks: ["all"]
137-
138-
# Issues configuration
53+
# Linter-specific settings (moved from top-level linters-settings)
54+
settings:
55+
# Settings for errcheck
56+
errcheck:
57+
# Report about not checking of errors in type assertions
58+
check-type-assertions: true
59+
# Report about assignment of errors to blank identifier
60+
check-blank: false
61+
# List of functions to exclude from checking
62+
exclude-functions:
63+
- (*os.File).Close
64+
- (*database/sql.Rows).Close
65+
66+
# Settings for govet
67+
govet:
68+
# Enable all analyzers
69+
enable-all: true
70+
# Disable specific analyzers
71+
disable:
72+
- shadow # Reports variables that shadow other variables (can be too noisy)
73+
- fieldalignment # Reports struct field ordering for memory optimization (too noisy)
74+
75+
# Settings for gocyclo (cyclomatic complexity)
76+
gocyclo:
77+
# Minimal code complexity to report (25 allows for existing complex functions)
78+
min-complexity: 25
79+
80+
# Settings for dupl (code duplication)
81+
dupl:
82+
# Threshold for duplicate code detection
83+
threshold: 100
84+
85+
# Settings for goconst
86+
goconst:
87+
# Minimal length of string constant
88+
min-len: 3
89+
# Minimum occurrences count to trigger issue
90+
min-occurrences: 3
91+
92+
# Settings for misspell
93+
misspell:
94+
# Correct spellings using locale preferences
95+
locale: US
96+
97+
# Exclusion rules (moved from issues section in v1.x)
98+
exclusions:
99+
# Generated files should be ignored
100+
generated: lax
101+
# Paths to exclude
102+
paths:
103+
- vendor
104+
- dist
105+
- .claude
106+
- ".*\\.pb\\.go$"
107+
# Rules to exclude specific linters in specific paths
108+
rules:
109+
# Ignore duplicate code and repeated strings in test files (test tables often have similar structure)
110+
- linters:
111+
- dupl
112+
- goconst
113+
path: "_test\\.go$"
114+
115+
# Issues configuration (v2.x format)
139116
issues:
140-
# Which dirs to skip: issues from them won't be reported
141-
exclude-dirs:
142-
- vendor
143-
- dist
144-
- .claude
145-
146-
# Which files to skip: issues from them won't be reported
147-
exclude-files:
148-
- ".*\\.pb\\.go$" # Skip generated protobuf files
149-
150-
# Exclude specific linters for matching issues
151-
exclude-rules:
152-
# Exclude known issues in generated files
153-
- path: ".*\\.pb\\.go"
154-
linters:
155-
- all
156-
157-
# Ignore long lines in comments (e.g., URLs)
158-
- linters:
159-
- revive
160-
text: "line is \\d+ characters"
161-
source: "^\\s*//.*https?://"
162-
163-
# Maximum issues count per one linter
164-
# Set to 0 to disable limit
117+
# Maximum issues count per one linter (0 = unlimited)
165118
max-issues-per-linter: 0
166-
167-
# Maximum count of issues with the same text
168-
# Set to 0 to disable limit
119+
# Maximum count of issues with the same text (0 = unlimited)
169120
max-same-issues: 0
170-
171-
# Show only new issues created after git revision
172-
# Useful for checking only your changes
173-
# new-from-rev: origin/main
174-
175-
# Independently of option `exclude` we use default exclude patterns
176-
exclude-use-default: false
121+
# Make issues output unique by line
122+
uniq-by-line: true

src/cmd/shim/main.go

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/dtvem/dtvem/src/internal/config"
1414
"github.com/dtvem/dtvem/src/internal/constants"
15+
"github.com/dtvem/dtvem/src/internal/path"
1516
"github.com/dtvem/dtvem/src/internal/runtime"
1617
"github.com/dtvem/dtvem/src/internal/shim"
1718
"github.com/dtvem/dtvem/src/internal/ui"
@@ -111,7 +112,7 @@ func runShim() error {
111112
// It attempts to fallback to system PATH or prompts for installation
112113
func handleNoConfiguredVersion(shimName, runtimeName string, provider runtime.ShimProvider) error {
113114
// Try to find the executable deeper in PATH (system installation)
114-
systemPath := findInSystemPath(shimName)
115+
systemPath := path.LookPathExcludingShims(shimName)
115116

116117
if systemPath != "" {
117118
// Found system installation - use it
@@ -143,57 +144,6 @@ func handleNoConfiguredVersion(shimName, runtimeName string, provider runtime.Sh
143144
return fmt.Errorf("no version configured")
144145
}
145146

146-
// findInSystemPath searches for an executable in PATH, excluding dtvem's shims directory
147-
func findInSystemPath(execName string) string {
148-
// Get the shims directory to exclude it from search
149-
shimsDir := config.DefaultPaths().Shims
150-
151-
// Get PATH environment variable
152-
pathEnv := os.Getenv("PATH")
153-
if pathEnv == "" {
154-
return ""
155-
}
156-
157-
// Split PATH into directories
158-
pathDirs := filepath.SplitList(pathEnv)
159-
160-
// Search each directory
161-
for _, dir := range pathDirs {
162-
// Skip the dtvem shims directory
163-
if strings.EqualFold(dir, shimsDir) {
164-
continue
165-
}
166-
167-
// Try to find the executable in this directory
168-
var candidatePath string
169-
if os.PathSeparator == '\\' {
170-
// Windows: try .exe, .cmd, .bat extensions
171-
for _, ext := range []string{".exe", ".cmd", ".bat"} {
172-
candidate := filepath.Join(dir, execName+ext)
173-
if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
174-
candidatePath = candidate
175-
break
176-
}
177-
}
178-
} else {
179-
// Unix: check if file exists and is executable
180-
candidate := filepath.Join(dir, execName)
181-
if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
182-
// Check if executable (has execute permission)
183-
if info.Mode()&0111 != 0 {
184-
candidatePath = candidate
185-
}
186-
}
187-
}
188-
189-
if candidatePath != "" {
190-
return candidatePath
191-
}
192-
}
193-
194-
return ""
195-
}
196-
197147
// getShimName returns the name of this shim binary
198148
func getShimName() string {
199149
shimPath := os.Args[0]

0 commit comments

Comments
 (0)