Skip to content

Commit

Permalink
fix(core): ensure output paths returned are unique (#18207)
Browse files Browse the repository at this point in the history
It is possible for users to define multiple duplicate outputs in their
project.json. This is leading to fs related issues like `ENOTEMPTY:
directory not empty, rmdir`. The reason this occurs is that the src will
tried to be copied to the cached directory in parallel for all output
paths (even duplicated ones) and is the reason why these errors are seen
sporadically. By ensuring output paths are unique, we only ever copy one
path which resolves this issue.

Note: There may still be an issue present if there is a glob that is
overlapping another directory i.e: `cdk.out/*` and `cdk.out`, however
have not been able to reproduce a fs error while testing.

fixes #17277, #16337

## Current Behavior
If you have a project.json which has duplicate output entires, it is
possible to receive fs related errors when the cache is being written to
disk.

## Expected Behavior
each output should only be copied once into the caches directory.

## Related Issue(s)
#17277, #16337

Fixes #17277, #16337

(cherry picked from commit 918b8fb)
  • Loading branch information
agdimech authored and FrozenPandaz committed Jul 24, 2024
1 parent 450a528 commit f2f0a4a
Showing 1 changed file with 16 additions and 13 deletions.
29 changes: 16 additions & 13 deletions packages/nx/src/tasks-runner/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,19 +322,22 @@ export function getOutputsForTargetAndConfiguration(
if (targetConfiguration?.outputs) {
validateOutputs(targetConfiguration.outputs);

return targetConfiguration.outputs
.map((output: string) => {
return interpolate(output, {
projectRoot: node.data.root,
projectName: node.name,
project: { ...node.data, name: node.name }, // this is legacy
options,
});
})
.filter(
(output) =>
!!output && !output.match(/{(projectRoot|workspaceRoot|(options.*))}/)
);
const result = new Set<string>();
for (const output of targetConfiguration.outputs) {
const interpolatedOutput = interpolate(output, {
projectRoot: node.data.root,
projectName: node.name,
project: { ...node.data, name: node.name }, // this is legacy
options,
});
if (
!!interpolatedOutput &&
!interpolatedOutput.match(/{(projectRoot|workspaceRoot|(options.*))}/)
) {
result.add(interpolatedOutput);
}
}
return Array.from(result);
}

// Keep backwards compatibility in case `outputs` doesn't exist
Expand Down

0 comments on commit f2f0a4a

Please sign in to comment.