aws-cdk
Version:
AWS CDK CLI, the command line tool for CDK apps
778 lines • 120 kB
JavaScript
"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.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(`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('Use --template-path to specify which template to use.');
}
}
throw new toolkit_lib_1.ToolkitError('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(`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(`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('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(`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(`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(`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(`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, 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(`Unsupported language: ${language}`);
}
const projectInfo = {
name: 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 cdkVersion = project.versions['aws-cdk-lib'];
const cdkCliVersion = project.versions['aws-cdk'];
let constructsVersion = project.versions.constructs;
switch (language) {
case 'java':
case 'csharp':
case 'fsharp':
constructsVersion = (0, util_1.rangeFromSemver)(constructsVersion, 'bracket');
break;
case 'python':
constructsVersion = (0, util_1.rangeFromSemver)(constructsVersion, 'pep');
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, 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, 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(`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('`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(`Directory does not exist: ${workDir}\n` +
'Please create the directory first using: mkdir -p ' + workDir);
}
throw new toolkit_lib_1.ToolkitError(`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 dotnetWarning = "Please run '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 });
await ioHelper.defaults.info(`Executing ${chalk.green('dotnet build')}...`);
await execute(ioHelper, 'dotnet', ['build'], { cwd });
}
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(`${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(`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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImluaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBMkZBLDBCQXNDQztBQXdiRCxnREFvQ0M7QUFVRCx3REFpQkM7QUFFRCx3REFXQztBQXVCRCwwREFjQztBQTZURCxnRkFHQztBQTErQkQsOENBQThDO0FBQzlDLDZCQUE2QjtBQUM3QixzREFBb0Q7QUFDcEQsK0JBQStCO0FBQy9CLCtCQUErQjtBQUMvQiw2Q0FBa0Q7QUFFbEQsaURBQWdEO0FBQ2hELCtDQUFrRDtBQUNsRCxxQ0FBNkU7QUFFN0UsMENBQTJGO0FBQzNGLHVEQUEwRTtBQUUxRSx1REFBdUQsQ0FBQyxvQ0FBb0M7QUFDNUYsaUVBQWlFO0FBQ2pFLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUN2QyxpRUFBaUU7QUFDakUsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBRXpDLE1BQU0sd0JBQXdCLEdBQUcsOEJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBZSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7QUFvRXRGOztHQUVHO0FBQ0ksS0FBSyxVQUFVLE9BQU8sQ0FBQyxPQUF1QjtJQUNuRCxNQUFNLHlCQUF5QixDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFM0QsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztJQUNsQyxNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQztJQUNwRCxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsWUFBWSxJQUFJLEtBQUssQ0FBQztJQUNuRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUVqRCwyRUFBMkU7SUFDM0UsSUFBSSxDQUFDLE9BQU8sQ0FBQyxR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