Skip to content

Commit

Permalink
fix(core): git hashing handles "unusual" pathname characters
Browse files Browse the repository at this point in the history
  • Loading branch information
bekos authored and vsavkin committed Mar 15, 2021
1 parent 9d863a7 commit 26a3839
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 28 deletions.
26 changes: 24 additions & 2 deletions packages/workspace/src/core/hasher/git-hasher.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { dirSync } from 'tmp';
import { rmdirSync } from 'fs-extra';
import { removeSync } from 'fs-extra';
import { execSync } from 'child_process';
import { getFileHashes } from './git-hasher';

Expand All @@ -14,7 +14,7 @@ describe('git-hasher', () => {
});

afterEach(() => {
rmdirSync(dir, { recursive: true });
removeSync(dir);
});

it('should work', () => {
Expand Down Expand Up @@ -112,6 +112,28 @@ describe('git-hasher', () => {
expect([...getFileHashes(dir).keys()]).toEqual([`${dir}/moda.txt`]);
});

it('should handle special characters in filenames', () => {
run(`echo AAA > "a-ū".txt`);
run(`echo BBB > "b-ū".txt`);
run(`git add .`);
run(`git commit -am init`);
expect([...getFileHashes(dir).keys()]).toEqual([
`${dir}/a-ū.txt`,
`${dir}/b-ū.txt`,
]);

run(`mv a-ū.txt moda-ū.txt`);
run(`git add .`);
run(`echo modified >> moda-ū.txt`);
expect([...getFileHashes(dir).keys()]).toEqual([
`${dir}/b-ū.txt`,
`${dir}/moda-ū.txt`,
]);

run(`rm "moda-ū.txt"`);
expect([...getFileHashes(dir).keys()]).toEqual([`${dir}/b-ū.txt`]);
});

function run(command: string) {
return execSync(command, { cwd: dir, stdio: ['pipe', 'pipe', 'pipe'] });
}
Expand Down
41 changes: 15 additions & 26 deletions packages/workspace/src/core/hasher/git-hasher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function parseGitLsTree(output: string): Map<string, string> {
const changes: Map<string, string> = new Map<string, string>();
if (output) {
const gitRegex: RegExp = /([0-9]{6})\s(blob|commit)\s([a-f0-9]{40})\s*(.*)/;
output.split('\n').forEach((line) => {
output.split('\0').forEach((line) => {
if (line) {
const matches: RegExpMatchArray | null = line.match(gitRegex);
if (matches && matches[3] && matches[4]) {
Expand All @@ -27,31 +27,18 @@ function parseGitStatus(output: string): Map<string, string> {
if (!output) {
return changes;
}
output
.trim()
.split('\n')
.forEach((line) => {
const [changeType, ...filenames] = line
.trim()
.match(/(?:[^\s"]+|"[^"]*")+/g)
.map((r) => (r.startsWith('"') ? r.substring(1, r.length - 1) : r))
.filter((r) => !!r);

if (changeType && filenames && filenames.length > 0) {
// the before filename we mark as deleted, so we remove it from the map
// changeType can be A/D/R/RM etc
// if it R and RM, we need to split the output into before and after
// the before part gets marked as deleted
if (changeType[0] === 'R') {
changes.set(filenames[0], 'D');
changes.set(filenames[filenames.length - 1], changeType);
} else if (changeType === '??') {
changes.set(filenames.join(' '), changeType);
} else {
changes.set(filenames[filenames.length - 1], changeType);
}
var chunks = output.split('\0');
for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i];
if (chunk.length) {
const change = chunk[0];
if (change === 'R') {
changes.set(chunks[++i], 'D');
}
});
changes.set(chunk.substring(2).trim(), change);
}
}
return changes;
}

Expand Down Expand Up @@ -92,7 +79,9 @@ function getGitHashForFiles(
}

function gitLsTree(path: string): Map<string, string> {
return parseGitLsTree(spawnProcess('git', ['ls-tree', 'HEAD', '-r'], path));
return parseGitLsTree(
spawnProcess('git', ['ls-tree', 'HEAD', '-r', '-z'], path)
);
}

function gitStatus(
Expand All @@ -101,7 +90,7 @@ function gitStatus(
const deletedFiles: string[] = [];
const filesToHash: string[] = [];
parseGitStatus(
spawnProcess('git', ['status', '-s', '-u', '.'], path)
spawnProcess('git', ['status', '-s', '-u', '-z', '.'], path)
).forEach((changeType: string, filename: string) => {
if (changeType !== 'D') {
filesToHash.push(filename);
Expand Down

0 comments on commit 26a3839

Please sign in to comment.