@jbrowse/cli 3.6.0 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/run +1 -1
- package/dist/base.js +5 -0
- package/dist/bin.js +3 -0
- package/dist/commands/add-assembly.js +143 -0
- package/dist/commands/add-connection.js +177 -0
- package/dist/commands/add-track-json.js +81 -0
- package/dist/commands/add-track-utils/adapter-utils.js +304 -0
- package/dist/commands/add-track-utils/file-operations.js +36 -0
- package/dist/commands/add-track-utils/track-config.js +63 -0
- package/dist/commands/add-track-utils/validators.js +74 -0
- package/dist/commands/add-track.js +193 -0
- package/dist/commands/admin-server-utils.js +238 -0
- package/dist/commands/admin-server.js +51 -0
- package/dist/commands/assembly-utils.js +410 -0
- package/dist/commands/create.js +121 -0
- package/dist/commands/make-pif-utils/cigar-utils.js +29 -0
- package/dist/commands/make-pif-utils/file-utils.js +38 -0
- package/dist/commands/make-pif-utils/pif-generator.js +64 -0
- package/dist/commands/make-pif-utils/validators.js +22 -0
- package/dist/commands/make-pif.js +58 -0
- package/dist/commands/remove-track.js +58 -0
- package/dist/commands/set-default-session.js +104 -0
- package/dist/commands/sort-bed-utils/constants.js +12 -0
- package/dist/commands/sort-bed-utils/process-utils.js +23 -0
- package/dist/commands/sort-bed-utils/sort-utils.js +24 -0
- package/dist/commands/sort-bed-utils/validators.js +22 -0
- package/dist/commands/sort-bed.js +49 -0
- package/dist/commands/sort-gff-utils/constants.js +13 -0
- package/dist/commands/sort-gff-utils/process-utils.js +23 -0
- package/dist/commands/sort-gff-utils/sort-utils.js +55 -0
- package/dist/commands/sort-gff-utils/validators.js +21 -0
- package/dist/commands/sort-gff.js +49 -0
- package/dist/commands/text-index-utils/adapter-utils.js +63 -0
- package/dist/commands/text-index-utils/aggregate.js +87 -0
- package/dist/commands/text-index-utils/config-utils.js +59 -0
- package/dist/commands/text-index-utils/file-list.js +31 -0
- package/dist/commands/text-index-utils/index.js +9 -0
- package/dist/commands/text-index-utils/indexing-utils.js +84 -0
- package/dist/commands/text-index-utils/per-track.js +65 -0
- package/dist/commands/text-index-utils/validators.js +20 -0
- package/dist/commands/text-index.js +113 -0
- package/dist/commands/track-utils.js +85 -0
- package/dist/commands/upgrade.js +122 -0
- package/dist/fetchWithProxy.js +12 -0
- package/dist/index.js +119 -0
- package/dist/types/common.js +128 -0
- package/dist/types/gff3Adapter.js +73 -0
- package/dist/types/vcfAdapter.js +76 -0
- package/dist/util.js +35 -0
- package/dist/utils.js +154 -0
- package/package.json +3 -3
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.run = run;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const util_1 = require("util");
|
|
9
|
+
const decompress_1 = __importDefault(require("decompress"));
|
|
10
|
+
const fetchWithProxy_1 = __importDefault(require("../fetchWithProxy"));
|
|
11
|
+
const utils_1 = require("../utils");
|
|
12
|
+
const fsPromises = fs_1.default.promises;
|
|
13
|
+
const description = 'Downloads and installs the latest JBrowse 2 release';
|
|
14
|
+
const examples = [
|
|
15
|
+
'# Download latest release from github, and put in specific path',
|
|
16
|
+
'$ jbrowse create /path/to/new/installation',
|
|
17
|
+
'',
|
|
18
|
+
'# Download latest release from github and force overwrite existing contents at path',
|
|
19
|
+
'$ jbrowse create /path/to/new/installation --force',
|
|
20
|
+
'',
|
|
21
|
+
'# Download latest release from a specific URL',
|
|
22
|
+
'$ jbrowse create /path/to/new/installation --url url.com/directjbrowselink.zip',
|
|
23
|
+
'',
|
|
24
|
+
'# Download a specific tag from github',
|
|
25
|
+
'$ jbrowse create /path/to/new/installation --tag v1.0.0',
|
|
26
|
+
'',
|
|
27
|
+
'# List available versions',
|
|
28
|
+
'$ jbrowse create --listVersions',
|
|
29
|
+
];
|
|
30
|
+
const options = {
|
|
31
|
+
help: {
|
|
32
|
+
type: 'boolean',
|
|
33
|
+
short: 'h',
|
|
34
|
+
description: 'Show help',
|
|
35
|
+
},
|
|
36
|
+
force: {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
short: 'f',
|
|
39
|
+
description: 'Overwrites existing JBrowse 2 installation if present in path',
|
|
40
|
+
},
|
|
41
|
+
listVersions: {
|
|
42
|
+
type: 'boolean',
|
|
43
|
+
short: 'l',
|
|
44
|
+
description: 'Lists out all versions of JBrowse 2',
|
|
45
|
+
},
|
|
46
|
+
branch: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'Download a development build from a named git branch',
|
|
49
|
+
},
|
|
50
|
+
nightly: {
|
|
51
|
+
type: 'boolean',
|
|
52
|
+
description: 'Download the latest development build from the main branch',
|
|
53
|
+
},
|
|
54
|
+
url: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
short: 'u',
|
|
57
|
+
description: 'A direct URL to a JBrowse 2 release',
|
|
58
|
+
},
|
|
59
|
+
tag: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
short: 't',
|
|
62
|
+
description: 'Version of JBrowse 2 to install. Format is v1.0.0.\nDefaults to latest',
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
async function run(args) {
|
|
66
|
+
const { positionals, values: runFlags } = (0, util_1.parseArgs)({
|
|
67
|
+
options,
|
|
68
|
+
allowPositionals: true,
|
|
69
|
+
args,
|
|
70
|
+
});
|
|
71
|
+
if (runFlags.help) {
|
|
72
|
+
(0, utils_1.printHelp)({
|
|
73
|
+
description,
|
|
74
|
+
examples,
|
|
75
|
+
usage: 'jbrowse create [localPath] [options]',
|
|
76
|
+
options,
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const argsPath = positionals[0];
|
|
81
|
+
if (!argsPath && !runFlags.listVersions) {
|
|
82
|
+
console.error(`Missing 1 required arg:
|
|
83
|
+
localPath Location where JBrowse 2 will be installed
|
|
84
|
+
See more help with --help`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const { force, url, listVersions, tag, branch, nightly } = runFlags;
|
|
88
|
+
if (listVersions) {
|
|
89
|
+
const versions = (await (0, utils_1.fetchGithubVersions)()).map(version => version.tag_name);
|
|
90
|
+
console.log(`All JBrowse versions:\n${versions.join('\n')}`);
|
|
91
|
+
process.exit(0);
|
|
92
|
+
}
|
|
93
|
+
// mkdir will do nothing if dir exists
|
|
94
|
+
await fsPromises.mkdir(argsPath, { recursive: true });
|
|
95
|
+
if (!force) {
|
|
96
|
+
await checkPath(argsPath);
|
|
97
|
+
}
|
|
98
|
+
const locationUrl = url ||
|
|
99
|
+
(nightly ? await (0, utils_1.getBranch)('main') : '') ||
|
|
100
|
+
(branch ? await (0, utils_1.getBranch)(branch) : '') ||
|
|
101
|
+
(tag ? await (0, utils_1.getTag)(tag) : await (0, utils_1.getLatest)());
|
|
102
|
+
console.log(`Fetching ${locationUrl}...`);
|
|
103
|
+
const response = await (0, fetchWithProxy_1.default)(locationUrl);
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new Error(`HTTP ${response.status} fetching ${locationUrl}: ${response.statusText}`);
|
|
106
|
+
}
|
|
107
|
+
const type = response.headers.get('content-type');
|
|
108
|
+
if (url &&
|
|
109
|
+
type !== 'application/zip' &&
|
|
110
|
+
type !== 'application/octet-stream') {
|
|
111
|
+
throw new Error('The URL provided does not seem to be a JBrowse installation URL');
|
|
112
|
+
}
|
|
113
|
+
await (0, decompress_1.default)(Buffer.from(await response.arrayBuffer()), argsPath);
|
|
114
|
+
console.log(`Unpacked ${locationUrl} at ${argsPath}`);
|
|
115
|
+
}
|
|
116
|
+
async function checkPath(userPath) {
|
|
117
|
+
const allFiles = await fsPromises.readdir(userPath);
|
|
118
|
+
if (allFiles.length > 0) {
|
|
119
|
+
throw new Error(`This directory (${userPath}) has existing files and could cause conflicts with create. Please choose another directory or use the force flag to overwrite existing files`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseCigar = parseCigar;
|
|
4
|
+
exports.flipCigar = flipCigar;
|
|
5
|
+
exports.swapIndelCigar = swapIndelCigar;
|
|
6
|
+
const cigarRegex = new RegExp(/([MIDNSHPX=])/);
|
|
7
|
+
function parseCigar(cigar = '') {
|
|
8
|
+
return cigar.split(cigarRegex).slice(0, -1);
|
|
9
|
+
}
|
|
10
|
+
function flipCigar(cigar) {
|
|
11
|
+
const arr = [];
|
|
12
|
+
for (let i = cigar.length - 2; i >= 0; i -= 2) {
|
|
13
|
+
arr.push(cigar[i]);
|
|
14
|
+
const op = cigar[i + 1];
|
|
15
|
+
if (op === 'D') {
|
|
16
|
+
arr.push('I');
|
|
17
|
+
}
|
|
18
|
+
else if (op === 'I') {
|
|
19
|
+
arr.push('D');
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
arr.push(op);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return arr;
|
|
26
|
+
}
|
|
27
|
+
function swapIndelCigar(cigar) {
|
|
28
|
+
return cigar.replaceAll('D', 'K').replaceAll('I', 'D').replaceAll('K', 'I');
|
|
29
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getReadline = getReadline;
|
|
7
|
+
exports.getStdReadline = getStdReadline;
|
|
8
|
+
exports.createWriteWithBackpressure = createWriteWithBackpressure;
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const readline_1 = __importDefault(require("readline"));
|
|
11
|
+
const zlib_1 = require("zlib");
|
|
12
|
+
function getReadline(filename) {
|
|
13
|
+
const stream = fs_1.default.createReadStream(filename);
|
|
14
|
+
return readline_1.default.createInterface({
|
|
15
|
+
input: /.b?gz$/.exec(filename) ? stream.pipe((0, zlib_1.createGunzip)()) : stream,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function getStdReadline() {
|
|
19
|
+
return readline_1.default.createInterface({
|
|
20
|
+
input: process.stdin,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function createWriteWithBackpressure(stream) {
|
|
24
|
+
return (data) => {
|
|
25
|
+
// If the stream buffer is full (write returns false), we need to wait for drain
|
|
26
|
+
if (!stream.write(data)) {
|
|
27
|
+
return new Promise(resolve => {
|
|
28
|
+
const drainHandler = () => {
|
|
29
|
+
stream.removeListener?.('drain', drainHandler);
|
|
30
|
+
resolve();
|
|
31
|
+
};
|
|
32
|
+
stream.once?.('drain', drainHandler);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// If write returns true, the buffer is not full, so we can continue immediately
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createPIF = createPIF;
|
|
7
|
+
exports.spawnSortProcess = spawnSortProcess;
|
|
8
|
+
exports.getOutputFilename = getOutputFilename;
|
|
9
|
+
exports.waitForProcessClose = waitForProcessClose;
|
|
10
|
+
const child_process_1 = require("child_process");
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const cigar_utils_1 = require("./cigar-utils");
|
|
13
|
+
const file_utils_1 = require("./file-utils");
|
|
14
|
+
async function createPIF(filename, stream) {
|
|
15
|
+
const rl1 = filename ? (0, file_utils_1.getReadline)(filename) : (0, file_utils_1.getStdReadline)();
|
|
16
|
+
const writeWithBackpressure = (0, file_utils_1.createWriteWithBackpressure)(stream);
|
|
17
|
+
// Process the file line by line with backpressure handling
|
|
18
|
+
try {
|
|
19
|
+
for await (const line of rl1) {
|
|
20
|
+
const [c1, l1, s1, e1, strand, c2, l2, s2, e2, ...rest] = line.split('\t');
|
|
21
|
+
// Write the first line and handle backpressure
|
|
22
|
+
await writeWithBackpressure(`${[`t${c2}`, l2, s2, e2, strand, c1, l1, s1, e1, ...rest].join('\t')}\n`);
|
|
23
|
+
const cigarIdx = rest.findIndex(f => f.startsWith('cg:Z'));
|
|
24
|
+
const CIGAR = rest[cigarIdx];
|
|
25
|
+
if (CIGAR) {
|
|
26
|
+
rest[cigarIdx] = `cg:Z:${strand === '-'
|
|
27
|
+
? (0, cigar_utils_1.flipCigar)((0, cigar_utils_1.parseCigar)(CIGAR.slice(5))).join('')
|
|
28
|
+
: (0, cigar_utils_1.swapIndelCigar)(CIGAR.slice(5))}`;
|
|
29
|
+
}
|
|
30
|
+
// Write the second line and handle backpressure
|
|
31
|
+
await writeWithBackpressure(`${[`q${c1}`, l1, s1, e1, strand, c2, l2, s2, e2, ...rest].join('\t')}\n`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error('Error processing PAF file:', error);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
rl1.close();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function spawnSortProcess(outputFile, useCsi) {
|
|
43
|
+
// Use a more portable approach to avoid E2BIG errors
|
|
44
|
+
const sortCmd = `sort -t"\`printf '\\t'\`" -k1,1 -k3,3n`;
|
|
45
|
+
const bgzipCommand = `bgzip > "${outputFile}"`;
|
|
46
|
+
const tabixCommand = `tabix ${useCsi ? '-C ' : ''}-s1 -b3 -e4 -0 "${outputFile}"`;
|
|
47
|
+
const fullCommand = `${sortCmd} | ${bgzipCommand}; ${tabixCommand}`;
|
|
48
|
+
const minimalEnv = {
|
|
49
|
+
...process.env,
|
|
50
|
+
LC_ALL: 'C',
|
|
51
|
+
};
|
|
52
|
+
return (0, child_process_1.spawn)('sh', ['-c', fullCommand], {
|
|
53
|
+
env: minimalEnv,
|
|
54
|
+
stdio: ['pipe', process.stdout, process.stderr],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function getOutputFilename(file, out) {
|
|
58
|
+
return out || `${path_1.default.basename(file || 'output', '.paf')}.pif.gz`;
|
|
59
|
+
}
|
|
60
|
+
async function waitForProcessClose(child) {
|
|
61
|
+
return new Promise(resolve => {
|
|
62
|
+
child.on('close', resolve);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateFileArgument = validateFileArgument;
|
|
4
|
+
exports.validateRequiredCommands = validateRequiredCommands;
|
|
5
|
+
const command_exists_1 = require("command-exists");
|
|
6
|
+
function validateFileArgument(file) {
|
|
7
|
+
// Allow no file argument for stdin input
|
|
8
|
+
if (!file && process.stdin.isTTY) {
|
|
9
|
+
console.error('Error: Missing required argument: file');
|
|
10
|
+
console.error('Usage: jbrowse make-pif <file> [options]');
|
|
11
|
+
console.error(' OR pipe data via stdin: cat file.paf | jbrowse make-pif');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function validateRequiredCommands() {
|
|
16
|
+
const requiredCommands = ['sh', 'sort', 'grep', 'tabix', 'bgzip'];
|
|
17
|
+
const missingCommands = requiredCommands.filter(cmd => !(0, command_exists_1.sync)(cmd));
|
|
18
|
+
if (missingCommands.length > 0) {
|
|
19
|
+
console.error('Error: Unable to sort, requires unix type environment with sort, grep, bgzip, tabix');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run = run;
|
|
4
|
+
const util_1 = require("util");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const pif_generator_1 = require("./make-pif-utils/pif-generator");
|
|
7
|
+
const validators_1 = require("./make-pif-utils/validators");
|
|
8
|
+
async function run(args) {
|
|
9
|
+
const options = {
|
|
10
|
+
help: {
|
|
11
|
+
type: 'boolean',
|
|
12
|
+
short: 'h',
|
|
13
|
+
},
|
|
14
|
+
out: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Where to write the output file. will write ${file}.pif.gz and ${file}.pif.gz.tbi',
|
|
17
|
+
},
|
|
18
|
+
csi: {
|
|
19
|
+
type: 'boolean',
|
|
20
|
+
description: 'Create a CSI index for the PIF file instead of TBI',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const { values: flags, positionals } = (0, util_1.parseArgs)({
|
|
24
|
+
args,
|
|
25
|
+
options,
|
|
26
|
+
allowPositionals: true,
|
|
27
|
+
});
|
|
28
|
+
const description = 'creates pairwise indexed PAF (PIF), with bgzip and tabix';
|
|
29
|
+
const examples = [
|
|
30
|
+
'$ jbrowse make-pif input.paf # creates input.pif.gz in same directory',
|
|
31
|
+
'',
|
|
32
|
+
'$ jbrowse make-pif input.paf --out output.pif.gz # specify output file, creates output.pif.gz.tbi also',
|
|
33
|
+
];
|
|
34
|
+
if (flags.help) {
|
|
35
|
+
(0, utils_1.printHelp)({
|
|
36
|
+
description,
|
|
37
|
+
examples,
|
|
38
|
+
usage: 'jbrowse make-pif <file> [options]',
|
|
39
|
+
options,
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const file = positionals[0];
|
|
44
|
+
(0, validators_1.validateFileArgument)(file);
|
|
45
|
+
(0, validators_1.validateRequiredCommands)();
|
|
46
|
+
const { out, csi = false } = flags;
|
|
47
|
+
const outputFile = (0, pif_generator_1.getOutputFilename)(file, out);
|
|
48
|
+
try {
|
|
49
|
+
const child = (0, pif_generator_1.spawnSortProcess)(outputFile, csi);
|
|
50
|
+
await (0, pif_generator_1.createPIF)(file, child.stdin);
|
|
51
|
+
child.stdin.end();
|
|
52
|
+
await (0, pif_generator_1.waitForProcessClose)(child);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error('Error during PIF creation:', error);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run = run;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const util_1 = require("util");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
async function run(args) {
|
|
8
|
+
const options = {
|
|
9
|
+
help: {
|
|
10
|
+
type: 'boolean',
|
|
11
|
+
short: 'h',
|
|
12
|
+
},
|
|
13
|
+
target: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Path to config file in JB2 installation directory to write out to',
|
|
16
|
+
},
|
|
17
|
+
out: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Synonym for target',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const { values: flags, positionals } = (0, util_1.parseArgs)({
|
|
23
|
+
args,
|
|
24
|
+
options,
|
|
25
|
+
allowPositionals: true,
|
|
26
|
+
});
|
|
27
|
+
const description = 'Remove a track configuration from a JBrowse 2 configuration. Be aware that this can cause crashes in saved sessions that refer to this track!';
|
|
28
|
+
const examples = ['$ jbrowse remove-track trackId'];
|
|
29
|
+
if (flags.help) {
|
|
30
|
+
(0, utils_1.printHelp)({
|
|
31
|
+
description,
|
|
32
|
+
examples,
|
|
33
|
+
usage: 'jbrowse remove-track <trackId> [options]',
|
|
34
|
+
options,
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const trackId = positionals[0];
|
|
39
|
+
if (!trackId) {
|
|
40
|
+
console.error('Error: Missing required argument: trackId');
|
|
41
|
+
console.error('Usage: jbrowse remove-track <trackId> [options]');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
const output = flags.target || flags.out || '.';
|
|
45
|
+
const isDir = (await fs_1.promises.lstat(output)).isDirectory();
|
|
46
|
+
const target = isDir ? `${output}/config.json` : output;
|
|
47
|
+
const config = await (0, utils_1.readJsonFile)(target);
|
|
48
|
+
const originalLength = config.tracks?.length || 0;
|
|
49
|
+
config.tracks = config.tracks?.filter(({ trackId: id }) => id !== trackId);
|
|
50
|
+
const newLength = config.tracks?.length || 0;
|
|
51
|
+
if (originalLength === newLength) {
|
|
52
|
+
console.log(`No track found with trackId: ${trackId}`);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
await (0, utils_1.writeJsonFile)(target, config);
|
|
56
|
+
console.log(`Removed track with trackId: ${trackId} from ${target}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.run = run;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const util_1 = require("util");
|
|
9
|
+
const json_parse_better_errors_1 = __importDefault(require("json-parse-better-errors"));
|
|
10
|
+
const utils_1 = require("../utils");
|
|
11
|
+
const fsPromises = fs_1.default.promises;
|
|
12
|
+
const description = 'Set a default session with views and tracks';
|
|
13
|
+
const examples = [
|
|
14
|
+
'# set default session for the config.json in your current directory',
|
|
15
|
+
'$ jbrowse set-default-session --session /path/to/default/session.json',
|
|
16
|
+
'',
|
|
17
|
+
'# make session.json the defaultSession on the specified target config.json file',
|
|
18
|
+
'$ jbrowse set-default-session --target /path/to/jb2/installation/config.json --session session.json',
|
|
19
|
+
'',
|
|
20
|
+
'# print current default session',
|
|
21
|
+
'$ jbrowse set-default-session --currentSession # Prints out current default session',
|
|
22
|
+
];
|
|
23
|
+
const options = {
|
|
24
|
+
session: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
short: 's',
|
|
27
|
+
description: 'set path to a file containing session in json format (required, unless using delete/currentSession flags)',
|
|
28
|
+
},
|
|
29
|
+
name: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
short: 'n',
|
|
32
|
+
description: 'Give a name for the default session',
|
|
33
|
+
default: 'New Default Session',
|
|
34
|
+
},
|
|
35
|
+
currentSession: {
|
|
36
|
+
type: 'boolean',
|
|
37
|
+
short: 'c',
|
|
38
|
+
description: 'List out the current default session',
|
|
39
|
+
},
|
|
40
|
+
target: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
description: 'path to config file in JB2 installation directory to write out to',
|
|
43
|
+
},
|
|
44
|
+
out: { type: 'string', description: 'synonym for target' },
|
|
45
|
+
delete: {
|
|
46
|
+
type: 'boolean',
|
|
47
|
+
description: 'Delete any existing default session.',
|
|
48
|
+
},
|
|
49
|
+
help: { type: 'boolean', short: 'h', description: 'Show help' },
|
|
50
|
+
};
|
|
51
|
+
async function run(args) {
|
|
52
|
+
const { values: runFlags } = (0, util_1.parseArgs)({ options, args });
|
|
53
|
+
if (runFlags.help) {
|
|
54
|
+
(0, utils_1.printHelp)({
|
|
55
|
+
description,
|
|
56
|
+
examples,
|
|
57
|
+
usage: 'jbrowse add-track <track> [options]',
|
|
58
|
+
options,
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const { session, currentSession, delete: deleteDefaultSession } = runFlags;
|
|
63
|
+
const output = runFlags.target || runFlags.out || '.';
|
|
64
|
+
const isDir = (await fsPromises.lstat(output)).isDirectory();
|
|
65
|
+
const target = isDir ? `${output}/config.json` : output;
|
|
66
|
+
const configContents = await (0, utils_1.readJsonFile)(target);
|
|
67
|
+
if (deleteDefaultSession) {
|
|
68
|
+
configContents.defaultSession = undefined;
|
|
69
|
+
await (0, utils_1.writeJsonFile)(target, configContents);
|
|
70
|
+
}
|
|
71
|
+
else if (currentSession) {
|
|
72
|
+
console.log(`The current default session is ${JSON.stringify(configContents.defaultSession)}`);
|
|
73
|
+
process.exit();
|
|
74
|
+
}
|
|
75
|
+
else if (!session) {
|
|
76
|
+
throw new Error('Please provide a --session file');
|
|
77
|
+
}
|
|
78
|
+
else if (session) {
|
|
79
|
+
await (0, utils_1.writeJsonFile)(target, {
|
|
80
|
+
...configContents,
|
|
81
|
+
defaultSession: await readDefaultSessionFile(session),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function readDefaultSessionFile(defaultSessionFile) {
|
|
86
|
+
let defaultSessionJson;
|
|
87
|
+
try {
|
|
88
|
+
defaultSessionJson = await fsPromises.readFile(defaultSessionFile, {
|
|
89
|
+
encoding: 'utf8',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new Error('Could not read the provided file');
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const session = (0, json_parse_better_errors_1.default)(defaultSessionJson);
|
|
97
|
+
// return top-level "session" if it exists, such as in files created by
|
|
98
|
+
// "File -> Export session"
|
|
99
|
+
return session.session || session;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
throw new Error('Could not parse the given default session file');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.REQUIRED_COMMANDS = exports.SORT_BED_EXAMPLES = exports.SORT_BED_DESCRIPTION = void 0;
|
|
4
|
+
exports.SORT_BED_DESCRIPTION = 'Helper utility to sort BED files for tabix. Moves all lines starting with # to the top of the file, and sort by refname and start position using unix utilities sort and grep';
|
|
5
|
+
exports.SORT_BED_EXAMPLES = [
|
|
6
|
+
'# sort bed and pipe to bgzip',
|
|
7
|
+
'$ jbrowse sort-bed input.bed | bgzip > sorted.bed.gz',
|
|
8
|
+
'$ tabix sorted.bed.gz',
|
|
9
|
+
'',
|
|
10
|
+
'# OR pipe data via stdin: cat file.bed | jbrowse sort-bed | bgzip > sorted.bed.gz',
|
|
11
|
+
];
|
|
12
|
+
exports.REQUIRED_COMMANDS = ['sh', 'sort', 'grep'];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.waitForProcessClose = waitForProcessClose;
|
|
4
|
+
exports.handleProcessError = handleProcessError;
|
|
5
|
+
async function waitForProcessClose(child) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
child.on('close', code => {
|
|
8
|
+
resolve(code);
|
|
9
|
+
});
|
|
10
|
+
child.on('error', err => {
|
|
11
|
+
reject(err);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function handleProcessError(error) {
|
|
16
|
+
if (error instanceof Error) {
|
|
17
|
+
console.error(`Process error: ${error.message}`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.error('Unknown process error:', error);
|
|
21
|
+
}
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMinimalEnvironment = getMinimalEnvironment;
|
|
4
|
+
exports.createSortCommandForFile = createSortCommandForFile;
|
|
5
|
+
exports.spawnSortProcess = spawnSortProcess;
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
function getMinimalEnvironment() {
|
|
8
|
+
return {
|
|
9
|
+
...process.env,
|
|
10
|
+
LC_ALL: 'C',
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function createSortCommandForFile(file) {
|
|
14
|
+
// BED files use columns 1,2 (0-based) for chromosome and start position
|
|
15
|
+
return `(grep "^#" "${file}"; grep -v "^#" "${file}" | sort -t"\`printf '\\t'\`" -k1,1 -k2,2n)`;
|
|
16
|
+
}
|
|
17
|
+
function spawnSortProcess(options) {
|
|
18
|
+
const command = createSortCommandForFile(options.file);
|
|
19
|
+
const env = getMinimalEnvironment();
|
|
20
|
+
return (0, child_process_1.spawn)('sh', ['-c', command], {
|
|
21
|
+
env,
|
|
22
|
+
stdio: 'inherit',
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateFileArgument = validateFileArgument;
|
|
4
|
+
exports.validateRequiredCommands = validateRequiredCommands;
|
|
5
|
+
const command_exists_1 = require("command-exists");
|
|
6
|
+
function validateFileArgument(file) {
|
|
7
|
+
// Allow no file argument for stdin input
|
|
8
|
+
if (!file && process.stdin.isTTY) {
|
|
9
|
+
console.error('Error: Missing required argument: file');
|
|
10
|
+
console.error('Usage: jbrowse sort-bed <file>');
|
|
11
|
+
console.error(' OR pipe data via stdin: cat file.bed | jbrowse sort-bed');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function validateRequiredCommands() {
|
|
16
|
+
const requiredCommands = ['sh', 'sort', 'grep'];
|
|
17
|
+
const missingCommands = requiredCommands.filter(cmd => !(0, command_exists_1.sync)(cmd));
|
|
18
|
+
if (missingCommands.length > 0) {
|
|
19
|
+
console.error('Error: Unable to sort, requires unix type environment with sort, grep');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run = run;
|
|
4
|
+
const util_1 = require("util");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const constants_1 = require("./sort-bed-utils/constants");
|
|
7
|
+
const process_utils_1 = require("./sort-bed-utils/process-utils");
|
|
8
|
+
const sort_utils_1 = require("./sort-bed-utils/sort-utils");
|
|
9
|
+
const validators_1 = require("./sort-bed-utils/validators");
|
|
10
|
+
async function run(args) {
|
|
11
|
+
const options = {
|
|
12
|
+
help: {
|
|
13
|
+
type: 'boolean',
|
|
14
|
+
short: 'h',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
const { values: flags, positionals } = (0, util_1.parseArgs)({
|
|
18
|
+
args,
|
|
19
|
+
options,
|
|
20
|
+
allowPositionals: true,
|
|
21
|
+
});
|
|
22
|
+
const description = constants_1.SORT_BED_DESCRIPTION;
|
|
23
|
+
const examples = constants_1.SORT_BED_EXAMPLES;
|
|
24
|
+
if (flags.help) {
|
|
25
|
+
(0, utils_1.printHelp)({
|
|
26
|
+
description,
|
|
27
|
+
examples,
|
|
28
|
+
usage: 'jbrowse sort-bed [file] [options]',
|
|
29
|
+
options,
|
|
30
|
+
});
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const file = positionals[0];
|
|
34
|
+
if (file) {
|
|
35
|
+
(0, validators_1.validateFileArgument)(file);
|
|
36
|
+
}
|
|
37
|
+
(0, validators_1.validateRequiredCommands)();
|
|
38
|
+
try {
|
|
39
|
+
const child = (0, sort_utils_1.spawnSortProcess)({ file: file || '-' });
|
|
40
|
+
const exitCode = await (0, process_utils_1.waitForProcessClose)(child);
|
|
41
|
+
if (exitCode !== 0) {
|
|
42
|
+
console.error(`Sort process exited with code ${exitCode}`);
|
|
43
|
+
process.exit(exitCode || 1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
(0, process_utils_1.handleProcessError)(error);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.REQUIRED_COMMANDS = exports.SORT_GFF_EXAMPLES = exports.SORT_GFF_DESCRIPTION = void 0;
|
|
4
|
+
exports.SORT_GFF_DESCRIPTION = 'Helper utility to sort GFF files for tabix. Moves all lines starting with # to the top of the file, and sort by refname and start position using unix utilities sort and grep';
|
|
5
|
+
exports.SORT_GFF_EXAMPLES = [
|
|
6
|
+
'# sort gff and pipe to bgzip',
|
|
7
|
+
'$ jbrowse sort-gff input.gff | bgzip > sorted.gff.gz',
|
|
8
|
+
'$ tabix sorted.gff.gz',
|
|
9
|
+
'',
|
|
10
|
+
'# sort gff from stdin',
|
|
11
|
+
'$ cat input.gff | jbrowse sort-gff | bgzip > sorted.gff.gz',
|
|
12
|
+
];
|
|
13
|
+
exports.REQUIRED_COMMANDS = ['sh', 'sort', 'grep'];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.waitForProcessClose = waitForProcessClose;
|
|
4
|
+
exports.handleProcessError = handleProcessError;
|
|
5
|
+
async function waitForProcessClose(child) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
child.on('close', code => {
|
|
8
|
+
resolve(code);
|
|
9
|
+
});
|
|
10
|
+
child.on('error', err => {
|
|
11
|
+
reject(err);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function handleProcessError(error) {
|
|
16
|
+
if (error instanceof Error) {
|
|
17
|
+
console.error(`Process error: ${error.message}`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.error('Unknown process error:', error);
|
|
21
|
+
}
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|