Merge pull request #361 from embark-framework/graphviz-contracts
Graphviz contracts
This commit is contained in:
commit
82726e07e1
14
lib/cmd.js
14
lib/cmd.js
|
@ -18,6 +18,7 @@ class Cmd {
|
||||||
this.simulator();
|
this.simulator();
|
||||||
this.test();
|
this.test();
|
||||||
this.reset();
|
this.reset();
|
||||||
|
this.graph();
|
||||||
this.upload();
|
this.upload();
|
||||||
this.versionCmd();
|
this.versionCmd();
|
||||||
this.otherCommands();
|
this.otherCommands();
|
||||||
|
@ -179,6 +180,18 @@ class Cmd {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
graph() {
|
||||||
|
program
|
||||||
|
.command('graph [environment]')
|
||||||
|
.description('generates documentation based on the smart contracts configured')
|
||||||
|
.action(function (env, options) {
|
||||||
|
embark.graph({
|
||||||
|
env: env || 'development',
|
||||||
|
logfile: options.logfile
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
program
|
program
|
||||||
.command('reset')
|
.command('reset')
|
||||||
|
@ -215,6 +228,7 @@ class Cmd {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Cmd;
|
module.exports = Cmd;
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
const Viz = require('viz.js');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
class GraphGenerator {
|
||||||
|
constructor(engine) {
|
||||||
|
this.engine = engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
generate() {
|
||||||
|
let id = 0;
|
||||||
|
let contractString = "";
|
||||||
|
let relationshipString = "";
|
||||||
|
let idMapping = {};
|
||||||
|
let contractInheritance = {};
|
||||||
|
|
||||||
|
|
||||||
|
for (let contract in this.engine.contractsManager.contracts) {
|
||||||
|
id++;
|
||||||
|
|
||||||
|
idMapping[contract] = id;
|
||||||
|
|
||||||
|
let contractLabel = "";
|
||||||
|
|
||||||
|
contractLabel += `${contract}`;
|
||||||
|
let tooltip = contract;
|
||||||
|
|
||||||
|
if(this.engine.contractsManager.contracts[contract].instanceOf !== undefined &&
|
||||||
|
this.engine.contractsManager.contracts[this.engine.contractsManager.contracts[contract].instanceOf] !== undefined){
|
||||||
|
contractInheritance[contract] = this.engine.contractsManager.contracts[contract].instanceOf;
|
||||||
|
contractLabel += ": " + this.engine.contractsManager.contracts[contract].instanceOf;
|
||||||
|
tooltip += " instance of " + this.engine.contractsManager.contracts[contract].instanceOf;
|
||||||
|
} else {
|
||||||
|
contractLabel += "|";
|
||||||
|
|
||||||
|
for(let i = 0; i < this.engine.contractsManager.contracts[contract].abiDefinition.length; i++){
|
||||||
|
switch(this.engine.contractsManager.contracts[contract].abiDefinition[i].type){
|
||||||
|
case 'fallback':
|
||||||
|
contractLabel += "«fallback»()\\l";
|
||||||
|
break;
|
||||||
|
case 'constructor':
|
||||||
|
contractLabel += "«constructor»(";
|
||||||
|
this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.forEach(function(elem, index){
|
||||||
|
contractLabel += (index == 0 ? "" : ", ") + elem.type;
|
||||||
|
});
|
||||||
|
contractLabel += ")\\l";
|
||||||
|
break;
|
||||||
|
case 'event':
|
||||||
|
contractLabel += "«event»" + this.engine.contractsManager.contracts[contract].abiDefinition[i].name + "(";
|
||||||
|
this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.forEach(function(elem, index){
|
||||||
|
contractLabel += (index == 0 ? "" : ", ") + elem.type;
|
||||||
|
});
|
||||||
|
contractLabel += ")\\l";
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fHashes = this.engine.contractsManager.contracts[contract].functionHashes;
|
||||||
|
if(fHashes != {} && fHashes != undefined){
|
||||||
|
for(let method in this.engine.contractsManager.contracts[contract].functionHashes){
|
||||||
|
contractLabel += method + '\\l';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let others = '';
|
||||||
|
if(!this.engine.contractsManager.contracts[contract].deploy){
|
||||||
|
others = 'fontcolor="#c3c3c3", color="#a0a0a0"';
|
||||||
|
tooltip += " (not deployed)";
|
||||||
|
}
|
||||||
|
|
||||||
|
contractString += `${id}[label = "{${contractLabel}}", tooltip="${tooltip}", fillcolor=gray95, ${others}]\n`;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let c in this.engine.contractsManager.contractDependencies){
|
||||||
|
let contractDependencies = Array.from(new Set(this.engine.contractsManager.contractDependencies[c]));
|
||||||
|
contractDependencies.forEach(function(d){
|
||||||
|
if(idMapping[c] !== undefined && idMapping[d] !== undefined){
|
||||||
|
relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond, tooltip="${c} uses ${d}"]\n`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let c in contractInheritance){
|
||||||
|
relationshipString += `${idMapping[contractInheritance[c]]}->${idMapping[c]}[tooltip="${c} instance of ${contractInheritance[c]}"]\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let dot = `
|
||||||
|
digraph Contracts {
|
||||||
|
node[shape=record,style=filled]
|
||||||
|
edge[dir=back, arrowtail=empty]
|
||||||
|
${contractString}
|
||||||
|
${relationshipString}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
let svg = Viz(dot);
|
||||||
|
|
||||||
|
let filename = "diagram.svg";
|
||||||
|
|
||||||
|
fs.writeFileSync(filename, svg, (err) => {
|
||||||
|
if (err) throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = GraphGenerator;
|
|
@ -17,6 +17,7 @@ class DeployManager {
|
||||||
this.gasLimit = false;
|
this.gasLimit = false;
|
||||||
this.fatalErrors = false;
|
this.fatalErrors = false;
|
||||||
this.deployOnlyOnConfig = false;
|
this.deployOnlyOnConfig = false;
|
||||||
|
this.onlyCompile = options.onlyCompile !== undefined ? options.onlyCompile : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
deployContracts(done) {
|
deployContracts(done) {
|
||||||
|
@ -33,6 +34,13 @@ class DeployManager {
|
||||||
self.contractsManager.deployOnlyOnConfig = self.deployOnlyOnConfig; // temporary, should refactor
|
self.contractsManager.deployOnlyOnConfig = self.deployOnlyOnConfig; // temporary, should refactor
|
||||||
self.contractsManager.build(callback);
|
self.contractsManager.build(callback);
|
||||||
},
|
},
|
||||||
|
function checkCompileOnly(contractsManager, callback){
|
||||||
|
if(self.onlyCompile){
|
||||||
|
self.events.emit('contractsDeployed', contractsManager);
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
return callback(contractsManager, null);
|
||||||
|
},
|
||||||
function checkWeb3IsConnected(contractsManager, callback) {
|
function checkWeb3IsConnected(contractsManager, callback) {
|
||||||
if (!self.web3) {
|
if (!self.web3) {
|
||||||
return callback(Error("no web3 instance found"));
|
return callback(Error("no web3 instance found"));
|
||||||
|
|
|
@ -153,7 +153,8 @@ class Engine {
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
plugins: this.plugins,
|
plugins: this.plugins,
|
||||||
events: this.events,
|
events: this.events,
|
||||||
contractsManager: this.contractsManager
|
contractsManager: this.contractsManager,
|
||||||
|
onlyCompile: options.onlyCompile
|
||||||
});
|
});
|
||||||
|
|
||||||
this.events.on('file-event', function (fileType, _path) {
|
this.events.on('file-event', function (fileType, _path) {
|
||||||
|
|
47
lib/index.js
47
lib/index.js
|
@ -194,6 +194,53 @@ class Embark {
|
||||||
return new Test(options);
|
return new Test(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
graph(options) {
|
||||||
|
options.onlyCompile = true;
|
||||||
|
|
||||||
|
let engine = new Engine({
|
||||||
|
env: options.env,
|
||||||
|
version: this.version,
|
||||||
|
embarkConfig: options.embarkConfig || 'embark.json',
|
||||||
|
logfile: options.logfile
|
||||||
|
});
|
||||||
|
engine.init();
|
||||||
|
|
||||||
|
|
||||||
|
async.parallel([
|
||||||
|
|
||||||
|
function (callback) {
|
||||||
|
let pluginList = engine.plugins.listPlugins();
|
||||||
|
if (pluginList.length > 0) {
|
||||||
|
engine.logger.info("loaded plugins: " + pluginList.join(", "));
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.startMonitor();
|
||||||
|
engine.startService("libraryManager");
|
||||||
|
engine.startService("pipeline");
|
||||||
|
engine.startService("codeGenerator");
|
||||||
|
engine.startService("deployment", {onlyCompile: true});
|
||||||
|
|
||||||
|
engine.deployManager.deployContracts(function (err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
], function (err, _result) {
|
||||||
|
if (err) {
|
||||||
|
engine.logger.error(err.message);
|
||||||
|
engine.logger.info(err.stack);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const GraphGenerator = require('./cmds/graph.js');
|
||||||
|
let graphGen = new GraphGenerator(engine);
|
||||||
|
graphGen.generate();
|
||||||
|
|
||||||
|
engine.logger.info("Done".underline);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
let resetCmd = require('./cmds/reset.js');
|
let resetCmd = require('./cmds/reset.js');
|
||||||
resetCmd();
|
resetCmd();
|
||||||
|
|
|
@ -10063,6 +10063,11 @@
|
||||||
"extsprintf": "1.3.0"
|
"extsprintf": "1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viz.js": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/viz.js/-/viz.js-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-KrSNgnIxec+JCAqDPliO6xYA69ToH2WTYB2Kbt8Bp/XRUvm23rTyfffFi4rvQLFkIRNUz/xCnnqhh/gChhsgGA=="
|
||||||
|
},
|
||||||
"vlq": {
|
"vlq": {
|
||||||
"version": "0.2.3",
|
"version": "0.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
"underscore": "^1.8.3",
|
"underscore": "^1.8.3",
|
||||||
"underscore.string": "^3.3.4",
|
"underscore.string": "^3.3.4",
|
||||||
"url-loader": "^0.6.2",
|
"url-loader": "^0.6.2",
|
||||||
|
"viz.js": "^1.8.1",
|
||||||
"web3": "1.0.0-beta.27",
|
"web3": "1.0.0-beta.27",
|
||||||
"webpack": "^3.10.0",
|
"webpack": "^3.10.0",
|
||||||
"window-size": "^1.1.0"
|
"window-size": "^1.1.0"
|
||||||
|
|
Loading…
Reference in New Issue