diff --git a/lib/config.js b/lib/config.js index a4a808066..bb06a9428 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,17 +1,19 @@ var fs = require('fs'); var grunt = require('grunt'); +var merge = require('merge'); // TODO: add wrapper for fs so it can also work in the browser // can work with both read and save -var Config = function(env) { - this.env = env; +var Config = function(options) { + this.env = options.env; this.blockchainConfig = {}; this.contractsConfig = {}; this.pipelineConfig = {}; this.chainTracker = {}; this.assetFiles = {}; this.contractsFiles = []; - this.configDir = 'config/'; + this.configDir = options.configDir || 'config/'; + this.chainsFile = options.chainsFile || './chains.json'; }; Config.prototype.loadConfigFiles = function(options) { @@ -31,17 +33,17 @@ Config.prototype.reloadConfig = function() { }; Config.prototype.loadBlockchainConfigFile = function() { - //var defaultBlockchainConfig = JSON.parse(fs.readFileSync(this.configDir + this.env + "/blockchain.json"))[this.env]; var defaultBlockchainConfig = JSON.parse(fs.readFileSync(this.configDir + "blockchain.json"))[this.env]; this.blockchainConfig = defaultBlockchainConfig; }; Config.prototype.loadContractsConfigFile = function() { - var defaultContractsConfig = JSON.parse(fs.readFileSync(this.configDir + "contracts.json"))['default']; - //var envContractsConfig = JSON.parse(fs.readFileSync(this.configDir + this.env + "/contracts.json"))[this.env]; + var contractsConfig = JSON.parse(fs.readFileSync(this.configDir + "contracts.json")); + var defaultContractsConfig = contractsConfig['default']; + var envContractsConfig = contractsConfig[this.env]; - //merge.recursive(defaultContractsConfig, envContractsConfig); - this.contractsConfig = defaultContractsConfig; + var mergedConfig = merge.recursive(defaultContractsConfig, envContractsConfig); + this.contractsConfig = mergedConfig; }; Config.prototype.loadPipelineConfigFile = function() { @@ -61,12 +63,12 @@ Config.prototype.loadChainTrackerFile = function() { //var self = this; var chainTracker; try { - chainTracker = JSON.parse(fs.readFileSync("./chains.json")); + chainTracker = JSON.parse(fs.readFileSync(this.chainsFile)); } catch(err) { - //self.logger.info('chains.json file not found, creating it...'); + //self.logger.info(this.chainsFile + ' file not found, creating it...'); chainTracker = {}; - fs.writeFileSync('./chains.json', '{}'); + fs.writeFileSync(this.chainsFile, '{}'); } this.chainTracker = chainTracker; }; diff --git a/lib/index.js b/lib/index.js index 78284bcb9..57c85e247 100644 --- a/lib/index.js +++ b/lib/index.js @@ -37,7 +37,7 @@ var Embark = { }, initConfig: function(env, options) { - this.config = new Config(env); + this.config = new Config({env: env}); this.config.loadConfigFiles(options); this.logger = new Logger({logLevel: 'debug'}); diff --git a/lib/test.js b/lib/test.js index 3e14537ed..49396dedb 100644 --- a/lib/test.js +++ b/lib/test.js @@ -29,7 +29,7 @@ Test.prototype.deployAll = function(contractsConfig, cb) { async.waterfall([ function buildContracts(callback) { - var config = new Config('test'); + var config = new Config({env: 'test'}); config.contractsFiles = config.loadFiles(["app/contracts/**"]); config.contractsConfig = {contracts: contractsConfig} ; diff --git a/package.json b/package.json index 53002f54f..032391a73 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "finalhandler": "^0.5.0", "grunt": "^0.4.5", "json-honey": "^0.4.1", + "merge": "^1.2.0", "meteor-build-client": "^0.1.6", "mkdirp": "^0.5.1", "read-yaml": "^1.0.0", diff --git a/test/compiler.js b/test/compiler.js new file mode 100644 index 000000000..631fe65d9 --- /dev/null +++ b/test/compiler.js @@ -0,0 +1,30 @@ +/*globals describe, it*/ +var Compiler = require('../lib/compiler.js'); +var assert = require('assert'); +var fs = require('fs'); + +var readFile = function(file) { + return {filename: file, content: fs.readFileSync(file).toString()}; +}; + +describe('embark.Compiler', function() { + var compiler = new Compiler(); + + describe('#compile_solidity', function() { + var compiledContracts = compiler.compile_solidity([ + readFile('test/contracts/simple_storage.sol'), + readFile('test/contracts/token.sol') + ]); + + var expectedObject = {}; + expectedObject["SimpleStorage"] = {"code":"6060604052604051602080607d83395060806040525160008190555060568060276000396000f3606060405260e060020a60003504632a1afcd98114602e57806360fe47b11460365780636d4ce63c146040575b005b604460005481565b600435600055602c565b6000545b60408051918252519081900360200190f3","runtimeBytecode":"606060405260e060020a60003504632a1afcd98114602e57806360fe47b11460365780636d4ce63c146040575b005b604460005481565b600435600055602c565b6000545b60408051918252519081900360200190f3","gasEstimates":{"creation":[20097,17200],"external":{"get()":221,"set(uint256)":20121,"storedData()":191},"internal":{}},"functionHashes":{"get()":"6d4ce63c","set(uint256)":"60fe47b1","storedData()":"2a1afcd9"},"abiDefinition":[{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"type":"function"},{"inputs":[{"name":"initialValue","type":"uint256"}],"type":"constructor"}]}; + + expectedObject["Token"] = {"code":"6060604052604051602080610382833950608060405251600160a060020a033316600090815260208190526040902081905560028190555061033d806100456000396000f3606060405236156100565760e060020a6000350463095ea7b3811461005857806318160ddd146100cd57806323b872dd146100e357806370a0823114610115578063a9059cbb14610135578063dd62ed3e14610164575b005b61019860043560243533600160a060020a03908116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b6002545b60408051918252519081900360200190f35b610198600435602435604435600160a060020a038316600090815260208190526040812054829010156101ac57610002565b600160a060020a03600435166000908152602081905260409020546100d1565b61019860043560243533600160a060020a0316600090815260208190526040812054829010156102a157610002565b6100d1600435602435600160a060020a038281166000908152600160209081526040808320938516835292905220546100c7565b604080519115158252519081900360200190f35b600160a060020a0384811660009081526001602090815260408083203390941683529290522054829010156101e057610002565b600160a060020a03831660009081526020819052604090205461020b90835b818101829010156100c7565b151561021657610002565b600160a060020a038481166000818152600160209081526040808320338616845282528083208054889003905583835282825280832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b600160a060020a0383166000908152602081905260409020546102c490836101ff565b15156102cf57610002565b33600160a060020a0390811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060016100c756","runtimeBytecode":"606060405236156100565760e060020a6000350463095ea7b3811461005857806318160ddd146100cd57806323b872dd146100e357806370a0823114610115578063a9059cbb14610135578063dd62ed3e14610164575b005b61019860043560243533600160a060020a03908116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b6002545b60408051918252519081900360200190f35b610198600435602435604435600160a060020a038316600090815260208190526040812054829010156101ac57610002565b600160a060020a03600435166000908152602081905260409020546100d1565b61019860043560243533600160a060020a0316600090815260208190526040812054829010156102a157610002565b6100d1600435602435600160a060020a038281166000908152600160209081526040808320938516835292905220546100c7565b604080519115158252519081900360200190f35b600160a060020a0384811660009081526001602090815260408083203390941683529290522054829010156101e057610002565b600160a060020a03831660009081526020819052604090205461020b90835b818101829010156100c7565b151561021657610002565b600160a060020a038481166000818152600160209081526040808320338616845282528083208054889003905583835282825280832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b600160a060020a0383166000908152602081905260409020546102c490836101ff565b15156102cf57610002565b33600160a060020a0390811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060016100c756","gasEstimates":{"creation":[40348,165800],"external":{"allowance(address,address)":532,"approve(address,uint256)":22208,"balanceOf(address)":382,"totalSupply()":217,"transfer(address,uint256)":null,"transferFrom(address,address,uint256)":63256},"internal":{"safeToAdd(uint256,uint256)":52}},"functionHashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"},"abiDefinition":[{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"ok","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"supply","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"ok","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"value","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"_allowance","type":"uint256"}],"type":"function"},{"inputs":[{"name":"initial_balance","type":"uint256"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]}; + + it('should generate compiled code and abi', function() { + assert.deepEqual(compiledContracts, expectedObject); + }); + + }); + +}); diff --git a/test/config.js b/test/config.js new file mode 100644 index 000000000..3f3ef9207 --- /dev/null +++ b/test/config.js @@ -0,0 +1,57 @@ +/*globals describe, it*/ +var Config = require('../lib/config.js'); +var assert = require('assert'); +var fs = require('fs'); + +describe('embark.Config', function() { + var config = new Config({ + env: 'myenv', + configDir: './test/test1/config/' + }); + + describe('#loadBlockchainConfigFile', function() { + it('should load blockchain config correctly', function() { + config.loadBlockchainConfigFile(); + var expectedConfig = { + "networkType": "custom", + "genesisBlock": "config/development/genesis.json", + "datadir": ".embark/development/datadir", + "mineWhenNeeded": true, + "nodiscover": true, + "rpcHost": "localhost", + "rpcPort": 8545, + "rpcCorsDomain": "http://localhost:8000", + "account": { + "password": "config/development/password" + } + }; + + assert.deepEqual(config.blockchainConfig, expectedConfig); + }); + }); + + describe('#loadContractsConfigFile', function() { + it('should load contract config correctly', function() { + config.loadContractsConfigFile(); + var expectedConfig = { + "gas": "auto", + "contracts": { + "SimpleStorage": { + "args": [ + 100 + ], + "gas": 123456 + }, + "Token": { + "args": [ + 200 + ] + } + } + }; + + assert.deepEqual(config.contractsConfig, expectedConfig); + }); + }); + +}); diff --git a/test/contracts/simple_storage.sol b/test/contracts/simple_storage.sol new file mode 100644 index 000000000..1137a7997 --- /dev/null +++ b/test/contracts/simple_storage.sol @@ -0,0 +1,17 @@ +contract SimpleStorage { + uint public storedData; + + function SimpleStorage(uint initialValue) { + storedData = initialValue; + } + + function set(uint x) { + storedData = x; + } + + function get() constant returns (uint retVal) { + return storedData; + } + +} + diff --git a/test/contracts/token.sol b/test/contracts/token.sol new file mode 100644 index 000000000..db836a662 --- /dev/null +++ b/test/contracts/token.sol @@ -0,0 +1,64 @@ +// https://github.com/nexusdev/erc20/blob/master/contracts/base.sol + +contract Token { + + event Transfer(address indexed from, address indexed to, uint value); + event Approval( address indexed owner, address indexed spender, uint value); + + mapping( address => uint ) _balances; + mapping( address => mapping( address => uint ) ) _approvals; + uint _supply; + function Token( uint initial_balance ) { + _balances[msg.sender] = initial_balance; + _supply = initial_balance; + } + function totalSupply() constant returns (uint supply) { + return _supply; + } + function balanceOf( address who ) constant returns (uint value) { + return _balances[who]; + } + function transfer( address to, uint value) returns (bool ok) { + if( _balances[msg.sender] < value ) { + throw; + } + if( !safeToAdd(_balances[to], value) ) { + throw; + } + _balances[msg.sender] -= value; + _balances[to] += value; + Transfer( msg.sender, to, value ); + return true; + } + function transferFrom( address from, address to, uint value) returns (bool ok) { + // if you don't have enough balance, throw + if( _balances[from] < value ) { + throw; + } + // if you don't have approval, throw + if( _approvals[from][msg.sender] < value ) { + throw; + } + if( !safeToAdd(_balances[to], value) ) { + throw; + } + // transfer and return true + _approvals[from][msg.sender] -= value; + _balances[from] -= value; + _balances[to] += value; + Transfer( from, to, value ); + return true; + } + function approve(address spender, uint value) returns (bool ok) { + // TODO: should increase instead + _approvals[msg.sender][spender] = value; + Approval( msg.sender, spender, value ); + return true; + } + function allowance(address owner, address spender) constant returns (uint _allowance) { + return _approvals[owner][spender]; + } + function safeToAdd(uint a, uint b) internal returns (bool) { + return (a + b >= a); + } +} diff --git a/test/test1/config/blockchain.json b/test/test1/config/blockchain.json new file mode 100644 index 000000000..090f40788 --- /dev/null +++ b/test/test1/config/blockchain.json @@ -0,0 +1,37 @@ +{ + "myenv": { + "networkType": "custom", + "genesisBlock": "config/development/genesis.json", + "datadir": ".embark/development/datadir", + "mineWhenNeeded": true, + "nodiscover": true, + "rpcHost": "localhost", + "rpcPort": 8545, + "rpcCorsDomain": "http://localhost:8000", + "account": { + "password": "config/development/password" + } + }, + "testnet": { + "networkType": "testnet", + "rpcHost": "localhost", + "rpcPort": 8545 + }, + "livenet": { + "networkType": "livenet", + "rpcHost": "localhost", + "rpcPort": 8545, + "rpcCorsDomain": "http://localhost:8000", + "account": { + "password": "config/production/password" + } + }, + "privatenet": { + "networkType": "custom", + "rpcHost": "localhost", + "rpcPort": 8545, + "datadir": "yourdatadir", + "networkId": "123", + "nodes": [] + } +} diff --git a/test/test1/config/contracts.json b/test/test1/config/contracts.json new file mode 100644 index 000000000..e63368fa9 --- /dev/null +++ b/test/test1/config/contracts.json @@ -0,0 +1,25 @@ +{ + "default": { + "gas": "auto", + "contracts": { + "SimpleStorage": { + "args": [ + 100 + ] + } + } + }, + "myenv": { + "gas": "auto", + "contracts": { + "SimpleStorage": { + "gas": 123456 + }, + "Token": { + "args": [ + 200 + ] + } + } + } +}