-
Notifications
You must be signed in to change notification settings - Fork 83
feat(cli): Add ui5 cache clean command #1455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
9a2a2e6
feat(cli): Add ui5 cache clean command
d3xter666 09370e9
refactor: Remove stale exports
d3xter666 53fb381
test: Add test cases
d3xter666 6dcd54f
fix: Cherry-pick missing methods
d3xter666 cdc0a74
docs: Update documentation
d3xter666 2beb71c
docs: Update JSdocs to reflect latest changes
d3xter666 5778b32
refactor: Rename orphaned dirs to start with underscore
d3xter666 01825d9
docs: Adjust JSdoc comments
d3xter666 5b593d9
docs: Update JSDoc
d3xter666 573495d
fix(cli): Resolve ui5DataDir without shared resolver
d3xter666 dbd18a1
test(cli): Cover cache ui5DataDir precedence
d3xter666 eeff300
docs: Adjust documentation
d3xter666 f3f317a
refactor: Align cleaners on common API
d3xter666 d8ebb21
docs: Adjust Troubleshooting cleanup section
d3xter666 c2afd62
refactor: DRY cleanups
d3xter666 63838f1
test: Add more test cases
d3xter666 cbe1bd0
refactor: Comment stale invocations
d3xter666 7e71d08
test: Fix missed stubs
d3xter666 cf82481
fix: Address potential race condition during dir rename
d3xter666 e3f3c4f
refactor: Long running Db cleanup
d3xter666 aa8806b
refactor: Optimize Db Vacuum
d3xter666 9e59f1b
refactor: Cleanups and UX alignment
d3xter666 298e23d
test: Improve coverage
d3xter666 f74804c
docs: Update docs
d3xter666 97e24d4
refactor: Remove redundant code
d3xter666 4b5e258
fix: Minor Bugs
d3xter666 6a3ccc1
fix: ESLint issues
d3xter666 a18397a
refactor: Return statements
d3xter666 f4a25d5
docs: Fix JSDoc comments
d3xter666 59c37f4
feat: Add usage warning for cache clean command
d3xter666 06dd017
refactor: Rename "orphaned" to "stale"
d3xter666 227c115
refactor: Group cache messages into Active & Stale groups
d3xter666 524283b
fix: ESLint issues
d3xter666 e664eec
refactor: DRY for data tables
d3xter666 bc3d34d
refactor: Consolidate common logic in CacheManager
d3xter666 5e0fc2b
refactor: Export cache clean modules for internal (@ui5/cli) usage
d3xter666 cdaec3b
refactor: Rename ambiguous const
d3xter666 a5a714e
revert: Bad renaming
d3xter666 6b89923
test: Fix failing tests
d3xter666 8f195c8
build: Update package-lock
d3xter666 90c1263
refactor: Remove redundant check
d3xter666 9fb4993
refactor: Provide complete path of the internal exports
d3xter666 948dd6d
refactor: Rename --yes flag to --force
d3xter666 46db12d
fix: ESLint findings
d3xter666 34ae040
feat: Enable detailed output only in verbose mode
d3xter666 79e7401
refactor: Reword confirmation prompt
d3xter666 04c5e9e
fix: Do not report wrongly stale cache
d3xter666 af83085
fix: Defensive logging for parallel executions
d3xter666 66c2376
refactor: Consistent output
d3xter666 c6b31f2
fix: Build info display
d3xter666 00c36b6
build: Align package-lock.json with main
d3xter666 ce8f608
docs: Update internal/documentation/docs/pages/Troubleshooting.md
d3xter666 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,182 @@ | ||
| import chalk from "chalk"; | ||
| import path from "node:path"; | ||
| import os from "node:os"; | ||
| import process from "node:process"; | ||
| import {isLogLevelEnabled} from "@ui5/logger"; | ||
| import baseMiddleware from "../middlewares/base.js"; | ||
| import Configuration from "@ui5/project/config/Configuration"; | ||
| import FrameworkCache from "@ui5/project/internal/ui5Framework/cache"; | ||
| import CacheManager from "@ui5/project/internal/build/cache/CacheManager"; | ||
| import { | ||
| CACHE_CLEAN_HELP_USAGE, | ||
| displayCacheCleanWarning, | ||
| displayCacheInfo, | ||
| displayCleanupResult, | ||
| } from "./helpers/cacheOutput.js"; | ||
|
|
||
| const cacheCommand = { | ||
| command: "cache", | ||
| describe: "Manage the UI5 CLI cache (downloaded framework packages and build data)", | ||
| middlewares: [baseMiddleware], | ||
| handler: handleCache | ||
| }; | ||
|
|
||
| cacheCommand.builder = function(cli) { | ||
| return cli | ||
| .demandCommand(1, "Command required. Available command is 'clean'") | ||
| .command("clean", "Remove all cached UI5 data", { | ||
| handler: handleCache, | ||
| builder: function(yargs) { | ||
| return yargs | ||
| .usage(CACHE_CLEAN_HELP_USAGE) | ||
| .option("force", { | ||
| alias: "f", | ||
| describe: "Skip the confirmation prompt, e.g. for use in CI pipelines", | ||
| default: false, | ||
| type: "boolean", | ||
| }) | ||
| .example("$0 cache clean", | ||
| "Remove all cached UI5 data after confirmation") | ||
| .example("$0 cache clean --force", | ||
| "Remove all cached UI5 data without confirmation (e.g. in CI scenarios)") | ||
| .example("UI5_DATA_DIR=/custom/path $0 cache clean", | ||
| "Remove cached data from a non-default UI5 data directory"); | ||
| }, | ||
| middlewares: [baseMiddleware], | ||
| }); | ||
| }; | ||
| /** | ||
| * Prompt the user for confirmation before proceeding with cache cleanup. | ||
| * | ||
| * @param {Yargs.Arguments} argv | ||
| * @returns {Promise<boolean>} Confirmation result | ||
| */ | ||
| async function getConfirmation(argv) { | ||
| if (argv.force) { | ||
| return true; | ||
| } | ||
| displayCacheCleanWarning(); | ||
| const {default: yesno} = await import("yesno"); | ||
| return yesno({ | ||
| question: "Proceed with cache cleanup? (y/N)", | ||
| defaultValue: false | ||
| }); | ||
| } | ||
|
|
||
| async function resolveCacheUi5DataDir() { | ||
| // TODO: Consolidate ui5DataDir resolution once PR #1456 follow-up cleanup is done. | ||
| // Keep behavior aligned with existing main-branch resolution order. | ||
| let ui5DataDir = process.env.UI5_DATA_DIR; | ||
| if (!ui5DataDir) { | ||
| const config = await Configuration.fromFile(); | ||
| ui5DataDir = config.getUi5DataDir(); | ||
| } | ||
| if (ui5DataDir) { | ||
| return path.resolve(process.cwd(), ui5DataDir); | ||
| } | ||
| return path.join(os.homedir(), ".ui5"); | ||
| } | ||
|
|
||
| function withAbsPath(entries, ui5DataDir) { | ||
| return entries.map((entry) => { | ||
| return {...entry, absPath: getAbsPath(ui5DataDir, entry)}; | ||
| }); | ||
| } | ||
|
|
||
| function getAbsPath(ui5DataDir, cacheEntry) { | ||
| if (!cacheEntry?.path) { | ||
| return null; | ||
| } | ||
| return path.join(ui5DataDir, cacheEntry.path); | ||
| } | ||
|
|
||
| async function handleCache(argv) { | ||
| const ui5DataDir = await resolveCacheUi5DataDir(); | ||
| const isVerbose = isLogLevelEnabled("verbose"); | ||
|
|
||
| if (isVerbose) { | ||
| // logger.verbose pollutes output with framework noise. | ||
| process.stderr.write(`Checking cache at ${chalk.bold(ui5DataDir)} …\n`); | ||
| } | ||
|
|
||
| const [frameworkInfo, buildInfo] = await Promise.all([ | ||
| FrameworkCache.getCacheInfo(ui5DataDir), | ||
| CacheManager.getCacheInfo(ui5DataDir), | ||
| ]); | ||
|
|
||
| const hasActiveCache = Boolean(frameworkInfo || buildInfo); | ||
| let staleInfo = []; | ||
| let buildStaleInfo = []; | ||
|
|
||
| if (isVerbose || !hasActiveCache) { | ||
| [staleInfo, buildStaleInfo] = await Promise.all([ | ||
| FrameworkCache.getAdditionalCacheInfo(ui5DataDir), | ||
| CacheManager.getAdditionalCacheInfo(ui5DataDir), | ||
| ]); | ||
| } | ||
|
|
||
| const hasStaleCache = staleInfo.length > 0 || buildStaleInfo.length > 0; | ||
|
|
||
| if (!hasActiveCache && !hasStaleCache) { | ||
| if (isVerbose) { | ||
| process.stderr.write(`${chalk.italic("Nothing to clean")}\n`); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| if (isVerbose) { | ||
| await displayCacheInfo({ | ||
| frameworkInfo, | ||
| buildInfo, | ||
| frameworkAbsPath: getAbsPath(ui5DataDir, frameworkInfo), | ||
| buildAbsPath: getAbsPath(ui5DataDir, buildInfo), | ||
| buildPreSize: buildInfo?.size ?? 0, | ||
| staleInfo: withAbsPath(staleInfo, ui5DataDir), | ||
| buildAdditionalInfo: withAbsPath(buildStaleInfo, ui5DataDir), | ||
| }); | ||
| } | ||
|
|
||
| const confirmed = await getConfirmation(argv); | ||
| if (!confirmed) { | ||
| if (isVerbose) { | ||
| process.stderr.write(`${chalk.italic("Cancelled")}\n`); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| if (isVerbose) { | ||
| // Get fresh build stale info to distinguish | ||
| // between active and stale build cache after cleanup. | ||
| buildStaleInfo = await CacheManager.getAdditionalCacheInfo(ui5DataDir); | ||
| } | ||
|
|
||
| const [frameworkCleanupResult, buildCleanupResult] = await Promise.all([ | ||
| FrameworkCache.cleanCache(ui5DataDir), | ||
| CacheManager.cleanCache(ui5DataDir), | ||
| ]); | ||
|
|
||
| const [additionalFrameworkCleanupResult, buildStaleCleanupResult] = await Promise.all([ | ||
| FrameworkCache.cleanAdditional(ui5DataDir), | ||
| CacheManager.cleanAdditional(ui5DataDir), | ||
| ]); | ||
|
|
||
| if (isVerbose) { | ||
| const staleBuildCleanupResult = buildStaleInfo?.length > 0 ? | ||
| buildStaleCleanupResult : []; | ||
| const cleanedStaleFramework = withAbsPath(additionalFrameworkCleanupResult, ui5DataDir); | ||
| const cleanedStaleBuild = withAbsPath(staleBuildCleanupResult, ui5DataDir); | ||
| const frameworkResultAbsPath = getAbsPath(ui5DataDir, frameworkCleanupResult); | ||
| const buildResultAbsPath = getAbsPath(ui5DataDir, buildCleanupResult); | ||
| await displayCleanupResult({ | ||
| frameworkResult: frameworkCleanupResult, | ||
| buildResult: buildCleanupResult, | ||
| frameworkAbsPath: frameworkResultAbsPath, | ||
| buildAbsPath: buildResultAbsPath, | ||
| buildSize: buildCleanupResult?.size ?? 0, | ||
| staleInfoWithAbsPaths: cleanedStaleFramework, | ||
| buildAdditionalResult: cleanedStaleBuild, | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| export default cacheCommand; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.