185 lines
4.9 KiB
TypeScript
185 lines
4.9 KiB
TypeScript
import { Architect } from '@angular-devkit/architect';
|
|
import { WorkspaceNodeModulesArchitectHost } from '@angular-devkit/architect/node';
|
|
import {
|
|
experimental,
|
|
json,
|
|
logging,
|
|
normalize,
|
|
schema,
|
|
terminal
|
|
} from '@angular-devkit/core';
|
|
import { NodeJsSyncHost } from '@angular-devkit/core/node';
|
|
import { getLogger } from '../shared/logger';
|
|
import {
|
|
coerceTypes,
|
|
convertToCamelCase,
|
|
handleErrors,
|
|
Schema
|
|
} from '../shared/params';
|
|
import { commandName, printHelp } from '../shared/print-help';
|
|
import minimist = require('minimist');
|
|
|
|
export interface RunOptions {
|
|
project: string;
|
|
target: string;
|
|
configuration: string;
|
|
help: boolean;
|
|
runOptions: { [k: string]: any };
|
|
}
|
|
|
|
function throwInvalidInvocation() {
|
|
throw new Error(
|
|
`Specify the project name and the target (e.g., ${commandName} run proj:build)`
|
|
);
|
|
}
|
|
|
|
function parseRunOpts(
|
|
args: string[],
|
|
defaultProjectName: string | null,
|
|
logger: logging.Logger
|
|
): RunOptions {
|
|
const runOptions = convertToCamelCase(
|
|
minimist(args, {
|
|
boolean: ['help', 'prod'],
|
|
string: ['configuration', 'project']
|
|
})
|
|
);
|
|
const help = runOptions.help;
|
|
if (!runOptions._ || !runOptions._[0]) {
|
|
throwInvalidInvocation();
|
|
}
|
|
let [project, target, configuration] = runOptions._[0].split(':');
|
|
if (!project && defaultProjectName) {
|
|
logger.debug(
|
|
`No project name specified. Using default project : ${terminal.bold(
|
|
defaultProjectName
|
|
)}`
|
|
);
|
|
project = defaultProjectName;
|
|
}
|
|
if (!project || !target) {
|
|
throwInvalidInvocation();
|
|
}
|
|
if (runOptions.configuration) {
|
|
configuration = runOptions.configuration;
|
|
}
|
|
if (runOptions.prod) {
|
|
configuration = 'production';
|
|
}
|
|
if (runOptions.project) {
|
|
project = runOptions.project;
|
|
}
|
|
const res = { project, target, configuration, help, runOptions };
|
|
delete runOptions['help'];
|
|
delete runOptions['_'];
|
|
delete runOptions['configuration'];
|
|
delete runOptions['prod'];
|
|
delete runOptions['project'];
|
|
|
|
return res;
|
|
}
|
|
|
|
function printRunHelp(
|
|
opts: RunOptions,
|
|
schema: Schema,
|
|
logger: logging.Logger
|
|
) {
|
|
printHelp(
|
|
`${commandName} run ${opts.project}:${opts.target}`,
|
|
schema,
|
|
logger
|
|
);
|
|
}
|
|
|
|
export function validateTargetAndConfiguration(
|
|
workspace: experimental.workspace.Workspace,
|
|
opts: RunOptions
|
|
) {
|
|
const targets = workspace.getProjectTargets(opts.project);
|
|
|
|
const target = targets[opts.target];
|
|
if (!target) {
|
|
throw new Error(
|
|
`Could not find target "${opts.target}" in the ${
|
|
opts.project
|
|
} project. Valid targets are: ${terminal.bold(
|
|
Object.keys(targets).join(', ')
|
|
)}`
|
|
);
|
|
}
|
|
|
|
// Not all targets have configurations
|
|
// and an undefined configuration is valid
|
|
if (opts.configuration) {
|
|
if (target.configurations) {
|
|
const configuration = target.configurations[opts.configuration];
|
|
if (!configuration) {
|
|
throw new Error(
|
|
`Could not find configuration "${opts.configuration}" in ${
|
|
opts.project
|
|
}:${opts.target}. Valid configurations are: ${Object.keys(
|
|
target.configurations
|
|
).join(', ')}`
|
|
);
|
|
}
|
|
} else {
|
|
throw new Error(
|
|
`No configurations are defined for ${opts.project}:${opts.target}, so "${opts.configuration}" is invalid.`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function run(root: string, args: string[], isVerbose: boolean) {
|
|
const logger = getLogger(isVerbose);
|
|
|
|
return handleErrors(logger, isVerbose, async () => {
|
|
const fsHost = new NodeJsSyncHost();
|
|
const workspace = await new experimental.workspace.Workspace(
|
|
normalize(root) as any,
|
|
fsHost
|
|
)
|
|
.loadWorkspaceFromHost('workspace.json' as any)
|
|
.toPromise();
|
|
|
|
const opts = parseRunOpts(args, workspace.getDefaultProjectName(), logger);
|
|
validateTargetAndConfiguration(workspace, opts);
|
|
|
|
const registry = new json.schema.CoreSchemaRegistry();
|
|
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
|
|
const architectHost = new WorkspaceNodeModulesArchitectHost(
|
|
workspace,
|
|
root
|
|
);
|
|
const architect = new Architect(architectHost, registry);
|
|
|
|
const builderConf = await architectHost.getBuilderNameForTarget({
|
|
project: opts.project,
|
|
target: opts.target
|
|
});
|
|
const builderDesc = await architectHost.resolveBuilder(builderConf);
|
|
const flattenedSchema = await registry
|
|
.flatten(builderDesc.optionSchema! as json.JsonObject)
|
|
.toPromise();
|
|
|
|
if (opts.help) {
|
|
printRunHelp(opts, flattenedSchema as any, logger);
|
|
return 0;
|
|
}
|
|
|
|
const runOptions = coerceTypes(opts.runOptions, flattenedSchema as any);
|
|
const run = await architect.scheduleTarget(
|
|
{
|
|
project: opts.project,
|
|
target: opts.target,
|
|
configuration: opts.configuration
|
|
},
|
|
runOptions,
|
|
{ logger }
|
|
);
|
|
const result = await run.output.toPromise();
|
|
await run.stop();
|
|
return result.success ? 0 : 1;
|
|
});
|
|
}
|