mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
Full CLI rework and repair
This commit is contained in:
parent
cbc6f46103
commit
28c73bc62a
|
|
@ -9,7 +9,7 @@ module.exports = {
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
project: "./tsconfig.json",
|
project: "./tsconfig.json",
|
||||||
},
|
},
|
||||||
ignorePatterns: ["node_modules/", "dist/", ".eslintrc.cjs", "cli.ts"],
|
ignorePatterns: ["node_modules/", "dist/", ".eslintrc.cjs"],
|
||||||
plugins: ["@typescript-eslint"],
|
plugins: ["@typescript-eslint"],
|
||||||
root: true,
|
root: true,
|
||||||
rules: {
|
rules: {
|
||||||
|
|
|
||||||
|
|
@ -152,22 +152,19 @@ bun start
|
||||||
|
|
||||||
### Using the CLI
|
### Using the CLI
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> The CLI is currently broken due to unknown bugs that are actively being investigated. The following instructions are for when this is fixed.
|
|
||||||
|
|
||||||
Lysand includes a built-in CLI for managing the server. To use it, simply run the following command:
|
Lysand includes a built-in CLI for managing the server. To use it, simply run the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun cli
|
bun cli help
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are running a production build, you will need to run `bun run dist/cli.js` or `./entrypoint.sh cli` instead.
|
If you are running a production build, you will need to run `bun run dist/cli.js` or `./entrypoint.sh cli` instead.
|
||||||
|
|
||||||
You can use the `help` command to see a list of available commands. These include creating users, deleting users and more.
|
You can use the `help` command to see a list of available commands. These include creating users, deleting users and more. Each command also has a `--help,-h` flag that you can use to see more information about the command.
|
||||||
|
|
||||||
#### Scripting with the CLI
|
#### Scripting with the CLI
|
||||||
|
|
||||||
Some CLI commands that return data as tables can be used in scripts. To do so, you can use the `--json` flag to output the data as JSON instead of a table, or even `--csv` to output the data as CSV. See `bun cli help` for more information.
|
Some CLI commands that return data as tables can be used in scripts. To convert them to JSON or CSV, some commands allow you to specify a `--format` flag that can be either `"json"` or `"csv"`. See `bun cli help` or `bun cli <command> -h` for more information.
|
||||||
|
|
||||||
Flags can be used in any order and anywhere in the script (except for the `bun cli` command itself). The command arguments themselves must be in the correct order, however.
|
Flags can be used in any order and anywhere in the script (except for the `bun cli` command itself). The command arguments themselves must be in the correct order, however.
|
||||||
|
|
||||||
|
|
|
||||||
13
package.json
13
package.json
|
|
@ -84,11 +84,14 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.461.0",
|
"@aws-sdk/client-s3": "^3.461.0",
|
||||||
"@iarna/toml": "^2.2.5",
|
"@iarna/toml": "^2.2.5",
|
||||||
|
"@json2csv/plainjs": "^7.0.6",
|
||||||
"@prisma/client": "^5.6.0",
|
"@prisma/client": "^5.6.0",
|
||||||
"blurhash": "^2.0.5",
|
"blurhash": "^2.0.5",
|
||||||
"bullmq": "latest",
|
"bullmq": "latest",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
|
"cli-parser": "file:packages/cli-parser",
|
||||||
"cli-table": "^0.3.11",
|
"cli-table": "^0.3.11",
|
||||||
|
"config-manager": "file:packages/config-manager",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"extract-zip": "^2.0.1",
|
"extract-zip": "^2.0.1",
|
||||||
"html-to-text": "^9.0.5",
|
"html-to-text": "^9.0.5",
|
||||||
|
|
@ -100,7 +103,9 @@
|
||||||
"linkify-html": "^4.1.3",
|
"linkify-html": "^4.1.3",
|
||||||
"linkify-string": "^4.1.3",
|
"linkify-string": "^4.1.3",
|
||||||
"linkifyjs": "^4.1.3",
|
"linkifyjs": "^4.1.3",
|
||||||
|
"log-manager": "file:packages/log-manager",
|
||||||
"marked": "latest",
|
"marked": "latest",
|
||||||
|
"media-manager": "file:packages/media-manager",
|
||||||
"megalodon": "^9.1.1",
|
"megalodon": "^9.1.1",
|
||||||
"meilisearch": "latest",
|
"meilisearch": "latest",
|
||||||
"merge-deep-ts": "^1.2.6",
|
"merge-deep-ts": "^1.2.6",
|
||||||
|
|
@ -108,12 +113,8 @@
|
||||||
"oauth4webapi": "^2.4.0",
|
"oauth4webapi": "^2.4.0",
|
||||||
"prisma": "^5.6.0",
|
"prisma": "^5.6.0",
|
||||||
"prisma-redis-middleware": "^4.8.0",
|
"prisma-redis-middleware": "^4.8.0",
|
||||||
"semver": "^7.5.4",
|
|
||||||
"sharp": "^0.33.0-rc.2",
|
|
||||||
"request-parser": "file:packages/request-parser",
|
"request-parser": "file:packages/request-parser",
|
||||||
"config-manager": "file:packages/config-manager",
|
"semver": "^7.5.4",
|
||||||
"cli-parser": "file:packages/cli-parser",
|
"sharp": "^0.33.0-rc.2"
|
||||||
"log-manager": "file:packages/log-manager",
|
|
||||||
"media-manager": "file:packages/media-manager"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +117,9 @@ export class CliBuilder {
|
||||||
prev.categories.length > current.categories.length ? prev : current
|
prev.categories.length > current.categories.length ? prev : current
|
||||||
);
|
);
|
||||||
|
|
||||||
const argsWithoutCategories = revelantArgs.slice(command.categories.length);
|
const argsWithoutCategories = revelantArgs.slice(
|
||||||
|
command.categories.length
|
||||||
|
);
|
||||||
|
|
||||||
return await command.run(argsWithoutCategories);
|
return await command.run(argsWithoutCategories);
|
||||||
}
|
}
|
||||||
|
|
@ -243,8 +245,6 @@ export class CliBuilder {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(optimal_length)
|
|
||||||
|
|
||||||
for (const line of writeBuffer.split("\n")) {
|
for (const line of writeBuffer.split("\n")) {
|
||||||
const [left, right] = line.split("|");
|
const [left, right] = line.split("|");
|
||||||
if (!right) {
|
if (!right) {
|
||||||
|
|
@ -261,6 +261,7 @@ export class CliBuilder {
|
||||||
type ExecuteFunction<T> = (
|
type ExecuteFunction<T> = (
|
||||||
instance: CliCommand,
|
instance: CliCommand,
|
||||||
args: Partial<T>
|
args: Partial<T>
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
||||||
) => Promise<number> | Promise<void> | number | void;
|
) => Promise<number> | Promise<void> | number | void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -364,7 +365,7 @@ ${unpositionedArgs
|
||||||
currentParameter = null;
|
currentParameter = null;
|
||||||
} else {
|
} else {
|
||||||
const positionedArgType = this.argTypes.find(
|
const positionedArgType = this.argTypes.find(
|
||||||
argType => argType.positioned
|
argType => argType.positioned && !parsedArgs[argType.name]
|
||||||
);
|
);
|
||||||
if (positionedArgType) {
|
if (positionedArgType) {
|
||||||
parsedArgs[positionedArgType.name] = this.castArgValue(
|
parsedArgs[positionedArgType.name] = this.castArgValue(
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ describe("CliCommand", () => {
|
||||||
).toEqual(["value1", "value2"]);
|
).toEqual(["value1", "value2"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should run the execute function with the parsed parameters", () => {
|
it("should run the execute function with the parsed parameters", async () => {
|
||||||
const mockExecute = jest.fn();
|
const mockExecute = jest.fn();
|
||||||
cliCommand = new CliCommand(
|
cliCommand = new CliCommand(
|
||||||
["category1", "category2"],
|
["category1", "category2"],
|
||||||
|
|
@ -142,7 +142,7 @@ describe("CliCommand", () => {
|
||||||
mockExecute
|
mockExecute
|
||||||
);
|
);
|
||||||
|
|
||||||
cliCommand.run([
|
await cliCommand.run([
|
||||||
"--arg1",
|
"--arg1",
|
||||||
"value1",
|
"value1",
|
||||||
"--arg2",
|
"--arg2",
|
||||||
|
|
@ -159,7 +159,7 @@ describe("CliCommand", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should work with a mix of positioned and non-positioned arguments", () => {
|
it("should work with a mix of positioned and non-positioned arguments", async () => {
|
||||||
const mockExecute = jest.fn();
|
const mockExecute = jest.fn();
|
||||||
cliCommand = new CliCommand(
|
cliCommand = new CliCommand(
|
||||||
["category1", "category2"],
|
["category1", "category2"],
|
||||||
|
|
@ -194,7 +194,7 @@ describe("CliCommand", () => {
|
||||||
mockExecute
|
mockExecute
|
||||||
);
|
);
|
||||||
|
|
||||||
cliCommand.run([
|
await cliCommand.run([
|
||||||
"--arg1",
|
"--arg1",
|
||||||
"value1",
|
"value1",
|
||||||
"--arg2",
|
"--arg2",
|
||||||
|
|
@ -324,7 +324,7 @@ describe("CliBuilder", () => {
|
||||||
expect(cliBuilder.commands).not.toContain(mockCommand2);
|
expect(cliBuilder.commands).not.toContain(mockCommand2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should process args correctly", () => {
|
it("should process args correctly", async () => {
|
||||||
const mockExecute = jest.fn();
|
const mockExecute = jest.fn();
|
||||||
const mockCommand = new CliCommand(
|
const mockCommand = new CliCommand(
|
||||||
["category1", "sub1"],
|
["category1", "sub1"],
|
||||||
|
|
@ -339,7 +339,7 @@ describe("CliBuilder", () => {
|
||||||
mockExecute
|
mockExecute
|
||||||
);
|
);
|
||||||
cliBuilder.registerCommand(mockCommand);
|
cliBuilder.registerCommand(mockCommand);
|
||||||
cliBuilder.processArgs([
|
await cliBuilder.processArgs([
|
||||||
"./cli.ts",
|
"./cli.ts",
|
||||||
"category1",
|
"category1",
|
||||||
"sub1",
|
"sub1",
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,24 @@ export class MediaBackend {
|
||||||
public backend: MediaBackendType
|
public backend: MediaBackendType
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
static async fromBackendType(
|
||||||
|
backend: MediaBackendType,
|
||||||
|
config: ConfigType
|
||||||
|
): Promise<MediaBackend> {
|
||||||
|
switch (backend) {
|
||||||
|
case MediaBackendType.LOCAL:
|
||||||
|
return new (await import("./backends/local")).LocalMediaBackend(
|
||||||
|
config
|
||||||
|
);
|
||||||
|
case MediaBackendType.S3:
|
||||||
|
return new (await import("./backends/s3")).S3MediaBackend(
|
||||||
|
config
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown backend type: ${backend as any}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getBackendType() {
|
public getBackendType() {
|
||||||
return this.backend;
|
return this.backend;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,39 @@ describe("MediaBackend", () => {
|
||||||
expect(mediaBackend.getBackendType()).toEqual(MediaBackendType.S3);
|
expect(mediaBackend.getBackendType()).toEqual(MediaBackendType.S3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("fromBackendType", () => {
|
||||||
|
it("should return a LocalMediaBackend instance for LOCAL backend type", async () => {
|
||||||
|
const backend = await MediaBackend.fromBackendType(
|
||||||
|
MediaBackendType.LOCAL,
|
||||||
|
mockConfig
|
||||||
|
);
|
||||||
|
expect(backend).toBeInstanceOf(LocalMediaBackend);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return a S3MediaBackend instance for S3 backend type", async () => {
|
||||||
|
const backend = await MediaBackend.fromBackendType(
|
||||||
|
MediaBackendType.S3,
|
||||||
|
{
|
||||||
|
s3: {
|
||||||
|
endpoint: "localhost:4566",
|
||||||
|
region: "us-east-1",
|
||||||
|
bucket_name: "test-bucket",
|
||||||
|
access_key: "test-access",
|
||||||
|
public_url: "test",
|
||||||
|
secret_access_key: "test-secret",
|
||||||
|
},
|
||||||
|
} as ConfigType
|
||||||
|
);
|
||||||
|
expect(backend).toBeInstanceOf(S3MediaBackend);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw an error for unknown backend type", () => {
|
||||||
|
expect(
|
||||||
|
MediaBackend.fromBackendType("unknown" as any, mockConfig)
|
||||||
|
).rejects.toThrow("Unknown backend type: unknown");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("should check if images should be converted", () => {
|
it("should check if images should be converted", () => {
|
||||||
expect(mediaBackend.shouldConvertImages(mockConfig)).toBe(true);
|
expect(mediaBackend.shouldConvertImages(mockConfig)).toBe(true);
|
||||||
mockConfig.media.conversion.convert_images = false;
|
mockConfig.media.conversion.convert_images = false;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue