You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ripple.apache.org by ti...@apache.org on 2015/04/09 10:22:22 UTC
incubator-ripple git commit: RIPPLE-80 Add some tools to jake to
support creating Apache archives.
Repository: incubator-ripple
Updated Branches:
refs/heads/master 4898a6312 -> 5ef3754ab
RIPPLE-80 Add some tools to jake to support creating Apache archives.
Adds new 'archive' task to jake:
Creates a tgz file for a tag or branch, either for the Apache archives or npm.
Usage:
jake archive[apache|npm,allow-pending,<tagname>]
apache: (default) Create an Apache archive (creates a git archive, signs it, and creates .md5 and .sha hashes).
npm: Create an npm package (requires built files to be present, and does not sign).
allow-pending: If specified, allow uncommitted changes to exist when packaging (only use this for testing). This option is ignored when creating an Apache archive, since that is created directly from git.
<tagname>: If specified, an existing tag or branch to archive. Otherwise defaults to the most recent tag.
examples:
jake archive
jake archive[npm,allow-pending]
jake archive[0.9.27]
jake archive[npm,my_feature_branch]
Project: http://git-wip-us.apache.org/repos/asf/incubator-ripple/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ripple/commit/5ef3754a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ripple/tree/5ef3754a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ripple/diff/5ef3754a
Branch: refs/heads/master
Commit: 5ef3754ab354724c0a29893969a561bc37e4361f
Parents: 4898a63
Author: Tim Barham <ti...@microsoft.com>
Authored: Thu Mar 19 17:00:55 2015 +1000
Committer: Tim Barham <ti...@microsoft.com>
Committed: Thu Apr 9 18:18:48 2015 +1000
----------------------------------------------------------------------
.gitignore | 1 +
Jakefile | 4 +
build/archive.js | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++
package.json | 21 ++--
4 files changed, 290 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ripple/blob/5ef3754a/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 1b051ba..1ebd44a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@ services
npm-debug.log
test/assets/cov/results.html
thirdparty/jasmine
+ripple-emulator-*.*
http://git-wip-us.apache.org/repos/asf/incubator-ripple/blob/5ef3754a/Jakefile
----------------------------------------------------------------------
diff --git a/Jakefile b/Jakefile
index bde2656..2505940 100644
--- a/Jakefile
+++ b/Jakefile
@@ -68,3 +68,7 @@ task('fixwhitespace', function() {
}, complete);
}, true);
+desc('creates an archive - jake archive[clean:<value>,sign:<value>,tag:<tagname>] or jake archive[help]');
+task('archive', [], function () {
+ require('./build/archive')(Array.prototype.slice.apply(arguments));
+});
http://git-wip-us.apache.org/repos/asf/incubator-ripple/blob/5ef3754a/build/archive.js
----------------------------------------------------------------------
diff --git a/build/archive.js b/build/archive.js
new file mode 100644
index 0000000..2674aed
--- /dev/null
+++ b/build/archive.js
@@ -0,0 +1,274 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+var child_process = require('child_process'),
+ fs = require('fs'),
+ jWorkflow = require('jWorkflow'),
+ semver = require('semver'),
+ path = require('path'),
+ _c = require('./conf');
+
+module.exports = function (options) {
+ if (options.length === 1 && options[0].toLowerCase() === "help") {
+ usage(true);
+ return;
+ }
+
+ var config = processOptions(options);
+
+ var order = jWorkflow.order(verifyBuiltFiles)
+ .andThen(verifyTagName)
+ .andThen(checkoutTag);
+
+ if (!config.allowPending) {
+ order.andThen(checkPendingChanges);
+ }
+
+ order.andThen(buildPackage);
+
+ if (config.sign) {
+ order.andThen(signArchive)
+ .andThen(computeMd5Hash)
+ .andThen(computeShaHash);
+ }
+
+ order.start({initialValue: config, callback: done});
+};
+
+function done(result) {
+ if (!result || !result.failed) {
+ console.log('\nArchive created.');
+ }
+}
+
+function processOptions(options, baton) {
+ var packageType,
+ allowPending = false,
+ tagName = null;
+
+ options.forEach(function (option) {
+ var lowerCaseOption = option.toLowerCase();
+ switch (lowerCaseOption) {
+ case 'apache':
+ case 'npm':
+ if (packageType) {
+ error("Can't set package type to '" + option + "' when it is already set to '" + packageType + "'.", baton);
+ }
+ packageType = lowerCaseOption;
+ break;
+
+ case 'allow-pending':
+ allowPending = true;
+ break;
+
+ default:
+ if (tagName) {
+ error("Can't set tag name to '" + option + "' when it is already set to '" + tagName + "'.", baton);
+ }
+ tagName = option;
+ }
+ });
+
+ var isNpm = packageType === 'npm';
+ return {
+ tagName: tagName,
+ allowPending: !isNpm || allowPending, // Pending files irrelevant when package from git
+ sign: !isNpm,
+ packageType: isNpm ? 'npm' : 'git',
+ includeBuilt: isNpm
+ };
+}
+
+function verifyBuiltFiles(config, baton) {
+ // Require or remove built files
+ if (config.includeBuilt) {
+ // Verify pkg folder exists and contains files
+ if (!fs.existsSync(_c.DEPLOY) || fs.readdirSync(_c.DEPLOY).length === 0) {
+ error('You must build Ripple before creating npm package.', baton);
+ }
+ }
+ return config;
+}
+
+function verifyTagName(config, baton) {
+ baton.take();
+
+ if (config.tagName) {
+ baton.pass(config);
+ return;
+ }
+
+ // Determine the most recent tag in the repository
+ exec('git tag --list', baton, function (allTags) {
+ config.tagName = allTags.split(/\s+/).reduce(function (currentBest, value) {
+ var modifiedValue = value.replace(/^v/, '');
+ if (semver.valid(modifiedValue)) {
+ return !currentBest ? value : semver.gt(currentBest.replace(/^v/, ''), modifiedValue) ? currentBest : value;
+ }
+ if (currentBest) {
+ return currentBest;
+ }
+ return null;
+ });
+
+ baton.pass(config);
+ });
+}
+
+function checkoutTag(config, baton) {
+ baton.take();
+
+ if (!config.tagName) {
+ error("Couldn't find the most recent tag name - please specify a tag or branch explicitly.", baton);
+ }
+
+ // Don't checkout the tag if its already checked out
+ exec('git symbolic-ref -q --short HEAD || git describe --tags --exact-match', baton, function (currentBranch) {
+ if (currentBranch === config.tagName) {
+ baton.pass(config);
+ return;
+ }
+
+ exec('git checkout -q ' + config.tagName, baton, function (result) {
+ baton.pass(config);
+ });
+ });
+}
+
+function checkPendingChanges(config, baton) {
+ baton.take();
+
+ if (config.allowPending) {
+ baton.pass(config);
+ }
+
+ exec('git status --porcelain', baton, function (result) {
+ if (result) {
+ error('Aborting because there are pending changes.', baton);
+ } else {
+ baton.pass(config);
+ }
+ });
+}
+
+function buildPackage(config, baton) {
+ baton.take();
+
+ console.log('Creating archive for tag: ' + config.tagName + '...');
+
+ if (config.packageType === 'npm') {
+ exec('npm pack', baton, function (filename, err) {
+ baton.pass(filename);
+ });
+ } else {
+ var filenameRoot = 'ripple-emulator' + '-' + config.tagName + '-incubating';
+ var filename = path.resolve(filenameRoot + '.tgz');
+ exec('git archive --prefix ' + filenameRoot + '/ -o ' + filename + ' ' + config.tagName, baton, function (result) {
+ baton.pass(filename);
+ });
+ }
+}
+
+function signArchive(filename, baton) {
+ baton.take();
+
+ console.log('Signing archive...');
+ exec('gpg --armor --detach-sig --output ' + filename + '.asc ' + filename, baton, function (result) {
+ baton.pass(filename);
+ });
+}
+
+function computeMd5Hash(filename, baton) {
+ computeHash(filename, 'md5', 'MD5', baton);
+}
+
+function computeShaHash(filename, baton) {
+ computeHash(filename, 'sha', 'SHA512', baton);
+}
+
+function computeHash(filename, ext, algo, baton) {
+ baton.take();
+
+ console.log('Computing ' + algo + ' for: ' + filename);
+ exec('gpg --print-md ' + algo + ' ' + filename, baton, function (result) {
+ fs.writeFileSync(filename + '.' + ext, extractHashFromOutput(result) + '\n');
+ baton.pass(filename);
+ });
+
+}
+
+function extractHashFromOutput(output) {
+ return output.slice(output.lastIndexOf(':') + 1).replace(/\s*/g, '').toLowerCase();
+}
+
+function exec(cmdLine, baton, callback) {
+ // If we're provided with a jWorkflow baton, then on error we'll use the baton to deal with it and not call callback().
+ // Otherwise we pass errors to callback().
+
+ if (!callback && typeof baton === 'function') {
+ callback = baton;
+ baton = null;
+ }
+
+ child_process.exec(cmdLine, function (err, stdout, stderr) {
+ var err = err || stderr;
+ err && baton ? error(err, baton) : callback((stdout || '').trim(), err);
+ });
+}
+
+function error(msg, baton) {
+ console.log();
+
+ if (typeof msg === 'object') {
+ // Error came from console or somewhere. Just display it.
+ console.log('' + msg);
+ } else {
+ // Error likely came from us - display it and also usage.
+ console.log('Error: ' + msg);
+ usage();
+ }
+
+ baton && baton.drop({failed: true});
+}
+
+function usage(includeIntro) {
+ if (includeIntro) {
+ console.log('');
+ console.log('Creates a tgz file for a tag or branch, either for the Apache archives or npm.');
+ }
+
+ console.log('');
+ console.log('Usage:');
+ console.log('');
+ console.log('jake archive[apache|npm,allow-pending,<tagname>]');
+ console.log('');
+ console.log(' apache: (default) Create an Apache archive (creates a git archive,\n' +
+ ' signs it, and creates .md5 and .sha hashes).');
+ console.log(' npm: Create an npm package (requires built files to be present,\n' +
+ ' and does not sign).');
+ console.log(' allow-pending: If specified, allow uncommitted changes to exist when\n' +
+ ' packaging (only use this for testing). This option is\n' +
+ ' ignored when creating an Apache archive, since that is created\n' +
+ ' directly from git.');
+ console.log(' <tagname>: If specified, an existing tag or branch to archive. Otherwise\n' +
+ ' defaults to the most recent tag.');
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-ripple/blob/5ef3754a/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index ef8b604..23cc9b7 100644
--- a/package.json
+++ b/package.json
@@ -27,23 +27,24 @@
"bin": { "ripple": "./bin/ripple" },
"main": "./lib/index",
"dependencies": {
- "express": "3.1.0",
+ "accounting": "0.x.x",
+ "colors": "0.6.0-1",
"connect-xcors": "0.5.2",
- "request": "2.12.0",
- "colors" : "0.6.0-1",
- "moment" : "1.x.x",
- "accounting" : "0.x.x",
- "open": "0.0.3"
+ "express": "3.1.0",
+ "moment": "1.x.x",
+ "open": "0.0.3",
+ "request": "2.12.0"
},
"devDependencies": {
+ "bower": "0.9.x",
"connect": "2.3.6",
- "jsdom": "0.6.x",
+ "coverjs": "0.0.14",
"cssmin": "0.3.1",
"html-minifier": "0.4.5",
+ "jsdom": "0.6.x",
"jWorkflow": "0.x.x",
- "xmlhttprequest": "1.4.2",
- "coverjs": "0.0.14",
- "bower": "0.9.x"
+ "semver": "^4.3.1",
+ "xmlhttprequest": "1.4.2"
},
"files": [
"README.md",