diff --git a/packages/xod-cli/src/commands/tabtest.js b/packages/xod-cli/src/commands/tabtest.js new file mode 100644 index 00000000..0bae3341 --- /dev/null +++ b/packages/xod-cli/src/commands/tabtest.js @@ -0,0 +1,159 @@ +/* eslint-disable no-param-reassign */ +import path from 'path'; +import { exit } from 'process'; +import { tmpdir } from 'os'; +import { append, compose, identity, map, pick, toPairs } from 'ramda'; +import fs from 'fs-extra'; +import { flags } from '@oclif/command'; + +import childProcess from 'child_process'; +import { createError, foldEither, allPromises } from 'xod-func-tools'; +import { loadProject, resolvePath } from 'xod-fs'; +import * as Tabtest from 'xod-tabtest'; + +import BaseCommand from '../baseCommand'; +import * as commonArgs from '../args'; +import * as myFlags from '../flags'; +import { getListr } from '../listr'; +import { + resolveBundledCatch2Path, + resolveBundledTabtestSrcPath, + resolveBundledTabtestWorkspacePath, + resolveBundledWorkspacePath, +} from '../paths'; + +const spawn = (cmd, args, opts) => + new Promise((resolve, reject) => { + childProcess.spawn(cmd, args, opts).on('exit', code => { + if (code === 0) { + resolve(); + } else { + reject(createError('TABTEST_PROCESS_NONZERO', { cmd, code })); + } + }); + }); + +class TabtestCommand extends BaseCommand { + async run() { + this.parseArgv(TabtestCommand); + await this.ensureWorkspace(); + await this.parseEntrypoint(); + const { + 'no-build': noBuild, + 'output-dir': outDir, + workspace, + quiet, + } = this.flags; + const { projectPath, patchName } = this.args; + + const workspaces = [ + workspace, + resolveBundledTabtestWorkspacePath(), + resolveBundledWorkspacePath(), + ]; + + const childProcessOpts = { + stdio: quiet + ? ['inherit', 'ignore', 'ignore'] + : ['inherit', 'inherit', 'inherit'], + shell: true, + cwd: outDir, + }; + + const prepareDirectoryTask = { + title: 'Preparing directory', + task: () => fs.ensureDir(outDir), + }; + + const loadProjectTask = { + title: 'Loading project', + task: ctx => + loadProject(workspaces, projectPath).then(project => { + ctx.project = project; + }), + }; + + const generateCppTask = { + title: 'Generating C++ code', + task: ctx => { + ctx.pairs = compose( + toPairs, + foldEither(err => { + throw err; + }, identity) + )( + patchName + ? Tabtest.generatePatchSuite(ctx.project, patchName) + : Tabtest.generateProjectSuite(ctx.project) + ); + }, + }; + + const saveFilesTask = { + title: 'Saving files', + task: async ctx => + await compose( + allPromises, + append(fs.copy(resolveBundledTabtestSrcPath(), outDir)), + append(fs.copy(resolveBundledCatch2Path(), outDir)), + map(([filename, content]) => + fs.outputFile(path.join(outDir, filename), content) + ) + )(ctx.pairs), + }; + + await getListr( + !quiet, + [prepareDirectoryTask, loadProjectTask, generateCppTask, saveFilesTask], + { collapse: false } + ) + .run() + .then(async () => { + if (!noBuild) { + this.info('Compiling...'); + await spawn('make', [], childProcessOpts); + this.info('Testing...'); + await spawn('make', ['test'], childProcessOpts); + } + }) + .then(() => exit(0)) + .catch(err => { + this.printError(err); + return exit(100); + }); + } +} + +TabtestCommand.description = 'tabtest project'; + +TabtestCommand.usage = 'tabtest [options] [entrypoint]'; + +TabtestCommand.flags = { + ...BaseCommand.flags, + ...pick(['workspace'], myFlags), + 'output-dir': flags.string({ + char: 'o', + description: 'path to directory where to save tabtest data', + env: 'XOD_OUTPUT', + helpValue: 'path', + default: path.join(tmpdir(), 'xod-tabtest'), + parse: p => resolvePath(p), + }), + 'no-build': flags.boolean({ + description: 'do not build', + default: false, + }), +}; + +TabtestCommand.args = [commonArgs.entrypoint]; + +TabtestCommand.examples = [ + `Build tabtests for project in current working directory\n` + + `$ xodc tabtest\n`, + `Specify target directory and project, only generate tests\n` + + `$ xodc tabtest --no-build --output-dir=/tmp/xod-tabtest ./workspace/__lib__/xod/net`, +]; + +TabtestCommand.strict = false; + +export default TabtestCommand;