feat: engine-specific commands and better organised environment
parent
18af761e9f
commit
cae5ffaf6c
|
|
@ -1,11 +1,28 @@
|
||||||
import { NonExistentCommand } from './command/non-existent-command.ts';
|
import { NonExistentCommand } from './command/non-existent-command.ts';
|
||||||
import { BuildCommand } from './command/build-command.ts';
|
import { BuildCommand } from './command/unity/build-command.ts';
|
||||||
import { BuildRemoteCommand } from './command/build-remote-command.ts';
|
import { BuildRemoteCommand } from './command/unity/build-remote-command.ts';
|
||||||
|
import { CommandInterface } from './command/command-interface.ts';
|
||||||
|
|
||||||
export class CommandFactory {
|
export class CommandFactory {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
public createCommand(commandName: string) {
|
selectEngine(engine: string, engineVersion: string) {
|
||||||
|
this.engine = engine;
|
||||||
|
this.engineVersion = engineVersion;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public createCommand(commandName: string): CommandInterface {
|
||||||
|
switch (this.engine) {
|
||||||
|
case 'unity':
|
||||||
|
return this.createUnityCommand(commandName);
|
||||||
|
default:
|
||||||
|
throw new Error(`Engine ${this.engine} is not yet supported.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createUnityCommand(commandName: string) {
|
||||||
switch (commandName) {
|
switch (commandName) {
|
||||||
case 'build':
|
case 'build':
|
||||||
return new BuildCommand(commandName);
|
return new BuildCommand(commandName);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { exec, OutputMode } from 'https://deno.land/x/exec@0.0.5/mod.ts';
|
import { exec, OutputMode } from 'https://deno.land/x/exec@0.0.5/mod.ts';
|
||||||
import { CommandInterface } from './command-interface.ts';
|
import { CommandInterface } from '../command-interface.ts';
|
||||||
import { Options } from '../../config/options.ts';
|
import { Options } from '../../../config/options.ts';
|
||||||
import { Action, Cache, CloudRunner, Docker, ImageTag, Input, Output } from '../../model/index.ts';
|
import { Action, Cache, CloudRunner, Docker, ImageTag, Input, Output } from '../../../model/index.ts';
|
||||||
import PlatformSetup from '../../model/platform-setup.ts';
|
import PlatformSetup from '../../../model/platform-setup.ts';
|
||||||
import { core, process } from '../../dependencies.ts';
|
import { core, process } from '../../../dependencies.ts';
|
||||||
import MacBuilder from '../../model/mac-builder.ts';
|
import MacBuilder from '../../../model/mac-builder.ts';
|
||||||
import Parameters from '../../model/parameters.ts';
|
import Parameters from '../../../model/parameters.ts';
|
||||||
|
|
||||||
export class BuildCommand implements CommandInterface {
|
export class BuildCommand implements CommandInterface {
|
||||||
public readonly name: string;
|
public readonly name: string;
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { CommandInterface } from './command-interface.ts';
|
import { CommandInterface } from '../command-interface.ts';
|
||||||
import { Options } from '../../config/options.ts';
|
import { Options } from '../../../config/options.ts';
|
||||||
import { CloudRunner, ImageTag, Input, Output } from '../../model/index.ts';
|
import { CloudRunner, ImageTag, Input, Output } from '../../../model/index.ts';
|
||||||
import { core } from '../../dependencies.ts';
|
import { core } from '../../../dependencies.ts';
|
||||||
import Parameters from '../../model/parameters.ts';
|
import Parameters from '../../../model/parameters.ts';
|
||||||
|
|
||||||
// Todo - Verify this entire flow
|
// Todo - Verify this entire flow
|
||||||
export class BuildRemoteCommand implements CommandInterface {
|
export class BuildRemoteCommand implements CommandInterface {
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
import { CliArguments } from '../core/cli/cli-arguments.ts';
|
import { CliArguments } from '../core/cli/cli-arguments.ts';
|
||||||
import { EnvVariables } from '../core/env/env-variables.ts';
|
|
||||||
import { Parameters, Input } from '../model/index.ts';
|
import { Parameters, Input } from '../model/index.ts';
|
||||||
import { CommandInterface } from '../commands/command/command-interface.ts';
|
import { CommandInterface } from '../commands/command/command-interface.ts';
|
||||||
|
import { Environment } from '../core/env/environment.ts';
|
||||||
|
|
||||||
export class Options {
|
export class Options {
|
||||||
public input: Input;
|
public input: Input;
|
||||||
public parameters: Parameters;
|
public parameters: Parameters;
|
||||||
private readonly env: EnvVariables;
|
private readonly env: Environment;
|
||||||
private readonly command: CommandInterface;
|
private command: CommandInterface;
|
||||||
|
|
||||||
constructor(command: CommandInterface, env: EnvVariables) {
|
constructor(command: CommandInterface, env: Environment) {
|
||||||
this.input = null;
|
|
||||||
this.parameters = null;
|
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.command = command;
|
this.command = command;
|
||||||
|
|
||||||
|
|
@ -26,4 +24,10 @@ export class Options {
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerCommand(command: CommandInterface) {
|
||||||
|
this.command = command;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ import { parseArgv } from './parse-argv.ts';
|
||||||
|
|
||||||
export class ArgumentsParser {
|
export class ArgumentsParser {
|
||||||
public parse(cliArguments: string[]) {
|
public parse(cliArguments: string[]) {
|
||||||
const [commandName, ...args] = cliArguments;
|
const [commandName, ...rest] = cliArguments;
|
||||||
|
const { subCommands, args } = parseArgv(rest);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
commandName,
|
commandName,
|
||||||
args: parseArgv(args),
|
subCommands,
|
||||||
|
args,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@ import { CliArguments } from './cli-arguments.ts';
|
||||||
* console.log(parseArgv(process.argv)); // Node
|
* console.log(parseArgv(process.argv)); // Node
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* deno run my-script -test1=1 -test2 "2" -test3 -test4 false -test5 "one" -test6= -test7=9BX9
|
* deno run my-script my-project -test1=1 -test2 "2" -test3 -test4 false -test5 "one" -test6= -test7=9BX9
|
||||||
*
|
*
|
||||||
* Output:
|
* Output:
|
||||||
|
* [
|
||||||
|
* [ 'my-project' ],
|
||||||
* Map {
|
* Map {
|
||||||
* "test1" => 1,
|
* "test1" => 1,
|
||||||
* "test2" => 2,
|
* "test2" => 2,
|
||||||
|
|
@ -20,11 +22,24 @@ import { CliArguments } from './cli-arguments.ts';
|
||||||
* "test6" => "",
|
* "test6" => "",
|
||||||
* "test7" => "9BX9"
|
* "test7" => "9BX9"
|
||||||
* }
|
* }
|
||||||
|
* ]
|
||||||
*/
|
*/
|
||||||
export const parseArgv = (argv: string[] = [], { verbose = false } = {}): CliArguments => {
|
export const parseArgv = (argv: string[] = [], { verbose = false } = {}): CliArguments => {
|
||||||
const providedArguments = new Map<string, string | number | boolean>();
|
const subCommands: string[] = [];
|
||||||
|
const args = new Map<string, string | number | boolean>();
|
||||||
|
|
||||||
|
let hasParsedSubCommands = false;
|
||||||
for (let current = 0, next = 1; current < argv.length; current += 1, next += 1) {
|
for (let current = 0, next = 1; current < argv.length; current += 1, next += 1) {
|
||||||
|
// Detect subCommands
|
||||||
|
if (!hasParsedSubCommands) {
|
||||||
|
if (argv[current].startsWith('-')) {
|
||||||
|
hasParsedSubCommands = true;
|
||||||
|
} else {
|
||||||
|
subCommands.push(argv[current]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Detect flag
|
// Detect flag
|
||||||
if (!argv[current].startsWith('-')) continue;
|
if (!argv[current].startsWith('-')) continue;
|
||||||
let flag = argv[current].replace(/^-+/, '');
|
let flag = argv[current].replace(/^-+/, '');
|
||||||
|
|
@ -44,8 +59,8 @@ export const parseArgv = (argv: string[] = [], { verbose = false } = {}): CliArg
|
||||||
// Assign
|
// Assign
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
if (verbose) console.log(`Found flag "${flag}" with value "${value}" (${typeof value}).`);
|
if (verbose) console.log(`Found flag "${flag}" with value "${value}" (${typeof value}).`);
|
||||||
providedArguments.set(flag, value);
|
args.set(flag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return providedArguments;
|
return { subCommands, args };
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
export class EngineDetector {
|
||||||
|
private projectPath: string;
|
||||||
|
|
||||||
|
constructor(subCommands: string[], args: string[]) {
|
||||||
|
this.projectPath = subCommands[0] || args.projectPath || '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public async detect(): Promise<{ engine: string; engineVersion: string }> {
|
||||||
|
// Todo - detect and return real versions
|
||||||
|
return {
|
||||||
|
engine: 'unity',
|
||||||
|
engineVersion: '2020.1.0f1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
type EnvVariables = { [index: string]: string };
|
||||||
|
|
||||||
|
export class Environment implements EnvVariables {
|
||||||
|
public readonly os: string;
|
||||||
|
public readonly arch: string;
|
||||||
|
|
||||||
|
constructor(env: Deno.env) {
|
||||||
|
// Make an immutable copy of the environment variables.
|
||||||
|
for (const [key, value] of Object.entries(env.toObject())) {
|
||||||
|
if (value !== undefined) this[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override specific variables.
|
||||||
|
this.os = Deno.build.os;
|
||||||
|
this.arch = Deno.build.arch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: string): string | undefined {
|
||||||
|
return this[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getOS(): string {
|
||||||
|
return this.os;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getArch(): string {
|
||||||
|
return this.arch;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/index.ts
33
src/index.ts
|
|
@ -1,34 +1,27 @@
|
||||||
import './core/logger/index.ts';
|
import './core/logger/index.ts';
|
||||||
import type { CommandInterface } from './commands/command/command-interface.ts';
|
|
||||||
import type { EnvVariables } from './core/env/env-variables.ts';
|
|
||||||
import { Options } from './config/options.ts';
|
import { Options } from './config/options.ts';
|
||||||
import { CommandFactory } from './commands/command-factory.ts';
|
import { CommandFactory } from './commands/command-factory.ts';
|
||||||
import { ArgumentsParser } from './core/cli/arguments-parser.ts';
|
import { ArgumentsParser } from './core/cli/arguments-parser.ts';
|
||||||
import System from './model/system.ts';
|
import { Environment } from './core/env/environment.ts';
|
||||||
|
import { EngineDetector } from './core/engine/engine-detector.ts';
|
||||||
|
|
||||||
export class GameCI {
|
export class GameCI {
|
||||||
private readonly commandFactory: CommandFactory;
|
private readonly env: Environment;
|
||||||
private readonly argumentsParser: ArgumentsParser;
|
|
||||||
private readonly env: EnvVariables;
|
|
||||||
|
|
||||||
private options?: Options;
|
constructor() {
|
||||||
private command?: CommandInterface;
|
this.env = new Environment(Deno.env);
|
||||||
|
this.args = Deno.args;
|
||||||
constructor(envVariables: EnvVariables) {
|
|
||||||
this.env = envVariables;
|
|
||||||
|
|
||||||
this.commandFactory = new CommandFactory();
|
|
||||||
this.argumentsParser = new ArgumentsParser();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async run(cliArguments: string[]) {
|
public async run() {
|
||||||
try {
|
try {
|
||||||
const { commandName, args } = this.argumentsParser.parse(cliArguments);
|
const { commandName, subCommands, args } = new ArgumentsParser().parse(this.args);
|
||||||
|
const { engine, engineVersion } = await new EngineDetector(subCommands, args).detect();
|
||||||
|
|
||||||
this.options = await new Options(this.env).generateParameters(args);
|
const command = new CommandFactory().selectEngine(engine, engineVersion).createCommand(commandName, subCommands);
|
||||||
this.command = this.commandFactory.createCommand(commandName);
|
const options = await new Options(command, this.env).registerCommand(command).generateParameters(args);
|
||||||
|
|
||||||
await this.command.execute(this.options);
|
await command.execute(options);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(error);
|
log.error(error);
|
||||||
Deno.exit(1);
|
Deno.exit(1);
|
||||||
|
|
@ -36,4 +29,4 @@ export class GameCI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await new GameCI(Deno.env.toObject()).run(Deno.args);
|
await new GameCI().run();
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import Versioning from './versioning.ts';
|
||||||
import { GitRepoReader } from './input-readers/git-repo.ts';
|
import { GitRepoReader } from './input-readers/git-repo.ts';
|
||||||
import { GithubCliReader } from './input-readers/github-cli.ts';
|
import { GithubCliReader } from './input-readers/github-cli.ts';
|
||||||
import { Cli } from './cli/cli.ts';
|
import { Cli } from './cli/cli.ts';
|
||||||
import { EnvVariables } from '../core/env/env-variables.ts';
|
|
||||||
import { CommandInterface } from '../commands/command/command-interface.ts';
|
import { CommandInterface } from '../commands/command/command-interface.ts';
|
||||||
|
import { Environment } from '../core/env/environment.ts';
|
||||||
|
|
||||||
class Parameters {
|
class Parameters {
|
||||||
private command: CommandInterface;
|
private command: CommandInterface;
|
||||||
|
|
@ -69,9 +69,9 @@ class Parameters {
|
||||||
public isCliMode!: boolean;
|
public isCliMode!: boolean;
|
||||||
|
|
||||||
private readonly input: Input;
|
private readonly input: Input;
|
||||||
private readonly env: EnvVariables;
|
private readonly env: Environment;
|
||||||
|
|
||||||
constructor(input: Input, env: EnvVariables) {
|
constructor(input: Input, env: Environment) {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.env = env;
|
this.env = env;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue