@authereum/zos
Version:
Command-line interface for the ZeppelinOS smart contract platform
155 lines • 8.53 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_map_1 = __importDefault(require("lodash.map"));
const lodash_uniq_1 = __importDefault(require("lodash.uniq"));
const lodash_flatten_1 = __importDefault(require("lodash.flatten"));
const lodash_frompairs_1 = __importDefault(require("lodash.frompairs"));
const semver_1 = __importDefault(require("semver"));
const npm_programmatic_1 = __importDefault(require("npm-programmatic"));
const child_process_1 = require("child_process");
const util_1 = require("util");
const zos_lib_1 = require("zos-lib");
const ProjectFile_1 = __importDefault(require("../files/ProjectFile"));
const NetworkFile_1 = __importDefault(require("../files/NetworkFile"));
const constants_1 = require("../files/constants");
class Dependency {
static fromNameWithVersion(nameAndVersion) {
const [name, version] = nameAndVersion.split('@');
return new this(name, version);
}
static satisfiesVersion(version, requirement) {
return (!requirement ||
version === requirement ||
semver_1.default.satisfies(semver_1.default.coerce(version), requirement));
}
static fetchVersionFromNpm(name) {
return __awaiter(this, void 0, void 0, function* () {
const execAsync = util_1.promisify(child_process_1.exec);
try {
const { stdout } = yield execAsync(`npm view ${name} | grep latest`);
const versionMatch = stdout.match(/([0-9]+\.){2}[0-9]+/);
return Array.isArray(versionMatch) && versionMatch.length > 0
? `${name}@${versionMatch[0]}`
: name;
}
catch (error) {
return name;
}
});
}
static hasDependenciesForDeploy(network) {
const dependencies = ProjectFile_1.default.getLinkedDependencies() || [];
const networkDependencies = new NetworkFile_1.default(null, network).dependencies;
const hasDependenciesForDeploy = dependencies.find((depNameAndVersion) => {
const [name, version] = depNameAndVersion.split('@');
const networkFilePath = Dependency.getExistingNetworkFilePath(name, network);
const projectDependency = networkDependencies[name];
const satisfiesVersion = projectDependency &&
this.satisfiesVersion(projectDependency.version, version);
return !zos_lib_1.FileSystem.exists(networkFilePath) && !satisfiesVersion;
});
return !!hasDependenciesForDeploy;
}
static install(nameAndVersion) {
return __awaiter(this, void 0, void 0, function* () {
zos_lib_1.Loggy.spin(__filename, 'install', `install-dependency-${nameAndVersion}`, `Installing ${nameAndVersion} via npm`);
yield npm_programmatic_1.default.install([nameAndVersion], { save: true, cwd: process.cwd() });
zos_lib_1.Loggy.succeed(`install-dependency-${nameAndVersion}`, `Dependency ${nameAndVersion} installed`);
return this.fromNameWithVersion(nameAndVersion);
});
}
constructor(name, requirement) {
this.name = name;
this._networkFiles = {};
const projectVersion = this.projectFile.version;
this.validateSatisfiesVersion(projectVersion, requirement);
this.version = projectVersion;
this.nameAndVersion = `${name}@${projectVersion}`;
this.requirement = requirement || tryWithCaret(projectVersion);
}
deploy(txParams) {
return __awaiter(this, void 0, void 0, function* () {
const version = semver_1.default.coerce(this.version).toString();
const project = yield zos_lib_1.PackageProject.fetchOrDeploy(version, txParams, {});
// REFACTOR: Logic for filling in solidity libraries is partially duplicated from network base controller,
// this should all be handled at the Project level. Consider adding a setImplementations (plural) method
// to Projects, which handle library deployment and linking for a set of contracts altogether.
const contracts = lodash_map_1.default(this.projectFile.contracts, (contractName, contractAlias) => [
zos_lib_1.Contracts.getFromNodeModules(this.name, contractName),
contractAlias,
]);
const pipeline = [
someContracts => lodash_map_1.default(someContracts, ([contract]) => zos_lib_1.getSolidityLibNames(contract.schema.bytecode)),
someContracts => lodash_flatten_1.default(someContracts),
someContracts => lodash_uniq_1.default(someContracts),
];
const libraryNames = pipeline.reduce((xs, f) => f(xs), contracts);
const libraries = lodash_frompairs_1.default(yield Promise.all(lodash_map_1.default(libraryNames, (libraryName) => __awaiter(this, void 0, void 0, function* () {
const implementation = yield project.setImplementation(zos_lib_1.Contracts.getFromNodeModules(this.name, libraryName), libraryName);
return [libraryName, implementation.address];
}))));
yield Promise.all(lodash_map_1.default(contracts, ([contract, contractAlias]) => __awaiter(this, void 0, void 0, function* () {
contract.link(libraries);
yield project.setImplementation(contract, contractAlias);
})));
return project;
});
}
get projectFile() {
if (!this._projectFile) {
const filePath = ProjectFile_1.default.getExistingFilePath(`node_modules/${this.name}`);
if (!filePath) {
throw new Error(`Could not find a project.json file for '${this.name}'. Make sure it is provided by the npm package.`);
}
this._projectFile = new ProjectFile_1.default(filePath);
}
return this._projectFile;
}
getNetworkFile(network) {
if (!this._networkFiles[network]) {
const filePath = Dependency.getExistingNetworkFilePath(this.name, network);
if (!zos_lib_1.FileSystem.exists(filePath)) {
throw Error(`Could not find a project file for network '${network}' for '${this.name}'`);
}
this._networkFiles[network] = new NetworkFile_1.default(this.projectFile, network, filePath);
this.validateSatisfiesVersion(this._networkFiles[network].version, this.requirement);
}
return this._networkFiles[network];
}
isDeployedOnNetwork(network) {
const filePath = Dependency.getExistingNetworkFilePath(this.name, network);
if (!zos_lib_1.FileSystem.exists(filePath))
return false;
return !!this.getNetworkFile(network).packageAddress;
}
static getExistingNetworkFilePath(name, network) {
// TODO-v3: Remove legacy project file support
let legacyFilePath = `node_modules/${name}/zos.${network}.json`;
legacyFilePath = zos_lib_1.FileSystem.exists(legacyFilePath) ? legacyFilePath : null;
let filePath = `node_modules/${this.name}/${constants_1.OPEN_ZEPPELIN_FOLDER}/${network}.json`;
filePath = zos_lib_1.FileSystem.exists(filePath) ? filePath : null;
return filePath || legacyFilePath;
}
validateSatisfiesVersion(version, requirement) {
if (!Dependency.satisfiesVersion(version, requirement)) {
throw Error(`Required dependency version ${requirement} does not match version ${version}`);
}
}
}
exports.default = Dependency;
function tryWithCaret(version) {
const cleaned = semver_1.default.clean(version);
return cleaned ? `^${cleaned}` : version;
}
//# sourceMappingURL=Dependency.js.map