From 7e3588c5f909ea19b1717ad63204c92c39927a9e Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Tue, 17 Sep 2024 10:58:14 -0400 Subject: [PATCH] fix(core): import handles argument escaping correctly in Windows --- packages/nx/src/utils/git-utils.ts | 46 ++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/nx/src/utils/git-utils.ts b/packages/nx/src/utils/git-utils.ts index a40af0acad46b..f247e6833b8be 100644 --- a/packages/nx/src/utils/git-utils.ts +++ b/packages/nx/src/utils/git-utils.ts @@ -166,20 +166,29 @@ export class GitRepository { const destinationPosixPath = destination.split(sep).join(posix.sep); // First, if the source is not a root project, then only include commits relevant to the subdirectory. if (source !== '') { + const indexFilterCommand = this.quoteArg( + `node ${join(__dirname, 'git-utils.index-filter.js') + // Need to keep two slashes for Windows or else the path will be invalid. + // e.g. 'C:\Users\bob\projects\repo' is invalid, but 'C:\\Users\\bob\\projects\\repo' is valid + .replace('\\', '\\\\')} "${sourcePosixPath}"` + ); await this.execAsync( - `git filter-branch -f --index-filter 'node ${join( - __dirname, - 'git-utils.index-filter.js' - )} "${sourcePosixPath}"' --prune-empty -- ${branchName}` + `git filter-branch -f --index-filter ${indexFilterCommand} --prune-empty -- ${branchName}` ); } // Then, move files to their new location if necessary. if (source === '' || source !== destination) { + const treeFilterCommand = this.quoteArg( + `node ${join(__dirname, 'git-utils.tree-filter.js') + // Need to keep two slashes for Windows or else the path will be invalid. + // e.g. 'C:\Users\bob\projects\repo' is invalid, but 'C:\\Users\\bob\\projects\\repo' is valid + .replace( + '\\', + '\\\\' + )} "${sourcePosixPath}" "${destinationPosixPath}"` + ); await this.execAsync( - `git filter-branch -f --tree-filter 'node ${join( - __dirname, - 'git-utils.tree-filter.js' - )} "${sourcePosixPath}" "${destinationPosixPath}"' -- ${branchName}` + `git filter-branch -f --tree-filter ${treeFilterCommand} -- ${branchName}` ); } } @@ -191,18 +200,25 @@ export class GitRepository { }); } - private quotePath(_path: string, ensureTrailingSlash?: true) { - const path = - ensureTrailingSlash && _path !== '' && !_path.endsWith('/') - ? `${_path}/` - : _path; + private quotePath(path: string, ensureTrailingSlash?: true) { + return this.quoteArg( + ensureTrailingSlash && path !== '' && !path.endsWith('/') + ? `${path}/` + : path + ); + } + + private quoteArg(arg: string) { return process.platform === 'win32' ? // Windows/CMD only understands double-quotes, single-quotes are treated as part of the file name // Bash and other shells will substitute `$` in file names with a variable value. - `"${path}"` + `"${ + // For Windows, double-quotes must be escaped by using two double-quotes. + arg.replace('"', '""') + }"` : // e.g. `git mv "$$file.txt" "libs/a/$$file.txt"` will not work since `$$` is swapped with the PID of the last process. // Using single-quotes prevents this substitution. - `'${path}'`; + `'${arg}'`; } }