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",