UNPKG

aws-cdk

Version:

AWS CDK CLI, the command line tool for CDK apps

788 lines 124 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InitTemplate = void 0; exports.cliInit = cliInit; exports.expandPlaceholders = expandPlaceholders; exports.availableInitTemplates = availableInitTemplates; exports.availableInitLanguages = availableInitLanguages; exports.printAvailableTemplates = printAvailableTemplates; exports.currentlyRecommendedAwsCdkLibFlags = currentlyRecommendedAwsCdkLibFlags; const childProcess = require("child_process"); const path = require("path"); const toolkit_lib_1 = require("@aws-cdk/toolkit-lib"); const chalk = require("chalk"); const fs = require("fs-extra"); const init_hooks_1 = require("./init-hooks"); const root_dir_1 = require("../../cli/root-dir"); const version_1 = require("../../cli/version"); const util_1 = require("../../util"); const language_1 = require("../language"); const package_manager_1 = require("./package-manager"); /* eslint-disable @typescript-eslint/no-var-requires */ // Packages don't have @types module // eslint-disable-next-line @typescript-eslint/no-require-imports const camelCase = require('camelcase'); // eslint-disable-next-line @typescript-eslint/no-require-imports const decamelize = require('decamelize'); const SUPPORTED_LANGUAGE_NAMES = language_1.SUPPORTED_LANGUAGES.map((l) => l.name); /** * Initialize a CDK package in the current directory */ async function cliInit(options) { await ensureValidCliInitOptions(options, options.ioHelper); const ioHelper = options.ioHelper; const canUseNetwork = options.canUseNetwork ?? true; const generateOnly = options.generateOnly ?? false; const workDir = options.workDir ?? process.cwd(); // Show available templates only if no fromPath, type, or language provided if (!options.fromPath && !options.type && !options.language) { await printAvailableTemplates(ioHelper); return; } // Step 1: Load template let template; if (options.fromPath) { template = await loadLocalTemplate(options.fromPath, options.templatePath); } else { template = await loadBuiltinTemplate(ioHelper, options.type, options.language); } // Step 2: Resolve language const language = await resolveLanguage(ioHelper, template, options.language, options.type); // Step 3: Initialize project following standard process await initializeProject(ioHelper, template, language, canUseNetwork, generateOnly, workDir, options.projectName, options.stackName, options.migrate, options.libVersion, options.packageManager); } /** * Validate CLI init options and handle invalid or incompatible option combinations */ async function ensureValidCliInitOptions(options, ioHelper) { if (options.packageManager && !['javascript', 'typescript'].includes(options.language ?? '')) { await ioHelper.defaults.warn(`--package-manager option is only applicable for JavaScript and TypeScript projects. Ignoring the provided value: ${options.packageManager}`); } } /** * Load a local custom template from file system path * @param fromPath - Path to the local template directory or multi-template repository * @param templatePath - Optional path to a specific template within a multi-template repository * @returns Promise resolving to the loaded InitTemplate */ async function loadLocalTemplate(fromPath, templatePath) { try { let actualTemplatePath = fromPath; // If templatePath is provided, it's a multi-template repository if (templatePath) { actualTemplatePath = path.join(fromPath, templatePath); if (!await fs.pathExists(actualTemplatePath)) { throw new toolkit_lib_1.ToolkitError('TemplatePathNotFound', `Template path does not exist: ${actualTemplatePath}`); } } const template = await InitTemplate.fromPath(actualTemplatePath); if (template.languages.length === 0) { // Check if this might be a multi-template repository if (!templatePath) { const availableTemplates = await findPotentialTemplates(fromPath); if (availableTemplates.length > 0) { throw new toolkit_lib_1.ToolkitError('TemplatePathRequired', 'Use --template-path to specify which template to use.'); } } throw new toolkit_lib_1.ToolkitError('NoLanguageDirectory', 'Custom template must contain at least one language directory'); } return template; } catch (error) { const displayPath = templatePath ? `${fromPath}/${templatePath}` : fromPath; throw new toolkit_lib_1.ToolkitError('TemplateLoadFailed', `Failed to load template from path: ${displayPath}. ${error.message}`); } } /** * Load a built-in template by name */ async function loadBuiltinTemplate(ioHelper, type, language) { const templateType = type || 'default'; // "default" is the default type (and maps to "app") const template = (await availableInitTemplates()).find((t) => t.hasName(templateType)); if (!template) { await printAvailableTemplates(ioHelper, language); throw new toolkit_lib_1.ToolkitError('UnknownTemplate', `Unknown init template: ${templateType}`); } return template; } /** * Resolve the programming language for the template * @param ioHelper - IO helper for user interaction * @param template - The template to resolve language for * @param requestedLanguage - User-requested language (optional) * @param type - The template type name for messages * @default undefined * @returns Promise resolving to the selected language */ async function resolveLanguage(ioHelper, template, requestedLanguage, type) { return (async () => { if (requestedLanguage) { return requestedLanguage; } if (template.languages.length === 1) { const templateLanguage = template.languages[0]; // Only show auto-detection message for built-in templates if (template.templateType !== TemplateType.CUSTOM) { await ioHelper.defaults.warn(`No --language was provided, but '${type || template.name}' supports only '${templateLanguage}', so defaulting to --language=${templateLanguage}`); } return templateLanguage; } await ioHelper.defaults.info(`Available languages for ${chalk.green(type || template.name)}: ${template.languages.map((l) => chalk.blue(l)).join(', ')}`); throw new toolkit_lib_1.ToolkitError('NoLanguageSelected', 'No language was selected'); })(); } /** * Find potential template directories in a multi-template repository * @param repositoryPath - Path to the repository root * @returns Promise resolving to array of potential template directory names */ async function findPotentialTemplates(repositoryPath) { const entries = await fs.readdir(repositoryPath, { withFileTypes: true }); const templateValidationPromises = entries .filter(entry => entry.isDirectory() && !entry.name.startsWith('.')) .map(async (entry) => { try { const templatePath = path.join(repositoryPath, entry.name); const { languages } = await getLanguageDirectories(templatePath); return languages.length > 0 ? entry.name : null; } catch (error) { // If we can't read a specific template directory, skip it but don't fail the entire operation return null; } }); /* eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism */ // Limited to directory entries const validationResults = await Promise.all(templateValidationPromises); return validationResults.filter((templateName) => templateName !== null); } /** * Get valid CDK language directories from a template path * @param templatePath - Path to the template directory * @returns Promise resolving to array of supported language names */ /** * Get valid CDK language directories from a template path * @param templatePath - Path to the template directory * @returns Promise resolving to array of supported language names and directory entries * @throws ToolkitError if directory cannot be read or validated */ async function getLanguageDirectories(templatePath) { try { const entries = await fs.readdir(templatePath, { withFileTypes: true }); const languageValidationPromises = entries .filter(directoryEntry => directoryEntry.isDirectory() && SUPPORTED_LANGUAGE_NAMES.includes(directoryEntry.name)) .map(async (directoryEntry) => { const languageDirectoryPath = path.join(templatePath, directoryEntry.name); try { const hasValidLanguageFiles = await hasLanguageFiles(languageDirectoryPath, (0, language_1.getLanguageExtensions)(directoryEntry.name)); return hasValidLanguageFiles ? directoryEntry.name : null; } catch (error) { throw new toolkit_lib_1.ToolkitError('LanguageDirectoryReadFailed', `Cannot read language directory '${directoryEntry.name}': ${error.message}`); } }); /* eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism */ // Limited to supported CDK languages (7 max) const validationResults = await Promise.all(languageValidationPromises); return { languages: validationResults.filter((languageName) => languageName !== null), entries, }; } catch (error) { throw new toolkit_lib_1.ToolkitError('TemplateDirectoryReadFailed', `Cannot read template directory '${templatePath}': ${error.message}`); } } /** * Iteratively check if a directory contains files with the specified extensions * @param directoryPath - Path to search for language files * @param extensions - Array of file extensions to look for * @returns Promise resolving to true if language files are found */ async function hasLanguageFiles(directoryPath, extensions) { const dirsToCheck = [directoryPath]; while (dirsToCheck.length > 0) { const currentDir = dirsToCheck.pop(); try { const entries = await fs.readdir(currentDir, { withFileTypes: true }); for (const entry of entries) { if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) { return true; } else if (entry.isDirectory()) { dirsToCheck.push(path.join(currentDir, entry.name)); } } } catch (error) { throw error; } } return false; } /** * Returns the name of the Python executable for this OS * @returns The Python executable name for the current platform */ function pythonExecutable() { let python = 'python3'; if (process.platform === 'win32') { python = 'python'; } return python; } const INFO_DOT_JSON = 'info.json'; var TemplateType; (function (TemplateType) { TemplateType["BUILT_IN"] = "builtin"; TemplateType["CUSTOM"] = "custom"; })(TemplateType || (TemplateType = {})); class InitTemplate { static async fromName(templatesDir, name) { const basePath = path.join(templatesDir, name); const languages = await listDirectory(basePath); const initInfo = await fs.readJson(path.join(basePath, INFO_DOT_JSON)); return new InitTemplate(basePath, name, languages, initInfo, TemplateType.BUILT_IN); } static async fromPath(templatePath) { const basePath = path.resolve(templatePath); if (!await fs.pathExists(basePath)) { throw new toolkit_lib_1.ToolkitError('TemplatePathNotFound', `Template path does not exist: ${basePath}`); } let templateSourcePath = basePath; let { languages, entries } = await getLanguageDirectories(basePath); if (languages.length === 0) { const languageDirs = entries.filter(entry => entry.isDirectory() && SUPPORTED_LANGUAGE_NAMES.includes(entry.name)); if (languageDirs.length === 1) { // Validate that the language directory contains appropriate files const langDir = languageDirs[0].name; templateSourcePath = path.join(basePath, langDir); const hasValidFiles = await hasLanguageFiles(templateSourcePath, (0, language_1.getLanguageExtensions)(langDir)); if (!hasValidFiles) { // If we found a language directory but it doesn't contain valid files, we should inform the user throw new toolkit_lib_1.ToolkitError('InvalidLanguageFiles', `Found '${langDir}' directory but it doesn't contain the expected language files. Ensure the template contains ${langDir} source files.`); } } } const name = path.basename(basePath); return new InitTemplate(templateSourcePath, name, languages, null, TemplateType.CUSTOM); } constructor(basePath, name, languages, initInfo, templateType) { this.basePath = basePath; this.name = name; this.languages = languages; this.aliases = new Set(); this.templateType = templateType; // Only built-in templates have descriptions and aliases from info.json if (templateType === TemplateType.BUILT_IN && initInfo) { this.description = initInfo.description; for (const alias of initInfo.aliases || []) { this.aliases.add(alias); } } } /** * @param name - the name that is being checked * @returns ``true`` if ``name`` is the name of this template or an alias of it. */ hasName(name) { return name === this.name || this.aliases.has(name); } /** * Creates a new instance of this ``InitTemplate`` for a given language to a specified folder. * * @param language - the language to instantiate this template with * @param targetDirectory - the directory where the template is to be instantiated into * @param stackName - the name of the stack to create * @default undefined * @param libVersion - the version of the CDK library to use * @default undefined */ async install(ioHelper, language, targetDirectory, projectName, stackName, libVersion, packageManager) { if (this.languages.indexOf(language) === -1) { await ioHelper.defaults.error(`The ${chalk.blue(language)} language is not supported for ${chalk.green(this.name)} ` + `(it supports: ${this.languages.map((l) => chalk.blue(l)).join(', ')})`); throw new toolkit_lib_1.ToolkitError('UnsupportedLanguage', `Unsupported language: ${language}`); } const projectInfo = { name: projectName ? decamelize(projectName) : decamelize(path.basename(path.resolve(targetDirectory))), stackName, versions: await loadInitVersions(), }; if (libVersion) { projectInfo.versions['aws-cdk-lib'] = libVersion; } let sourceDirectory = path.join(this.basePath, language); // For auto-detected single language templates, use basePath directly if (this.templateType === TemplateType.CUSTOM && this.languages.length === 1 && path.basename(this.basePath) === language) { sourceDirectory = this.basePath; } if (this.templateType === TemplateType.CUSTOM) { // For custom templates, copy files without processing placeholders await this.installFilesWithoutProcessing(sourceDirectory, targetDirectory); } else { // For built-in templates, process placeholders as usual await this.installFiles(sourceDirectory, targetDirectory, language, projectInfo, packageManager); await this.applyFutureFlags(targetDirectory); await (0, init_hooks_1.invokeBuiltinHooks)(ioHelper, { targetDirectory, language, templateName: this.name }, { substitutePlaceholdersIn: async (...fileNames) => { const fileProcessingPromises = fileNames.map(async (fileName) => { const fullPath = path.join(targetDirectory, fileName); const template = await fs.readFile(fullPath, { encoding: 'utf-8' }); await fs.writeFile(fullPath, expandPlaceholders(template, language, projectInfo, packageManager)); }); /* eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism */ // Processing a small, known set of template files await Promise.all(fileProcessingPromises); }, placeholder: (ph) => expandPlaceholders(`%${ph}%`, language, projectInfo, packageManager), }); } } async installFiles(sourceDirectory, targetDirectory, language, project, packageManager) { for (const file of await fs.readdir(sourceDirectory)) { const fromFile = path.join(sourceDirectory, file); const toFile = path.join(targetDirectory, expandPlaceholders(file, language, project, packageManager)); if ((await fs.stat(fromFile)).isDirectory()) { await fs.mkdir(toFile); await this.installFiles(fromFile, toFile, language, project, packageManager); continue; } else if (file.match(/^.*\.template\.[^.]+$/)) { await this.installProcessed(fromFile, toFile.replace(/\.template(\.[^.]+)$/, '$1'), language, project, packageManager); continue; } else if (file.match(/^.*\.hook\.(d.)?[^.]+$/)) { // Ignore continue; } else { await fs.copy(fromFile, toFile); } } } async installProcessed(templatePath, toFile, language, project, packageManager) { const template = await fs.readFile(templatePath, { encoding: 'utf-8' }); await fs.writeFile(toFile, expandPlaceholders(template, language, project, packageManager)); } /** * Copy template files without processing placeholders (for custom templates) */ async installFilesWithoutProcessing(sourceDirectory, targetDirectory) { await fs.copy(sourceDirectory, targetDirectory, { filter: (src) => { const filename = path.basename(src); return !filename.match(/^.*\.hook\.(d.)?[^.]+$/); }, }); } /** * Adds context variables to `cdk.json` in the generated project directory to * enable future behavior for new projects. */ async applyFutureFlags(projectDir) { const cdkJson = path.join(projectDir, 'cdk.json'); if (!(await fs.pathExists(cdkJson))) { return; } const config = await fs.readJson(cdkJson); config.context = { ...config.context, ...await currentlyRecommendedAwsCdkLibFlags(), }; await fs.writeJson(cdkJson, config, { spaces: 2 }); } async addMigrateContext(projectDir) { const cdkJson = path.join(projectDir, 'cdk.json'); if (!(await fs.pathExists(cdkJson))) { return; } const config = await fs.readJson(cdkJson); config.context = { ...config.context, 'cdk-migrate': true, }; await fs.writeJson(cdkJson, config, { spaces: 2 }); } } exports.InitTemplate = InitTemplate; function expandPlaceholders(template, language, project, packageManager) { const cdkCliVersion = project.versions['aws-cdk']; let cdkVersion = project.versions['aws-cdk-lib']; let constructsVersion = project.versions.constructs; switch (language) { case 'java': cdkVersion = (0, util_1.rangeFromSemver)(cdkVersion, 'bracket'); constructsVersion = (0, util_1.rangeFromSemver)(constructsVersion, 'bracket'); break; case 'csharp': case 'fsharp': cdkVersion = (0, util_1.rangeFromSemver)(cdkVersion, 'bracket'); // ^2.123.0 => [2.123.0,3.0.0) constructsVersion = (0, util_1.rangeFromSemver)(constructsVersion, 'major.*'); // ^10.0.0 => 10.*/ break; case 'python': cdkVersion = (0, util_1.rangeFromSemver)(cdkVersion, 'pep'); constructsVersion = (0, util_1.rangeFromSemver)(constructsVersion, 'pep'); break; case 'go': cdkVersion = (0, util_1.stripCaret)(cdkVersion); constructsVersion = (0, util_1.stripCaret)(constructsVersion); break; } return template .replace(/%name%/g, project.name) .replace(/%stackname%/, project.stackName ?? '%name.PascalCased%Stack') .replace(/%PascalNameSpace%/, project.stackName ? camelCase(project.stackName + 'Stack', { pascalCase: true }) : '%name.PascalCased%') .replace(/%PascalStackProps%/, project.stackName ? camelCase(project.stackName, { pascalCase: true }) + 'StackProps' : 'StackProps') .replace(/%name\.camelCased%/g, camelCase(project.name)) .replace(/%name\.PascalCased%/g, camelCase(project.name, { pascalCase: true })) .replace(/%cdk-version%/g, cdkVersion) .replace(/%cdk-cli-version%/g, cdkCliVersion) .replace(/%constructs-version%/g, constructsVersion) .replace(/%cdk-home%/g, (0, util_1.cdkHomeDir)()) .replace(/%name\.PythonModule%/g, project.name.replace(/-/g, '_')) .replace(/%python-executable%/g, pythonExecutable()) .replace(/%name\.StackName%/g, project.name.replace(/[^A-Za-z0-9-]/g, '-')) .replace(/%pm-cmd%/g, (0, package_manager_1.getPmCmdPrefix)(packageManager ?? 'npm')); } async function availableInitTemplates() { try { const templatesDir = path.join((0, root_dir_1.cliRootDir)(), 'lib', 'init-templates'); const templateNames = await listDirectory(templatesDir); const templatePromises = templateNames.map(templateName => InitTemplate.fromName(templatesDir, templateName)); /* eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism */ // Built-in templates are limited in number return await Promise.all(templatePromises); } catch (error) { // Return empty array if templates directory doesn't exist or can't be read // This allows the CLI to gracefully handle missing built-in templates if (error.code === 'ENOENT' || error.code === 'EACCES') { return []; } throw error; } } async function availableInitLanguages() { const templates = await availableInitTemplates(); const result = new Set(); for (const template of templates) { for (const language of template.languages) { const alias = (0, language_1.getLanguageAlias)(language); result.add(language); alias && result.add(alias); } } return [...result]; } /** * @param dirPath - is the directory to be listed. * @returns the list of file or directory names contained in ``dirPath``, excluding any dot-file, and sorted. */ async function listDirectory(dirPath) { return ((await fs.readdir(dirPath)) .filter((p) => !p.startsWith('.')) .filter((p) => !(p === 'LICENSE')) // if, for some reason, the temp folder for the hook doesn't get deleted we don't want to display it in this list .filter((p) => !(p === INFO_DOT_JSON)) .sort()); } /** * Print available templates to the user * @param ioHelper - IO helper for user interaction * @param language - Programming language filter * @default undefined */ async function printAvailableTemplates(ioHelper, language) { await ioHelper.defaults.info('Available templates:'); for (const template of await availableInitTemplates()) { if (language && template.languages.indexOf(language) === -1) { continue; } await ioHelper.defaults.info(`* ${chalk.green(template.name)}: ${template.description}`); const languageArg = language ? chalk.bold(language) : template.languages.length > 1 ? `[${template.languages.map((t) => chalk.bold(t)).join('|')}]` : chalk.bold(template.languages[0]); await ioHelper.defaults.info(` └─ ${chalk.blue(`cdk init ${chalk.bold(template.name)} --language=${languageArg}`)}`); } } async function initializeProject(ioHelper, template, language, canUseNetwork, generateOnly, workDir, projectName, stackName, migrate, cdkVersion, packageManager) { // Step 1: Ensure target directory is empty await assertIsEmptyDirectory(workDir); // Step 2: Copy template files await ioHelper.defaults.info(`Applying project template ${chalk.green(template.name)} for ${chalk.blue(language)}`); await template.install(ioHelper, language, workDir, projectName, stackName, cdkVersion, packageManager); if (migrate) { await template.addMigrateContext(workDir); } if (await fs.pathExists(`${workDir}/README.md`)) { const readme = await fs.readFile(`${workDir}/README.md`, { encoding: 'utf-8' }); await ioHelper.defaults.info(chalk.green(readme)); } if (!generateOnly) { // Step 3: Initialize Git repository and create initial commit await initializeGitRepository(ioHelper, workDir); // Step 4: Post-install steps await postInstall(ioHelper, language, canUseNetwork, workDir, packageManager); } await ioHelper.defaults.info('✅ All done!'); } /** * Validate that a directory exists and is empty (ignoring hidden files) * @param workDir - Directory path to validate * @throws ToolkitError if directory doesn't exist or is not empty */ async function assertIsEmptyDirectory(workDir) { try { const stats = await fs.stat(workDir); if (!stats.isDirectory()) { throw new toolkit_lib_1.ToolkitError('PathNotDirectory', `Path exists but is not a directory: ${workDir}`); } const files = await fs.readdir(workDir); const visibleFiles = files.filter(f => !f.startsWith('.')); if (visibleFiles.length > 0) { throw new toolkit_lib_1.ToolkitError('DirectoryNotEmpty', '`cdk init` cannot be run in a non-empty directory!\n' + `Found ${visibleFiles.length} visible files in ${workDir}:\n` + visibleFiles.map(f => ` - ${f}`).join('\n')); } } catch (e) { if (e.code === 'ENOENT') { throw new toolkit_lib_1.ToolkitError('DirectoryNotFound', `Directory does not exist: ${workDir}\n` + 'Please create the directory first using: mkdir -p ' + workDir); } throw new toolkit_lib_1.ToolkitError('DirectoryValidationFailed', `Failed to validate directory ${workDir}: ${e.message}`); } } async function initializeGitRepository(ioHelper, workDir) { if (await isInGitRepository(workDir)) { return; } await ioHelper.defaults.info('Initializing a new git repository...'); try { await execute(ioHelper, 'git', ['init'], { cwd: workDir }); await execute(ioHelper, 'git', ['add', '.'], { cwd: workDir }); await execute(ioHelper, 'git', ['commit', '--message="Initial commit"', '--no-gpg-sign'], { cwd: workDir }); } catch { await ioHelper.defaults.warn('Unable to initialize git repository for your project.'); } } async function postInstall(ioHelper, language, canUseNetwork, workDir, packageManager) { switch (language) { case 'javascript': return postInstallJavascript(ioHelper, canUseNetwork, workDir, packageManager); case 'typescript': return postInstallTypescript(ioHelper, canUseNetwork, workDir, packageManager); case 'java': return postInstallJava(ioHelper, canUseNetwork, workDir); case 'python': return postInstallPython(ioHelper, workDir); case 'go': return postInstallGo(ioHelper, canUseNetwork, workDir); case 'csharp': return postInstallCSharp(ioHelper, canUseNetwork, workDir); case 'fsharp': return postInstallFSharp(ioHelper, canUseNetwork, workDir); } } async function postInstallJavascript(ioHelper, canUseNetwork, cwd, packageManager) { return postInstallTypescript(ioHelper, canUseNetwork, cwd, packageManager); } async function postInstallTypescript(ioHelper, canUseNetwork, cwd, packageManager) { const command = packageManager ?? 'npm'; if (!canUseNetwork) { await ioHelper.defaults.warn(`Please run '${command} install'!`); return; } await ioHelper.defaults.info(`Executing ${chalk.green(`${command} install`)}...`); try { await execute(ioHelper, command, ['install'], { cwd }); } catch (e) { await ioHelper.defaults.warn(`${command} install failed: ` + (0, util_1.formatErrorMessage)(e)); } } async function postInstallJava(ioHelper, canUseNetwork, cwd) { // Check if this is a Gradle or Maven project const hasGradleBuild = await fs.pathExists(path.join(cwd, 'build.gradle')); const hasMavenPom = await fs.pathExists(path.join(cwd, 'pom.xml')); if (hasGradleBuild) { // Gradle project const gradleWarning = "Please run './gradlew build'!"; if (!canUseNetwork) { await ioHelper.defaults.warn(gradleWarning); return; } await ioHelper.defaults.info("Executing './gradlew build'"); try { await execute(ioHelper, './gradlew', ['build'], { cwd }); } catch { await ioHelper.defaults.warn('Unable to build Gradle project'); await ioHelper.defaults.warn(gradleWarning); } } else if (hasMavenPom) { // Maven project const mvnPackageWarning = "Please run 'mvn package'!"; if (!canUseNetwork) { await ioHelper.defaults.warn(mvnPackageWarning); return; } await ioHelper.defaults.info("Executing 'mvn package'"); try { await execute(ioHelper, 'mvn', ['package'], { cwd }); } catch { await ioHelper.defaults.warn('Unable to package compiled code as JAR'); await ioHelper.defaults.warn(mvnPackageWarning); } } else { // No recognized build file await ioHelper.defaults.warn('No build.gradle or pom.xml found. Please set up your build system manually.'); } } async function postInstallPython(ioHelper, cwd) { const python = pythonExecutable(); // Check if requirements.txt exists const hasRequirements = await fs.pathExists(path.join(cwd, 'requirements.txt')); if (hasRequirements) { await ioHelper.defaults.info(`Executing ${chalk.green('Creating virtualenv...')}`); try { await execute(ioHelper, python, ['-m', 'venv', '.venv'], { cwd }); await ioHelper.defaults.info(`Executing ${chalk.green('Installing dependencies...')}`); // Install dependencies in the virtual environment const pipPath = process.platform === 'win32' ? '.venv\\Scripts\\pip' : '.venv/bin/pip'; await execute(ioHelper, pipPath, ['install', '-r', 'requirements.txt'], { cwd }); } catch { await ioHelper.defaults.warn('Unable to create virtualenv or install dependencies automatically'); await ioHelper.defaults.warn(`Please run '${python} -m venv .venv && .venv/bin/pip install -r requirements.txt'!`); } } else { await ioHelper.defaults.warn('No requirements.txt found. Please set up your Python environment manually.'); } } async function postInstallGo(ioHelper, canUseNetwork, cwd) { if (!canUseNetwork) { await ioHelper.defaults.warn('Please run \'go mod tidy\'!'); return; } await ioHelper.defaults.info(`Executing ${chalk.green('go mod tidy')}...`); try { await execute(ioHelper, 'go', ['mod', 'tidy'], { cwd }); } catch (e) { await ioHelper.defaults.warn('\'go mod tidy\' failed: ' + (0, util_1.formatErrorMessage)(e)); } } async function postInstallCSharp(ioHelper, canUseNetwork, cwd) { const solutionDir = path.join(cwd, 'src'); // the dotnet solution is inside the src dir const dotnetWarning = "Please run 'cd src && dotnet restore && dotnet build'!"; if (!canUseNetwork) { await ioHelper.defaults.warn(dotnetWarning); return; } await ioHelper.defaults.info(`Executing ${chalk.green('dotnet restore')}...`); try { await execute(ioHelper, 'dotnet', ['restore'], { cwd: solutionDir }); await ioHelper.defaults.info(`Executing ${chalk.green('dotnet build')}...`); await execute(ioHelper, 'dotnet', ['build'], { cwd: solutionDir }); } catch (e) { await ioHelper.defaults.warn('Unable to restore/build .NET project: ' + (0, util_1.formatErrorMessage)(e)); await ioHelper.defaults.warn(dotnetWarning); } } async function postInstallFSharp(ioHelper, canUseNetwork, cwd) { // F# uses the same build system as C# return postInstallCSharp(ioHelper, canUseNetwork, cwd); } /** * @param dir - a directory to be checked * @returns true if ``dir`` is within a git repository. */ async function isInGitRepository(dir) { while (true) { if (await fs.pathExists(path.join(dir, '.git'))) { return true; } if (isRoot(dir)) { return false; } dir = path.dirname(dir); } } /** * @param dir - a directory to be checked. * @returns true if ``dir`` is the root of a filesystem. */ function isRoot(dir) { return path.dirname(dir) === dir; } /** * Executes `command`. STDERR is emitted in real-time. * * If command exits with non-zero exit code, an exception is thrown and includes * the contents of STDOUT. * * @returns STDOUT (if successful). */ async function execute(ioHelper, cmd, args, { cwd }) { const child = childProcess.spawn(cmd, args, { cwd, shell: true, stdio: ['ignore', 'pipe', 'inherit'], }); let stdout = ''; child.stdout.on('data', (chunk) => (stdout += chunk.toString())); return new Promise((ok, fail) => { child.once('error', (err) => fail(err)); child.once('exit', (status) => { if (status === 0) { return ok(stdout); } else { return fail(new toolkit_lib_1.ToolkitError('CommandFailed', `${cmd} exited with status ${status}`)); } }); }).catch(async (err) => { await ioHelper.defaults.error(stdout); throw err; }); } /** * Return the 'aws-cdk-lib' version we will init * * This has been built into the CLI at build time. */ async function loadInitVersions() { const initVersionFile = path.join((0, root_dir_1.cliRootDir)(), 'lib', 'init-templates', '.init-version.json'); const contents = JSON.parse(await fs.readFile(initVersionFile, { encoding: 'utf-8' })); const ret = { 'aws-cdk-lib': contents['aws-cdk-lib'], 'constructs': contents.constructs, 'aws-cdk': (0, version_1.versionNumber)(), }; for (const [key, value] of Object.entries(ret)) { if (!value) { throw new toolkit_lib_1.ToolkitError('MissingInitVersion', `Missing init version from ${initVersionFile}: ${key}`); } } return ret; } /** * Return the currently recommended flags for `aws-cdk-lib`. * * These have been built into the CLI at build time. */ async function currentlyRecommendedAwsCdkLibFlags() { const recommendedFlagsFile = path.join((0, root_dir_1.cliRootDir)(), 'lib', 'init-templates', '.recommended-feature-flags.json'); return JSON.parse(await fs.readFile(recommendedFlagsFile, { encoding: 'utf-8' })); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImluaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBZ0dBLDBCQXVDQztBQTBiRCxnREE2Q0M7QUFVRCx3REFpQkM7QUFFRCx3REFXQztBQXVCRCwwREFjQztBQWlVRCxnRkFHQztBQS8vQkQsOENBQThDO0FBQzlDLDZCQUE2QjtBQUM3QixzREFBb0Q7QUFDcEQsK0JBQStCO0FBQy9CLCtCQUErQjtBQUMvQiw2Q0FBa0Q7QUFFbEQsaURBQWdEO0FBQ2hELCtDQUFrRDtBQUNsRCxxQ0FBeUY7QUFFekYsMENBQTJGO0FBQzNGLHVEQUEwRTtBQUUxRSx1REFBdUQsQ0FBQyxvQ0FBb0M7QUFDNUYsaUVBQWlFO0FBQ2pFLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUN2QyxpRUFBaUU7QUFDakUsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBRXpDLE1BQU0sd0JBQXdCLEdBQUcsOEJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBZSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7QUF5RXRGOztHQUVHO0FBQ0ksS0FBSyxVQUFVLE9BQU8sQ0FBQyxPQUF1QjtJQUNuRCxNQUFNLHlCQUF5QixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFM0QsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztJQUNsQyxNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQztJQUNwRCxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsWUFBWSxJQUFJLEtBQUssQ0FBQztJQUNuRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUVqRCwyRUFBMkU7SUFDM0UsSUFBSSxDQUFDLE9BQU8sQ0FBQyxR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