From 403b2c2257f4e96a6a4bb7d1d3ab115ee4993fc0 Mon Sep 17 00:00:00 2001 From: pancake Date: Tue, 24 May 2016 01:12:22 +0200 Subject: [PATCH] Update release-notes script --- libr/anal/data.c | 4 +- libr/anal/fcn.c | 3 +- sys/release-notes.js | 183 ---------------- sys/release-notes/index.js | 375 +++++++++++++++++++++++++++++++++ sys/release-notes/package.json | 6 + 5 files changed, 385 insertions(+), 186 deletions(-) delete mode 100644 sys/release-notes.js create mode 100755 sys/release-notes/index.js create mode 100644 sys/release-notes/package.json diff --git a/libr/anal/data.c b/libr/anal/data.c index 5de2083db3..7aa765903b 100644 --- a/libr/anal/data.c +++ b/libr/anal/data.c @@ -1,4 +1,4 @@ -/* radare - LGPL - Copyright 2012-2014 - pancake */ +/* radare - LGPL - Copyright 2012-2016 - pancake */ #include @@ -95,7 +95,7 @@ R_API char *r_anal_data_to_string(RAnalData *d) { line = malloc (mallocsz); if (!line) { - eprintf ("Cannot allocate %"PFMT64d" bytes\n", mallocsz); + eprintf ("Cannot allocate %d bytes\n", mallocsz); return NULL; } snprintf (line, mallocsz, "0x%08" PFMT64x " ", d->addr); diff --git a/libr/anal/fcn.c b/libr/anal/fcn.c index 26db90f3d2..ad7c752292 100644 --- a/libr/anal/fcn.c +++ b/libr/anal/fcn.c @@ -1249,7 +1249,8 @@ R_API int r_anal_str_to_fcn(RAnal *a, RAnalFunction *f, const char *sig) { /* Add 'function' keyword */ str = malloc (strlen(sig) + 10); if (!str) { - eprintf ("Cannot allocate %d bytes\n", strlen(sig) + 10); + const int length = strlen (sig) + 10; + eprintf ("Cannot allocate %d bytes\n", length); return false; } strcpy (str, "function "); diff --git a/sys/release-notes.js b/sys/release-notes.js deleted file mode 100644 index 7268a40711..0000000000 --- a/sys/release-notes.js +++ /dev/null @@ -1,183 +0,0 @@ -'use strict'; - -var exec = require('child_process').exec; -var spawn = require('child_process').spawn; -function execute(command, cb){ - let output = ''; - function callback(error, stdout, stderr) { - cb(stdout); - } - exec (command, { maxBuffer: 1024*1024*1024 }, callback) -}; - -function getDifflines(upto, path, cb) { - if (typeof upto === 'function') { - cb = upto; - path = ''; - upto = ''; - } else if (typeof path === 'function') { - cb = path; - path = ''; - } - execute('git diff '+upto+'..@ '+path, (log) => { - let o = { - add: 0, - del: 0 - }; - for (let line of log.split(/\n/g)) { - if (line.match(/^\+/)) { - o.add ++; - } else if (line.match(/^-/)) { - o.del ++; - } - } - o.diff = o.add - o.del; - cb (o); - }); -} - -function getChangelog(upto, path, cb) { - if (typeof upto === 'function') { - cb = upto; - path = ''; - upto = ''; - } else if (typeof path === 'function') { - cb = path; - path = ''; - } - execute('git log '+upto+'..@ '+path, (log) => { - let o = { - upto: upto, - path: path, - authors: {}, - commits: [] - }; - const lines = log.split('\n'); - let date = null; - let commit = null; - let message = ''; - for (let line of lines) { - if (line.match("^Author")) { - const author = line.substring(8); - if (o.authors[author] === undefined) { - o.authors[author] = 1; - } else o.authors[author]++; - } else if (line.match("^Date:")) { - date = line.substring(8); - } else if (line.match("^commit")) { - if (commit !== null) { - var doh = { - hash: commit, - date: date, - msg: message.trim() - }; - o.commits.push(doh); - message = ''; - date = ''; - } - commit = line.substring(7); - } else if (line[0] == ' ') { - message += line + '\n'; - } - } - cb (o); - }); -} - -function countWord(x,y) { - let count = 0; - for (let a of x) { - if (a.msg.match(y)) { - count++; - } - } - return count; -} - -function computeStats(o) { - return { - commits: o.commits.length, - fix: countWord(o.commits, /fix/i), - crash: countWord(o.commits, /crash/i), - 'new': countWord(o.commits, /new/i), - add: countWord(o.commits, /add/i), - anal: countWord(o.commits, /anal/i), - leak: countWord(o.commits, /leak/i), - esil: countWord(o.commits, /esil/i), - enhance: countWord(o.commits, /enhance/i), - } -} - -function computeRanking(o) { - let r = []; - for (let a in o.authors) { - r.push(o.authors[a]+ ' '+a); - // console.log(a); - } - r = r.sort(function(a, b) { - a = +((a.split(' ')[0])); - b = +((b.split(' ')[0])); - return (a < b) ? 1 : -1; - }); - return { - count: Object.keys(o.authors).length, - authors: r - }; -} - -String.prototype.repeat = function(times) { - return (new Array(times + 1)).join(this); -}; - -function printMdList(md_list, list_level) { - var elems = Object.keys(md_list); - elems.forEach(function(elem) { - if (typeof md_list[elem] === "object") { - console.log("\t".repeat(list_level) + "- " + elem + ":"); - return printMdList(md_list[elem], list_level + 1); - } else { - var elem_name = isNaN(elem) ? (elem + ": ") : ""; - console.log ("\t".repeat(list_level) + "- " + elem_name + md_list[elem]); - } - }); -} - -const last_tag = '0.10.1'; - -const paths = [ - '', // total - 'binr/r2pm/d', - 'libr/debug', - 'libr/bin', - 'libr/core', - 'libr/crypto', - 'libr/cons', - 'libr/anal', - 'libr/asm', - 'man', -]; - -var count = 0; -var doner = []; -var ready = false; - -for (let one_path of paths) { - count ++; - getChangelog(last_tag, one_path, function(o) { - getDifflines(last_tag, one_path, function(d) { - let r = computeStats (o); - r.path = one_path; - r.rank = computeRanking (o); - r.diff = d; - doner.push (r); - count --; - if (count == 0 && ready) { - for(let one_doner of doner) { - printMdList(one_doner, 0); - console.log("\n"); - } - } - }); - }); -} -ready = true; diff --git a/sys/release-notes/index.js b/sys/release-notes/index.js new file mode 100755 index 0000000000..0cbabd7c6d --- /dev/null +++ b/sys/release-notes/index.js @@ -0,0 +1,375 @@ +#!/usr/bin/env node +'use strict'; + +const exec = require('child_process').exec; +const spawn = require('child_process').spawn; +const AsciiTable = require('ascii-table'); + +const lastTag = '0.10.2'; +const curVersion = '0.10.3'; +const showOnlyFinalReport = true; +const codeName = 'Tooth'; +const topTen = 0; +const topFive = 999; + +const authorAlias = { + 'sirmy15': 'ret2libc', + 'ahmedsoliman0x666': 'oddcoder', + 'jroi.martin': 'nibble', + 'ayman.khamouma': 'ayman', + 'rlaemmert': 'defragger', + 'maijin21': 'maijin', + 'krytarowski': 'kamil', + 'rakholiyajenish.07': 'p4n74', + 'P4N74': 'p4n74', + 'damien': 'damo22', + 'alvaro.felipe91': 'alvarofe', + 'lol': 'gk', + 'github.jdrake': 'jduck', + 'andrey.torsunov': 'torsunov', + 'gautier.colajanni': 'gautier', + 'davide.balzarotti': 'davide', + 'eternalsushant': 'sushant', + 'Qwokka': 'qwokka', + 'naveenboggarapu': 'naveen', + 'anton.kochkov': 'xvilka', + 'a.kochkov': 'xvilka', + 'incredible.angst': 'kolen', +}; + +const columns = [ 'name', 'commits', 'fix', 'add', 'leak', 'update', 'r2pm', 'clean', 'esil', 'endian', 'commits', 'authors' ]; + +const paths = [ + '', // total + 'binr/r2pm/d', + 'binr/radare2', + 'binr/rabin2', + 'binr/radiff2', + 'binr/rahash2', + 'binr/ragg2', + 'libr/hash', + 'libr/debug', + 'libr/bin', + 'libr/core', + 'libr/crypto', + 'libr/cons', + 'libr/anal', + 'libr/asm', + 'libr/util', + 'libr/bp', + 'libr/egg', +/* + 'libr/flags', + 'libr/diff', + 'libr/search', + 'shlr/sdb', +*/ + 'shlr/tcc', + 'shlr/bochs', + 'man', +]; + +function execute(command, cb){ + let output = ''; + function callback(error, stdout, stderr) { + cb(stdout); + } + exec (command, { maxBuffer: 1024 * 1024 * 1024 }, callback); +}; + +function getDifflines(upto, path, cb) { + if (typeof upto === 'function') { + cb = upto; + path = ''; + upto = ''; + } else if (typeof path === 'function') { + cb = path; + path = ''; + } + execute('git diff '+upto+'..@ '+path, (log) => { + const o = { + add: 0, + del: 0 + }; + for (let line of log.split(/\n/g)) { + if (line.match(/^\+/)) { + o.add ++; + } else if (line.match(/^-/)) { + o.del ++; + } + } + o.diff = o.add - o.del; + cb (o); + }); +} + +function getChangelog(upto, path, cb) { + path = __dirname + '/../../' + path; + if (typeof upto === 'function') { + cb = upto; + path = ''; + upto = ''; + } else if (typeof path === 'function') { + cb = path; + path = ''; + } + execute('git log '+upto+'..@ '+path, (log) => { + let o = { + upto: upto, + path: path, + authors: {}, + commits: [] + }; + const lines = log.split('\n'); + let date = null; + let commit = null; + let message = ''; + for (let line of lines) { + if (line.match('^Author')) { + const realname = line.substring(8); + const author = renderAuthor(realname); + if (o.authors[author] === undefined) { + o.authors[author] = 1; + } else o.authors[author]++; + } else if (line.match('^Date:')) { + date = line.substring(8); + } else if (line.match('^commit')) { + if (commit !== null) { + const doh = { + hash: commit, + date: date, + msg: message.trim() + }; + o.commits.push(doh); + message = ''; + date = ''; + } + commit = line.substring(7); + } else if (line[0] == ' ') { + message += line.trim() + '\n'; + } + } + cb (o); + }); +} + +function countWord(x,y) { + let count = 0; + for (let a of x) { + if (a.msg.match(y)) { + count++; + } + } + return count; +} + +function computeStats(o) { + return { + commits: o.commits.length, + fix: countWord(o.commits, /fix/i), + crash: countWord(o.commits, /crash/i), + 'new': countWord(o.commits, /new/i), + add: countWord(o.commits, /add/i), + anal: countWord(o.commits, /anal/i), + leak: countWord(o.commits, /leak/i), + esil: countWord(o.commits, /esil/i), + debug: countWord(o.commits, /debug/i), + type: countWord(o.commits, /type/i), + oob: countWord(o.commits, /oob/i), + honor: countWord(o.commits, /honor/i), + update: countWord(o.commits, /update/i), + r2pm: countWord(o.commits, /r2pm/i), + clean: countWord(o.commits, /clean/i), + 'import': countWord(o.commits, /import/i), + endian: countWord(o.commits, /endian/i), + indent: countWord(o.commits, /indent/i), + command: countWord(o.commits, /command/i), + enhance: countWord(o.commits, /enhance/i), + } +} + +function computeRanking(o) { + let r = []; + for (let a in o.authors) { + r.push(o.authors[a]+ ' '+a); + // console.log(a); + } + r = r.sort(function(a, b) { + a = +((a.split(' ')[0])); + b = +((b.split(' ')[0])); + return (a < b) ? 1 : -1; + }); + if (topTen > 0) { + r = r.slice(0, topTen); + } + return { + count: Object.keys(o.authors).length, + authors: r + }; +} + +String.prototype.repeat = function(times) { + return (new Array(times + 1)).join(this); +}; + +function printMdList(mdList, listLevel) { + const elems = Object.keys(mdList); + elems.forEach(function(elem) { + if (elem === 'priv' || elem == 'path') { + return; + } + if (typeof mdList[elem] === 'object') { + console.log('\t'.repeat(listLevel) + '- ' + elem + ':'); + return printMdList(mdList[elem], listLevel + 1); + } else { + const elemName = isNaN(elem) ? (elem + ': ') : ''; + console.log ('\t'.repeat(listLevel) + '- ' + elemName + mdList[elem]); + } + }); +} + +function findStatsFor(as, x) { + for (let c of as) { + if (c.path == x) { + return c; + } + } + return undefined; +} + +function renderAuthor(str) { + for (let k in authorAlias) { + const v = authorAlias[k]; + if (str.indexOf (k) != -1) { + return v; + // return str.replace(k, v); + } + } + const res = str.match(/<([^@]*)/g); + if (res !== null) { + return res[0].substring(1).replace('@', '').trim(); + } + return str; +} + +function getAuthor(str) { + const space = str.indexOf(' '); + if (space !== -1) { + return str.substring(space).trim(); + } + return str; +} + +var first = true; + +function printFinalReportTable(obj) { + function getFinalReportFor(x) { + const arr = []; + arr.push(x); + let o = findStatsFor(obj, x); + for (let col of columns.slice(1)) { + const ocol = o[col]; + if (typeof ocol === 'undefined') { + if (first) { + first = false; + } else { + let last = topFive; + let auth = ''; + for (let a of o.ranking.authors) { + auth += getAuthor(a) + ' '; + if (!last--) break; + } + arr.push (auth); + } + } else { + arr.push (o[col]); + } + } + return arr; + } + const table = new AsciiTable('Release ' + curVersion) + paths.forEach((path) => { + table.addRow(getFinalReportFor(path)); + }); + table.setHeading(columns); + + console.log('```'); + console.log(table.toString()) + console.log('```'); +} + +function getLogMessages(x) { + let msg = ''; + for (let m of x) { + msg += m.msg; + } + return msg; +} + +function main() { + let count = 0; + let doner = []; + let ready = false; + + console.log('Release ' + curVersion); + console.log('=============='); + console.log(); + console.log('Project: radare2'); + console.log('Codename: ' + codeName); + console.log('Date: ' + new Date().toString()); + console.log('Website: http://radare.org'); + console.log('Tarball: https://github.com/radare/radare2/releases'); + + for (let onePath of paths) { + count ++; + getChangelog(lastTag, onePath, function(o) { + getDifflines(lastTag, onePath, function(d) { + let r = computeStats (o); + r.path = onePath; + r.ranking = computeRanking (o); + r.diff = d; + r.priv = { + commits: o.commits + }; + doner.push (r); + count --; + if (count == 0 && ready) { + if (!showOnlyFinalReport) { + for (let oneDoner of doner) { + printMdList(oneDoner, 0); + console.log('\n'); + } + } + for (let oneDoner of doner) { + if (oneDoner.path == '') { + console.log(); + console.log('Numbers:'); + console.log('--------'); + let r = oneDoner.ranking; + oneDoner.ranking = {}; + printMdList(oneDoner, 0); + oneDoner.ranking = r; + printFinalReportTable(doner); + console.log(); + console.log('Contributors:'); + console.log('-------------'); + console.log(); + printMdList(oneDoner.ranking.authors, 0); + console.log(); + console.log('Changes:'); + console.log('--------'); + console.log(); + console.log('Commits:'); + console.log('--------'); + const logMessages = getLogMessages(oneDoner.priv.commits); + console.log(logMessages); + } + } + } + }); + }); + } + ready = true; +} + +main(); diff --git a/sys/release-notes/package.json b/sys/release-notes/package.json new file mode 100644 index 0000000000..b73f2ae1a4 --- /dev/null +++ b/sys/release-notes/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "ascii-table": "*" + }, + "version": "0.1.0" +}