UNPKG

generator-pyhipster

Version:

Python (Flask) + Angular/React/Vue in one handy generator

283 lines (260 loc) 11.9 kB
/** * Copyright 2013-2022 the original author or authors from the JHipster project. * * This file is part of the JHipster project, see https://www.jhipster.tech/ * for more information. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const chalk = require('chalk'); const { Option } = require('commander'); const didYouMean = require('didyoumean'); const fs = require('fs'); const path = require('path'); const EnvironmentBuilder = require('./environment-builder'); const SUB_GENERATORS = require('./commands'); const JHipsterCommand = require('./jhipster-command'); const PyHipsterCommand = require('./pyhipster-command'); const { CLI_NAME, logger, getCommand, done } = require('./utils'); const { version: PYHIPSTER_VERSION } = require('../package.json'); const { packageNameToNamespace } = require('../generators/utils'); const { logo } = require('../lib/constants/logo.cjs'); const JHIPSTER_NS = CLI_NAME; const PYHIPSTER_NS = CLI_NAME; const moreInfo = `\n For more info visit ${chalk.blue('https://www.jhipster.tech')}\n`; const printPyHipsterLogo = () => { // eslint-disable-next-line no-console console.log(); // eslint-disable-next-line no-console console.log(logo); }; const createProgram = ({ executableName = CLI_NAME, executableVersion } = {}) => { return ( new PyHipsterCommand() .name(executableName) .storeOptionsAsProperties(false) .version(executableVersion ? `${executableVersion} (generator-pyhipster ${PYHIPSTER_VERSION})` : PYHIPSTER_VERSION) .addHelpText('after', moreInfo) // JHipster common options .option( '--blueprints <value>', 'A comma separated list of one or more generator blueprints to use for the sub generators, e.g. --blueprints kotlin,vuejs' ) .option('--force-insight', 'Force insight') .option('--no-insight', 'Disable insight') // Conflicter options .option('--force', 'Override every file', false) .option('--dry-run', 'Print conflicts', false) .option('--whitespace', 'Whitespace changes will not trigger conflicts', false) .option('--bail', 'Fail on first conflict', false) .option('--install-path', 'Show jhipster install path', false) .option('--skip-regenerate', "Don't regenerate identical files", false) .option('--skip-yo-resolve', 'Ignore .yo-resolve files', false) .addOption(new Option('--from-jdl', 'Allow every option jdl forwards').default(false).hideHelp()) .addOption(new Option('--bundled', 'Use JHipster generators bundled with current cli')) .addOption(new Option('--prefer-global', 'Alias for --blundled').hideHelp()) .addOption(new Option('--prefer-local', 'Prefer JHipster generators installed in current folder node repository.').hideHelp()) ); }; const rejectExtraArgs = ({ program, command, extraArgs }) => { // if extraArgs exists: Unknown commands or unknown argument. const first = extraArgs[0]; if (command.name() !== 'app') { logger.fatal( `${chalk.yellow(command.name())} command doesn't take ${chalk.yellow(first)} argument. See '${chalk.white( `${program.name()} ${command.name()} --help` )}'.` ); } const availableCommands = program.commands.map(c => c._name); const suggestion = didYouMean(first, availableCommands); if (suggestion) { logger.info(`Did you mean ${chalk.yellow(suggestion)}?`); } const message = `${chalk.yellow(first)} is not a known command. See '${chalk.white(`${CLI_NAME} --help`)}'.`; logger.fatal(message); }; const buildCommands = ({ program, commands = {}, envBuilder, env, loadCommand, defaultCommand = 'app', printLogo = printPyHipsterLogo, printBlueprintLogo = () => {}, }) => { /* create commands */ Object.entries(commands).forEach(([cmdName, opts]) => { const { desc, blueprint, argument, options: commandOptions, alias, help: commandHelp, cliOnly, useOptions = {} } = opts; program .command(cmdName, '', { isDefault: cmdName === defaultCommand }) .description(desc + (blueprint ? chalk.yellow(` (blueprint: ${blueprint})`) : '')) .addCommandArguments(argument) .addCommandOptions(commandOptions) .addHelpText('after', commandHelp) .addAlias(alias) .excessArgumentsCallback(function (receivedArgs) { rejectExtraArgs({ program, command: this, extraArgs: receivedArgs }); }) .lazyBuildCommand(async function (operands) { logger.debug(`cmd: lazyBuildCommand ${cmdName} ${operands}`); const command = this; if (cmdName === 'run') { command.usage(`${operands} [options]`); operands = Array.isArray(operands) ? operands : [operands]; command.generatorNamespaces = operands.map( namespace => `${namespace.startsWith(PYHIPSTER_NS) ? '' : `${PYHIPSTER_NS}-`}${namespace}` ); envBuilder.lookupGenerators(command.generatorNamespaces.map(namespace => `generator-${namespace.split(':')[0]}`)); await Promise.all( command.generatorNamespaces.map(async namespace => { if (!(await env.getPackagePath(namespace))) { logger.fatal(chalk.red(`\nGenerator ${namespace} not found.\n`)); } const generator = await env.create(namespace, { options: { help: true } }); this.addGeneratorArguments(generator._arguments).addGeneratorOptions(generator._options); }) ); return; } if (!cliOnly || cmdName === 'jdl') { if (blueprint) { // Blueprint only command. const generator = await env.create(`${packageNameToNamespace(blueprint)}:${cmdName}`, { options: { help: true } }); command.addGeneratorArguments(generator._arguments).addGeneratorOptions(generator._options); } else { const generatorName = cmdName === 'jdl' ? 'app' : cmdName; const dependencies = []; // Register jhipster upstream options. if (cmdName !== 'jdl') { const helpOptions = { options: { help: true } }; const generator = await env.create(`${PYHIPSTER_NS}:${cmdName}`, helpOptions); command.addGeneratorArguments(generator._arguments).addGeneratorOptions(generator._options); const addDependenciesOptions = newDependencies => Promise.all( newDependencies.map(async dependency => { if (dependencies.includes(dependency)) return undefined; dependencies.push(dependency); const dependecyGenerator = await env.create(`${PYHIPSTER_NS}:${dependency}`, helpOptions); command.addGeneratorOptions(dependecyGenerator._options); return addDependenciesOptions(await dependecyGenerator.getPossibleDependencies()); }) ); await addDependenciesOptions(await generator.getPossibleDependencies()); const usagePath = path.resolve(generator.sourceRoot(), '../USAGE'); if (fs.existsSync(usagePath)) { command.addHelpText('after', `\n${fs.readFileSync(usagePath, 'utf8')}`); } } if (cmdName === 'jdl' || program.opts().fromJdl) { const appGenerator = await env.create(`${PYHIPSTER_NS}:app`, { options: { help: true } }); command.addGeneratorOptions(appGenerator._options, chalk.gray(' (application)')); const workspacesGenerator = await env.create(`${PYHIPSTER_NS}:workspaces`, { options: { help: true } }); command.addGeneratorOptions(workspacesGenerator._options, chalk.gray(' (workspaces)')); } // Register blueprint specific options. await Promise.all( envBuilder .getBlueprintsNamespaces() .map(blueprintNamespace => [generatorName, ...dependencies].map(async dependency => { const generatorNamespace = `${blueprintNamespace}:${generatorName}`; if (!(await env.get(generatorNamespace))) { return; } const blueprintName = blueprintNamespace.replace(/^jhipster-/, ''); const blueprintGenerator = await env.create(generatorNamespace, { options: { help: true } }); try { command.addGeneratorOptions(blueprintGenerator._options, chalk.yellow(` (blueprint option: ${blueprintName})`)); } catch (error) { logger.info(`Error parsing options for generator ${generatorNamespace}, error: ${error}`); } }) ) .flat() ); } } command.addHelpText('after', moreInfo); }) .action(async (...everything) => { logger.debug('cmd: action'); // [args, opts, command] const command = everything.pop(); const cmdOptions = everything.pop(); const args = everything; const options = { ...program.opts(), ...cmdOptions, ...useOptions, commandName: cmdName, blueprints: envBuilder.getBlueprintsOption(), }; if (options.installPath) { // eslint-disable-next-line no-console console.log(`Using pyhipster at ${path.dirname(__dirname)}`); return undefined; } printLogo(); printBlueprintLogo(); if (cliOnly) { logger.debug('Executing CLI only script'); return loadCommand(cmdName)(args, options, env, envBuilder); } await env.composeWith('pyhipster:bootstrap', options); if (cmdName === 'run') { return Promise.all(command.generatorNamespaces.map(generator => env.run(generator, options))).then( results => done(results.find(result => result)), errors => done(errors.find(error => error)) ); } const namespace = blueprint ? `${packageNameToNamespace(blueprint)}:${cmdName}` : `${PYHIPSTER_NS}:${cmdName}`; const generatorCommand = getCommand(namespace, args, opts); return env.run(generatorCommand, options).then(done, done); }); }); }; const buildPyHipster = ({ executableName, executableVersion, program = createProgram({ executableName, executableVersion }), blueprints, lookups, envBuilder = EnvironmentBuilder.create().prepare({ blueprints, lookups }), commands = { ...SUB_GENERATORS, ...envBuilder.getBlueprintCommands() }, printLogo, printBlueprintLogo, env = envBuilder.getEnvironment(), /* eslint-disable-next-line global-require, import/no-dynamic-require */ loadCommand = key => require(`./${key}`), defaultCommand, } = {}) => { /* setup debugging */ logger.init(program); buildCommands({ program, commands, envBuilder, env, loadCommand, defaultCommand, printLogo, printBlueprintLogo }); return program; }; const runPyHipster = (args = {}) => { const { argv = process.argv } = args; return buildPyHipster(args).parseAsync(argv); }; module.exports = { createProgram, buildCommands, buildPyHipster, runPyHipster, printPyHipsterLogo, done, logger, };