diff --git a/.eslintrc.json b/.eslintrc.json index 08001ef8..907b5374 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -16,6 +16,9 @@ "es6": true, "jest/globals": true }, + "globals": { + "Deno": true + }, "rules": { // Error out for code formatting errors "prettier/prettier": "error", diff --git a/cli/arguments-parser/arguments-parser.ts b/cli/arguments-parser/arguments-parser.ts new file mode 100644 index 00000000..20c93e2b --- /dev/null +++ b/cli/arguments-parser/arguments-parser.ts @@ -0,0 +1,12 @@ +import { parseArgv } from '../core/parse-argv.ts'; + +export class ArgumentsParser { + static parse(cliArguments: string[]) { + const [commandName, ...arguments] = cliArguments; + + return { + commandName, + options: parseArgv(arguments), + }; + } +} diff --git a/cli/bootstrapper.ts b/cli/bootstrapper.ts new file mode 100644 index 00000000..a617c943 --- /dev/null +++ b/cli/bootstrapper.ts @@ -0,0 +1,28 @@ +import { CommandFactory } from './commands/command-factory.ts'; +import { ArgumentsParser } from './arguments-parser/arguments-parser.ts'; +import { Options } from './config/options.ts'; +import { CommandInterface } from './commands/command/CommandInterface.ts'; + +export class Bootstrapper { + private readonly commandFactory: CommandFactory; + private readonly argumentsParser: ArgumentsParser; + + private options?: Options; + private command?: CommandInterface; + + constructor() { + this.commandFactory = new CommandFactory(); + this.argumentsParser = ArgumentsParser; + } + + public async run(cliArguments: string[]) { + const { commandName, options } = this.argumentsParser.parse(cliArguments); + + this.options = new Options(options); + this.command = this.commandFactory.createCommand(commandName); + + // Command agnostic stuff here + + await this.command.execute(this.options); + } +} diff --git a/cli/commands/command-factory.ts b/cli/commands/command-factory.ts new file mode 100644 index 00000000..65ab38e8 --- /dev/null +++ b/cli/commands/command-factory.ts @@ -0,0 +1,15 @@ +import { NonExistentCommand } from './command/non-existent-command.ts'; +import { BuildCommand } from './command/build-command.ts'; + +export class CommandFactory { + constructor() {} + + public createCommand(commandName) { + switch (commandName) { + case 'build': + return new BuildCommand(); + default: + return new NonExistentCommand(commandName); + } + } +} diff --git a/cli/commands/command/CommandInterface.ts b/cli/commands/command/CommandInterface.ts new file mode 100644 index 00000000..74689cc2 --- /dev/null +++ b/cli/commands/command/CommandInterface.ts @@ -0,0 +1,6 @@ +import { Options } from '../../config/options.ts'; + +export interface CommandInterface { + name: string; + execute: (options: Options) => Promise; +} diff --git a/cli/controller/bootstrapper.ts b/cli/commands/command/build-command.ts similarity index 50% rename from cli/controller/bootstrapper.ts rename to cli/commands/command/build-command.ts index ee109846..2f8ab2cf 100644 --- a/cli/controller/bootstrapper.ts +++ b/cli/commands/command/build-command.ts @@ -1,17 +1,15 @@ -/* eslint-disable no-console */ +import { CommandInterface } from './CommandInterface.ts'; import { exec, OutputMode } from 'https://deno.land/x/exec@0.0.5/mod.ts'; -import { CliOptions } from '../core/cli-options.ts'; +import { Options } from '../../config/options.ts'; -export class Bootstrapper { - private readonly options: CliOptions; +export class BuildCommand implements CommandInterface { + public readonly name: string; - constructor(cliOptions: CliOptions) { - this.options = cliOptions; + constructor(name: string) { + this.name = name; } - public async run() { - console.log('using options', this.options); - + public async execute(options: Options) { const result = await exec('docker run -it unityci/editor:2020.3.15f2-base-1 /bin/bash -c "echo test"', { output: OutputMode.Capture, continueOnError: true, @@ -19,6 +17,7 @@ export class Bootstrapper { // verbose: true, }); + console.log(options); console.log(result.output); } } diff --git a/cli/commands/command/non-existent-command.ts b/cli/commands/command/non-existent-command.ts new file mode 100644 index 00000000..67ac00d7 --- /dev/null +++ b/cli/commands/command/non-existent-command.ts @@ -0,0 +1,14 @@ +import { CommandInterface } from './CommandInterface.ts'; +import { Options } from '../../config/options.ts'; + +export class NonExistentCommand implements CommandInterface { + public name: string; + + constructor(name: string) { + this.name = name; + } + + public async execute(options: Options) { + throw new Error(`Command ${this.name} does not exist`); + } +} diff --git a/cli/config/options.ts b/cli/config/options.ts new file mode 100644 index 00000000..d646edc5 --- /dev/null +++ b/cli/config/options.ts @@ -0,0 +1,9 @@ +import { CliOptions } from '../core/cli-options.ts'; + +export class Options { + public options: CliOptions; + + constructor(optionsFromCli) { + this.options = optionsFromCli; + } +} diff --git a/cli/core/kernel.ts b/cli/core/kernel.ts deleted file mode 100644 index fd3b97a3..00000000 --- a/cli/core/kernel.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { parseArgv } from './parse-argv.ts'; -import { Bootstrapper } from '../controller/bootstrapper.ts'; - -export class Kernel { - public async run() { - const cliOptions = parseArgv(Deno.args); - - const bootstrapper = new Bootstrapper(cliOptions); - bootstrapper.run(); - } -} diff --git a/cli/index.ts b/cli/index.ts index 1ae8eaa0..7a2b224b 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -1,7 +1,11 @@ -import { Kernel } from './core/kernel.ts'; +/* eslint-disable no-console */ +import { Bootstrapper } from './bootstrapper.ts'; (async () => { - const kernel = new Kernel(); - - await kernel.run(); + try { + await new Bootstrapper().run(Deno.args); + } catch (error) { + console.error(error); + Deno.exit(1); + } })(); diff --git a/tsconfig.json b/tsconfig.json index 236ef4cd..474bccee 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, "outDir": "./lib" /* Redirect output structure to the directory. */, - "rootDir": "./" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + "rootDir": "./cli" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, "strict": true /* Enable all strict type-checking options. */, "noImplicitAny": false /* Re-enable after fixing compatibility */ /* Raise error on expressions and declarations with an implied 'any' type. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */