From 6171a4abdaeb0b5ec8f3681f9c7f31be4eaa9d6f Mon Sep 17 00:00:00 2001 From: linbudu599 Date: Tue, 15 Mar 2022 20:26:18 +0800 Subject: [PATCH] feat: enable fork workspace --- package.json | 2 + pnpm-lock.yaml | 11 ++- scripts/cli.ts | 2 + scripts/fork-workspace.ts | 155 ++++++++++++++++++++++++++++++++++++++ scripts/utils.ts | 13 +++- 5 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 scripts/fork-workspace.ts diff --git a/package.json b/package.json index 9798f7d..c8b5ec5 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,8 @@ "fs-extra": "^10.0.1", "jsonfile": "^6.1.0", "minimist": "^1.2.5", + "nanoid": "^3.3.1", + "ora": "^5.0.0", "preferred-pm": "^3.0.3", "prettier": "^2.5.1", "prompts": "^2.4.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a7592fc..9d370d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,6 +27,8 @@ importers: jsonfile: ^6.1.0 lodash: ^4.17.21 minimist: ^1.2.5 + nanoid: ^3.3.1 + ora: ^5.0.0 preferred-pm: ^3.0.3 prettier: ^2.5.1 prompts: ^2.4.2 @@ -57,6 +59,8 @@ importers: fs-extra: 10.0.1 jsonfile: 6.1.0 minimist: 1.2.5 + nanoid: 3.3.1 + ora: 5.4.1 preferred-pm: 3.0.3 prettier: 2.5.1 prompts: 2.4.2 @@ -23886,11 +23890,6 @@ packages: resolution: {integrity: sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==} dev: false - /nanoid/3.2.0: - resolution: {integrity: sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - /nanoid/3.3.1: resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -27650,7 +27649,7 @@ packages: resolution: {integrity: sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.2.0 + nanoid: 3.3.1 picocolors: 1.0.0 source-map-js: 1.0.2 diff --git a/scripts/cli.ts b/scripts/cli.ts index 541bf08..8df2793 100644 --- a/scripts/cli.ts +++ b/scripts/cli.ts @@ -9,6 +9,7 @@ import useCreateSimplePackage from './create-package'; import useCopyPackage from './copy-package'; import useCachePackage from './cache-package'; import useRenameWorkspacePackage from './rename-package'; +import useForkWorkspace from './fork-workspace'; const cli = cac('LinbuduLab-Starter'); @@ -22,6 +23,7 @@ useCreateSimplePackage(cli); useCopyPackage(cli); useCachePackage(cli); useRenameWorkspacePackage(cli); +useForkWorkspace(cli); cli.help(); cli.parse(); diff --git a/scripts/fork-workspace.ts b/scripts/fork-workspace.ts new file mode 100644 index 0000000..c15f197 --- /dev/null +++ b/scripts/fork-workspace.ts @@ -0,0 +1,155 @@ +import { CAC } from 'cac'; +import fs from 'fs-extra'; + +import chalk from 'chalk'; +import { CLIUtils, Constants } from './utils'; +import consola from 'consola'; +import path from 'path'; +import ora from 'ora'; + +export default function useForkWorkspace(cli: CAC) { + cli + .command('fork [workspaceName] ', 'fork workspace to a new folder') + .option('-f, --force', 'rm workspace dir if exists') + .action( + async ( + workspaceName: string, + dir?: string, + options?: { + force: boolean; + } + ) => { + const { force = false } = options ?? {}; + + const defaultBaseDir = path.dirname(process.cwd()); + + const forkedWorkspaceLocation = path.resolve( + defaultBaseDir, + 'tmp', + dir ?? 'forked' + ); + + consola.info( + `Forked workspace will be created in: ${chalk.green( + forkedWorkspaceLocation + )}` + ); + + if (fs.existsSync(forkedWorkspaceLocation)) { + if (force) { + // TODO: confirm + consola.warn(`A non-empty dir will be removed.`); + + const confirm = await CLIUtils.createConfirmSelector( + 'Confirm Operation?' + ); + + confirm + ? fs.rmSync(forkedWorkspaceLocation, { + recursive: true, + }) + : consola.info('Operation Cancelled'); + + !confirm && process.exit(0); + } else { + consola.fatal( + `Target workspace dir: ${chalk.green( + forkedWorkspaceLocation + )} exists, use ${chalk.white('-f, --force')} to overwrite it.` + ); + + process.exit(0); + } + } + + const pickedPackages = await CLIUtils.createPackageMultiSelector( + 'picked', + 'Pick packages to use in forked workspace', + false + ); + + consola.info( + `Forking workspace packages: ${chalk.white( + pickedPackages.join(', ') + )}...` + ); + + for (const pkg of pickedPackages) { + const packageSourcePath = CLIUtils.resolvePackageDir(pkg); + const packageDestPath = path.resolve( + forkedWorkspaceLocation, + 'packages', + pkg + ); + + fs.copySync(packageSourcePath, packageDestPath, { + recursive: true, + filter: (src, dest) => { + const filtered = ['node_modules', 'dist', 'tmp'].every( + (pattern) => !src.includes(pattern) + ); + + return filtered; + }, + }); + } + + consola.success(`Workspace packages copied.`); + + consola.info(`Forking workspace assets...`); + + const workspaceBase = fs + .readdirSync(process.cwd()) + .filter( + (d) => + !['node_modules', 'dist', 'tmp', '.git', 'packages'].includes(d) + ); + + for (const baseAsset of workspaceBase) { + const baseAssetPath = path.resolve(process.cwd(), baseAsset); + + const forkedAssetPath = path.resolve( + forkedWorkspaceLocation, + baseAsset + ); + + fs.copySync(baseAssetPath, forkedAssetPath); + } + + consola.success(`Workspace assets copied.`); + + consola.success( + `Brand new workspace forked to ${chalk.green( + forkedWorkspaceLocation + )}` + ); + + console.log(''); + consola.info( + `Executing ${chalk.white('Deps Installation')} and ${chalk.white( + 'Env Setup' + )}...` + ); + + const spinner = ora('Installing dependencies...').start(); + + CLIUtils.useChildProcess( + 'pnpm install --registry=https://registry.npmmirror.com', + { + cwd: forkedWorkspaceLocation, + stdio: 'ignore', + } + ) + .then(() => { + spinner.succeed('Dependencies installed!'); + + return Promise.resolve(); + }) + .then(() => { + consola.success('Openning workspace in VS Code...'); + CLIUtils.useChildProcess(`code ${forkedWorkspaceLocation}`); + return Promise.resolve(); + }); + } + ); +} diff --git a/scripts/utils.ts b/scripts/utils.ts index f09bf94..750c2be 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -119,6 +119,16 @@ export class CLIUtils { return null; } + public static async createConfirmSelector(message: string): Promise { + const res = await enquirer.prompt>({ + type: 'confirm', + name: 'confirm', + message, + }); + + return res.confirm; + } + public static async createPackageMultiSelector( name: T, message: string, @@ -264,7 +274,8 @@ export class CLIUtils { command: string, options?: execa.Options ) { - consola.info(`Executing command: ${command} \n`); + console.log(''); + consola.info(`Executing command: ${chalk.cyan(command)}`); await execa(command, { stdio: 'inherit',