mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-25 06:09:50 +00:00
Update release-notes script
This commit is contained in:
parent
00626b9b02
commit
403b2c2257
@ -1,4 +1,4 @@
|
||||
/* radare - LGPL - Copyright 2012-2014 - pancake */
|
||||
/* radare - LGPL - Copyright 2012-2016 - pancake */
|
||||
|
||||
#include <r_anal.h>
|
||||
|
||||
@ -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);
|
||||
|
@ -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 ");
|
||||
|
@ -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;
|
375
sys/release-notes/index.js
Executable file
375
sys/release-notes/index.js
Executable file
@ -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();
|
6
sys/release-notes/package.json
Normal file
6
sys/release-notes/package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"ascii-table": "*"
|
||||
},
|
||||
"version": "0.1.0"
|
||||
}
|
Loading…
Reference in New Issue
Block a user