Skip to content

Commit 41eed91

Browse files
committed
refactor(project): Refactor task resource request tracking
Track requests for the project separate from the dependencies
1 parent 2a1aeaa commit 41eed91

12 files changed

Lines changed: 1209 additions & 1261 deletions

File tree

packages/project/lib/build/ProjectBuilder.js

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -236,17 +236,8 @@ class ProjectBuilder {
236236
}));
237237

238238
const alreadyBuilt = [];
239-
const changedDependencyResources = [];
240239
for (const projectBuildContext of queue) {
241-
if (changedDependencyResources.length) {
242-
// Notify build cache of changed resources from dependencies
243-
projectBuildContext.dependencyResourcesChanged(changedDependencyResources);
244-
}
245-
const changedResources = await projectBuildContext.determineChangedResources();
246-
for (const resourcePath of changedResources) {
247-
changedDependencyResources.push(resourcePath);
248-
}
249-
if (!await projectBuildContext.requiresBuild()) {
240+
if (!await projectBuildContext.possiblyRequiresBuild()) {
250241
const projectName = projectBuildContext.getProject().getName();
251242
alreadyBuilt.push(projectName);
252243
}
@@ -292,13 +283,13 @@ class ProjectBuilder {
292283
this.#log.verbose(`Processing project ${projectName}...`);
293284

294285
// Only build projects that are not already build (i.e. provide a matching build manifest)
295-
if (alreadyBuilt.includes(projectName) || !(await projectBuildContext.requiresBuild())) {
286+
if (alreadyBuilt.includes(projectName)) {
296287
this.#log.skipProjectBuild(projectName, projectType);
297288
} else {
298-
const {changedResources} = await this._buildProject(projectBuildContext);
299-
for (const pbc of queue) {
300-
// Propagate resource changes to following projects
301-
pbc.getBuildCache().dependencyResourcesChanged(changedResources);
289+
if (await projectBuildContext.prepareProjectBuildAndValidateCache(true)) {
290+
this.#log.skipProjectBuild(projectName, projectType);
291+
} else {
292+
await this._buildProject(projectBuildContext);
302293
}
303294
}
304295
if (!requestedProjects.includes(projectName)) {
@@ -313,12 +304,12 @@ class ProjectBuilder {
313304
}
314305

315306
if (!alreadyBuilt.includes(projectName) && !process.env.UI5_BUILD_NO_CACHE_UPDATE) {
316-
this.#log.verbose(`Saving cache...`);
317-
const buildManifest = await createBuildManifest(
318-
project,
319-
this._graph, this._buildContext.getBuildConfig(), this._buildContext.getTaskRepository(),
320-
projectBuildContext.getBuildSignature());
321-
pWrites.push(projectBuildContext.getBuildCache().writeCache(buildManifest));
307+
this.#log.verbose(`Triggering cache write...`);
308+
// const buildManifest = await createBuildManifest(
309+
// project,
310+
// this._graph, this._buildContext.getBuildConfig(), this._buildContext.getTaskRepository(),
311+
// projectBuildContext.getBuildSignature());
312+
pWrites.push(projectBuildContext.getBuildCache().writeCache());
322313
}
323314
}
324315
await Promise.all(pWrites);
@@ -349,7 +340,6 @@ class ProjectBuilder {
349340

350341
async #update(projectBuildContexts, requestedProjects, fsTarget) {
351342
const queue = [];
352-
const changedDependencyResources = [];
353343
await this._graph.traverseDepthFirst(async ({project}) => {
354344
const projectName = project.getName();
355345
const projectBuildContext = projectBuildContexts.get(projectName);
@@ -358,15 +348,6 @@ class ProjectBuilder {
358348
// => This project needs to be built or, in case it has already
359349
// been built, it's build result needs to be written out (if requested)
360350
queue.push(projectBuildContext);
361-
362-
if (changedDependencyResources.length) {
363-
// Notify build cache of changed resources from dependencies
364-
await projectBuildContext.dependencyResourcesChanged(changedDependencyResources);
365-
}
366-
const changedResources = await projectBuildContext.determineChangedResources();
367-
for (const resourcePath of changedResources) {
368-
changedDependencyResources.push(resourcePath);
369-
}
370351
}
371352
});
372353

@@ -382,15 +363,18 @@ class ProjectBuilder {
382363
const projectType = project.getType();
383364
this.#log.verbose(`Updating project ${projectName}...`);
384365

385-
if (!await projectBuildContext.requiresBuild()) {
366+
let changedPaths = await projectBuildContext.prepareProjectBuildAndValidateCache();
367+
if (changedPaths) {
386368
this.#log.skipProjectBuild(projectName, projectType);
387-
continue;
369+
} else {
370+
changedPaths = await this._buildProject(projectBuildContext);
388371
}
389372

390-
const {changedResources} = await this._buildProject(projectBuildContext);
391-
for (const pbc of queue) {
392-
// Propagate resource changes to following projects
393-
pbc.getBuildCache().dependencyResourcesChanged(changedResources);
373+
if (changedPaths.length) {
374+
for (const pbc of queue) {
375+
// Propagate resource changes to following projects
376+
pbc.getBuildCache().dependencyResourcesChanged(changedPaths);
377+
}
394378
}
395379
if (!requestedProjects.includes(projectName)) {
396380
// Project has not been requested
@@ -406,12 +390,12 @@ class ProjectBuilder {
406390
if (process.env.UI5_BUILD_NO_CACHE_UPDATE) {
407391
continue;
408392
}
409-
this.#log.verbose(`Updating cache...`);
410-
const buildManifest = await createBuildManifest(
411-
project,
412-
this._graph, this._buildContext.getBuildConfig(), this._buildContext.getTaskRepository(),
413-
projectBuildContext.getBuildSignature());
414-
pWrites.push(projectBuildContext.getBuildCache().writeCache(buildManifest));
393+
this.#log.verbose(`Triggering cache write...`);
394+
// const buildManifest = await createBuildManifest(
395+
// project,
396+
// this._graph, this._buildContext.getBuildConfig(), this._buildContext.getTaskRepository(),
397+
// projectBuildContext.getBuildSignature());
398+
pWrites.push(projectBuildContext.getBuildCache().writeCache());
415399
}
416400
await Promise.all(pWrites);
417401
}
@@ -422,7 +406,7 @@ class ProjectBuilder {
422406
const projectType = project.getType();
423407

424408
this.#log.startProjectBuild(projectName, projectType);
425-
const changedResources = await projectBuildContext.runTasks();
409+
const changedResources = await projectBuildContext.buildProject();
426410
this.#log.endProjectBuild(projectName, projectType);
427411

428412
return {changedResources};

packages/project/lib/build/TaskRunner.js

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -81,31 +81,19 @@ class TaskRunner {
8181
}
8282

8383
await this._addCustomTasks();
84-
85-
// Create readers for *all* dependencies
86-
const depReaders = [];
87-
await this._graph.traverseBreadthFirst(project.getName(), async function({project: dep}) {
88-
if (dep.getName() === project.getName()) {
89-
// Ignore project itself
90-
return;
91-
}
92-
depReaders.push(dep.getReader());
93-
});
94-
95-
this._allDependenciesReader = createReaderCollection({
96-
name: `Dependency reader collection of project ${project.getName()}`,
97-
readers: depReaders
98-
});
99-
this._buildCache.setDependencyReader(this._allDependenciesReader);
10084
}
10185

10286
/**
10387
* Takes a list of tasks which should be executed from the available task list of the current builder
10488
*
105-
* @returns {Promise} Returns promise resolving once all tasks have been executed
89+
* @returns {Promise<string[]>} Resolves with list of changed resources since the last build
10690
*/
10791
async runTasks() {
10892
await this._initTasks();
93+
94+
// Ensure cached dependencies reader is initialized and up-to-date (TODO: improve this lifecycle)
95+
await this.getDependenciesReader(this._directDependencies);
96+
10997
const tasksToRun = composeTaskList(Object.keys(this._tasks), this._buildConfig);
11098
const allTasks = this._taskExecutionOrder.filter((taskName) => {
11199
// There might be a numeric suffix in case a custom task is configured multiple times.
@@ -141,6 +129,9 @@ class TaskRunner {
141129
* @returns {Set<string>} Returns a set containing the names of all required direct project dependencies
142130
*/
143131
async getRequiredDependencies() {
132+
if (this._requiredDependencies) {
133+
return this._requiredDependencies;
134+
}
144135
await this._initTasks();
145136
const tasksToRun = composeTaskList(Object.keys(this._tasks), this._buildConfig);
146137
const allTasks = this._taskExecutionOrder.filter((taskName) => {
@@ -155,7 +146,7 @@ class TaskRunner {
155146
const taskWithoutSuffixCounter = taskName.replace(/--\d+$/, "");
156147
return tasksToRun.includes(taskWithoutSuffixCounter);
157148
});
158-
return allTasks.reduce((requiredDependencies, taskName) => {
149+
this._requiredDependencies = allTasks.reduce((requiredDependencies, taskName) => {
159150
if (this._tasks[taskName].requiredDependencies.size) {
160151
this._log.verbose(`Task ${taskName} for project ${this._project.getName()} requires dependencies`);
161152
}
@@ -164,6 +155,7 @@ class TaskRunner {
164155
}
165156
return requiredDependencies;
166157
}, new Set());
158+
return this._requiredDependencies;
167159
}
168160

169161
/**
@@ -198,7 +190,7 @@ class TaskRunner {
198190
options.projectName = this._project.getName();
199191
options.projectNamespace = this._project.getNamespace();
200192
// TODO: Apply cache and stage handling for custom tasks as well
201-
const cacheInfo = await this._buildCache.prepareTaskExecution(taskName);
193+
const cacheInfo = await this._buildCache.prepareTaskExecutionAndValidateCache(taskName);
202194
if (cacheInfo === true) {
203195
this._log.skipTask(taskName);
204196
return;
@@ -213,7 +205,7 @@ class TaskRunner {
213205

214206
let dependencies;
215207
if (requiresDependencies) {
216-
dependencies = createMonitor(this._allDependenciesReader);
208+
dependencies = createMonitor(this._cachedDependenciesReader);
217209
params.dependencies = dependencies;
218210
}
219211
if (usingCache) {
@@ -387,9 +379,9 @@ class TaskRunner {
387379
getBuildSignatureCallback,
388380
getExpectedOutputCallback,
389381
differentialUpdateCallback,
390-
getDependenciesReader: () => {
382+
getDependenciesReaderCb: () => {
391383
// Create the dependencies reader on-demand
392-
return this._createDependenciesReader(requiredDependencies);
384+
return this.getDependenciesReader(requiredDependencies);
393385
},
394386
}),
395387
requiredDependencies
@@ -422,7 +414,7 @@ class TaskRunner {
422414
}
423415

424416
_createCustomTaskWrapper({
425-
project, taskUtil, getDependenciesReader, provideDependenciesReader, task, taskName, taskConfiguration
417+
project, taskUtil, getDependenciesReaderCb, provideDependenciesReader, task, taskName, taskConfiguration
426418
}) {
427419
return async function() {
428420
/* Custom Task Interface
@@ -469,7 +461,7 @@ class TaskRunner {
469461
}
470462

471463
if (provideDependenciesReader) {
472-
params.dependencies = await getDependenciesReader();
464+
params.dependencies = await getDependenciesReaderCb();
473465
}
474466
return taskFunction(params);
475467
};
@@ -485,33 +477,26 @@ class TaskRunner {
485477
* @returns {Promise} Resolves when task has finished
486478
*/
487479
async _executeTask(taskName, taskFunction, taskParams) {
488-
// if (this._buildCache.isTaskCacheValid(taskName)) {
489-
// // Immediately skip task if cache is valid
490-
// // Continue if cache is (potentially) invalid, in which case taskFunction will
491-
// // validate the cache thoroughly
492-
// this._log.skipTask(taskName);
493-
// return;
494-
// }
495480
this._taskStart = performance.now();
496481
await taskFunction(taskParams, this._log);
497482
if (this._log.isLevelEnabled("perf")) {
498483
this._log.perf(`Task ${taskName} finished in ${Math.round((performance.now() - this._taskStart))} ms`);
499484
}
500485
}
501486

502-
async _createDependenciesReader(requiredDirectDependencies) {
503-
if (requiredDirectDependencies.size === this._directDependencies.size) {
487+
async getDependenciesReader(dependencyNames, forceUpdate = false) {
488+
if (!forceUpdate && dependencyNames.size === this._directDependencies.size) {
504489
// Shortcut: If all direct dependencies are required, just return the already created reader
505-
return this._allDependenciesReader;
490+
return this._cachedDependenciesReader;
506491
}
507492
const rootProject = this._project;
508493

509494
// Collect readers for all requested dependencies
510495
const readers = [];
511496

512497
// Add transitive dependencies to set of required dependencies
513-
const requiredDependencies = new Set(requiredDirectDependencies);
514-
for (const projectName of requiredDirectDependencies) {
498+
const requiredDependencies = new Set(dependencyNames);
499+
for (const projectName of dependencyNames) {
515500
this._graph.getTransitiveDependencies(projectName).forEach((depName) => {
516501
requiredDependencies.add(depName);
517502
});
@@ -525,10 +510,15 @@ class TaskRunner {
525510
});
526511

527512
// Create a reader collection for that
528-
return createReaderCollection({
513+
const reader = createReaderCollection({
529514
name: `Reduced dependency reader collection of project ${rootProject.getName()}`,
530515
readers
531516
});
517+
518+
if (dependencyNames.size === this._directDependencies.size) {
519+
this._cachedDependenciesReader = reader;
520+
}
521+
return reader;
532522
}
533523
}
534524

0 commit comments

Comments
 (0)