@nomiclabs/buidler
Version:
Buidler is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
310 lines • 13 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 chalk_1 = __importDefault(require("chalk"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const constants_1 = require("../constants");
const execution_mode_1 = require("../core/execution-mode");
const project_structure_1 = require("../core/project-structure");
const packageInfo_1 = require("../util/packageInfo");
const emoji_1 = require("./emoji");
const CREATE_SAMPLE_PROJECT_ACTION = "Create a sample project";
const CREATE_EMPTY_BUIDLER_CONFIG_ACTION = "Create an empty buidler.config.js";
const QUIT_ACTION = "Quit";
const SAMPLE_PROJECT_DEPENDENCIES = {
"@nomiclabs/buidler-waffle": "^2.0.0",
"ethereum-waffle": "^3.0.0",
chai: "^4.2.0",
"@nomiclabs/buidler-ethers": "^2.0.0",
ethers: "^5.0.0",
};
async function removeProjectDirIfPresent(projectRoot, dirName) {
const dirPath = path_1.default.join(projectRoot, dirName);
if (await fs_extra_1.default.pathExists(dirPath)) {
await fs_extra_1.default.remove(dirPath);
}
}
async function removeTempFilesIfPresent(projectRoot) {
await removeProjectDirIfPresent(projectRoot, "cache");
await removeProjectDirIfPresent(projectRoot, "artifacts");
}
function printAsciiLogo() {
console.log(chalk_1.default.blue(`888 d8b 888 888`));
console.log(chalk_1.default.blue(`888 Y8P 888 888`));
console.log(chalk_1.default.blue("888 888 888"));
console.log(chalk_1.default.blue("88888b. 888 888 888 .d88888 888 .d88b. 888d888"));
console.log(chalk_1.default.blue('888 "88b 888 888 888 d88" 888 888 d8P Y8b 888P"'));
console.log(chalk_1.default.blue("888 888 888 888 888 888 888 888 88888888 888"));
console.log(chalk_1.default.blue("888 d88P Y88b 888 888 Y88b 888 888 Y8b. 888"));
console.log(chalk_1.default.blue(`88888P" "Y88888 888 "Y88888 888 "Y8888 888`));
console.log("");
}
async function printWelcomeMessage() {
const packageJson = await packageInfo_1.getPackageJson();
console.log(chalk_1.default.cyan(`${emoji_1.emoji("👷 ")}Welcome to ${constants_1.BUIDLER_NAME} v${packageJson.version}${emoji_1.emoji(" 👷")}\n`));
}
async function copySampleProject(projectRoot) {
const packageRoot = await packageInfo_1.getPackageRoot();
await fs_extra_1.default.ensureDir(projectRoot);
await fs_extra_1.default.copy(path_1.default.join(packageRoot, "sample-project"), projectRoot);
// This is just in case we have been using the sample project for dev/testing
await removeTempFilesIfPresent(projectRoot);
await fs_extra_1.default.remove(path_1.default.join(projectRoot, "LICENSE.md"));
}
async function addGitIgnore(projectRoot) {
const gitIgnorePath = path_1.default.join(projectRoot, ".gitignore");
let content = await project_structure_1.getRecommendedGitIgnore();
if (await fs_extra_1.default.pathExists(gitIgnorePath)) {
const existingContent = await fs_extra_1.default.readFile(gitIgnorePath, "utf-8");
content = `${existingContent}
${content}`;
}
await fs_extra_1.default.writeFile(gitIgnorePath, content);
}
async function addGitAttributes(projectRoot) {
const gitAttributesPath = path_1.default.join(projectRoot, ".gitattributes");
let content = "*.sol linguist-language=Solidity";
if (await fs_extra_1.default.pathExists(gitAttributesPath)) {
const existingContent = await fs_extra_1.default.readFile(gitAttributesPath, "utf-8");
if (existingContent.includes(content)) {
return;
}
content = `${existingContent}
${content}`;
}
await fs_extra_1.default.writeFile(gitAttributesPath, content);
}
function printSuggestedCommands() {
const npx = execution_mode_1.getExecutionMode() === execution_mode_1.ExecutionMode.EXECUTION_MODE_GLOBAL_INSTALLATION
? ""
: "npx ";
console.log(`Try running some of the following tasks:`);
console.log(` ${npx}buidler accounts`);
console.log(` ${npx}buidler compile`);
console.log(` ${npx}buidler test`);
console.log(` ${npx}buidler node`);
console.log(` node scripts/sample-script.js`);
console.log(` ${npx}buidler help`);
}
async function printRecommendedDepsInstallationInstructions() {
console.log(`You need to install these dependencies to run the sample project:`);
const cmd = await getRecommendedDependenciesInstallationCommand();
console.log(` ${cmd.join(" ")}`);
}
async function writeEmptyBuidlerConfig() {
return fs_extra_1.default.writeFile("buidler.config.js", "module.exports = {};\n", "utf-8");
}
async function getAction() {
const { default: enquirer } = await Promise.resolve().then(() => __importStar(require("enquirer")));
try {
const actionResponse = await enquirer.prompt([
{
name: "action",
type: "select",
message: "What do you want to do?",
initial: 0,
choices: [
{
name: CREATE_SAMPLE_PROJECT_ACTION,
message: CREATE_SAMPLE_PROJECT_ACTION,
value: CREATE_SAMPLE_PROJECT_ACTION,
},
{
name: CREATE_EMPTY_BUIDLER_CONFIG_ACTION,
message: CREATE_EMPTY_BUIDLER_CONFIG_ACTION,
value: CREATE_EMPTY_BUIDLER_CONFIG_ACTION,
},
{ name: QUIT_ACTION, message: QUIT_ACTION, value: QUIT_ACTION },
],
},
]);
return actionResponse.action;
}
catch (e) {
if (e === "") {
return QUIT_ACTION;
}
// tslint:disable-next-line only-buidler-error
throw e;
}
}
async function createProject() {
const { default: enquirer } = await Promise.resolve().then(() => __importStar(require("enquirer")));
printAsciiLogo();
await printWelcomeMessage();
const action = await getAction();
if (action === QUIT_ACTION) {
return;
}
if (action === CREATE_EMPTY_BUIDLER_CONFIG_ACTION) {
await writeEmptyBuidlerConfig();
console.log(`${emoji_1.emoji("✨ ")}${chalk_1.default.cyan(`Config file created`)}${emoji_1.emoji(" ✨")}`);
return;
}
let responses;
try {
responses = await enquirer.prompt([
{
name: "projectRoot",
type: "input",
initial: process.cwd(),
message: "Buidler project root:",
},
createConfirmationPrompt("shouldAddGitIgnore", "Do you want to add a .gitignore?"),
createConfirmationPrompt("shouldAddGitAttributes", "Do you want to add a .gitattributes to enable Soldity highlighting on GitHub?"),
]);
}
catch (e) {
if (e === "") {
return;
}
// tslint:disable-next-line only-buidler-error
throw e;
}
const { projectRoot, shouldAddGitIgnore, shouldAddGitAttributes } = responses;
await copySampleProject(projectRoot);
if (shouldAddGitIgnore) {
await addGitIgnore(projectRoot);
}
if (shouldAddGitAttributes) {
await addGitAttributes(projectRoot);
}
let shouldShowInstallationInstructions = true;
if (await canInstallRecommendedDeps()) {
const recommendedDeps = Object.keys(SAMPLE_PROJECT_DEPENDENCIES);
const installedRecommendedDeps = recommendedDeps.filter(isInstalled);
if (installedRecommendedDeps.length === recommendedDeps.length) {
shouldShowInstallationInstructions = false;
}
else if (installedRecommendedDeps.length === 0) {
const shouldInstall = await confirmRecommendedDepsInstallation();
if (shouldInstall) {
const installed = await installRecommendedDependencies();
if (!installed) {
console.warn(chalk_1.default.red("Failed to install the sample project's dependencies"));
}
shouldShowInstallationInstructions = !installed;
}
}
}
if (shouldShowInstallationInstructions) {
console.log(``);
await printRecommendedDepsInstallationInstructions();
}
console.log(`\n${emoji_1.emoji("✨ ")}${chalk_1.default.cyan("Project created")}${emoji_1.emoji(" ✨")}`);
console.log(``);
printSuggestedCommands();
}
exports.createProject = createProject;
function createConfirmationPrompt(name, message) {
return {
type: "confirm",
name,
message,
initial: "y",
default: "(Y/n)",
isTrue(input) {
if (typeof input === "string") {
return input.toLowerCase() === "y";
}
return input;
},
isFalse(input) {
if (typeof input === "string") {
return input.toLowerCase() === "n";
}
return input;
},
format() {
const that = this;
const value = that.value === true ? "y" : "n";
if (that.state.submitted === true) {
return that.styles.submitted(value);
}
return value;
},
};
}
async function canInstallRecommendedDeps() {
return ((await fs_extra_1.default.pathExists("package.json")) &&
(execution_mode_1.getExecutionMode() === execution_mode_1.ExecutionMode.EXECUTION_MODE_LOCAL_INSTALLATION ||
execution_mode_1.getExecutionMode() === execution_mode_1.ExecutionMode.EXECUTION_MODE_LINKED) &&
// TODO: Figure out why this doesn't work on Win
os_1.default.type() !== "Windows_NT");
}
function isInstalled(dep) {
const packageJson = fs_extra_1.default.readJSONSync("package.json");
const allDependencies = Object.assign(Object.assign(Object.assign({}, packageJson.dependencies), packageJson.devDependencies), packageJson.optionalDependencies);
return dep in allDependencies;
}
async function isYarnProject() {
return fs_extra_1.default.pathExists("yarn.lock");
}
async function installRecommendedDependencies() {
console.log("");
const installCmd = await getRecommendedDependenciesInstallationCommand();
return installDependencies(installCmd[0], installCmd.slice(1));
}
async function confirmRecommendedDepsInstallation() {
const { default: enquirer } = await Promise.resolve().then(() => __importStar(require("enquirer")));
let responses;
const packageManager = (await isYarnProject()) ? "yarn" : "npm";
try {
responses = await enquirer.prompt([
createConfirmationPrompt("shouldInstallPlugin", `Do you want to install the sample project's dependencies with ${packageManager} (${Object.keys(SAMPLE_PROJECT_DEPENDENCIES).join(" ")})?`),
]);
}
catch (e) {
if (e === "") {
return false;
}
// tslint:disable-next-line only-buidler-error
throw e;
}
return responses.shouldInstallPlugin === true;
}
async function installDependencies(packageManager, args) {
const { spawn } = await Promise.resolve().then(() => __importStar(require("child_process")));
console.log(`${packageManager} ${args.join(" ")}`);
const childProcess = spawn(packageManager, args, {
stdio: "inherit",
});
return new Promise((resolve, reject) => {
childProcess.once("close", (status) => {
childProcess.removeAllListeners("error");
if (status === 0) {
resolve(true);
return;
}
reject(false);
});
childProcess.once("error", (status) => {
childProcess.removeAllListeners("close");
reject(false);
});
});
}
async function getRecommendedDependenciesInstallationCommand() {
const isGlobal = execution_mode_1.getExecutionMode() === execution_mode_1.ExecutionMode.EXECUTION_MODE_GLOBAL_INSTALLATION;
const deps = Object.entries(SAMPLE_PROJECT_DEPENDENCIES).map(([name, version]) => `${name}@${version}`);
if (!isGlobal && (await isYarnProject())) {
return ["yarn", "add", "--dev", ...deps];
}
const npmInstall = ["npm", "install"];
if (isGlobal) {
npmInstall.push("--global");
}
return [...npmInstall, "--save-dev", ...deps];
}
//# sourceMappingURL=project-creation.js.map
;