mirror of https://github.com/lukechilds/node.git
Browse Source
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
5 changed files with 961 additions and 595 deletions
File diff suppressed because it is too large
@ -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); |
|||
} |
@ -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!'); |
|||
} |
|||
}); |
@ -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…
Reference in new issue