// Tag support by Ondrej Jombik [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); ?>