@apollo-annotation/cli 0.1.18 → 0.1.20
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/README.md +374 -135
- package/bin/dev.js +2 -2
- package/bin/run.js +2 -2
- package/dist/ApolloConf.js +1 -0
- package/dist/baseCommand.d.ts +1 -1
- package/dist/baseCommand.js +7 -7
- package/dist/commands/assembly/add-from-fasta.d.ts +23 -0
- package/dist/commands/assembly/add-from-fasta.js +165 -0
- package/dist/commands/assembly/{add-gff.d.ts → add-from-gff.d.ts} +5 -3
- package/dist/commands/assembly/{add-gff.js → add-from-gff.js} +20 -22
- package/dist/commands/assembly/check.js +9 -9
- package/dist/commands/assembly/delete.js +4 -4
- package/dist/commands/assembly/get.js +4 -4
- package/dist/commands/assembly/get.test.js +3 -3
- package/dist/commands/assembly/sequence.js +8 -14
- package/dist/commands/change/get.js +7 -7
- package/dist/commands/change/get.test.js +1 -1
- package/dist/commands/config.js +4 -5
- package/dist/commands/feature/add-child.js +18 -19
- package/dist/commands/feature/check.js +11 -11
- package/dist/commands/feature/copy.js +12 -14
- package/dist/commands/feature/delete.js +13 -19
- package/dist/commands/feature/edit-attribute.js +18 -11
- package/dist/commands/feature/edit-coords.js +36 -21
- package/dist/commands/feature/edit-type.js +7 -11
- package/dist/commands/feature/edit.js +5 -6
- package/dist/commands/feature/get-id.js +5 -6
- package/dist/commands/feature/get.js +3 -4
- package/dist/commands/feature/import.d.ts +2 -2
- package/dist/commands/feature/import.js +26 -39
- package/dist/commands/feature/search.js +7 -7
- package/dist/commands/file/delete.d.ts +13 -0
- package/dist/commands/file/delete.js +58 -0
- package/dist/commands/file/download.d.ts +14 -0
- package/dist/commands/file/download.js +45 -0
- package/dist/commands/file/get.d.ts +13 -0
- package/dist/commands/file/get.js +38 -0
- package/dist/commands/file/upload.d.ts +16 -0
- package/dist/commands/file/upload.js +88 -0
- package/dist/commands/jbrowse/get-config.d.ts +10 -0
- package/dist/commands/jbrowse/get-config.js +21 -0
- package/dist/commands/jbrowse/set-config.d.ts +13 -0
- package/dist/commands/jbrowse/set-config.js +51 -0
- package/dist/commands/login.js +12 -16
- package/dist/commands/logout.js +3 -3
- package/dist/commands/{assembly/add-fasta.d.ts → refseq/add-alias.d.ts} +3 -4
- package/dist/commands/refseq/add-alias.js +72 -0
- package/dist/commands/refseq/get.js +8 -8
- package/dist/commands/status.js +5 -4
- package/dist/commands/user/get.js +3 -3
- package/dist/commands/user/get.test.js +1 -1
- package/dist/fileCommand.d.ts +5 -0
- package/dist/fileCommand.js +76 -0
- package/dist/test/fixtures.js +2 -2
- package/dist/utils.d.ts +20 -9
- package/dist/utils.js +33 -80
- package/oclif.manifest.json +495 -58
- package/package.json +56 -42
- package/dist/commands/assembly/add-fasta.js +0 -88
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import { Flags } from '@oclif/core';
|
|
3
|
-
import { fetch } from 'undici';
|
|
4
|
-
import {
|
|
5
|
-
import { convertAssemblyNameToId, createFetchErrorMessage, localhostToAddress,
|
|
6
|
-
export default class Import extends
|
|
3
|
+
import { Agent, fetch } from 'undici';
|
|
4
|
+
import { FileCommand } from '../../fileCommand.js';
|
|
5
|
+
import { convertAssemblyNameToId, createFetchErrorMessage, localhostToAddress, } from '../../utils.js';
|
|
6
|
+
export default class Import extends FileCommand {
|
|
7
7
|
static summary = 'Import features from local gff file';
|
|
8
8
|
static description = 'By default, features are added to the existing ones.';
|
|
9
9
|
static examples = [
|
|
@@ -15,7 +15,7 @@ export default class Import extends BaseCommand {
|
|
|
15
15
|
static flags = {
|
|
16
16
|
'input-file': Flags.string({
|
|
17
17
|
char: 'i',
|
|
18
|
-
description: 'Input gff
|
|
18
|
+
description: 'Input gff file',
|
|
19
19
|
required: true,
|
|
20
20
|
}),
|
|
21
21
|
assembly: Flags.string({
|
|
@@ -33,45 +33,32 @@ export default class Import extends BaseCommand {
|
|
|
33
33
|
if (!fs.existsSync(flags['input-file'])) {
|
|
34
34
|
this.error(`File "${flags['input-file']}" does not exist`);
|
|
35
35
|
}
|
|
36
|
-
const access = await this.getAccess(
|
|
36
|
+
const access = await this.getAccess();
|
|
37
37
|
const assembly = await convertAssemblyNameToId(access.address, access.accessToken, [flags.assembly]);
|
|
38
38
|
if (assembly.length === 0) {
|
|
39
39
|
this.error(`Assembly "${flags.assembly}" does not exist. Perhaps you want to create this assembly first`);
|
|
40
40
|
}
|
|
41
|
-
const uploadId = await uploadFile(access.address, access.accessToken, flags['input-file'], 'text/x-gff3');
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
const uploadId = await this.uploadFile(access.address, access.accessToken, flags['input-file'], 'text/x-gff3', false);
|
|
42
|
+
const body = {
|
|
43
|
+
typeName: 'AddFeaturesFromFileChange',
|
|
44
|
+
assembly: assembly[0],
|
|
45
|
+
fileId: uploadId,
|
|
46
|
+
deleteExistingFeatures: flags['delete-existing'],
|
|
47
|
+
};
|
|
48
|
+
const auth = {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
body: JSON.stringify(body),
|
|
51
|
+
headers: {
|
|
52
|
+
Authorization: `Bearer ${access.accessToken}`,
|
|
53
|
+
'Content-Type': 'application/json',
|
|
54
|
+
},
|
|
55
|
+
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
|
|
56
|
+
};
|
|
57
|
+
const url = new URL(localhostToAddress(`${access.address}/changes`));
|
|
58
|
+
const response = await fetch(url, auth);
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const errorMessage = await createFetchErrorMessage(response, 'importFeatures failed');
|
|
45
61
|
throw new Error(errorMessage);
|
|
46
62
|
}
|
|
47
|
-
this.exit(0);
|
|
48
63
|
}
|
|
49
64
|
}
|
|
50
|
-
async function importFeatures(address, accessToken, assembly, fileId, deleteExistingFeatures) {
|
|
51
|
-
const body = {
|
|
52
|
-
typeName: 'AddFeaturesFromFileChange',
|
|
53
|
-
assembly,
|
|
54
|
-
fileId,
|
|
55
|
-
deleteExistingFeatures,
|
|
56
|
-
};
|
|
57
|
-
const controller = new AbortController();
|
|
58
|
-
setTimeout(() => {
|
|
59
|
-
controller.abort();
|
|
60
|
-
}, 24 * 60 * 60 * 1000);
|
|
61
|
-
const auth = {
|
|
62
|
-
method: 'POST',
|
|
63
|
-
body: JSON.stringify(body),
|
|
64
|
-
headers: {
|
|
65
|
-
Authorization: `Bearer ${accessToken}`,
|
|
66
|
-
'Content-Type': 'application/json',
|
|
67
|
-
},
|
|
68
|
-
signal: controller.signal,
|
|
69
|
-
};
|
|
70
|
-
const url = new URL(localhostToAddress(`${address}/changes`));
|
|
71
|
-
const response = await fetch(url, auth);
|
|
72
|
-
if (!response.ok) {
|
|
73
|
-
const errorMessage = await createFetchErrorMessage(response, 'importFeatures failed');
|
|
74
|
-
throw new Error(errorMessage);
|
|
75
|
-
}
|
|
76
|
-
return response;
|
|
77
|
-
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Flags } from '@oclif/core';
|
|
3
3
|
import { fetch } from 'undici';
|
|
4
4
|
import { BaseCommand } from '../../baseCommand.js';
|
|
5
|
-
import { convertAssemblyNameToId, createFetchErrorMessage, idReader, localhostToAddress, queryApollo,
|
|
5
|
+
import { convertAssemblyNameToId, createFetchErrorMessage, idReader, localhostToAddress, queryApollo, } from '../../utils.js';
|
|
6
6
|
async function searchFeatures(address, accessToken, assemblies, term) {
|
|
7
7
|
const url = new URL(localhostToAddress(`${address}/features/searchFeatures`));
|
|
8
8
|
const searchParams = new URLSearchParams({
|
|
@@ -25,7 +25,7 @@ async function searchFeatures(address, accessToken, assemblies, term) {
|
|
|
25
25
|
}
|
|
26
26
|
export default class Search extends BaseCommand {
|
|
27
27
|
static summary = 'Free text search for feature in one or more assemblies';
|
|
28
|
-
static description =
|
|
28
|
+
static description = `Return features matching a query string. This command searches only in:
|
|
29
29
|
|
|
30
30
|
- Attribute *values* (not attribute names)
|
|
31
31
|
- Source field (which in fact is stored as an attribute)
|
|
@@ -47,7 +47,7 @@ export default class Search extends BaseCommand {
|
|
|
47
47
|
- "with"
|
|
48
48
|
- "Finger"
|
|
49
49
|
- "chr1"
|
|
50
|
-
- "0.987"
|
|
50
|
+
- "0.987"`;
|
|
51
51
|
static examples = [
|
|
52
52
|
{
|
|
53
53
|
description: 'Search "bac" in these assemblies:',
|
|
@@ -63,21 +63,21 @@ export default class Search extends BaseCommand {
|
|
|
63
63
|
assembly: Flags.string({
|
|
64
64
|
char: 'a',
|
|
65
65
|
multiple: true,
|
|
66
|
-
description:
|
|
66
|
+
description: 'Assembly names or IDs to search; use "-" to read it from stdin. If omitted search all assemblies',
|
|
67
67
|
}),
|
|
68
68
|
};
|
|
69
69
|
async run() {
|
|
70
70
|
const { flags } = await this.parse(Search);
|
|
71
|
-
const access = await this.getAccess(
|
|
71
|
+
const access = await this.getAccess();
|
|
72
72
|
let assemblyIds = [];
|
|
73
73
|
if (flags.assembly === undefined) {
|
|
74
74
|
const asm = await queryApollo(access.address, access.accessToken, 'assemblies');
|
|
75
75
|
for (const x of (await asm.json())) {
|
|
76
|
-
assemblyIds.push(x
|
|
76
|
+
assemblyIds.push(x._id);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
else {
|
|
80
|
-
const assembly = idReader(flags.assembly);
|
|
80
|
+
const assembly = await idReader(flags.assembly);
|
|
81
81
|
assemblyIds = await convertAssemblyNameToId(access.address, access.accessToken, assembly);
|
|
82
82
|
}
|
|
83
83
|
if (assemblyIds.length === 0) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
2
|
+
export default class Delete extends BaseCommand<typeof Delete> {
|
|
3
|
+
static summary: string;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: {
|
|
6
|
+
description: string;
|
|
7
|
+
command: string;
|
|
8
|
+
}[];
|
|
9
|
+
static flags: {
|
|
10
|
+
'file-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[], import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { fetch } from 'undici';
|
|
3
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
4
|
+
import { createFetchErrorMessage, filterJsonList, idReader, localhostToAddress, queryApollo, } from '../../utils.js';
|
|
5
|
+
export default class Delete extends BaseCommand {
|
|
6
|
+
static summary = 'Delete files from the Apollo server';
|
|
7
|
+
static description = 'Deleted files are printed to stdout. See also `apollo file get` to list the files on the server';
|
|
8
|
+
static examples = [
|
|
9
|
+
{
|
|
10
|
+
description: 'Delete file multiple files:',
|
|
11
|
+
command: '<%= config.bin %> <%= command.id %> -i 123...abc xyz...789',
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
'file-id': Flags.string({
|
|
16
|
+
char: 'i',
|
|
17
|
+
description: 'IDs of the files to delete',
|
|
18
|
+
default: ['-'],
|
|
19
|
+
multiple: true,
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { flags } = await this.parse(Delete);
|
|
24
|
+
const access = await this.getAccess();
|
|
25
|
+
const files = await queryApollo(access.address, access.accessToken, 'files');
|
|
26
|
+
const json = (await files.json());
|
|
27
|
+
const ff = await idReader(flags['file-id']);
|
|
28
|
+
let deleted = [];
|
|
29
|
+
for (const id of ff) {
|
|
30
|
+
const res = await deleteFile(access.address, access.accessToken, id);
|
|
31
|
+
if (res.status === 404) {
|
|
32
|
+
this.logToStderr(`File id "${id}" not found`);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const fid = filterJsonList(json, [id], '_id');
|
|
36
|
+
deleted = [...deleted, ...fid];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
this.log(JSON.stringify(deleted, null, 2));
|
|
40
|
+
this.logToStderr(`${deleted.length.toString()} file(s) deleted.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function deleteFile(address, accessToken, fileId) {
|
|
44
|
+
const auth = {
|
|
45
|
+
method: 'DELETE',
|
|
46
|
+
headers: {
|
|
47
|
+
Authorization: `Bearer ${accessToken}`,
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
const url = new URL(localhostToAddress(`${address}/files/${fileId}`));
|
|
52
|
+
const response = await fetch(url, auth);
|
|
53
|
+
if (!response.ok && response.status != 404) {
|
|
54
|
+
const errorMessage = await createFetchErrorMessage(response, 'deleteFile failed');
|
|
55
|
+
throw new Error(errorMessage);
|
|
56
|
+
}
|
|
57
|
+
return response;
|
|
58
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
2
|
+
export default class Download extends BaseCommand<typeof Download> {
|
|
3
|
+
static summary: string;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: {
|
|
6
|
+
description: string;
|
|
7
|
+
command: string;
|
|
8
|
+
}[];
|
|
9
|
+
static flags: {
|
|
10
|
+
'file-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
|
+
output: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createWriteStream } from 'node:fs';
|
|
2
|
+
import { Writable } from 'node:stream';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
5
|
+
import { filterJsonList, idReader, queryApollo } from '../../utils.js';
|
|
6
|
+
export default class Download extends BaseCommand {
|
|
7
|
+
static summary = 'Download a file from the Apollo server';
|
|
8
|
+
static description = 'See also `apollo file get` to list the files on the server';
|
|
9
|
+
static examples = [
|
|
10
|
+
{
|
|
11
|
+
description: 'Download file with id xyz',
|
|
12
|
+
command: '<%= config.bin %> <%= command.id %> -i xyz -o genome.fa',
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
static flags = {
|
|
16
|
+
'file-id': Flags.string({
|
|
17
|
+
char: 'i',
|
|
18
|
+
description: 'ID of the file to download',
|
|
19
|
+
default: '-',
|
|
20
|
+
}),
|
|
21
|
+
output: Flags.string({
|
|
22
|
+
char: 'o',
|
|
23
|
+
description: 'Write output to this file or "-" for stdout. Default to the name of the uploaded file.',
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
const { flags } = await this.parse(Download);
|
|
28
|
+
const access = await this.getAccess();
|
|
29
|
+
const ff = await idReader([flags['file-id']]);
|
|
30
|
+
let res = await queryApollo(access.address, access.accessToken, 'files');
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
32
|
+
const json = JSON.parse(await res.text());
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
34
|
+
const [fileRec] = filterJsonList(json, ff, '_id');
|
|
35
|
+
const fileId = fileRec['_id'];
|
|
36
|
+
res = await queryApollo(access.address, access.accessToken, `files/${fileId}`);
|
|
37
|
+
let { output } = flags;
|
|
38
|
+
if (output === undefined) {
|
|
39
|
+
output = fileRec['basename'];
|
|
40
|
+
}
|
|
41
|
+
const fileWriteStream = createWriteStream(output);
|
|
42
|
+
await res.body?.pipeTo(Writable.toWeb(output === '-' ? process.stdout : fileWriteStream));
|
|
43
|
+
fileWriteStream.close();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
2
|
+
export default class Get extends BaseCommand<typeof Get> {
|
|
3
|
+
static summary: string;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: {
|
|
6
|
+
description: string;
|
|
7
|
+
command: string;
|
|
8
|
+
}[];
|
|
9
|
+
static flags: {
|
|
10
|
+
'file-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
3
|
+
import { idReader, queryApollo } from '../../utils.js';
|
|
4
|
+
export default class Get extends BaseCommand {
|
|
5
|
+
static summary = 'Get list of files uploaded to the Apollo server';
|
|
6
|
+
static description = 'Print to stdout the list of files in json format';
|
|
7
|
+
static examples = [
|
|
8
|
+
{
|
|
9
|
+
description: 'Get files by id:',
|
|
10
|
+
command: '<%= config.bin %> <%= command.id %> -i xyz abc',
|
|
11
|
+
},
|
|
12
|
+
];
|
|
13
|
+
static flags = {
|
|
14
|
+
'file-id': Flags.string({
|
|
15
|
+
char: 'i',
|
|
16
|
+
description: 'Get files matching this IDs',
|
|
17
|
+
multiple: true,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
async run() {
|
|
21
|
+
const { flags } = await this.parse(Get);
|
|
22
|
+
const access = await this.getAccess();
|
|
23
|
+
const files = await queryApollo(access.address, access.accessToken, 'files');
|
|
24
|
+
const json = (await files.json());
|
|
25
|
+
let fileIds = [];
|
|
26
|
+
if (flags['file-id'] !== undefined) {
|
|
27
|
+
fileIds = await idReader(flags['file-id']);
|
|
28
|
+
}
|
|
29
|
+
const keep = [];
|
|
30
|
+
for (const x of json) {
|
|
31
|
+
if (flags['file-id'] === undefined ||
|
|
32
|
+
fileIds.includes(x['_id'])) {
|
|
33
|
+
keep.push(x);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
this.log(JSON.stringify(keep, null, 2));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FileCommand } from '../../fileCommand.js';
|
|
2
|
+
export default class Upload extends FileCommand {
|
|
3
|
+
static summary: string;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: {
|
|
6
|
+
description: string;
|
|
7
|
+
command: string;
|
|
8
|
+
}[];
|
|
9
|
+
static flags: {
|
|
10
|
+
'input-file': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
|
+
type: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
|
+
gzip: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
13
|
+
decompressed: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { FileCommand } from '../../fileCommand.js';
|
|
3
|
+
import { filterJsonList, queryApollo } from '../../utils.js';
|
|
4
|
+
export default class Upload extends FileCommand {
|
|
5
|
+
static summary = 'Upload a local file to the Apollo server';
|
|
6
|
+
static description = `This command only uploads a file and returns the corresponding file id.
|
|
7
|
+
To add an assembly based on this file or to upload & add an assembly in a single pass \
|
|
8
|
+
see \`apollo assembly add-from-fasta\` and \`add-from-gff\``;
|
|
9
|
+
static examples = [
|
|
10
|
+
{
|
|
11
|
+
description: 'Upload local file, type auto-detected:',
|
|
12
|
+
command: '<%= config.bin %> <%= command.id %> -i genome.fa > file.json',
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
static flags = {
|
|
16
|
+
'input-file': Flags.string({
|
|
17
|
+
char: 'i',
|
|
18
|
+
description: 'Local file to upload',
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
type: Flags.string({
|
|
22
|
+
char: 't',
|
|
23
|
+
description: 'Set file type or autodetected it if not set.\n\
|
|
24
|
+
NB: There is no check for whether the file complies to this type',
|
|
25
|
+
options: [
|
|
26
|
+
'text/x-fasta',
|
|
27
|
+
'text/x-gff3',
|
|
28
|
+
'application/x-bgzip-fasta',
|
|
29
|
+
'text/x-fai',
|
|
30
|
+
'application/x-gzi',
|
|
31
|
+
],
|
|
32
|
+
}),
|
|
33
|
+
gzip: Flags.boolean({
|
|
34
|
+
char: 'z',
|
|
35
|
+
description: 'Override autodetection and instruct that input is gzip compressed',
|
|
36
|
+
exclusive: ['decompressed'],
|
|
37
|
+
}),
|
|
38
|
+
decompressed: Flags.boolean({
|
|
39
|
+
char: 'd',
|
|
40
|
+
description: 'Override autodetection and instruct that input is decompressed',
|
|
41
|
+
exclusive: ['gzip'],
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
async run() {
|
|
45
|
+
const { flags } = await this.parse(Upload);
|
|
46
|
+
const access = await this.getAccess();
|
|
47
|
+
let { type } = flags;
|
|
48
|
+
if (type === undefined) {
|
|
49
|
+
const hasGzipExt = flags['input-file'].endsWith('.gz');
|
|
50
|
+
const infile = flags['input-file'].replace(/\.gz$/, '');
|
|
51
|
+
if (/\.fasta$|\.fas$|\.fa$|\.fna$/.test(infile) && hasGzipExt) {
|
|
52
|
+
this.error(`Unable to auto-detect file type for "${flags['input-file']}" since it may be gzip or bgzip compressed. Please set the -t/--type option`);
|
|
53
|
+
}
|
|
54
|
+
else if (/\.fasta$|\.fas$|\.fa$|\.fna$/.test(infile)) {
|
|
55
|
+
type = 'text/x-fasta';
|
|
56
|
+
}
|
|
57
|
+
else if (/\.gff$|\.gff3/.test(infile)) {
|
|
58
|
+
type = 'text/x-gff3';
|
|
59
|
+
}
|
|
60
|
+
else if (infile.endsWith('.fai')) {
|
|
61
|
+
type = 'text/x-fai';
|
|
62
|
+
}
|
|
63
|
+
else if (infile.endsWith('.gzi')) {
|
|
64
|
+
type = 'application/x-gzi';
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.error(`Unable to auto-detect the type of file "${flags['input-file']}". Please set the --type/-t option.`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
let isGzip = flags['input-file'].endsWith('.gz');
|
|
71
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
72
|
+
if (flags.gzip) {
|
|
73
|
+
isGzip = true;
|
|
74
|
+
}
|
|
75
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
76
|
+
if (flags.decompressed) {
|
|
77
|
+
isGzip = false;
|
|
78
|
+
}
|
|
79
|
+
this.logToStderr(`Input is gzip'd: ${isGzip}`);
|
|
80
|
+
const fileId = await this.uploadFile(access.address, access.accessToken, flags['input-file'], type, isGzip);
|
|
81
|
+
const res = await queryApollo(access.address, access.accessToken, 'files');
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
83
|
+
const json = JSON.parse(await res.text());
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
85
|
+
const [rec] = filterJsonList(json, [fileId], '_id');
|
|
86
|
+
this.log(JSON.stringify(rec, null, 2));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
2
|
+
export default class GetConfig extends BaseCommand<typeof GetConfig> {
|
|
3
|
+
static summary: string;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: {
|
|
6
|
+
description: string;
|
|
7
|
+
command: string;
|
|
8
|
+
}[];
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
2
|
+
import { queryApollo } from '../../utils.js';
|
|
3
|
+
export default class GetConfig extends BaseCommand {
|
|
4
|
+
static summary = 'Get JBrowse configuration from Apollo';
|
|
5
|
+
static description = 'Print to stdout the JBrowse configuration from Apollo in JSON format';
|
|
6
|
+
static examples = [
|
|
7
|
+
{
|
|
8
|
+
description: 'Get JBrowse configuration:',
|
|
9
|
+
command: '<%= config.bin %> <%= command.id %> > config.json',
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
async run() {
|
|
13
|
+
const access = await this.getAccess();
|
|
14
|
+
const response = await queryApollo(access.address, access.accessToken, 'jbrowse/config.json');
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
throw new Error('Failed to fetch JBrowse configuration');
|
|
17
|
+
}
|
|
18
|
+
const json = (await response.json());
|
|
19
|
+
this.log(JSON.stringify(json, null, 2));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
2
|
+
export default class SetConfig extends BaseCommand<typeof SetConfig> {
|
|
3
|
+
static summary: string;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: {
|
|
6
|
+
description: string;
|
|
7
|
+
command: string;
|
|
8
|
+
}[];
|
|
9
|
+
static args: {
|
|
10
|
+
inputFile: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { Args } from '@oclif/core';
|
|
3
|
+
import { Agent, fetch } from 'undici';
|
|
4
|
+
import { ConfigError } from '../../ApolloConf.js';
|
|
5
|
+
import { BaseCommand } from '../../baseCommand.js';
|
|
6
|
+
import { localhostToAddress, createFetchErrorMessage } from '../../utils.js';
|
|
7
|
+
export default class SetConfig extends BaseCommand {
|
|
8
|
+
static summary = 'Set JBrowse configuration';
|
|
9
|
+
static description = 'Set JBrowse configuration in Apollo collaboration server';
|
|
10
|
+
static examples = [
|
|
11
|
+
{
|
|
12
|
+
description: 'Add JBrowse configuration:',
|
|
13
|
+
command: '<%= config.bin %> <%= command.id %> config.json',
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
static args = {
|
|
17
|
+
inputFile: Args.string({
|
|
18
|
+
description: 'JBrowse configuration file',
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { args } = await this.parse(SetConfig);
|
|
24
|
+
if (!fs.existsSync(args.inputFile)) {
|
|
25
|
+
this.error(`File ${args.inputFile} does not exist`);
|
|
26
|
+
}
|
|
27
|
+
const access = await this.getAccess();
|
|
28
|
+
const filehandle = await fs.promises.open(args.inputFile);
|
|
29
|
+
const fileContent = await filehandle.readFile({ encoding: 'utf8' });
|
|
30
|
+
await filehandle.close();
|
|
31
|
+
const change = {
|
|
32
|
+
typeName: 'ImportJBrowseConfigChange',
|
|
33
|
+
newJBrowseConfig: JSON.parse(fileContent),
|
|
34
|
+
};
|
|
35
|
+
const auth = {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
body: JSON.stringify(change),
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: `Bearer ${access.accessToken}`,
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
},
|
|
42
|
+
dispatcher: new Agent({ headersTimeout: 60 * 60 * 1000 }),
|
|
43
|
+
};
|
|
44
|
+
const url = new URL(localhostToAddress(`${access.address}/changes`));
|
|
45
|
+
const response = await fetch(url, auth);
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const errorMessage = await createFetchErrorMessage(response, 'Failed to add JBrowse configuration');
|
|
48
|
+
throw new ConfigError(errorMessage);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
package/dist/commands/login.js
CHANGED
|
@@ -8,21 +8,21 @@ import * as querystring from 'node:querystring';
|
|
|
8
8
|
import { Errors, Flags, ux } from '@oclif/core';
|
|
9
9
|
import open from 'open';
|
|
10
10
|
import { fetch } from 'undici';
|
|
11
|
-
import { ApolloConf } from '../ApolloConf.js';
|
|
11
|
+
import { ApolloConf, KEYS } from '../ApolloConf.js';
|
|
12
12
|
import { BaseCommand } from '../baseCommand.js';
|
|
13
|
-
import { basicCheckConfig, createFetchErrorMessage,
|
|
13
|
+
import { basicCheckConfig, createFetchErrorMessage, localhostToAddress, waitFor, } from '../utils.js';
|
|
14
14
|
export default class Login extends BaseCommand {
|
|
15
15
|
static summary = 'Login to Apollo';
|
|
16
|
-
static description =
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
static description = 'Use the provided credentials to obtain and save the token to access Apollo. \
|
|
17
|
+
Once the token for the given profile has been saved in the configuration file, users do not normally \
|
|
18
|
+
need to execute this command again unless the token has expired. To setup a new profile use "apollo config"';
|
|
19
19
|
static examples = [
|
|
20
20
|
{
|
|
21
|
-
description:
|
|
21
|
+
description: 'The most basic and probably most typical usage is to login using the default profile in configuration file:',
|
|
22
22
|
command: '<%= config.bin %> <%= command.id %>',
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
description:
|
|
25
|
+
description: 'Login with a different profile:',
|
|
26
26
|
command: '<%= config.bin %> <%= command.id %> --profile my-profile',
|
|
27
27
|
},
|
|
28
28
|
];
|
|
@@ -55,7 +55,7 @@ export default class Login extends BaseCommand {
|
|
|
55
55
|
const { flags } = await this.parse(Login);
|
|
56
56
|
let configFile = flags['config-file'];
|
|
57
57
|
if (configFile === undefined) {
|
|
58
|
-
configFile = path.join(this.config.configDir, 'config.
|
|
58
|
+
configFile = path.join(this.config.configDir, 'config.yml');
|
|
59
59
|
}
|
|
60
60
|
let profileName = flags.profile;
|
|
61
61
|
if (profileName === undefined) {
|
|
@@ -71,7 +71,7 @@ export default class Login extends BaseCommand {
|
|
|
71
71
|
let userCredentials = { accessToken: '' };
|
|
72
72
|
try {
|
|
73
73
|
if (!flags.force) {
|
|
74
|
-
await this.checkUserAlreadyLoggedIn();
|
|
74
|
+
await this.checkUserAlreadyLoggedIn(config, profileName);
|
|
75
75
|
}
|
|
76
76
|
if (accessType === 'root' || flags.username !== undefined) {
|
|
77
77
|
const username = flags.username ??
|
|
@@ -104,13 +104,9 @@ export default class Login extends BaseCommand {
|
|
|
104
104
|
}
|
|
105
105
|
config.set(`${profileName}.accessToken`, userCredentials.accessToken);
|
|
106
106
|
}
|
|
107
|
-
async checkUserAlreadyLoggedIn() {
|
|
108
|
-
const
|
|
109
|
-
if (!
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
const alreadyLoggedIn = Object.keys(userCredentials).every((key) => Boolean(userCredentials[key]));
|
|
113
|
-
if (!alreadyLoggedIn) {
|
|
107
|
+
async checkUserAlreadyLoggedIn(userCredentials, profileName) {
|
|
108
|
+
const accessToken = userCredentials.get(`${profileName}.${KEYS.accessToken}`);
|
|
109
|
+
if (!accessToken) {
|
|
114
110
|
return;
|
|
115
111
|
}
|
|
116
112
|
const reAuthenticate = await ux.confirm("You're already logged. Do you want to re-authenticate? (y/n)");
|
package/dist/commands/logout.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { ApolloConf, KEYS } from '../ApolloConf.js';
|
|
3
3
|
import { BaseCommand } from '../baseCommand.js';
|
|
4
|
-
import { basicCheckConfig
|
|
4
|
+
import { basicCheckConfig } from '../utils.js';
|
|
5
5
|
export default class Logout extends BaseCommand {
|
|
6
6
|
static summary = 'Logout of Apollo';
|
|
7
|
-
static description =
|
|
7
|
+
static description = 'Logout by removing the access token from the selected profile';
|
|
8
8
|
static examples = [
|
|
9
9
|
{
|
|
10
10
|
description: 'Logout default profile:',
|
|
@@ -23,7 +23,7 @@ export default class Logout extends BaseCommand {
|
|
|
23
23
|
}
|
|
24
24
|
let configFile = flags['config-file'];
|
|
25
25
|
if (configFile === undefined) {
|
|
26
|
-
configFile = path.join(this.config.configDir, 'config.
|
|
26
|
+
configFile = path.join(this.config.configDir, 'config.yml');
|
|
27
27
|
}
|
|
28
28
|
basicCheckConfig(configFile, profileName);
|
|
29
29
|
const config = new ApolloConf(configFile);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BaseCommand } from '../../baseCommand.js';
|
|
2
|
-
export default class
|
|
2
|
+
export default class AddRefNameAlias extends BaseCommand<typeof AddRefNameAlias> {
|
|
3
|
+
static summary: string;
|
|
3
4
|
static description: string;
|
|
4
5
|
static examples: {
|
|
5
6
|
description: string;
|
|
@@ -7,9 +8,7 @@ export default class Get extends BaseCommand<typeof Get> {
|
|
|
7
8
|
}[];
|
|
8
9
|
static flags: {
|
|
9
10
|
'input-file': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
10
|
-
assembly: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string
|
|
11
|
-
index: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
|
-
force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
|
+
assembly: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
13
12
|
};
|
|
14
13
|
run(): Promise<void>;
|
|
15
14
|
}
|