From 2f8abfe96331f623f10da5b72d8b9e93408d5262 Mon Sep 17 00:00:00 2001 From: Clayton Carter Date: Thu, 18 Jan 2024 07:27:27 -0500 Subject: [PATCH] feat(link): add --force flag --- spec/link-spec.js | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/link.js | 4 ++++ 2 files changed, 55 insertions(+) diff --git a/spec/link-spec.js b/spec/link-spec.js index 9d399e36..84aebf42 100644 --- a/spec/link-spec.js +++ b/spec/link-spec.js @@ -69,6 +69,57 @@ describe('apm link/unlink', () => { }); }); + describe('when linking a path that already exists', () => { + it('logs an error and exits', () => { + const atomHome = temp.mkdirSync('apm-home-dir-'); + process.env.ATOM_HOME = atomHome; + const packageToLink = temp.mkdirSync('a-package-'); + + const existingPackageDir = path.join(atomHome, 'packages', path.basename(packageToLink)); + fs.mkdirSync(existingPackageDir, {recursive: true}); + fs.writeFileSync(path.join(existingPackageDir, 'foo.txt'), ''); + + fs.writeFileSync(path.join(packageToLink, 'bar.txt'), ''); + process.chdir(packageToLink); + const callback = jasmine.createSpy('callback'); + + apm.run(['link'], callback); + waitsFor('command to complete', () => callback.callCount > 0); + + runs(() => { + expect(console.error.mostRecentCall.args[0].length).toBeGreaterThan(0); + expect(callback.mostRecentCall.args[0]).not.toBeUndefined(); + + expect(fs.existsSync(path.join(existingPackageDir, 'foo.txt'))).toBeTruthy(); + expect(fs.existsSync(path.join(existingPackageDir, 'bar.txt'))).toBeFalsy(); + }); + }); + + it('overwrites the path if the --force flag is passed', () => { + const atomHome = temp.mkdirSync('apm-home-dir-'); + process.env.ATOM_HOME = atomHome; + const packageToLink = temp.mkdirSync('a-package-'); + + const existingPackageDir = path.join(atomHome, 'packages', path.basename(packageToLink)); + fs.mkdirSync(existingPackageDir, {recursive: true}); + fs.writeFileSync(path.join(existingPackageDir, 'foo.txt'), ''); + + fs.writeFileSync(path.join(packageToLink, 'bar.txt'), ''); + process.chdir(packageToLink); + const callback = jasmine.createSpy('callback'); + + apm.run(['link', '--force'], callback); + waitsFor('command to complete', () => callback.callCount > 0); + + runs(() => { + expect(fs.existsSync(existingPackageDir)).toBeTruthy(); + expect(fs.realpathSync(existingPackageDir)).toBe(fs.realpathSync(packageToLink)); + expect(fs.existsSync(path.join(existingPackageDir, 'foo.txt'))).toBeFalsy(); + expect(fs.existsSync(path.join(existingPackageDir, 'bar.txt'))).toBeTruthy(); + }); + }); + }); + describe('when the hard flag is true', () => { it('unlinks the package from both $ATOM_HOME/packages and $ATOM_HOME/dev/packages', () => { const atomHome = temp.mkdirSync('apm-home-dir-'); diff --git a/src/link.js b/src/link.js index 5b3492e6..d47bad48 100644 --- a/src/link.js +++ b/src/link.js @@ -25,6 +25,7 @@ Run \`ppm links\` to view all the currently linked packages.\ ` ); options.alias('h', 'help').describe('help', 'Print this usage message'); + options.alias('f', 'force').boolean('force').describe('force', 'Remove the target path before linking'); return options.alias('d', 'dev').boolean('dev').describe('dev', 'Link to ~/.pulsar/dev/packages'); } @@ -50,6 +51,9 @@ Run \`ppm links\` to view all the currently linked packages.\ try { if (fs.isSymbolicLinkSync(targetPath)) { fs.unlinkSync(targetPath); } + else if (options.argv.force && fs.existsSync(targetPath)) { + fs.rmSync(targetPath, { recursive: true, force: true }); + } fs.makeTreeSync(path.dirname(targetPath)); fs.symlinkSync(linkPath, targetPath, 'junction'); console.log(`${targetPath} -> ${linkPath}`);