-
-
Notifications
You must be signed in to change notification settings - Fork 260
fix(config): expand leading ~ in config paths (supersedes #301) #370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
40f017c
34bef5a
da13af6
83c9f9c
f98824a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { describe, expect, it } from 'vitest'; | ||
| import path from 'node:path'; | ||
| import { homedir } from 'node:os'; | ||
| import { resolveEffectiveDerivedDataPath } from '../derived-data-path.ts'; | ||
| import { DERIVED_DATA_DIR } from '../log-paths.ts'; | ||
|
|
||
| describe('resolveEffectiveDerivedDataPath', () => { | ||
| it('returns the default derived data dir when input is undefined', () => { | ||
| expect(resolveEffectiveDerivedDataPath(undefined)).toBe(DERIVED_DATA_DIR); | ||
| }); | ||
|
|
||
| it('returns the default derived data dir when input is empty', () => { | ||
| expect(resolveEffectiveDerivedDataPath('')).toBe(DERIVED_DATA_DIR); | ||
| }); | ||
|
|
||
| it('returns the default derived data dir when input is whitespace', () => { | ||
| expect(resolveEffectiveDerivedDataPath(' ')).toBe(DERIVED_DATA_DIR); | ||
| }); | ||
|
|
||
| it('returns absolute paths unchanged', () => { | ||
| expect(resolveEffectiveDerivedDataPath('/abs/path/dd')).toBe('/abs/path/dd'); | ||
| }); | ||
|
|
||
| it('resolves relative paths against the current working directory', () => { | ||
| expect(resolveEffectiveDerivedDataPath('.derivedData/e2e')).toBe( | ||
| path.resolve(process.cwd(), '.derivedData/e2e'), | ||
| ); | ||
| }); | ||
|
|
||
| it('expands a bare ~ input to the home directory', () => { | ||
| expect(resolveEffectiveDerivedDataPath('~')).toBe(homedir()); | ||
| }); | ||
|
|
||
| it('expands a ~/-prefixed input under the home directory', () => { | ||
| expect(resolveEffectiveDerivedDataPath('~/.foo/derivedData')).toBe( | ||
| path.join(homedir(), '.foo/derivedData'), | ||
| ); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { describe, expect, it } from 'vitest'; | ||
| import path from 'node:path'; | ||
| import { homedir } from 'node:os'; | ||
| import { expandHomePrefix } from '../expand-home.ts'; | ||
|
|
||
| describe('expandHomePrefix', () => { | ||
| it('expands a bare ~ to the home directory', () => { | ||
| expect(expandHomePrefix('~')).toBe(homedir()); | ||
| }); | ||
|
|
||
| it('expands a leading ~/ to the home directory', () => { | ||
| expect(expandHomePrefix('~/foo/bar')).toBe(path.join(homedir(), 'foo/bar')); | ||
| }); | ||
|
|
||
| it('expands a leading ~\\ on Windows-style separators', () => { | ||
| expect(expandHomePrefix('~\\foo\\bar')).toBe(path.join(homedir(), 'foo\\bar')); | ||
| }); | ||
|
|
||
| it('returns absolute paths unchanged', () => { | ||
| expect(expandHomePrefix('/absolute/path')).toBe('/absolute/path'); | ||
| }); | ||
|
|
||
| it('returns relative paths unchanged', () => { | ||
| expect(expandHomePrefix('relative/path')).toBe('relative/path'); | ||
| }); | ||
|
|
||
| it('does not expand ~user style prefixes', () => { | ||
| expect(expandHomePrefix('~other/foo')).toBe('~other/foo'); | ||
| }); | ||
|
|
||
| it('does not expand ~ embedded later in the path', () => { | ||
| expect(expandHomePrefix('foo/~/bar')).toBe('foo/~/bar'); | ||
| }); | ||
|
|
||
| it('returns an empty string unchanged', () => { | ||
| expect(expandHomePrefix('')).toBe(''); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ import { | |
| import path from 'path'; | ||
| import os from 'node:os'; | ||
| import { resolveEffectiveDerivedDataPath } from './derived-data-path.ts'; | ||
| import { expandHomePrefix } from './expand-home.ts'; | ||
| import type { XcodebuildPipeline } from './xcodebuild-pipeline.ts'; | ||
| import { createNoticeFragment } from './xcodebuild-output.ts'; | ||
|
|
||
|
|
@@ -22,10 +23,11 @@ export interface BuildCommandResult { | |
| } | ||
|
|
||
| function resolvePathFromCwd(pathValue: string): string { | ||
| if (path.isAbsolute(pathValue)) { | ||
| return pathValue; | ||
| const expanded = expandHomePrefix(pathValue); | ||
| if (path.isAbsolute(expanded)) { | ||
| return expanded; | ||
| } | ||
| return path.resolve(process.cwd(), pathValue); | ||
| return path.resolve(process.cwd(), expanded); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate
|
||
| } | ||
|
|
||
| function getDefaultSwiftPackageCachePath(): string { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,14 @@ | ||
| import * as path from 'node:path'; | ||
| import { DERIVED_DATA_DIR } from './log-paths.ts'; | ||
| import { expandHomePrefix } from './expand-home.ts'; | ||
|
|
||
| export function resolveEffectiveDerivedDataPath(input?: string): string { | ||
| if (!input || input.trim().length === 0) { | ||
| return DERIVED_DATA_DIR; | ||
| } | ||
| if (path.isAbsolute(input)) { | ||
| return input; | ||
| const expanded = expandHomePrefix(input); | ||
| if (path.isAbsolute(expanded)) { | ||
| return expanded; | ||
| } | ||
| return path.resolve(process.cwd(), input); | ||
| return path.resolve(process.cwd(), expanded); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import path from 'node:path'; | ||
| import { homedir } from 'node:os'; | ||
|
|
||
| /** | ||
| * Expand a leading ~ or ~/ (or ~\ on Windows) prefix to the user's home directory. | ||
| * Returns the path unchanged if it does not start with ~. | ||
| */ | ||
| export function expandHomePrefix(inputPath: string): string { | ||
| if (inputPath === '~') { | ||
| return homedir(); | ||
| } | ||
|
|
||
| if (inputPath.startsWith('~/') || inputPath.startsWith('~\\')) { | ||
| return path.join(homedir(), inputPath.slice(2)); | ||
| } | ||
|
|
||
| return inputPath; | ||
| } |


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tilde expansion missed in duplicate
resolvePathFromCwdMedium Severity
app-path-resolver.tscontains its ownresolvePathFromCwdthat is functionally identical to the one inbuild-utils.ts, but was not updated withexpandHomePrefix. This means tilde-prefixed paths like~/Code/App.xcodeprojare correctly expanded when passed toexecuteXcodeBuildCommandbut remain literal~when the same params flow intoresolveAppPathFromBuildSettings(used by device build/run, get-app-path, and macOS build tools). Within a single tool execution (e.g.,build_macos.ts), the sameprojectPathis now expanded in the build step but not in the app-path resolution step — an inconsistency introduced by this PR.Reviewed by Cursor Bugbot for commit f98824a. Configure here.