in extensions/packageManager/src/node/index.ts [285:434]
import: async function (req, res) {
const user = await composer.context.getUserFromRequest(req);
const projectId = req.params.projectId;
const currentProject = await composer.getProjectById(projectId, user);
const runtime = composer.getRuntimeByProject(currentProject);
// get URL or package name
const packageName = req.body.package;
const version = req.body.version;
const source = req.body.source;
const isUpdating = req.body.isUpdating || false;
const isPreview = req.body.isPreview || false;
const mergeErrors: string[] = [];
const captureErrors = (msg: string): void => {
composer.log(msg);
mergeErrors.push(msg);
};
const runtimePath = currentProject.getRuntimePath();
if (packageName && runtimePath) {
try {
// Call the runtime's component install mechanism.
const installOutput = await runtime.installComponent(
runtimePath,
packageName,
version,
source,
currentProject,
isPreview
);
const manifestFile = runtime.identifyManifest(runtimePath, currentProject.name);
// call do a dry run on the dialog merge
const dryrun = new SchemaMerger(
[manifestFile, `!${path.join(currentProject.dir, 'generated')}/**`],
path.join(currentProject.dataDir, 'schemas/sdk'),
path.join(currentProject.dataDir, 'dialogs/imported'),
true, // copy only? true = dry run
false, // verbosity: true = verbose
composer.log,
composer.log,
captureErrors
);
const dryRunMergeResults = await dryrun.merge();
// evaluate dry run.
// Did we have any conflicts that prevent moving forward? if so, install
// Otherwise, copy the files into the project
if (!dryRunMergeResults) {
throw new Error('A problem occured during the install of this Component:\n' + mergeErrors.join('\n'));
}
// check the results to see if we have any problems
if (dryRunMergeResults?.conflicts?.length && !isUpdating) {
// we need to prompt the user to confirm the changes before proceeding
res.json({
success: false,
components: dryRunMergeResults.components.filter(isAdaptiveComponent),
});
} else {
const realMerge = new SchemaMerger(
[manifestFile, `!${path.join(currentProject.dir, 'generated')}/**`],
path.join(currentProject.dataDir, 'schemas/sdk'),
path.join(currentProject.dataDir, 'dialogs/imported'),
false, // copy only? true = dry run
false, // verbosity: true = verbose
composer.log,
composer.log,
composer.log
);
const mergeResults = await realMerge.merge();
composer.log(
'MERGE RESULTS',
path.join(currentProject.dataDir, 'dialogs/imported'),
JSON.stringify(mergeResults, null, 2)
);
const installedComponents = await loadPackageAssets(mergeResults.components.filter(isAdaptiveComponent));
if (mergeResults) {
let runtimeLanguage = 'c#';
if (
currentProject.settings.runtime.key === 'node-azurewebapp' ||
currentProject.settings.runtime.key.startsWith('adaptive-runtime-js')
) {
runtimeLanguage = 'js';
}
// update the settings.components array
const newlyInstalledPlugin = installedComponents.find((c) => hasSchema(c) && c.name == packageName);
if (
newlyInstalledPlugin &&
!currentProject.settings.runtimeSettings?.components?.find((p) => p.name === newlyInstalledPlugin.name)
) {
const newSettings = await currentProject.getEnvSettings();
// guard against missing settings keys
if (!newSettings.runtimeSettings) {
newSettings.runtimeSettings = {
components: [],
};
}
if (!newSettings.runtimeSettings.components) {
newSettings.runtimeSettings.components = [];
}
newSettings.runtimeSettings.components.push({
name: newlyInstalledPlugin.name,
settingsPrefix: newlyInstalledPlugin.name,
});
currentProject.updateEnvSettings(newSettings);
}
updateRecentlyUsed(installedComponents, runtimeLanguage);
res.json({
success: true,
components: installedComponents,
});
} else {
res.json({
success: false,
results: 'Could not merge components',
});
}
}
} catch (err) {
composer.log('Error in import', { message: err.message });
try {
await runtime.uninstallComponent(runtimePath, packageName, currentProject);
} catch (err) {
composer.log('Error uninstalling', err);
}
// if packageName is in the github form <username/package> remove the first part, because otherwise the unisntall doesn't work
if (packageName.match(/.*\/.*/)) {
const [user, realPackageName] = packageName.split(/\//);
if (!user.match(/^@/)) {
await runtime.uninstallComponent(runtimePath, realPackageName, currentProject);
}
}
res.status(500).json({ success: false, message: err.message });
}
} else if (!runtimePath) {
res.status(500).json({ message: 'Please eject your runtime before installing a package.' });
} else {
res.status(500).json({ message: 'Please specify a package name or git url to import.' });
}
},