Browse Source

tools: improve tooling around AUTHORS file

Replace tools/updateAuthors.awk with tools/update-authors.js. The new
tool generates an AUTHORS file that is stable-ordered alphanumerically.

Fixes #9077.

PR: #9088
PR-URL: https://github.com/joyent/node/pull/9088
Reviewed-By: Timothy J Fontaine <tjfontaine@gmail.com>
v0.12.0-release
Julien Gilli 10 years ago
parent
commit
31610d0db4
  1. 12
      .mailmap
  2. 1238
      AUTHORS
  3. 149
      tools/common.js
  4. 144
      tools/update-authors.js
  5. 13
      tools/updateAuthors.awk

12
.mailmap

@ -2,6 +2,8 @@ Aaron Heckmann <aaron.heckmann@gmail.com> <aaron.heckmann+github@gmail.com>
Abe Fettig <abefettig@gmail.com> <abe@fettig.net>
Alex Kocharin <rlidwka@kocharin.ru>
Alex Kocharin <rlidwka@kocharin.ru> <alex@kocharin.ru>
Alexey Kupershtokh <wicked@alawar.com>
Alexis Campailla <orangemocha@github.com>
Alexis Sellier <self@cloudhead.net>
Alexis Sellier <self@cloudhead.net> <alexis@cloudhead.io>
Arlo Breault <arlolra@gmail.com>
@ -13,10 +15,12 @@ Bert Belder <bertbelder@gmail.com> <bert@piscisaureus2.(none)>
Bert Belder <bertbelder@gmail.com> <info@2bs.nl>
Bert Belder <bertbelder@gmail.com> <piscisaureus@Berts-MacBook-Pro.local>
Brandon Benvie <brandon@bbenvie.com> <brandon@brandonbenvie.com>
Brandon Cheng <bcheng.gt@gmail.com>
Brian White <mscdex@mscdex.net>
Brian White <mscdex@mscdex.net> <mscdex@gmail.com>
Chew Choon Keat <choonkeat@gmail.com>
Christopher Lenz <cmlenz@gmail.com> <chris@lamech.local>
Colin Ihrig <cjihrig@gmail.com>
Daniel Berger <code+node@dpbis.net>
Daniel Chcouri <333222@gmail.com>
Daniel Gröber <darklord@darkboxed.org>
@ -25,6 +29,7 @@ Daniel Pihlström <sciolist.se@gmail.com>
Dave Pacheco <dap@joyent.com> <dap@cs.brown.edu>
David Siegel <david@artcom.de> <david.siegel@artcom.de>
Domenic Denicola <domenic@domenicdenicola.com>
Doron Pagot <doronpagot@gmail.com>
Eduard Burtescu <eddy_me08@yahoo.com>
Einar Otto Stangvik <einaros@gmail.com>
Elliott Cable <me@ell.io>
@ -38,6 +43,7 @@ Friedemann Altrock <frodenius@gmail.com>
Fuji Goro <gfuji@cpan.org>
Gabriel de Perthuis <g2p.code@gmail.com>
Gil Pedersen <git@gpost.dk> <github@gpost.dk>
Guillaume Goussard <guillaume.goussard@mgo.com>
Henry Chin <hheennrryy@gmail.com>
Herbert Vojčík <herby@mailbox.sk>
Igor Soarez <igorsoarez@gmail.com>
@ -46,6 +52,7 @@ Isaac Z. Schlueter <i@izs.me>
Isaac Z. Schlueter <i@izs.me> <i@foohack.com>
Jake Verbaten <raynos2@gmail.com>
Jered Schmidt <tr@nslator.jp>
Jochen Eisinger <jochen@chromium.org>
Joe Shaw <joe@joeshaw.org> <joeshaw@litl.com>
Johan Bergström <bugs@bergstroem.nu>
Johan Dahlberg <jfd@distrop.com> <dahlberg.johan@gmail.com>
@ -69,6 +76,7 @@ Micheil Smith <micheil@brandedcode.com> <micheil@yettobebranded.net>
Mikael Bourges-Sevenier <mikeseven@gmail.com> <msevenier@motorola.com>
Nebu Pookins<nebu@nebupookins.net>
Nicholas Kinsey <pyrotechnick@feistystudios.com>
Nicholas Vavilov <vvnicholas@gmail.com>
Onne Gorter <onne@onnlucky.com>
Paul Querna <pquerna@apache.org> <paul@querna.org>
Ray Morgan <rmorgan@zappos.com>
@ -104,8 +112,10 @@ Trevor Burnham <trevor@databraid.com> <trevorburnham@gmail.com>
Tyler Larson <talltyler@gmail.com>
Vincent Voyer <v@fasterize.com>
Willi Eggeling <email@wje-online.de>
Yiyu He <dead_horse@qq.com>
Yoshihiro KIKUCHI <yknetg@gmail.com>
Yuichiro MASUI <masui@masuidrive.jp>
Yunsong Guo <eilian.yunsong@gmail.com>
Zachary Scott <zachary@zacharyscott.net> <zachary.s.scott@gmail.com>
Zoran Tomicic <ztomicic@gmail.com>
@ -120,3 +130,5 @@ Michael Starzinger <mstarzinger@chromium.org>
Toon Verwaest <verwaest@chromium.org>
Vyacheslav Egorov <vegorov@chromium.org>
Yang Guo <yangguo@chromium.org>
Dan Carney <dcarney@chromium.org>
Sven Panne <svenpanne@chromium.org>

1238
AUTHORS

File diff suppressed because it is too large

149
tools/common.js

@ -0,0 +1,149 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var assert = require('assert');
/*
* stableSort sorts the array "array" using the predicate "compare" in a
* stable way.
* It returns a new object that represents the sorted array.
*/
function stableSort(array, compare) {
assert(Array.isArray(array), 'array must be an array');
if (!compare) {
compare = defaultCompare;
}
assert(typeof compare === 'function', 'compare must be a function');
var indexedArray = array.map(function addIndex(item, index) {
return { v: item, i: index };
});
function defaultCompare(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
indexedArray.sort(function stableCompare(a, b) {
var r = compare(a.v, b.v);
if (r === 0) {
return a.i - b.i;
} else {
return r;
}
});
return indexedArray.map(function removeIndex(item) {
return item.v;
});
}
exports.stableSort = stableSort;
if (module === require.main) {
/*
* The following code is a tests suite that makes sure that:
* 1) The default sort implementation of the Node.js JavaScript runtime (V8)
* is not stable.
* 2) The "stableSort" function above provides a stable sort.
*/
function standardSort(array, compare) {
var dupArray = array.splice(0);
dupArray.sort(compare);
return dupArray;
}
function testSortStability(count, bins, sortFunc) {
var unstable = false;
for (var iter = 0; iter < 10; ++iter) {
var array = [];
for (var i = 0; i < count; ++i)
array.push({ u: Math.floor(Math.random() * bins), i: i });
array = sortFunc(array, function(a, b) { return a.u - b.u });
var u = -1, i = -1;
for (var ii = 0; ii < count; ++ii) {
var v = array[ii];
if (v.u > u) {
u = v.u; i = -1;
} else if (v.i > i) {
i = v.i;
} else {
return false;
}
}
}
return true;
}
var stableSortMsg = "Stable sort should be stable for all arrays";
var standardSmallArrayMsg = "Standard sort should be stable for small arrays";
var standardUnstableMsg = "Standard sort should NOT be stable for non-small arrays";
var stableSorts = [
{ count: 5, bins: 2, sort: standardSort, msg: standardSmallArrayMsg },
{ count: 10, bins: 3, sort: standardSort, msg: standardSmallArrayMsg },
{ count: 5, bins: 2, sort: stableSort, msg: stableSortMsg },
{ count: 10, bins: 3, sort: stableSort, msg: stableSortMsg },
{ count: 11, bins: 3, sort: stableSort, msg: stableSortMsg },
{ count: 12, bins: 3, sort: stableSort, msg: stableSortMsg },
{ count: 13, bins: 3, sort: stableSort, msg: stableSortMsg },
{ count: 14, bins: 3, sort: stableSort, msg: stableSortMsg },
{ count: 15, bins: 3, sort: stableSort, msg: stableSortMsg },
{ count: 20, bins: 3, sort: stableSort, msg: stableSortMsg },
{ count: 50, bins: 3, sort: stableSort, msg: stableSortMsg },
{ count: 100, bins: 4, sort: stableSort, msg: stableSortMsg },
{ count: 1000, bins: 4, sort: stableSort, msg: stableSortMsg },
{ count: 10000, bins: 4, sort: stableSort, msg: stableSortMsg },
];
var unstableSorts = [
{ count: 11, bins: 3, sort: standardSort, msg: standardUnstableMsg },
{ count: 12, bins: 3, sort: standardSort, msg: standardUnstableMsg },
{ count: 13, bins: 3, sort: standardSort, msg: standardUnstableMsg },
{ count: 14, bins: 3, sort: standardSort, msg: standardUnstableMsg },
{ count: 15, bins: 3, sort: standardSort, msg: standardUnstableMsg },
{ count: 20, bins: 3, sort: standardSort, msg: standardUnstableMsg },
{ count: 50, bins: 4, sort: standardSort, msg: standardUnstableMsg },
{ count: 100, bins: 4, sort: standardSort, msg: standardUnstableMsg },
{ count: 1000, bins: 4, sort: standardSort, msg: standardUnstableMsg },
{ count: 10000, bins: 4, sort: standardSort, msg: standardUnstableMsg },
];
function runTests(tests, stability) {
tests.forEach(function(test) {
console.log('Running test with sort: %s, count: %s, bins: %s',
test.sort.name, test.count, test.bins);
assert.equal(testSortStability(test.count, test.bins, test.sort),
stability,
test.msg);
});
}
runTests(stableSorts, true);
runTests(unstableSorts, false);
}

144
tools/update-authors.js

@ -0,0 +1,144 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
/*
* This script updates the AUTHORS so that it contains a list of contributors'
* names ordered alphabetically. The sorting algorithm used is stable, see
* function "stableSort" in tools/common.js.
*/
'use strict';
var child_process = require('child_process');
var fs = require('fs');
var assert = require('assert');
var util = require('util');
var path = require('path');
var os = require('os');
var debug = util.debuglog('update-authors');
var commonTools = require(path.join(__dirname, './common.js'));
// Use '%aN <%aE>' and not '%an <%ae>' as we want to have git log use the
// .mailmap file.
var GIT_LOG_COMMAND_ARGS = ['log', "--format='%aN <%aE>'"];
var MAILMAP_FILE = '.mailmap';
var OPTS = processCmdLineArgs();
var AUTHORS_FILE = OPTS.authorsFile || 'AUTHORS';
var PLATFORM_AGNOSTIC_EOL = /\r|\n|\r\n/;
var authorsMap = {};
function usage() {
console.log('Usage: [NODE_DEBUG=update-authors] ./node update-authors.js ' +
' [-a AUTHORS-FILE]');
process.exit(1);
}
function processCmdLineArgs() {
var cmdLineOpts = {};
var cmdLineArgs = process.argv.splice(2);
for (var i = 0; i < cmdLineArgs.length; ++i) {
if (cmdLineArgs[i] === '-a') {
if (!cmdLineArgs[++i]) {
usage();
} else {
cmdLineOpts.authorsFile = cmdLineArgs[i];
}
} else {
usage();
}
}
return cmdLineOpts;
}
function generateAuthorsFile(authorsFilePath, cb) {
assert(typeof authorsFilePath === 'string',
'authorsFilePath must be a string');
var sortedAuthorsNames = commonTools.stableSort(Object.keys(authorsMap));
var authorsFileContent = sortedAuthorsNames.join('\n') + '\n';
fs.writeFile(authorsFilePath, authorsFileContent, cb);
}
var latestAuthorsLineChunk = '';
function addAuthors(authors) {
assert(typeof authors === 'string', 'authors must be a string');
var authors = (latestAuthorsLineChunk + authors).split(PLATFORM_AGNOSTIC_EOL);
latestAuthorsLineChunk = '';
authors.forEach(function eachAuthor(author) {
if (author && author.length > 0) {
var matches = author.match(/^'([^<>]*)\s+<.*>'$/);
if (matches) {
var authorName = matches[1];
debug('MATCHING: ' + authorName);
authorsMap[authorName] = 1;
} else {
debug('NOT MATCHING: ' + author);
latestAuthorsLineChunk = author;
}
}
});
}
function loadAuthorsFromGitLog(cb) {
var gitLog = child_process.spawn('git', GIT_LOG_COMMAND_ARGS);
gitLog.on('close', function onGitLogClose(exitCode, signal) {
if (exitCode === 0 && signal === null) {
debug('NB AUTHORS:' + Object.keys(authorsMap).length);
generateAuthorsFile(AUTHORS_FILE, function onAuthorsFileGenerated(err) {
if (err) {
return cb(new Error('Error when generating authors file:', err));
} else {
console.log('Authors file generated successfully!');
}
});
}
});
gitLog.on('error', function onGitLogError(err) {
var errorMsg = util.format('Error when executing command %s: %s',
GIT_LOG_COMMAND, err);
return cb(new Error(errorMsg));
});
gitLog.stdout.on('data', function onGitLogData(data) {
addAuthors(data.toString());
});
}
loadAuthorsFromGitLog(function done(err) {
if (err) {
console.error('Error when updating authors file:', err);
} else {
console.log('Updated authors file successfully!');
}
});

13
tools/updateAuthors.awk

@ -1,13 +0,0 @@
# git log --pretty='format:%ae %an' | tac | awk -f tools/updateAuthors.awk
{
if (!x[$1]++) {
#print $0
n = split($0, a, " ");
s = a[2];
for (i = 3; i <= n ; i++) {
s = s " " a[i];
}
print s " <" $1 ">";
}
}
Loading…
Cancel
Save