diff --git a/README.md b/README.md index 3d98cb5..971a6aa 100644 --- a/README.md +++ b/README.md @@ -67,11 +67,26 @@ If the binaries don't work in `mac` or `windows` please install it via `npm` glo #### Usage +Bootstrapping the packages +It will run `npm install` inside the current working directory +This will install local packages referenced inside `fireDependencies` +It means that `node_modules` folder will be already populated with appropriate packages after `npm install` + +```bash +firelink --bootstrap --no-runner +``` + +Deploying as usual + ```bash firelink deploy ``` -The same as `firebase deploy` the only differance is that it will COPY monorepos replace package.json > dependencies with appropriate local file structure and then will revert changes after `firebase` script exit +You can also use one liner replacement for `npm install` and `firebase deploy` + +```bash +firelink deploy --bootstrap +``` #### Leave changes to package.json after command execution exited @@ -133,19 +148,6 @@ Revert the changes made inside `package.json` firelink --no-runner --revert-changes ``` -#### Native Nodejs Copy instead of `rsync` - -This argument is introduced due to recent issue that has being made https://github.com/rxdi/firelink/issues/55 -It appears that in the newest nodejs 16 docker image rsync package is missing - -There is a way to specify which runner firelink will use -when specify `--use-native-copy` it will default to nodejs implementation of recursive copy the files -By default in windows environment this is the main method used to copy files since `rsync` is missing in windows - -``` -firelink --use-native-copy -``` - # Configuration Default runner is command `firebase` but you can change it for example to `gcloud` or `serverless` by defining `fireConfig` inside `package.json` @@ -153,30 +155,13 @@ Default runner is command `firebase` but you can change it for example to `gclou ```json { "fireConfig": { - "runner": "firebase", - "outFolderName": ".packages", - "outFolderLocation": ".", - "excludes": ["node_modules"], - "useNativeCopy": true + "runner": "firebase" } } ``` -`excludes` property can exclude some folders or files from being copied it accepts `Array` from `string` - -For example we may want to install dependencies of the packages when deploying using local npm path, -so we want to not waste time duplicating node modules - -Equivalent of excludes inside package.json `.fireignore` can be specified as a file inside a directory where the command `firelink` will be executed. `.fireignore` behaviour is the same as `.gitignore` - -If you do not wish to use `.fireignore` file name the name can be specified from `fireConfig.excludesFileName` - You can pass `--runner dir` argument to the command which will override the default runner `firebase` -By default packages will be saved in `.packages` folder and `current` directory will be used -U can change that by specifiyng properties `outFolderName` and `outFolderLocation` inside `fireConfig` -Check `example` folder inside this repository - You can put even `dir` command ```json diff --git a/example/package-lock.json b/example/package-lock.json index cdf3899..233d803 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -4,7 +4,7 @@ "lockfileVersion": 1, "dependencies": { "@test/dependency": { - "version": "file:.packages/dependency" + "version": "file:packages/dependency" } } } diff --git a/example/package.json b/example/package.json index 9509d1f..27fb36f 100644 --- a/example/package.json +++ b/example/package.json @@ -7,12 +7,6 @@ "@test/dependency": "./packages/dependency" }, "fireConfig": { - "runner": "npm", - "outFolderName": ".packages", - "outFolderLocation": ".", - "excludes": [ - "node_modules" - ], - "useNativeCopy": true + "runner": "firebase" } } \ No newline at end of file diff --git a/package.json b/package.json index 6d5c312..e0cc989 100644 --- a/package.json +++ b/package.json @@ -42,4 +42,4 @@ "ts-jest": "29.0.3", "typescript": "^4.8.4" } -} +} \ No newline at end of file diff --git a/src/create-virtual-symlink.spec.ts b/src/create-virtual-symlink.spec.ts index d95e1a2..a1cf8b9 100644 --- a/src/create-virtual-symlink.spec.ts +++ b/src/create-virtual-symlink.spec.ts @@ -2,7 +2,7 @@ import { createVirtualSymlink } from './create-virtual-symlink'; import { PackageJson } from './injection-tokens'; const mockBuildPackages = jest.fn(); -const mockCopyPackages = jest.fn(); +// const mockCopyPackages = jest.fn(); const mockExitHandler = jest.fn(); const mockModifyJson = jest.fn(); const mockRevertJson = jest.fn(); @@ -11,15 +11,15 @@ const mockRunCommand = jest.fn(); jest.mock('./helpers/build-packages', () => ({ buildPackages: async (...args: unknown[]) => mockBuildPackages(...args), })); -jest.mock('./helpers/copy-packages', () => ({ - copyPackages: - (...args: unknown[]) => - () => - () => - () => - () => - mockCopyPackages(...args), -})); +// jest.mock('./helpers/copy-packages', () => ({ +// copyPackages: +// (...args: unknown[]) => +// () => +// () => +// () => +// () => +// mockCopyPackages(...args), +// })); jest.mock('./helpers/exit-handler', () => ({ exitHandler: (...args: unknown[]) => mockExitHandler(...args), })); @@ -75,7 +75,7 @@ describe('createVirtualSymlink', () => { it('should update dependencies if fireDependencies are present in original package.json', async () => { mockRunCommand.mockImplementationOnce(() => Promise.resolve(true)); await createVirtualSymlink(fakePackageJson, outFolder, outFolderName); - expect(mockCopyPackages).toHaveBeenCalledTimes(1); + // expect(mockCopyPackages).toHaveBeenCalledTimes(1); expect(mockModifyJson).toHaveBeenCalledTimes(1); expect(mockRunCommand).toHaveBeenCalledTimes(1); expect(mockExitHandler).toHaveBeenCalledWith(fakePackageJson, true); @@ -85,7 +85,7 @@ describe('createVirtualSymlink', () => { process.argv.push('--buildCommand'); mockRunCommand.mockImplementationOnce(() => Promise.resolve(true)); await createVirtualSymlink(fakePackageJson, outFolder, outFolderName); - expect(mockCopyPackages).toHaveBeenCalledTimes(1); + // expect(mockCopyPackages).toHaveBeenCalledTimes(1); expect(mockBuildPackages).toHaveBeenCalledTimes(1); expect(mockModifyJson).toHaveBeenCalledTimes(1); expect(mockRunCommand).toHaveBeenCalledTimes(1); diff --git a/src/create-virtual-symlink.ts b/src/create-virtual-symlink.ts index e605067..69b6eca 100644 --- a/src/create-virtual-symlink.ts +++ b/src/create-virtual-symlink.ts @@ -1,11 +1,10 @@ import { includes, nextOrDefault } from './helpers/args-extractors'; import { buildPackages } from './helpers/build-packages'; -import { copyPackages } from './helpers/copy-packages'; import { exitHandler } from './helpers/exit-handler'; import { modifyJson } from './helpers/modify-json'; -import { readExcludes } from './helpers/read-excludes'; import { revertJson } from './helpers/revert-json'; import { runCommand } from './helpers/run-command'; +import { Worker } from './helpers/worker'; import { DEFAULT_RUNNER, FireLinkConfig, @@ -27,13 +26,6 @@ export async function createVirtualSymlink( packageJson.fireConfig.runner || DEFAULT_RUNNER; - const excludes = [ - ...(packageJson.fireConfig.excludes || []), - ...(await readExcludes( - packageJson.fireConfig.excludesFileName || '.fireignore', - )), - ]; - if (includes(Tasks.REVERT)) { return await revertJson( WorkingFiles.PACKAGE_JSON, @@ -49,9 +41,7 @@ export async function createVirtualSymlink( dep, folder: linkedDepndencies[dep], })); - await copyPackages(dependencies)(outFolder)(outFolderName)(excludes)( - includes(Tasks.USE_NATIVE_COPY) || packageJson.fireConfig.useNativeCopy, - ); + if (includes(Tasks.BUILD)) { try { await buildPackages(outFolder, outFolderName); @@ -75,6 +65,9 @@ export async function createVirtualSymlink( } try { + if (includes(Tasks.BOOTSTRAP)) { + await Worker({ command: 'npm', args: ['install'] }); + } if (!includes(Tasks.NO_RUNNER)) { await runCommand(runner, process.argv); } diff --git a/src/helpers/build-packages.ts b/src/helpers/build-packages.ts index 68e5500..3d990cc 100644 --- a/src/helpers/build-packages.ts +++ b/src/helpers/build-packages.ts @@ -11,14 +11,11 @@ export async function buildPackages(outFolder: string, outFolderName: string) { ( await promisify(readdir)(join(outFolder, outFolderName)) ).map(async (dir) => { - await Worker( - { - command: 'npx', - args: (nextOrDefault(Tasks.BUILD, 'tsc') as string).split(' '), - cwd: join(outFolder, outFolderName, dir), - }, - false, - ); + await Worker({ + command: 'npx', + args: (nextOrDefault(Tasks.BUILD, 'tsc') as string).split(' '), + cwd: join(outFolder, outFolderName, dir), + }); }), ); } diff --git a/src/helpers/copy-packages.ts b/src/helpers/copy-packages.ts deleted file mode 100644 index 370424d..0000000 --- a/src/helpers/copy-packages.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { join } from 'path'; - -import { DependenciesLink, isWin } from '../injection-tokens'; -import { FolderSync } from './copy-recursive'; -import { Worker } from './worker'; - -function copyOther( - folder: string, - outFolder: string, - outFolderName: string, - excludes: string[], -) { - return Worker({ - command: 'rsync', - args: [ - '-r', - '--force', - ...(excludes - ? excludes.reduce( - (prev, curr) => [...prev, '--exclude', curr], - [] as string[], - ) - : []), - folder, - `${outFolder}/${outFolderName}`, - ], - }); -} - -export function copyPackages(dependencies: DependenciesLink[]) { - return (outFolder: string) => - (outFolderName: string) => - (excludes: string[]) => - (nativeCopyEnabled?: boolean) => - Promise.all( - dependencies.map(({ folder }) => - nativeCopyEnabled || isWin - ? FolderSync.copyFolderRecursive( - folder, - join(outFolder, outFolderName), - ) - : copyOther(folder, outFolder, outFolderName, excludes), - ), - ); -} - -/* Cannot make it work to behave the same as rsync in windows for now */ - -// function copyWindows( -// folder: string, -// outFolder: string, -// outFolderName: string, -// excludes: string[], -// ) { -// console.log(folder); -// console.log([outFolder, outFolderName].join('\\')); -// return Worker({ -// command: 'cmd', -// args: [ -// '/c', -// 'robocopy', -// folder, -// [outFolder, outFolderName].join('\\'), -// '/s', -// '/e', -// '*.*', -// ...(excludes -// ? excludes.reduce( -// (prev, curr) => [...prev, '/xd', curr], -// [] as string[], -// ) -// : []), -// ], -// }); -// } diff --git a/src/helpers/copy-recursive.ts b/src/helpers/copy-recursive.ts deleted file mode 100644 index 6aad562..0000000 --- a/src/helpers/copy-recursive.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { lstat, mkdir, readdir, readFile, writeFile } from 'fs'; -import { basename, join } from 'path'; -import { promisify } from 'util'; - -import { fileExists } from './file-exists'; - -export class FolderSync { - public static async copyFile(source: string, target: string) { - let targetFile = target; - - if (await fileExists(target)) { - if ((await promisify(lstat)(target)).isDirectory()) { - targetFile = join(target, basename(source)); - } - } - - await promisify(writeFile)(targetFile, await promisify(readFile)(source)); - } - - public static async copyFolderRecursive(source: string, target: string) { - const targetFolder = join(target, basename(source)); - if (!(await fileExists(targetFolder))) { - await promisify(mkdir)(targetFolder, { recursive: true }); - } - - const sourceExists = await promisify(lstat)(source); - - if (sourceExists.isDirectory()) { - const files = await promisify(readdir)(source); - await Promise.all( - files.map(async (file) => { - const currrentSource = join(source, file); - const isCurrentExists = await this.isExists(currrentSource); - - if (isCurrentExists.isDirectory()) { - await this.copyFolderRecursive(currrentSource, targetFolder); - } else { - await this.copyFile(currrentSource, targetFolder); - } - }), - ); - } - return new Promise((resolve) => { - /** - * There is a time between notifiyng the OS for saving files and saving them actually. - * Lets wait 1 second for everything to finish and to be actually saved in the storage - */ - setTimeout(() => { - resolve(true); - }, 1000); - }); - } - - private static isExists(source: string) { - return promisify(lstat)(source); - } -} diff --git a/src/helpers/read-excludes.ts b/src/helpers/read-excludes.ts deleted file mode 100644 index 7f27c50..0000000 --- a/src/helpers/read-excludes.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { readFile } from 'fs'; -import { promisify } from 'util'; - -import { parseIgnoredFiles } from './parse-ignore'; - -export async function readExcludes(file: string) { - try { - const ignore = await promisify(readFile)(file, { - encoding: 'utf-8', - }); - return parseIgnoredFiles(ignore); - } catch (e) { - return []; - } -} diff --git a/src/helpers/run-command.ts b/src/helpers/run-command.ts index e8deedf..57ba16b 100644 --- a/src/helpers/run-command.ts +++ b/src/helpers/run-command.ts @@ -12,12 +12,7 @@ export async function runCommand( runner, ...args .slice(2) - .filter( - (a) => - a !== Tasks.LEAVE_CHANGES && - a !== Tasks.REVERT && - a !== Tasks.BUILD, - ), + .filter((a) => !Object.values(Tasks).includes(a as never)), ], }); } diff --git a/src/helpers/worker.ts b/src/helpers/worker.ts index d57a2d2..934c270 100644 --- a/src/helpers/worker.ts +++ b/src/helpers/worker.ts @@ -8,14 +8,11 @@ export const Worker = ( args: [], }, - log = true, ): Promise => { return new Promise((resolve, reject) => { - const child = spawn(command, args, { cwd }); - if (log) { - child.stderr.pipe(process.stderr); - child.stdout.pipe(process.stdout); - } + const child = spawn(command, args, { cwd: cwd || process.cwd() }); + child.stderr.pipe(process.stderr); + child.stdout.pipe(process.stdout); child.on('close', (code: number) => { if (code !== 0) { return reject(!code); diff --git a/src/injection-tokens.ts b/src/injection-tokens.ts index 5c81b44..32727e1 100644 --- a/src/injection-tokens.ts +++ b/src/injection-tokens.ts @@ -38,8 +38,8 @@ export enum Tasks { BUILD = '--buildCommand', LEAVE_CHANGES = '--leave-changes', NO_RUNNER = '--no-runner', - USE_NATIVE_COPY = '--use-native-copy', RUNNER = '--runner', + BOOTSTRAP = '--bootstrap', } export interface DependenciesLink {