Skip to content

Commit

Permalink
Reorganize the chaincode package logic
Browse files Browse the repository at this point in the history
Change-Id: I3009893c0f4c4e67fc3f9b83c08b5d6b2e7b1ea7
Signed-off-by: Greg Haskins <[email protected]>
  • Loading branch information
ghaskins committed Feb 26, 2017
1 parent 6c3547e commit d61f388
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 179 deletions.
112 changes: 2 additions & 110 deletions fabric-client/lib/Chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ var utils = require('./utils.js');
var urlParser = require('url');
var net = require('net');
var util = require('util');
var fs = require('fs-extra');
var os = require('os');
var path = require('path');
var Peer = require('./Peer.js');
var Orderer = require('./Orderer.js');
var Packager = require('./Packager.js');
var settle = require('promise-settle');
var grpc = require('grpc');
var logger = utils.getLogger('Chain.js');
Expand Down Expand Up @@ -1068,49 +1068,6 @@ var Chain = class {
}


/**
* Utility function to package a chaincode. All of the files
* in the directory of the environment variable GOPATH joined
* to the request.chaincodePath will be included in an archive
* file. The contents will be returned as a byte array.
*
* @param {Object} chaincodePath required - String of the path to location of
* the source code of the chaincode
* @param {Object} chaincodeType optional - String of the type of chaincode
* ['golang', 'car', 'java'] (default 'golang')
* @param {boolean} devmode optional - True if using dev mode
* @returns {Promise} A promise for the data as a byte array
*/
static packageChaincode(chaincodePath, chaincodeType, devmode) {
logger.debug('Chain.packageChaincode chaincodePath: %s, chaincodeType: %s, devmode: %s',chaincodePath,chaincodeType,devmode);
return new Promise(function(resolve, reject) {
if (devmode) {
logger.debug('Chain.packageChaincode Skipping chaincode packaging due to devmode configuration');
return resolve(null);
}

if (!chaincodePath || chaincodePath && chaincodePath.length < 1) {
// Verify that chaincodePath is being passed
return reject(new Error('Missing chaincodePath parameter in Chain.packageChaincode'));
}

let type = !!chaincodeType ? chaincodeType : 'golang';
logger.debug('Chain.packageChaincode type %s ',type);

let handler;

switch (type) {
case 'car':
handler = packageCarChaincode;
break;
default:
handler = packageGolangChaincode;
}

return resolve(handler(chaincodePath));
});
}

/**
* Sends an instantiate proposal to one or more endorsing peers.
*
Expand Down Expand Up @@ -1648,7 +1605,7 @@ var Chain = class {
static _getChaincodePackageData(request, devMode) {
return new Promise((resolve,reject) => {
if (!request.chaincodePackage) {
resolve(Chain.packageChaincode(request.chaincodePath, request.chaincodeType, devMode));
resolve(Packager.package(request.chaincodePath, request.chaincodeType, devMode));
} else {
resolve(request.chaincodePackage);
}
Expand Down Expand Up @@ -1677,71 +1634,6 @@ function toKeyValueStoreName(name) {
return 'member.' + name;
}

function readFile(path) {
return new Promise(function(resolve, reject) {
fs.readFile(path, function(err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}

function writeFile(path, contents) {
return new Promise(function(resolve, reject) {
fs.writeFile(path, contents, function(err) {
if (err) {
reject(new Error(util.format('Error writing file [%s]: %s', path, err)));
} else {
resolve(path);
}
});
});
}

function packageGolangChaincode(chaincodePath) {
return new Promise(function(resolve, reject) {
logger.info('Chain.packageGolangChaincode packaging GOLANG from %s', chaincodePath);

// Determine the user's $GOPATH
let goPath = process.env['GOPATH'];

// Compose the path to the chaincode project directory
let projDir = path.join(goPath, 'src', chaincodePath);

// Create the .tar.gz file of the chaincode package
fs.mkdtemp(path.join(os.tmpdir(), path.sep), (err, folder) => {
if (err) return reject(new Error('Failed to create temp folder. ' + err));

// first copy all the target chaincode files from the source folder to
// <this_temp_folder>/src/<chaincodePath> folder so that the tar.gz
// archive can be created with the folder structure preserved
var dest = path.join(folder, 'src', chaincodePath);
fs.copy(projDir, dest, (err) => {
if (err) return reject(new Error('Failed to copy chaincode source to temp folder. ' + err));

let targzFilePath = path.join(folder, 'deployment-package.tar.gz');
return utils.generateTarGz(folder, targzFilePath)
.then(function() {
logger.debug('Chain.packageGolangChaincode - Successfully generated chaincode archive %s ', targzFilePath);
return readFile(targzFilePath)
.then((data) => {
logger.debug('Chain.packageGolangChaincode - Successful readFile to data in bytes');
return resolve(data);
});
});
});
});
});
}

function packageCarChaincode(chaincodePath) {
logger.info('Chain.packageCarChaincode packaging CAR file from %s', chaincodePath);
return readFile(chaincodePath);
}

//utility method to build a common chain header
function buildChannelHeader(type, chain_id, tx_id, epoch, chaincode_id, time_stamp) {
logger.debug('buildChannelHeader - type %s chain_id %s tx_id %d epoch % chaincode_id %s',
Expand Down
61 changes: 61 additions & 0 deletions fabric-client/lib/Packager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var Golang = require('./packager/Golang.js');
var Car = require('./packager/Car.js');
var utils = require('./utils.js');

var logger = utils.getLogger('packager');

/**
* Utility function to package a chaincode. The contents will be returned as a byte array.
*
* @param {Object} chaincodePath required - String of the path to location of
* the source code of the chaincode
* @param {Object} chaincodeType optional - String of the type of chaincode
* ['golang', 'car', 'java'] (default 'golang')
* @param {boolean} devmode optional - True if using dev mode
* @returns {Promise} A promise for the data as a byte array
*/
module.exports.package = function(chaincodePath, chaincodeType, devmode) {
logger.debug('packager: chaincodePath: %s, chaincodeType: %s, devmode: %s',chaincodePath,chaincodeType,devmode);
return new Promise(function(resolve, reject) {
if (devmode) {
logger.debug('packager: Skipping chaincode packaging due to devmode configuration');
return resolve(null);
}

if (!chaincodePath || chaincodePath && chaincodePath.length < 1) {
// Verify that chaincodePath is being passed
return reject(new Error('Missing chaincodePath parameter'));
}

let type = !!chaincodeType ? chaincodeType : 'golang';
logger.debug('packager: type %s ',type);

let handler;

switch (type) {
case 'car':
handler = Car.package;
break;
default:
handler = Golang.package;
}

return resolve(handler(chaincodePath));
});
};
24 changes: 24 additions & 0 deletions fabric-client/lib/packager/Car.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var utils = require('../utils.js');

var logger = utils.getLogger('packager/Car.js');

module.exports.package = function(path) {
logger.info('Packaging CAR file from %s', path);
return utils.readFile(path);
};
119 changes: 119 additions & 0 deletions fabric-client/lib/packager/Golang.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var os = require('os');
var fs = require('fs-extra');
var tar = require('tar-fs');
var path = require('path');
var zlib = require('zlib');
var utils = require('../utils.js');

var logger = utils.getLogger('packager/Golang.js');

/**
* All of the files in the directory of the environment variable
* GOPATH joined to the request.chaincodePath will be included
* in an archive file.
*/
module.exports.package = function(chaincodePath) {
return new Promise(function(resolve, reject) {
logger.info('packaging GOLANG from %s', chaincodePath);

// Determine the user's $GOPATH
let goPath = process.env['GOPATH'];

// Compose the path to the chaincode project directory
let projDir = path.join(goPath, 'src', chaincodePath);

// Create the .tar.gz file of the chaincode package
fs.mkdtemp(path.join(os.tmpdir(), path.sep), (err, folder) => {
if (err) return reject(new Error('Failed to create temp folder. ' + err));

// first copy all the target chaincode files from the source folder to
// <this_temp_folder>/src/<chaincodePath> folder so that the tar.gz
// archive can be created with the folder structure preserved
var dest = path.join(folder, 'src', chaincodePath);
fs.copy(projDir, dest, (err) => {
if (err) return reject(new Error('Failed to copy chaincode source to temp folder. ' + err));

let targzFilePath = path.join(folder, 'deployment-package.tar.gz');
return generateTarGz(folder, targzFilePath)
.then(function() {
logger.debug('Successfully generated chaincode archive %s ', targzFilePath);
return utils.readFile(targzFilePath)
.then((data) => {
logger.debug('Successful readFile to data in bytes');
return resolve(data);
});
});
});
});
});
};

//
// generateTarGz creates a .tar.gz file from contents in the src directory and
// saves them in a dest file.
//
function generateTarGz(src, dest) {
// A list of file extensions that should be packaged into the .tar.gz.
// Files with all other file extenstions will be excluded to minimize the size
// of the install payload.
var keep = [
'.go',
'.yaml',
'.json',
'.c',
'.h'
];

return new Promise(function(resolve, reject) {
// Create the pack stream specifying the ignore/filtering function
var pack = tar.pack(src, {
ignore: function(name) {
// Check whether the entry is a file or a directory
if (fs.statSync(name).isDirectory()) {
// If the entry is a directory, keep it in order to examine it further
return false;
} else {
// If the entry is a file, check to see if it's the Dockerfile
if (name.indexOf('Dockerfile') > -1) {
return false;
}

// If it is not the Dockerfile, check its extension
var ext = path.extname(name);

// Ignore any file who's extension is not in the keep list
if (keep.indexOf(ext) === -1) {
return true;
} else {
return false;
}
}
}
})
.pipe(zlib.Gzip())
.pipe(fs.createWriteStream(dest));

pack.on('close', function() {
return resolve(dest);
});
pack.on('error', function() {
return reject(new Error('Error on fs.createWriteStream'));
});
});
};
Loading

0 comments on commit d61f388

Please sign in to comment.