diff --git a/lib/cmd.js b/lib/cmd.js index 419e194d5..5f6576c14 100644 --- a/lib/cmd.js +++ b/lib/cmd.js @@ -45,6 +45,7 @@ class Cmd { .description(__('New Application')) .option('--simple', __('create a barebones project meant only for contract development')) .option('--locale [locale]', __('language to use (default: en)')) + .option('--template [url]', __('download template')) .action(function (name, options) { i18n.setOrDetectLocale(options.locale); if (name === undefined) { @@ -63,7 +64,7 @@ class Cmd { if (options.simple) { embark.generateTemplate('simple', './', inputvalue); } else { - embark.generateTemplate('boilerplate', './', inputvalue); + embark.generateTemplate('boilerplate', './', inputvalue, options.template); } } }); @@ -71,7 +72,7 @@ class Cmd { if (options.simple) { embark.generateTemplate('simple', './', name); } else { - embark.generateTemplate('boilerplate', './', name); + embark.generateTemplate('boilerplate', './', name, options.template); } } }); diff --git a/lib/cmds/template_generator.js b/lib/cmds/template_generator.js index aa6720371..fec599418 100644 --- a/lib/cmds/template_generator.js +++ b/lib/cmds/template_generator.js @@ -6,6 +6,26 @@ class TemplateGenerator { this.templateName = templateName; } + downloadAndGenerate(uri, destinationFolder, name) { + let {url, filePath} = this.getExternalProject(uri); + let tmpFilePath = fs.tmpDir(filePath); + + fs.mkdirpSync(utils.dirname(tmpFilePath)); + utils.downloadFile(url, tmpFilePath, () => { + let fspath = utils.joinPath(destinationFolder, name); + const decompress = require('decompress'); + + decompress(tmpFilePath, fspath, { + map: file => { + let fixed_path = file.path.split('/'); + fixed_path.shift(); // remove first directory + file.path = utils.joinPath(...fixed_path); + return file; + } + }); + }); + } + generate(destinationFolder, name) { let templatePath = fs.embarkPath(utils.joinPath('templates', this.templateName)); console.log(__('Initializing Embark Template....').green); @@ -34,6 +54,37 @@ class TemplateGenerator { console.log(__('For more info go to http://embark.status.im').green); } } + + getExternalProject(uri) { + const constants = require('../constants'); + const RAW_URL = 'https://github.com/'; + + let match = uri.match( + /\.[a-z]+\/([-a-zA-Z0-9@:%_+.~#?&\/=]+)/ + ); + + let url, folder; + + if (uri.startsWith('http')) { + url = uri + "/archive/master.zip" + folder = match[1] + } else if (uri.startsWith('github')) { + url = "https://" + uri + "/archive/master.zip" + folder = match[1] + } else if (uri.split('/').length === 2) { + url = "https://github.com/" + uri + "/archive/master.zip" + folder = uri + } else if (uri.indexOf('/') === -1) { + url = "https://github.com/embark-framework/embark-" + uri + "-template/archive/master.zip" + folder = "embark-framework/embark-" + uri + "-template" + } + + return { + url, + filePath: utils.joinPath(".embark/templates/", folder, "archive.zip") + }; + } + } module.exports = TemplateGenerator; diff --git a/lib/core/fs.js b/lib/core/fs.js index bd6c4be5b..927632c73 100644 --- a/lib/core/fs.js +++ b/lib/core/fs.js @@ -90,6 +90,11 @@ function createWriteStream() { return fs.createWriteStream.apply(fs.createWriteStream, arguments); } +function tmpDir() { + let os = require('os'); + return utils.joinPath(os.tmpdir(), ...arguments); +} + module.exports = { mkdirpSync, mkdirp, @@ -110,5 +115,6 @@ module.exports = { removeSync, embarkPath, dappPath, - createWriteStream + createWriteStream, + tmpDir }; diff --git a/lib/index.js b/lib/index.js index 86b07bacf..558ee8022 100644 --- a/lib/index.js +++ b/lib/index.js @@ -49,10 +49,14 @@ class Embark { simulator.run(options); } - generateTemplate(templateName, destinationFolder, name) { + generateTemplate(templateName, destinationFolder, name, url) { this.context = [constants.contexts.templateGeneration]; let TemplateGenerator = require('./cmds/template_generator.js'); let templateGenerator = new TemplateGenerator(templateName); + + if (url) { + return templateGenerator.downloadAndGenerate(url, destinationFolder, name); + } templateGenerator.generate(destinationFolder, name); } diff --git a/lib/utils/utils.js b/lib/utils/utils.js index 193b142d1..c9d710104 100644 --- a/lib/utils/utils.js +++ b/lib/utils/utils.js @@ -9,6 +9,11 @@ function joinPath() { return path.join.apply(path.join, arguments); } +function dirname() { + const path = require('path'); + return path.dirname.apply(path.dirname, arguments); +} + function filesMatchingPattern(files) { const globule = require('globule'); return globule.find(files, {nonull: true}); @@ -171,6 +176,15 @@ function extractTar(filename, packageDirectory, cb) { ); } +function extractZip(filename, packageDirectory, cb) { + const decompress = require('decompress'); + + decompress(filename, packageDirectory).then(files => { + console.log('done!'); + cb(); + }); +} + function proposeAlternative(word, _dictionary, _exceptions) { const propose = require('propose'); let exceptions = _exceptions || []; @@ -341,6 +355,7 @@ function getHexBalanceFromString(balanceString, web3) { module.exports = { joinPath: joinPath, + dirname: dirname, filesMatchingPattern: filesMatchingPattern, fileMatchesPattern: fileMatchesPattern, recursiveMerge: recursiveMerge, @@ -358,6 +373,7 @@ module.exports = { exit: exit, downloadFile: downloadFile, extractTar: extractTar, + extractZip: extractZip, proposeAlternative: proposeAlternative, pwd: pwd, getExternalContractUrl, diff --git a/package.json b/package.json index defcf7158..b5154031a 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "colors": "^1.1.2", "commander": "^2.15.1", "css-loader": "^0.28.11", + "decompress": "^4.2.0", "deep-equal": "^1.0.1", "ejs": "^2.5.8", "eth-ens-namehash": "^2.0.8", diff --git a/test/template.js b/test/template.js new file mode 100644 index 000000000..b539e7c9c --- /dev/null +++ b/test/template.js @@ -0,0 +1,61 @@ +/*globals describe, it*/ +const assert = require('assert'); +const TemplateGenerator = require('../lib/cmds/template_generator'); + +describe('TemplateGenerator', function () { + describe('getExternalProject', function () { + let templateGenerator; + + before(() => { + templateGenerator = new TemplateGenerator(); + }); + + describe('with github link', function () { + + it('return correct zip filename for https link', function (done) { + let result = templateGenerator.getExternalProject("https://github.com/embark-framework/embark"); + assert.deepEqual(result.url, "https://github.com/embark-framework/embark/archive/master.zip"); + assert.deepEqual(result.filePath, ".embark/templates/embark-framework/embark/archive.zip"); + done(); + }); + + it('return correct zip filename for http link', function (done) { + let result = templateGenerator.getExternalProject("http://github.com/embark-framework/embark"); + assert.deepEqual(result.url, "http://github.com/embark-framework/embark/archive/master.zip"); + assert.deepEqual(result.filePath, ".embark/templates/embark-framework/embark/archive.zip"); + done(); + }); + + it('return correct zip filename without protocol specified ', function (done) { + let result = templateGenerator.getExternalProject("github.com/embark-framework/embark"); + assert.deepEqual(result.url, "https://github.com/embark-framework/embark/archive/master.zip"); + assert.deepEqual(result.filePath, ".embark/templates/embark-framework/embark/archive.zip"); + done(); + }); + + it('return correct zip filename without protocol specified ', function (done) { + let result = templateGenerator.getExternalProject("github.com/embark-framework/embark"); + assert.deepEqual(result.url, "https://github.com/embark-framework/embark/archive/master.zip"); + assert.deepEqual(result.filePath, ".embark/templates/embark-framework/embark/archive.zip"); + done(); + }); + + it('return correct zip filename with just username/repo specified', function (done) { + let result = templateGenerator.getExternalProject("embark-framework/embark"); + assert.deepEqual(result.url, "https://github.com/embark-framework/embark/archive/master.zip"); + assert.deepEqual(result.filePath, ".embark/templates/embark-framework/embark/archive.zip"); + done(); + }); + + it('return correct zip filename with just embark template specified', function (done) { + let result = templateGenerator.getExternalProject("react"); + assert.deepEqual(result.url, "https://github.com/embark-framework/embark-react-template/archive/master.zip"); + assert.deepEqual(result.filePath, ".embark/templates/embark-framework/embark-react-template/archive.zip"); + done(); + }); + + }); + + }); +}); +