From 0f2ae2e6b5e139976506a9560f02d4605d79dfbd Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 12 May 2021 11:13:10 -0400 Subject: [PATCH] Fix ability to use add-track force --- .../src/commands/add-track.test.ts | 118 ++++++++---------- .../jbrowse-cli/src/commands/add-track.ts | 51 ++++---- 2 files changed, 76 insertions(+), 93 deletions(-) diff --git a/products/jbrowse-cli/src/commands/add-track.test.ts b/products/jbrowse-cli/src/commands/add-track.test.ts index e4c2e1394ea..5b660122e5a 100644 --- a/products/jbrowse-cli/src/commands/add-track.test.ts +++ b/products/jbrowse-cli/src/commands/add-track.test.ts @@ -9,43 +9,27 @@ import { setup } from '../testUtil' const fsPromises = fs.promises -const simpleBam = path.join(__dirname, '..', '..', 'test', 'data', 'simple.bam') -const simpleBai = path.join(__dirname, '..', '..', 'test', 'data', 'simple.bai') -const testConfig = path.join( - __dirname, - '..', - '..', - 'test', - 'data', - 'test_config.json', -) +const baseDir = path.join(__dirname, '..', '..', 'test', 'data') +const simpleBam = path.join(baseDir, 'simple.bam') +const simpleBai = path.join(baseDir, 'simple.bai') +const testConfig = path.join(baseDir, 'test_config.json') async function initctx(ctx: { dir: string }) { - await fsPromises.copyFile( - testConfig, - path.join(ctx.dir, path.basename(testConfig)), - ) - - await fsPromises.rename( - path.join(ctx.dir, path.basename(testConfig)), - path.join(ctx.dir, 'config.json'), - ) + await fsPromises.copyFile(testConfig, path.join(ctx.dir, 'config.json')) } async function init2bit(ctx: { dir: string }) { - const simple2bit = path.join( - __dirname, - '..', - '..', - 'test', - 'data', - 'simple.2bit', - ) await fsPromises.copyFile( - simple2bit, - path.join(ctx.dir, path.basename(simple2bit)), + path.join(baseDir, 'simple.2bit'), + path.join(ctx.dir, 'simple.2bit'), ) } +async function readConf(ctx: { dir: string }) { + return fsPromises.readFile(path.join(ctx.dir, 'config.json'), { + encoding: 'utf8', + }) +} + describe('add-track', () => { setup.command(['add-track']).exit(2).it('fails if no track is specified') setup @@ -67,11 +51,36 @@ describe('add-track', () => { .command(['add-track', simpleBam, '--load', 'copy']) .command(['add-track', simpleBam, '--load', 'copy']) .exit(160) - .it('Cannot add a track with the same track id') + .it('cannot add a track with the same track id') + + setup + .do(initctx) + .command(['add-track', simpleBam, '--load', 'symlink']) + .command(['add-track', simpleBam, '--load', 'symlink', '--force']) + .it('use force to overwrite a symlink') + + setup + .do(initctx) + .command(['add-track', simpleBam, '--load', 'copy']) + .command(['add-track', simpleBam, '--load', 'copy', '--force']) + .it('use force to overwrite a copied file') + + // setting up a test for move difficult currently, because it would literally + // move the file in our test data... + // setup + // .do(initctx) + // .do(async ctx => { + // await fsPromises.copyFile(simpleBam, path.join(ctx.dir, 'new.bam')) + // await fsPromises.copyFile(simpleBai, path.join(ctx.dir, 'new.bam.bai')) + // }) + // .command(['add-track', 'new.bam', '--load', 'move']) + // .command(['add-track', 'new.bam', '--load', 'move', '--force']) + // .it('use force to overwrite a moved file') + setup .command(['add-track', simpleBam, '--load', 'copy']) .catch(/no such file or directory/) - .it('Cannot add a track if there is no config file') + .it('cannot add a track if there is no config file') setup .do(initctx) .do(ctx => { @@ -88,11 +97,7 @@ describe('add-track', () => { .do(initctx) .command(['add-track', simpleBam, '--load', 'copy']) .it('adds a track', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) - + const contents = await readConf(ctx) expect(fs.existsSync(path.join(ctx.dir, 'simple.bam'))).toBeTruthy() expect(fs.existsSync(path.join(ctx.dir, 'simple.bam.bai'))).toBeTruthy() @@ -128,10 +133,7 @@ describe('add-track', () => { .do(initctx) .command(['add-track', '/testing/in/place.bam', '--load', 'inPlace']) .it('adds a track with load inPlace', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) + const contents = await readConf(ctx) expect(JSON.parse(contents).tracks).toEqual([ { @@ -171,10 +173,7 @@ describe('add-track', () => { '/something/else/random.bai', ]) .it('adds a track with load inPlace', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) + const contents = await readConf(ctx) expect(JSON.parse(contents).tracks).toEqual([ { @@ -215,11 +214,7 @@ describe('add-track', () => { simpleBai, ]) .it('adds a track', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) - + const contents = await readConf(ctx) expect(fs.existsSync(path.join(ctx.dir, 'simple.bam'))).toBeTruthy() expect(fs.existsSync(path.join(ctx.dir, 'simple.bai'))).toBeTruthy() @@ -255,10 +250,7 @@ describe('add-track', () => { .do(initctx) .command(['add-track', simpleBam, '--load', 'copy', '--subDir', 'bam']) .it('adds a track with subDir', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) + const contents = await readConf(ctx) expect(JSON.parse(contents).tracks).toEqual([ { type: 'AlignmentsTrack', @@ -300,10 +292,7 @@ describe('add-track', () => { 'bam', ]) .it('adds a track with subDir', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) + const contents = await readConf(ctx) expect(JSON.parse(contents).tracks).toEqual([ { type: 'AlignmentsTrack', @@ -355,10 +344,7 @@ describe('add-track', () => { '{"defaultRendering": "test"}', ]) .it('adds a track with all the custom fields', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) + const contents = await readConf(ctx) expect(JSON.parse(contents).tracks).toEqual([ { type: 'CustomTrackType', @@ -388,10 +374,7 @@ describe('add-track', () => { .do(initctx) .command(['add-track', 'https://mysite.com/data/simple.bam']) .it('adds a track from a url', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) + const contents = await readConf(ctx) expect(JSON.parse(contents).tracks).toEqual([ { type: 'AlignmentsTrack', @@ -445,10 +428,7 @@ describe('add-track', () => { 'testAssembly', ]) .it('adds a track to a config with multiple assemblies', async ctx => { - const contents = await fsPromises.readFile( - path.join(ctx.dir, 'config.json'), - { encoding: 'utf8' }, - ) + const contents = await readConf(ctx) expect(JSON.parse(contents).tracks).toEqual([ { type: 'AlignmentsTrack', diff --git a/products/jbrowse-cli/src/commands/add-track.ts b/products/jbrowse-cli/src/commands/add-track.ts index feb09326b63..dd93b376917 100644 --- a/products/jbrowse-cli/src/commands/add-track.ts +++ b/products/jbrowse-cli/src/commands/add-track.ts @@ -292,21 +292,28 @@ export default class AddTrack extends JBrowseCommand { } // copy/symlinks/moves the track into the jbrowse installation directory - const filePaths = Object.values(this.guessFileNames(location, index)) + const filePaths = Object.values( + this.guessFileNames(location, index), + ).filter(f => !!f) as string[] + + const destinationFn = (dir: string, file: string) => + path.join(dir, subDir, path.basename(file)) switch (load) { case 'copy': { await Promise.all( filePaths.map(async filePath => { - if (!filePath) { - return undefined + const dest = destinationFn(configDirectory, filePath) + try { + if (force) await fsPromises.unlink(dest) + } catch (e) { + this.error(e) } - const dataLocation = path.join( - configDirectory, - subDir, - path.basename(filePath), + return fsPromises.copyFile( + filePath, + dest, + fs.constants.COPYFILE_EXCL, ) - return fsPromises.copyFile(filePath, dataLocation) }), ) break @@ -314,15 +321,13 @@ export default class AddTrack extends JBrowseCommand { case 'symlink': { await Promise.all( filePaths.map(async filePath => { - if (!filePath) { - return undefined + const dest = destinationFn(configDirectory, filePath) + try { + if (force) await fsPromises.unlink(dest) + } catch (e) { + this.error(e) } - const dataLocation = path.join( - configDirectory, - subDir, - path.basename(filePath), - ) - return fsPromises.symlink(filePath, dataLocation) + return fsPromises.symlink(filePath, dest) }), ) break @@ -330,15 +335,13 @@ export default class AddTrack extends JBrowseCommand { case 'move': { await Promise.all( filePaths.map(async filePath => { - if (!filePath) { - return undefined + const dest = destinationFn(configDirectory, filePath) + try { + if (force) await fsPromises.unlink(dest) + } catch (e) { + this.error(e) } - const dataLocation = path.join( - configDirectory, - subDir, - path.basename(filePath), - ) - return fsPromises.rename(filePath, dataLocation) + return fsPromises.rename(filePath, dest) }), ) break