diff options
Diffstat (limited to 'src/upd8.js')
-rwxr-xr-x | src/upd8.js | 401 |
1 files changed, 276 insertions, 125 deletions
diff --git a/src/upd8.js b/src/upd8.js index a3840424..9b347e61 100755 --- a/src/upd8.js +++ b/src/upd8.js @@ -51,6 +51,7 @@ import {isMain, traverse} from '#node-utils'; import {bindReverse} from '#reverse'; import {writeSearchData} from '#search'; import {sortByName} from '#sort'; +import thingConstructors from '#things'; import {identifyAllWebRoutes} from '#web-routes'; import { @@ -133,8 +134,8 @@ const defaultStepStatus = {status: STATUS_NOT_STARTED, annotation: null}; // Defined globally for quick access outside the main() function's contents. // This will be initialized and mutated over the course of main(). let stepStatusSummary; -let showStepStatusSummary = false; -let showStepMemoryInSummary = false; +let shouldShowStepStatusSummary = false; +let shouldShowStepMemoryInSummary = false; async function main() { Error.stackTraceLimit = Infinity; @@ -190,6 +191,13 @@ async function main() { {...defaultStepStatus, name: `precache nearly all data`, for: ['build']}, + sortWikiDataSourceFiles: + {...defaultStepStatus, name: `apply sorting rules to wiki data files`, + for: ['build']}, + + checkWikiDataSourceFileSorting: + {...defaultStepStatus, name: `check sorting rules against wiki data files`}, + loadURLFiles: {...defaultStepStatus, name: `load internal & custom url spec files`, for: ['build']}, @@ -270,6 +278,35 @@ async function main() { })); let selectedBuildModeFlag; + let sortInAdditionToBuild = false; + + // As an exception, --sort can be combined with another build mode. + if (selectedBuildModeFlags.length >= 2 && selectedBuildModeFlags.includes('sort')) { + sortInAdditionToBuild = true; + selectedBuildModeFlags.splice(selectedBuildModeFlags.indexOf('sort'), 1); + } + + if (sortInAdditionToBuild) { + Object.assign(stepStatusSummary.sortWikiDataSourceFiles, { + status: STATUS_NOT_STARTED, + annotation: `--sort provided with another build mode`, + }); + + Object.assign(stepStatusSummary.checkWikiDataSourceFileSorting, { + status: STATUS_NOT_APPLICABLE, + annotation: `--sort provided, dry run not applicable`, + }); + } else { + Object.assign(stepStatusSummary.sortWikiDataSourceFiles, { + status: STATUS_NOT_APPLICABLE, + annotation: `--sort not provided, dry run only`, + }); + + Object.assign(stepStatusSummary.checkWikiDataSourceFileSorting, { + status: STATUS_NOT_STARTED, + annotation: `--sort not provided, dry run applicable`, + }); + } if (empty(selectedBuildModeFlags)) { // No build mode selected. This is not a valid state for building the wiki, @@ -525,8 +562,8 @@ async function main() { ...buildOptions, }); - showStepStatusSummary = cliOptions['show-step-summary'] ?? false; - showStepMemoryInSummary = cliOptions['show-step-memory'] ?? false; + shouldShowStepStatusSummary = cliOptions['show-step-summary'] ?? false; + shouldShowStepMemoryInSummary = cliOptions['show-step-memory'] ?? false; if (cliOptions['help']) { console.log( @@ -1846,6 +1883,77 @@ async function main() { }); } + if (stepStatusSummary.sortWikiDataSourceFiles.status === STATUS_NOT_STARTED) { + Object.assign(stepStatusSummary.sortWikiDataSourceFiles, { + status: STATUS_STARTED_NOT_DONE, + timeStart: Date.now(), + }); + + const {SortingRule} = thingConstructors; + const results = + await Array.fromAsync(SortingRule.go({dataPath, wikiData})); + + if (results.some(result => result.changed)) { + logInfo`Updated data files to satisfy sorting.`; + logInfo`Restarting automatically, since that's now needed!`; + + Object.assign(stepStatusSummary.sortWikiDataSourceFiles, { + status: STATUS_DONE_CLEAN, + annotation: `changes cueing restart`, + timeEnd: Date.now(), + memory: process.memoryUsage(), + }); + + return 'restart'; + } else { + logInfo`All sorting rules are satisfied. Nice!`; + paragraph = false; + + Object.assign(stepStatusSummary.sortWikiDataSourceFiles, { + status: STATUS_DONE_CLEAN, + annotation: `no changes needed`, + timeEnd: Date.now(), + memory: process.memoryUsage(), + }); + } + } else if (stepStatusSummary.checkWikiDataSourceFileSorting.status === STATUS_NOT_STARTED) { + Object.assign(stepStatusSummary.checkWikiDataSourceFileSorting, { + status: STATUS_STARTED_NOT_DONE, + timeStart: Date.now(), + }); + + const {SortingRule} = thingConstructors; + const results = + await Array.fromAsync(SortingRule.go({dataPath, wikiData, dry: true})); + + const needed = results.filter(result => result.changed); + + if (empty(needed)) { + logInfo`All sorting rules are satisfied. Nice!`; + paragraph = false; + + Object.assign(stepStatusSummary.checkWikiDataSourceFileSorting, { + status: STATUS_DONE_CLEAN, + timeEnd: Date.now(), + memory: process.memoryUsage(), + }); + } else { + logWarn`Some of this wiki's sorting rules currently aren't satisfied:`; + for (const {rule} of needed) { + logWarn`- ${rule.message}`; + } + logWarn`Run ${'hsmusic --sort'} to automatically update data files.`; + paragraph = false; + + Object.assign(stepStatusSummary.checkWikiDataSourceFileSorting, { + status: STATUS_HAS_WARNINGS, + annotation: `not all rules satisfied`, + timeEnd: Date.now(), + memory: process.memoryUsage(), + }); + } + } + if (stepStatusSummary.performBuild.status === STATUS_NOT_APPLICABLE) { displayCompositeCacheAnalysis(); @@ -3094,141 +3202,67 @@ async function main() { if (true || isMain(import.meta.url) || path.basename(process.argv[1]) === 'hsmusic') { (async () => { let result; + let numRestarts = 0; const totalTimeStart = Date.now(); - try { - result = await main(); - } catch (error) { - if (error instanceof AggregateError) { - showAggregate(error); - } else if (error.cause) { - console.error(error); - showAggregate(error); - } else { - console.error(error); - } - } - - const totalTimeEnd = Date.now(); - - const formatDuration = timeDelta => { - const seconds = timeDelta / 1000; - - if (seconds > 90) { - const modSeconds = Math.floor(seconds % 60); - const minutes = Math.floor(seconds - seconds % 60) / 60; - return `${minutes}m${modSeconds}s`; - } - - if (seconds < 0.1) { - return 'instant'; + while (true) { + try { + result = await main(); + } catch (error) { + if (error instanceof AggregateError) { + showAggregate(error); + } else if (error.cause) { + console.error(error); + showAggregate(error); + } else { + console.error(error); + } } - const precision = (seconds > 1 ? 3 : 2); - return `${seconds.toPrecision(precision)}s`; - }; - - if (showStepStatusSummary) { - const totalDuration = formatDuration(totalTimeEnd - totalTimeStart); - - console.error(colors.bright(`Step summary:`)); - - const longestNameLength = - Math.max(... - Object.values(stepStatusSummary) - .map(({name}) => name.length)); - - const stepsNotClean = - Object.values(stepStatusSummary) - .map(({status}) => - status === STATUS_HAS_WARNINGS || - status === STATUS_FATAL_ERROR || - status === STATUS_STARTED_NOT_DONE); - - const anyStepsNotClean = - stepsNotClean.includes(true); - - const stepDetails = Object.values(stepStatusSummary); - - const stepDurations = - stepDetails.map(({status, timeStart, timeEnd}) => { - if ( - status === STATUS_NOT_APPLICABLE || - status === STATUS_NOT_STARTED || - status === STATUS_STARTED_NOT_DONE - ) { - return '-'; - } + if (result === 'restart') { + console.log(''); - if (typeof timeStart !== 'number' || typeof timeEnd !== 'number') { - return 'unknown'; + if (shouldShowStepStatusSummary) { + if (numRestarts >= 1) { + console.error(colors.bright(`Step summary since latest restart:`)); + } else { + console.error(colors.bright(`Step summary before restart:`)); } - return formatDuration(timeEnd - timeStart); - }); - - const longestDurationLength = - Math.max(...stepDurations.map(duration => duration.length)); - - const stepMemories = - stepDetails.map(({memory}) => - (memory - ? Math.round(memory["heapUsed"] / 1024 / 1024) + 'MB' - : '-')); - - const longestMemoryLength = - Math.max(...stepMemories.map(memory => memory.length)); - - for (let index = 0; index < stepDetails.length; index++) { - const {name, status, annotation} = stepDetails[index]; - const duration = stepDurations[index]; - const memory = stepMemories[index]; - - let message = - (stepsNotClean[index] - ? `!! ` - : ` - `); - - message += `(${duration} `.padStart(longestDurationLength + 2, ' '); - - if (showStepMemoryInSummary) { - message += ` ${memory})`.padStart(longestMemoryLength + 2, ' '); + showStepStatusSummary(); + console.log(''); } - message += ` `; - message += `${name}: `.padEnd(longestNameLength + 4, '.'); - message += ` `; - message += status; - - if (annotation) { - message += ` (${annotation})`; + if (numRestarts > 5) { + logError`A restart was cued, but we've restarted a bunch already.`; + logError`Exiting because this is probably a bug!`; + console.log(''); + break; + } else { + console.log(''); + logInfo`A restart was cued. This is probably normal, and required`; + logInfo`to load updated data files. Restarting automatically now!`; + console.log(''); + numRestarts++; } + } else { + break; + } + } - switch (status) { - case STATUS_DONE_CLEAN: - console.error(colors.green(message)); - break; - - case STATUS_NOT_STARTED: - case STATUS_NOT_APPLICABLE: - console.error(colors.dim(message)); - break; - - case STATUS_HAS_WARNINGS: - case STATUS_STARTED_NOT_DONE: - console.error(colors.yellow(message)); - break; + if (shouldShowStepStatusSummary) { + if (numRestarts >= 1) { + console.error(colors.bright(`Step summary after final restart:`)); + } else { + console.error(colors.bright(`Step summary:`)); + } - case STATUS_FATAL_ERROR: - console.error(colors.red(message)); - break; + const {anyStepsNotClean} = + showStepStatusSummary(); - default: - console.error(message); - break; - } - } + const totalTimeEnd = Date.now(); + const totalDuration = formatDuration(totalTimeEnd - totalTimeStart); console.error(colors.bright(`Done in ${totalDuration}.`)); @@ -3257,3 +3291,120 @@ if (true || isMain(import.meta.url) || path.basename(process.argv[1]) === 'hsmus process.exit(0); })(); } + +function formatDuration(timeDelta) { + const seconds = timeDelta / 1000; + + if (seconds > 90) { + const modSeconds = Math.floor(seconds % 60); + const minutes = Math.floor(seconds - seconds % 60) / 60; + return `${minutes}m${modSeconds}s`; + } + + if (seconds < 0.1) { + return 'instant'; + } + + const precision = (seconds > 1 ? 3 : 2); + return `${seconds.toPrecision(precision)}s`; +} + +function showStepStatusSummary() { + const longestNameLength = + Math.max(... + Object.values(stepStatusSummary) + .map(({name}) => name.length)); + + const stepsNotClean = + Object.values(stepStatusSummary) + .map(({status}) => + status === STATUS_HAS_WARNINGS || + status === STATUS_FATAL_ERROR || + status === STATUS_STARTED_NOT_DONE); + + const anyStepsNotClean = + stepsNotClean.includes(true); + + const stepDetails = Object.values(stepStatusSummary); + + const stepDurations = + stepDetails.map(({status, timeStart, timeEnd}) => { + if ( + status === STATUS_NOT_APPLICABLE || + status === STATUS_NOT_STARTED || + status === STATUS_STARTED_NOT_DONE + ) { + return '-'; + } + + if (typeof timeStart !== 'number' || typeof timeEnd !== 'number') { + return 'unknown'; + } + + return formatDuration(timeEnd - timeStart); + }); + + const longestDurationLength = + Math.max(...stepDurations.map(duration => duration.length)); + + const stepMemories = + stepDetails.map(({memory}) => + (memory + ? Math.round(memory["heapUsed"] / 1024 / 1024) + 'MB' + : '-')); + + const longestMemoryLength = + Math.max(...stepMemories.map(memory => memory.length)); + + for (let index = 0; index < stepDetails.length; index++) { + const {name, status, annotation} = stepDetails[index]; + const duration = stepDurations[index]; + const memory = stepMemories[index]; + + let message = + (stepsNotClean[index] + ? `!! ` + : ` - `); + + message += `(${duration} `.padStart(longestDurationLength + 2, ' '); + + if (shouldShowStepMemoryInSummary) { + message += ` ${memory})`.padStart(longestMemoryLength + 2, ' '); + } + + message += ` `; + message += `${name}: `.padEnd(longestNameLength + 4, '.'); + message += ` `; + message += status; + + if (annotation) { + message += ` (${annotation})`; + } + + switch (status) { + case STATUS_DONE_CLEAN: + console.error(colors.green(message)); + break; + + case STATUS_NOT_STARTED: + case STATUS_NOT_APPLICABLE: + console.error(colors.dim(message)); + break; + + case STATUS_HAS_WARNINGS: + case STATUS_STARTED_NOT_DONE: + console.error(colors.yellow(message)); + break; + + case STATUS_FATAL_ERROR: + console.error(colors.red(message)); + break; + + default: + console.error(message); + break; + } + } + + return {anyStepsNotClean}; +} |