aws-cdk
Version:
AWS CDK CLI, the command line tool for CDK apps
788 lines • 124 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.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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