@nomiclabs/buidler
Version:
Buidler is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
152 lines • 6.54 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const debug_1 = __importDefault(require("debug"));
const path = __importStar(require("path"));
const semver = __importStar(require("semver"));
const errors_1 = require("./errors");
const errors_list_1 = require("./errors-list");
const execution_mode_1 = require("./execution-mode");
const log = debug_1.default("buidler:core:plugins");
/**
* Validates a plugin dependencies and loads it.
* @param pluginName - The plugin name
* @param buidlerContext - The BuidlerContext
* @param from - Where to resolve plugins and dependencies from. Only for
* testing purposes.
*/
function usePlugin(buidlerContext, pluginName, from) {
log("Loading plugin %s", pluginName);
const executionMode = execution_mode_1.getExecutionMode();
if (from === undefined) {
// We have two different ways to search for plugins.
//
// If Buidler is installed globally, we want to force the plugins to also be
// installed globally, otherwise we can end up in a very chaotic situation.
// The way we enforce this is by setting `from` to something inside Buidler
// itself, as it will be placed in the global node_modules.
//
// If Buidler is not installed globally, we want the plugins to be
// accessible from the project's root, not from the Buidler installation.
// The reason for this is that yarn workspaces can easily hoist Buidler and
// not the plugins, leaving you with something like this:
//
// root/
// node_modules/
// buidler
// subpackage1/
// node_modules/
// plugin@v1/
// buidler.config.js
// subpackage2/
// node_modules/
// plugin@v2/
// buidler.config.js
//
// If we were to load the plugins from the Buidler installation in this
// situation, they wouldn't be found. Instead, we should load them from the
// project's root.
//
// To make things slightly more complicated, we don't really know the
// project's root, as we are still loading the config. What we do know
// though, is the config file's path, which must be inside the project, so
// we use that instead.
if (executionMode === execution_mode_1.ExecutionMode.EXECUTION_MODE_GLOBAL_INSTALLATION) {
from = __dirname;
}
else {
from = buidlerContext.getConfigPath();
}
}
let globalFlag = "";
let globalWarning = "";
if (executionMode === execution_mode_1.ExecutionMode.EXECUTION_MODE_GLOBAL_INSTALLATION) {
globalFlag = " --global";
globalWarning =
"You are using a global installation of Buidler. Plugins and their dependencies must also be global.\n";
}
const pluginPackageJson = readPackageJson(pluginName, from);
if (pluginPackageJson === undefined) {
const installExtraFlags = globalFlag;
throw new errors_1.BuidlerError(errors_list_1.ERRORS.PLUGINS.NOT_INSTALLED, {
plugin: pluginName,
extraMessage: globalWarning,
extraFlags: installExtraFlags,
});
}
// We use the package.json's version of the name, as it is normalized.
pluginName = pluginPackageJson.name;
if (buidlerContext.loadedPlugins.includes(pluginName)) {
return;
}
if (pluginPackageJson.peerDependencies !== undefined) {
for (const [dependencyName, versionSpec] of Object.entries(pluginPackageJson.peerDependencies)) {
const dependencyPackageJson = readPackageJson(dependencyName, from);
let installExtraFlags = globalFlag;
if (versionSpec.match(/^[0-9]/) !== null) {
installExtraFlags += " --save-exact";
}
if (dependencyPackageJson === undefined) {
throw new errors_1.BuidlerError(errors_list_1.ERRORS.PLUGINS.MISSING_DEPENDENCY, {
plugin: pluginName,
dependency: dependencyName,
extraMessage: globalWarning,
extraFlags: installExtraFlags,
versionSpec,
});
}
const installedVersion = dependencyPackageJson.version;
if (!semver.satisfies(installedVersion, versionSpec, {
includePrerelease: true,
})) {
throw new errors_1.BuidlerError(errors_list_1.ERRORS.PLUGINS.DEPENDENCY_VERSION_MISMATCH, {
plugin: pluginName,
dependency: dependencyName,
extraMessage: globalWarning,
extraFlags: installExtraFlags,
versionSpec,
installedVersion,
});
}
}
}
const options = from !== undefined ? { paths: [from] } : undefined;
const pluginPath = require.resolve(pluginName, options);
loadPluginFile(pluginPath);
buidlerContext.setPluginAsLoaded(pluginName);
}
exports.usePlugin = usePlugin;
function loadPluginFile(absolutePluginFilePath) {
log("Loading plugin file %s", absolutePluginFilePath);
const imported = require(absolutePluginFilePath);
const plugin = imported.default !== undefined ? imported.default : imported;
if (typeof plugin === "function") {
plugin();
}
}
exports.loadPluginFile = loadPluginFile;
function readPackageJson(packageName, from) {
try {
const options = from !== undefined ? { paths: [from] } : undefined;
const packageJsonPath = require.resolve(path.join(packageName, "package.json"), options);
return require(packageJsonPath);
}
catch (error) {
return undefined;
}
}
exports.readPackageJson = readPackageJson;
function ensurePluginLoadedWithUsePlugin() {
// No-op. Only here for backwards compatibility
}
exports.ensurePluginLoadedWithUsePlugin = ensurePluginLoadedWithUsePlugin;
//# sourceMappingURL=plugins.js.map
;