<?php
// parsecvs.php - Platon SDG CVS commit reports prettyfier
// Developed by Martin Karas <wolcano@pobox.sk>
// Tag support by Ondrej Jombik <nepto@php.net> [11/1/2003]
// Copyright (c) 2002-2003 Platon SDG, http://www.platon.sk/
// Licensed under terms of GNU General Public License
// $Platon: scripts/php/parsecvs/parsecvs.php,v 1.26 2005-02-07 22:38:46 rajo Exp $
#
# CONSTANTS
#
// Specify input/output streams (ie. files, sockets or std's)
$input_file = 'php://stdin';
$output_file = 'php://stdout';
// Made more liberal (20 compulsory dashes, others are arbitrary)
// old: $begin_line = '----------------------------------------------';
$begin_line = '--------------------[-]*';
$msg_log_begin = '^Log Message:';
$date_format = '^([A-Z][a-z]{2} *)?([A-Z][a-z]{2} *[0-9]+ *' .
'[0-9]{2}:[0-9]{2}:[0-9]{2}) *CES?T *([0-9]{4})';
$user_format = '^CVSUSER=([0-9a-zA-Z]*)';
$directory_format = '^In directory';
$project_name_format = '^Update of /home/cvs/(.*)';
$cvsweblink_format = '^(http:[^ ]*)';
$tag_oper_begin = '^Tag operation: (.*)$';
$tag_name_begin = '^Tag name: (.*)$';
$add_files_begin = '^Added Files:';
$mod_files_begin = '^Modified Files:';
$del_files_begin = '^Removed Files:';
$in_file_list = "^(\t| )";
$project_head = '--[ Project %s ]--';
$project_head_folding_char = '-';
$sub_projects_separator = "----\n";
$log_message_folding = ' ';
#
# FUNCTIONS
#
function my_array_walk($x)
{
// This will do array_unique() on third-level values of $x
$ik = array_keys($x);
for ($i = 0; $i < sizeof($ik); $i++) {
$jk = array_keys($x[$ik[$i]]);
for ($j = 0; $j < sizeof($jk); $j++)
if (is_array($x[$ik[$i]][$jk[$j]])) {
/* To prevent merging [0] => array(), [1] => array(), ...
into one [0] => array(). Note that merging algorithm
in array_unique() is string-based, thus it saw
[0] => 'Array', [1] => 'Array', ... and it logically
merge it into one [0] => 'Array'. However, this is not
desirable for us.
-- Nepto [11/1/2003] */
$all_values_are_arrays = true;
foreach ($x[$ik[$i]][$jk[$j]] as $val) {
if (! is_array($val)) {
$all_values_are_arrays = false;
break;
}
}
// Skip merging process if all values are arrays
if (! $all_values_are_arrays) {
$x[$ik[$i]][$jk[$j]] = array_unique($x[$ik[$i]][$jk[$j]]);
}
}
}
return $x;
} // my_array_walk()
function write_out_file_set($op = '*', $file_ar, $tags)
{
if (! is_array($file_ar) || count($file_ar) <= 0)
return;
$additional_file_infos = array();
if (is_array($tags)) {
foreach ($tags as $tag_ar) {
foreach ($tag_ar['files'] as $file) {
$additional_file_infos[$file][] =
$tag_ar['operation'].' '.$tag_ar['name'];
}
}
}
global $out, $indent_str;
$prefix = "$indent_str$op ";
foreach ($file_ar as $filename) {
fwrite($out, $prefix);
if (is_array($additional_file_infos[$filename])) {
for ($i = 0; $i < count($additional_file_infos[$filename]); $i++) {
if ($i == 0) {
$filename2 = str_pad($filename, 35, ' ', STR_PAD_RIGHT);
} else if ($i == 1) {
$filename2 = str_repeat(' ', 35 + strlen($prefix));
}
$add_info = $additional_file_infos[$filename][$i];
fwrite($out, "$filename2 $add_info\n");
}
} else {
fwrite($out, "$filename\n");
}
}
}
#
# MAIN JOB
#
$in = file($input_file); // input split into array by lines
$i = 0; // starting line to parse
$j = -1; // current parsed report
// Rewind to the beginning of the first commit. This will allow us
// to parse commits with garbage texts on the top (ie. e-mails).
for (; ! ereg($begin_line, $in[$i]); $i++);
while ($i < sizeof($in)) {
// BEGIN NEW COMMIT
if (ereg($begin_line, $in[$i])) {
// increasing report index
$j++;
// reseting all flags
$in_msg_log = false;
$in_add_files = false;
$in_mod_files = false;
$in_del_files = false;
// moving to the next line
$i++;
continue;
}
// LOG MESSAGE
if (ereg($msg_log_begin, $in[$i])) {
$in_msg_log = true;
$i++;
continue;
}
if ($in_msg_log) {
if (ereg($begin_line, $in[$i])) {
$in_msg_log = false;
$i++;
continue;
}
else {
$reports[$j]['log_msg'][sizeof($reports[$j]['log_msg']) - 1] .=
rtrim($in[$i]);
//$reports[$j]['log_msg'][0] .= rtrim($in[$i]) . "\n";
}
}
// ADDED FILES
if (ereg($add_files_begin, $in[$i])) {
$in_add_files = true;
$i++;
continue;
}
if ($in_add_files) {
if (!ereg($in_file_list, $in[$i])) {
$in_add_files = false;
continue;
}
$reports[$j]['added'] =
array_merge($reports[$j]['added'],
explode(' ', trim($in[$i])));
}
// MODIFIED FILES
if (ereg($mod_files_begin, $in[$i])) {
$in_mod_files = true;
$i++;
continue;
}
if ($in_mod_files) {
if (!ereg($in_file_list, $in[$i])) {
$in_mod_files = false;
continue;
}
$reports[$j]['modified'] =
@array_merge($reports[$j]['modified'],
explode(' ', trim($in[$i])));
}
// DELETED FILES
if (ereg($del_files_begin, $in[$i])) {
$in_del_files = true;
$i++;
continue;
}
if ($in_del_files) {
if (!ereg($in_file_list, $in[$i])) {
$in_del_files = false;
continue;
}
$reports[$j]['deleted'] =
array_merge($reports[$j]['deleted'],
explode(' ', trim($in[$i])));
}
// DATE //Accepted format: Mon May 20 18:06:09 CEST 2002
if (ereg($date_format, $in[$i], $regs)) {
$reports[$j]['date'][] = $regs[2] . ' ' . $regs[3];
}
// USERS
if (ereg($user_format, $in[$i], $regs)) {
$reports[$j]['users'][] = $regs[1];
}
// DIRECTORY
if (ereg($directory_format, $in[$i])) {
// This is redundant, simply ignoring it
}
// NAME
if (ereg($project_name_format, $in[$i], $regs)) {
// only project name
$reports[$j]['name'] = trim(strtok($regs[1], '/'));
$reports[$j]['directory'] = trim($regs[1]);
}
// CVSWEB link
if (ereg($cvsweblink_format, $in[$i], $regs)) {
// only URL
$reports[$j]['cvsweblink'] =
@array_merge($reports[$j]['cvsweblink'], trim($regs[1]));
}
// TAG OPERATION
if (ereg($tag_oper_begin, $in[$i], $regs)) {
//$reports[$j]['tag_operation'][0] = trim($regs[1]);
$reports[$j]['tag'][0]['operation'] = trim($regs[1]);
}
// TAG NAME
if (ereg($tag_name_begin, $in[$i], $regs)) {
//$reports[$j]['tag_name'][0] = trim($regs[1]);
$reports[$j]['tag'][0]['name'] = trim($regs[1]);
}
$i++;
}
$merged = array();
// Merge recursively all reports into one array
// eg. join reports in same directory
for ($i = 0; $i < sizeof($reports); $i++) {
if (isset($reports[$i]['tag'][0]['name'])) {
$reports[$i]['tag'][0]['files'] =
(array) $reports[$i]['added'] +
(array) $reports[$i]['modified'] +
(array) $reports[$i]['deleted'];
switch (@$reports[$i]['tag'][0]['operation']) {
case 'add': $op = '+'; break;
case 'del': $op = '-'; break;
default: $op = '?'; break;
}
$reports[$i]['tag'][0]['operation'] = $op;
}
unset($a);
$a[$reports[$i]['directory']] = $reports[$i];
$merged = array_merge_recursive($merged, $a);
}
unset($i);
unset($a);
$merged_unique = my_array_walk($merged);
ksort($merged_unique);
// DEBUG
//var_dump($reports);
//var_dump($merged);
//var_dump($merged_unique);
unset($reports);
unset($merged);
$out = fopen($output_file, 'w');
$keys = array_keys($merged_unique);
$i = 0;
$name = '';
// OUTPUT:
// Print out the merged/unique to $out
while ($i < sizeof($merged_unique)) {
$k = $keys[$i];
$m = $merged_unique[$k];
$new_name = is_array($m['name']) ? join(', ', $m['name']) : $m['name'];
if (strcmp($new_name, $name)) {
// Print new project name
fwrite($out, sprintf($project_head, $new_name));
;
fwrite($out, str_repeat($project_head_folding_char, 70 - strlen($new_name) - 16));
fwrite($out, "\n");
$name = $new_name;
}
else {
// Separate subdirectories of the same project
fwrite($out, $sub_projects_separator);
}
// DIRECTORY
fwrite($out, 'Path: ');
fwrite($out, is_array($m['directory'])
? join(', ', $m['directory'])
: $m['directory']);
fwrite($out, "/\n");
// DATE
if (is_array($m['date'])) {
fwrite($out, 'Date: ' . $m['date'][sizeof($m['date']) - 1]);
fwrite($out, "\n");
}
// EDITORS
if (is_array($m['users'])) {
/* there is no fprintf() in PHP,
so we must use fwrite()/sprintf() combo */
fwrite($out, sprintf('User%s ',
count($m['users']) == 1 ? ': ' : 's:'));
fwrite($out, implode(', ', $m['users']) . "\n");
}
// MODIFIED FILES
if (is_array($m['added']) || is_array($m['modified']) ||
is_array($m['deleted'])) {
if ((count($m['added']) + count($m['modified']) +
count($m['deleted'])) > 1)
fwrite($out, "Files:\n");
else
fwrite($out, "File:\n");
}
// mod = mod - add
if (is_array($m['added']) && is_array($m['modified'])) {
$m['modified'] = array_diff($m['modified'], $m['added']);
}
// $indent_str is used as global in write_out_file_set()
$indent_str = str_repeat(' ', strlen('Files') + 2);
write_out_file_set('+', $m['added'], $m['tag']);
write_out_file_set('*', $m['modified'], $m['tag']);
write_out_file_set('-', $m['deleted'], $m['tag']);
// LOG MESSAGES
if (is_array($m['log_msg'])) {
fwrite($out, "Message:\n");
for ($l = 0; $l < count($m['log_msg']); $l++) {
if (trim($m['log_msg'][$l]) == '')
unset($m['log_msg'][$l]);
}
fwrite($out, $log_message_folding .
implode("\n$log_message_folding",
//str_replace("\n", "\n$log_message_folding", $m['log_msg'])
$m['log_msg']
) . "\n");
}
// LOG MESSAGES
if (is_array($m['cvsweblink'])) {
fwrite($out, "CVSweb URL:\n");
fwrite($out, $log_message_folding .
implode("\n$log_message_folding",
$m['cvsweblink']
) . "\n");
}
$i++;
}
fflush($out);
?>
Platon Group <platon@platon.org> http://platon.org/
|