Skip to content

Commit e50f4c2

Browse files
CammisuliFrozenPandaz
authored andcommitted
fix(core): create multi-glob function (#29880)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> Whenever there are multiple plugins using in a workspace, all the configuration paths are collected and used as 1 giant glob to test against the workspace context files. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> Each plugin configuration glob is now handled separately and are not joined together into one giant one. This allows each glob pattern to have separate files for each plugin. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #29473 --------- Co-authored-by: FrozenPandaz <[email protected]>
1 parent 33ade03 commit e50f4c2

File tree

12 files changed

+343
-112
lines changed

12 files changed

+343
-112
lines changed

packages/nx/src/daemon/client/client.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ import {
3434
ProjectGraphError,
3535
} from '../../project-graph/error-types';
3636
import { IS_WASM, NxWorkspaceFiles, TaskRun, TaskTarget } from '../../native';
37-
import { HandleGlobMessage } from '../message-types/glob';
37+
import {
38+
HandleGlobMessage,
39+
HandleMultiGlobMessage,
40+
} from '../message-types/glob';
3841
import {
3942
GET_NX_WORKSPACE_FILES,
4043
HandleNxWorkspaceFilesMessage,
@@ -339,6 +342,15 @@ export class DaemonClient {
339342
return this.sendToDaemonViaQueue(message);
340343
}
341344

345+
multiGlob(globs: string[], exclude?: string[]): Promise<string[][]> {
346+
const message: HandleMultiGlobMessage = {
347+
type: 'MULTI_GLOB',
348+
globs,
349+
exclude,
350+
};
351+
return this.sendToDaemonViaQueue(message);
352+
}
353+
342354
getWorkspaceContextFileData(): Promise<FileData[]> {
343355
const message: HandleContextFileDataMessage = {
344356
type: GET_CONTEXT_FILE_DATA,

packages/nx/src/daemon/message-types/glob.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,21 @@ export function isHandleGlobMessage(
1616
message['type'] === GLOB
1717
);
1818
}
19+
20+
export const MULTI_GLOB = 'MULTI_GLOB' as const;
21+
export type HandleMultiGlobMessage = {
22+
type: typeof MULTI_GLOB;
23+
globs: string[];
24+
exclude?: string[];
25+
};
26+
27+
export function isHandleMultiGlobMessage(
28+
message: unknown
29+
): message is HandleMultiGlobMessage {
30+
return (
31+
typeof message === 'object' &&
32+
message !== null &&
33+
'type' in message &&
34+
message['type'] === MULTI_GLOB
35+
);
36+
}

packages/nx/src/daemon/server/handle-glob.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { workspaceRoot } from '../../utils/workspace-root';
2-
import { globWithWorkspaceContext } from '../../utils/workspace-context';
2+
import {
3+
globWithWorkspaceContext,
4+
multiGlobWithWorkspaceContext,
5+
} from '../../utils/workspace-context';
36
import { HandlerResult } from './server';
47

58
export async function handleGlob(
@@ -12,3 +15,18 @@ export async function handleGlob(
1215
description: 'handleGlob',
1316
};
1417
}
18+
19+
export async function handleMultiGlob(
20+
globs: string[],
21+
exclude?: string[]
22+
): Promise<HandlerResult> {
23+
const files = await multiGlobWithWorkspaceContext(
24+
workspaceRoot,
25+
globs,
26+
exclude
27+
);
28+
return {
29+
response: JSON.stringify(files),
30+
description: 'handleMultiGlob',
31+
};
32+
}

packages/nx/src/daemon/server/server.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,13 @@ import {
5555
watchOutputFiles,
5656
watchWorkspace,
5757
} from './watcher';
58-
import { handleGlob } from './handle-glob';
59-
import { GLOB, isHandleGlobMessage } from '../message-types/glob';
58+
import { handleGlob, handleMultiGlob } from './handle-glob';
59+
import {
60+
GLOB,
61+
isHandleGlobMessage,
62+
isHandleMultiGlobMessage,
63+
MULTI_GLOB,
64+
} from '../message-types/glob';
6065
import {
6166
GET_NX_WORKSPACE_FILES,
6267
isHandleNxWorkspaceFilesMessage,
@@ -239,6 +244,10 @@ async function handleMessage(socket, data: string) {
239244
await handleResult(socket, GLOB, () =>
240245
handleGlob(payload.globs, payload.exclude)
241246
);
247+
} else if (isHandleMultiGlobMessage(payload)) {
248+
await handleResult(socket, MULTI_GLOB, () =>
249+
handleMultiGlob(payload.globs, payload.exclude)
250+
);
242251
} else if (isHandleNxWorkspaceFilesMessage(payload)) {
243252
await handleResult(socket, GET_NX_WORKSPACE_FILES, () =>
244253
handleNxWorkspaceFiles(payload.projectRootMap)

packages/nx/src/native/index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ export declare class WorkspaceContext {
9393
constructor(workspaceRoot: string, cacheDir: string)
9494
getWorkspaceFiles(projectRootMap: Record<string, string>): NxWorkspaceFiles
9595
glob(globs: Array<string>, exclude?: Array<string> | undefined | null): Array<string>
96+
/**
97+
* Performs multiple glob pattern matches against workspace files in parallel
98+
* @returns An array of arrays, where each inner array contains the file paths
99+
* that matched the corresponding glob pattern in the input. The outer array maintains the same order
100+
* as the input globs.
101+
*/
102+
multiGlob(globs: Array<string>, exclude?: Array<string> | undefined | null): Array<Array<string>>
96103
hashFilesMatchingGlob(globs: Array<string>, exclude?: Array<string> | undefined | null): string
97104
incrementalUpdate(updatedFiles: Array<string>, deletedFiles: Array<string>): Record<string, string>
98105
updateProjectFiles(projectRootMappings: ProjectRootMappings, projectFiles: ExternalObject<ProjectFiles>, globalFiles: ExternalObject<Array<FileData>>, updatedFiles: Record<string, string>, deletedFiles: Array<string>): UpdatedWorkspaceFiles

packages/nx/src/native/workspace/context.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,28 @@ impl WorkspaceContext {
231231
Ok(globbed_files.map(|file| file.file.to_owned()).collect())
232232
}
233233

234+
/// Performs multiple glob pattern matches against workspace files in parallel
235+
/// @returns An array of arrays, where each inner array contains the file paths
236+
/// that matched the corresponding glob pattern in the input. The outer array maintains the same order
237+
/// as the input globs.
238+
#[napi]
239+
pub fn multi_glob(
240+
&self,
241+
globs: Vec<String>,
242+
exclude: Option<Vec<String>>,
243+
) -> napi::Result<Vec<Vec<String>>> {
244+
let file_data = self.all_file_data();
245+
246+
globs
247+
.into_iter()
248+
.map(|glob| {
249+
let globbed_files =
250+
config_files::glob_files(&file_data, vec![glob], exclude.clone())?;
251+
Ok(globbed_files.map(|file| file.file.to_owned()).collect())
252+
})
253+
.collect()
254+
}
255+
234256
#[napi]
235257
pub fn hash_files_matching_glob(
236258
&self,

packages/nx/src/project-graph/affected/locators/project-glob-changes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { minimatch } from 'minimatch';
33
import { workspaceRoot } from '../../../utils/workspace-root';
44
import { join } from 'path';
55
import { existsSync } from 'fs';
6-
import { configurationGlobs } from '../../utils/retrieve-workspace-files';
6+
import { getGlobPatternsOfPlugins } from '../../utils/retrieve-workspace-files';
77
import { combineGlobPatterns } from '../../../utils/globs';
88
import { getPlugins } from '../../plugins/get-plugins';
99

@@ -20,8 +20,8 @@ export const getTouchedProjectsFromProjectGlobChanges: TouchedProjectLocator =
2020
'package.json',
2121
]);
2222
}
23-
const plugins = await getPlugins();
24-
return combineGlobPatterns(configurationGlobs(plugins));
23+
const plugins = (await getPlugins()).filter((p) => !!p.createNodes);
24+
return combineGlobPatterns(getGlobPatternsOfPlugins(plugins));
2525
})();
2626

2727
const touchedProjects = new Set<string>();

packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
import {
66
ConfigurationSourceMaps,
77
SourceInformation,
8-
createProjectConfigurations,
8+
createProjectConfigurationsWithPlugins,
99
isCompatibleTarget,
1010
mergeProjectConfigurationIntoRootMap,
1111
mergeTargetConfigurations,
@@ -1679,16 +1679,17 @@ describe('project-configuration-utils', () => {
16791679
};
16801680

16811681
it('should create nodes for files matching included patterns only', async () => {
1682-
const projectConfigurations = await createProjectConfigurations(
1683-
undefined,
1684-
{},
1685-
['libs/a/project.json', 'libs/b/project.json'],
1686-
[
1687-
new LoadedNxPlugin(fakeTagPlugin, {
1688-
plugin: fakeTagPlugin.name,
1689-
}),
1690-
]
1691-
);
1682+
const projectConfigurations =
1683+
await createProjectConfigurationsWithPlugins(
1684+
undefined,
1685+
{},
1686+
[['libs/a/project.json', 'libs/b/project.json']],
1687+
[
1688+
new LoadedNxPlugin(fakeTagPlugin, {
1689+
plugin: fakeTagPlugin.name,
1690+
}),
1691+
]
1692+
);
16921693

16931694
expect(projectConfigurations.projects).toEqual({
16941695
'libs/a': {
@@ -1705,17 +1706,18 @@ describe('project-configuration-utils', () => {
17051706
});
17061707

17071708
it('should create nodes for files matching included patterns only', async () => {
1708-
const projectConfigurations = await createProjectConfigurations(
1709-
undefined,
1710-
{},
1711-
['libs/a/project.json', 'libs/b/project.json'],
1712-
[
1713-
new LoadedNxPlugin(fakeTagPlugin, {
1714-
plugin: fakeTagPlugin.name,
1715-
include: ['libs/a/**'],
1716-
}),
1717-
]
1718-
);
1709+
const projectConfigurations =
1710+
await createProjectConfigurationsWithPlugins(
1711+
undefined,
1712+
{},
1713+
[['libs/a/project.json', 'libs/b/project.json']],
1714+
[
1715+
new LoadedNxPlugin(fakeTagPlugin, {
1716+
plugin: fakeTagPlugin.name,
1717+
include: ['libs/a/**'],
1718+
}),
1719+
]
1720+
);
17191721

17201722
expect(projectConfigurations.projects).toEqual({
17211723
'libs/a': {
@@ -1727,17 +1729,18 @@ describe('project-configuration-utils', () => {
17271729
});
17281730

17291731
it('should not create nodes for files matching excluded patterns', async () => {
1730-
const projectConfigurations = await createProjectConfigurations(
1731-
undefined,
1732-
{},
1733-
['libs/a/project.json', 'libs/b/project.json'],
1734-
[
1735-
new LoadedNxPlugin(fakeTagPlugin, {
1736-
plugin: fakeTagPlugin.name,
1737-
exclude: ['libs/b/**'],
1738-
}),
1739-
]
1740-
);
1732+
const projectConfigurations =
1733+
await createProjectConfigurationsWithPlugins(
1734+
undefined,
1735+
{},
1736+
[['libs/a/project.json', 'libs/b/project.json']],
1737+
[
1738+
new LoadedNxPlugin(fakeTagPlugin, {
1739+
plugin: fakeTagPlugin.name,
1740+
exclude: ['libs/b/**'],
1741+
}),
1742+
]
1743+
);
17411744

17421745
expect(projectConfigurations.projects).toEqual({
17431746
'libs/a': {
@@ -1749,10 +1752,10 @@ describe('project-configuration-utils', () => {
17491752
});
17501753

17511754
it('should normalize targets', async () => {
1752-
const { projects } = await createProjectConfigurations(
1755+
const { projects } = await createProjectConfigurationsWithPlugins(
17531756
undefined,
17541757
{},
1755-
['libs/a/project.json'],
1758+
[['libs/a/project.json'], ['libs/a/project.json']],
17561759
[
17571760
new LoadedNxPlugin(fakeTargetsPlugin, 'fake-targets-plugin'),
17581761
new LoadedNxPlugin(fakeTagPlugin, 'fake-tag-plugin'),
@@ -1771,10 +1774,10 @@ describe('project-configuration-utils', () => {
17711774
});
17721775

17731776
it('should validate that project names are unique', async () => {
1774-
const error = await createProjectConfigurations(
1777+
const error = await createProjectConfigurationsWithPlugins(
17751778
undefined,
17761779
{},
1777-
['libs/a/project.json', 'libs/b/project.json', 'libs/c/project.json'],
1780+
[['libs/a/project.json', 'libs/b/project.json', 'libs/c/project.json']],
17781781
[new LoadedNxPlugin(sameNamePlugin, 'same-name-plugin')]
17791782
).catch((e) => e);
17801783
const isErrorType = isProjectConfigurationsError(error);
@@ -1795,10 +1798,10 @@ describe('project-configuration-utils', () => {
17951798
});
17961799

17971800
it('should validate that projects have a name', async () => {
1798-
const error = await createProjectConfigurations(
1801+
const error = await createProjectConfigurationsWithPlugins(
17991802
undefined,
18001803
{},
1801-
['libs/a/project.json', 'libs/b/project.json', 'libs/c/project.json'],
1804+
[['libs/a/project.json', 'libs/b/project.json', 'libs/c/project.json']],
18021805
[new LoadedNxPlugin(fakeTargetsPlugin, 'fake-targets-plugin')]
18031806
).catch((e) => e);
18041807
const isErrorType = isProjectConfigurationsError(error);
@@ -1816,10 +1819,10 @@ describe('project-configuration-utils', () => {
18161819
});
18171820

18181821
it('should correctly set source maps', async () => {
1819-
const { sourceMaps } = await createProjectConfigurations(
1822+
const { sourceMaps } = await createProjectConfigurationsWithPlugins(
18201823
undefined,
18211824
{},
1822-
['libs/a/project.json'],
1825+
[['libs/a/project.json'], ['libs/a/project.json']],
18231826
[
18241827
new LoadedNxPlugin(fakeTargetsPlugin, 'fake-targets-plugin'),
18251828
new LoadedNxPlugin(fakeTagPlugin, 'fake-tag-plugin'),

packages/nx/src/project-graph/utils/project-configuration-utils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,10 @@ export type ConfigurationResult = {
319319
* @param workspaceFiles A list of non-ignored workspace files
320320
* @param plugins The plugins that should be used to infer project configuration
321321
*/
322-
export async function createProjectConfigurations(
322+
export async function createProjectConfigurationsWithPlugins(
323323
root: string = workspaceRoot,
324324
nxJson: NxJsonConfiguration,
325-
projectFiles: string[], // making this parameter allows devkit to pick up newly created projects
325+
projectFiles: string[][], // making this parameter allows devkit to pick up newly created projects
326326
plugins: LoadedNxPlugin[]
327327
): Promise<ConfigurationResult> {
328328
performance.mark('build-project-configs:start');
@@ -386,7 +386,7 @@ export async function createProjectConfigurations(
386386
}
387387

388388
const matchingConfigFiles: string[] = findMatchingConfigFiles(
389-
projectFiles,
389+
projectFiles[index],
390390
pattern,
391391
include,
392392
exclude
@@ -439,15 +439,15 @@ export async function createProjectConfigurations(
439439
externalNodes,
440440
projectRootMap: rootMap,
441441
sourceMaps: configurationSourceMaps,
442-
matchingProjectFiles: projectFiles,
442+
matchingProjectFiles: projectFiles.flat(),
443443
};
444444
} else {
445445
throw new ProjectConfigurationsError(errors, {
446446
projects: projectRootMap,
447447
externalNodes,
448448
projectRootMap: rootMap,
449449
sourceMaps: configurationSourceMaps,
450-
matchingProjectFiles: projectFiles,
450+
matchingProjectFiles: projectFiles.flat(),
451451
});
452452
}
453453
});

0 commit comments

Comments
 (0)