⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cvs2cl.pl

📁 RAM Defragmentation tools
💻 PL
📖 第 1 页 / 共 5 页
字号:
#!/bin/shexec perl -w -x $0 ${1+"$@"} # -*- mode: perl; perl-indent-level: 2; -*-#!perl -w#################################################################                                                        ###### cvs2cl.pl: produce ChangeLog(s) from `cvs log` output. ######                                                        ################################################################### $Revision: 1.2 $## $Date: 2004/07/17 23:37:51 $## $Author: knilch $##use strict;use File::Basename qw( fileparse );use Getopt::Long   qw( GetOptions );use Text::Wrap     qw( );use User::pwent    qw( getpwnam );# The Plan:## Read in the logs for multiple files, spit out a nice ChangeLog that# mirrors the information entered during `cvs commit'.## The problem presents some challenges. In an ideal world, we could# detect files with the same author, log message, and checkin time --# each <filelist, author, time, logmessage> would be a changelog entry.# We'd sort them; and spit them out.  Unfortunately, CVS is *not atomic*# so checkins can span a range of times.  Also, the directory structure# could be hierarchical.## Another question is whether we really want to have the ChangeLog# exactly reflect commits. An author could issue two related commits,# with different log entries, reflecting a single logical change to the# source. GNU style ChangeLogs group these under a single author/date.# We try to do the same.## So, we parse the output of `cvs log', storing log messages in a# multilevel hash that stores the mapping:#   directory => author => time => message => filelist# As we go, we notice "nearby" commit times and store them together# (i.e., under the same timestamp), so they appear in the same log# entry.## When we've read all the logs, we twist this mapping into# a time => author => message => filelist mapping for each directory.## If we're not using the `--distributed' flag, the directory is always# considered to be `./', even as descend into subdirectories.# Call Tree# name                         number of lines (10.xii.03)# parse_options                         192# derive_changelog                       13# +-maybe_grab_accumulation_date         38# +-read_changelog                      277#   +-maybe_read_user_map_file           94#     +-run_ext                           9#   +-read_file_path                     29#   +-read_symbolic_name                 43#   +-read_revision                      49#   +-read_date_author_and_state         25#     +-parse_date_author_and_state      20#   +-read_branches                      36# +-output_changelog                    424#   +-pretty_file_list                  290#     +-common_path_prefix               35#   +-preprocess_msg_text                30#     +-min                               1#   +-mywrap                             16#   +-last_line_len                       5#   +-wrap_log_entry                    177## Utilities## xml_escape                              6# slurp_file                             11# debug                                   5# version                                 2# usage                                 142# -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*-## Note about a bug-slash-opportunity:# -----------------------------------## There's a bug in Text::Wrap, which affects cvs2cl.  This script# reveals it:##   #!/usr/bin/perl -w##   use Text::Wrap;##   my $test_text =#   "This script demonstrates a bug in Text::Wrap.  The very long line#   following this paragraph will be relocated relative to the surrounding#   text:##   ====================================================================##   See?  When the bug happens, we'll get the line of equal signs below#   this paragraph, even though it should be above.";###   # Print out the test text with no wrapping:#   print "$test_text";#   print "\n";#   print "\n";##   # Now print it out wrapped, and see the bug:#   print wrap ("\t", "        ", "$test_text");#   print "\n";#   print "\n";## If the line of equal signs were one shorter, then the bug doesn't# happen.  Interesting.## Anyway, rather than fix this in Text::Wrap, we might as well write a# new wrap() which has the following much-needed features:## * initial indentation, like current Text::Wrap()# * subsequent line indentation, like current Text::Wrap()# * user chooses among: force-break long words, leave them alone, or die()?# * preserve existing indentation: chopped chunks from an indented line#   are indented by same (like this line, not counting the asterisk!)# * optional list of things to preserve on line starts, default ">"## Note that the last two are essentially the same concept, so unify in# implementation and give a good interface to controlling them.## And how about:## Optionally, when encounter a line pre-indented by same as previous# line, then strip the newline and refill, but indent by the same.# Yeah...# Globals --------------------------------------------------------------------# In case we have to print it out:my $VERSION = '$Revision: 1.2 $';$VERSION =~ s/\S+\s+(\S+)\s+\S+/$1/;## Vars set by options:# Print debugging messages?my $Debug = 0;# Just show version and exit?my $Print_Version = 0;# Just print usage message and exit?my $Print_Usage = 0;# What file should we generate (defaults to "ChangeLog")?my $Log_File_Name = "ChangeLog";# Grab most recent entry date from existing ChangeLog file, just add# to that ChangeLog.my $Cumulative = 0;# `cvs log -d`, this will repeat the last entry in the old log.  This is OK,# as it guarantees at least one entry in the update changelog, which means# that there will always be a date to extract for the next update.  The repeat# entry can be removed in postprocessing, if necessary.# MJP 2003-08-02# I don't think this actually does anything usefulmy $Update = 0;# Expand usernames to email addresses based on a map file?my $User_Map_File = '';my $User_Passwd_File;my $Mail_Domain;# Output log in chronological order? [default is reverse chronological order]my $Chronological_Order = 0;# Grab user details via gecosmy $Gecos = 0;# User domain for gecos email addressesmy $Domain;# Output to a file or to stdout?my $Output_To_Stdout = 0;# Eliminate empty log messages?my $Prune_Empty_Msgs = 0;# Tags of which not to outputmy %ignore_tags;# Show only revisions with Tagsmy %show_tags;# Don't call Text::Wrap on the body of the messagemy $No_Wrap = 0;# Indentation of log messagesmy $Indent = "\t";# Don't do any pretty print processingmy $Summary = 0;# Separates header from log message.  Code assumes it is either " " or# "\n\n", so if there's ever an option to set it to something else,# make sure to go through all conditionals that use this var.my $After_Header = " ";# XML Encodingmy $XML_Encoding = '';# Format more for programs than for humans.my $XML_Output = 0;my $No_XML_Namespace = 0;my $No_XML_ISO_Date = 0;# Do some special tweaks for log data that was written in FSF# ChangeLog style.my $FSF_Style = 0;# Show times in UTC instead of local timemy $UTC_Times = 0;# Show times in output?my $Show_Times = 1;# Show day of week in output?my $Show_Day_Of_Week = 0;# Show revision numbers in output?my $Show_Revisions = 0;# Show dead files in output?my $Show_Dead = 0;# Hide dead trunk files which were created as a result of additions on a# branch?my $Hide_Branch_Additions = 1;# Show tags (symbolic names) in output?my $Show_Tags = 0;# Show tags separately in output?my $Show_Tag_Dates = 0;# Show branches by symbolic name in output?my $Show_Branches = 0;# Show only revisions on these branches or their ancestors.my @Follow_Branches;# Show only revisions on these branches or their ancestors; ignore descendent# branches.my @Follow_Only;# Don't bother with files matching this regexp.my @Ignore_Files;# How exactly we match entries.  We definitely want "o",# and user might add "i" by using --case-insensitive option.my $Case_Insensitive = 0;# Maybe only show log messages matching a certain regular expression.my $Regexp_Gate = '';# Pass this global option string along to cvs, to the left of `log':my $Global_Opts = '';# Pass this option string along to the cvs log subcommand:my $Command_Opts = '';# Read log output from stdin instead of invoking cvs log?my $Input_From_Stdin = 0;# Don't show filenames in output.my $Hide_Filenames = 0;# Don't shorten directory names from filenames.my $Common_Dir = 1;# Max checkin duration. CVS checkin is not atomic, so we may have checkin# times that span a range of time. We assume that checkins will last no# longer than $Max_Checkin_Duration seconds, and that similarly, no# checkins will happen from the same users with the same message less# than $Max_Checkin_Duration seconds apart.my $Max_Checkin_Duration = 180;# What to put at the front of [each] ChangeLog.my $ChangeLog_Header = '';# Whether to enable 'delta' mode, and for what start/end tags.my $Delta_Mode = 0;my $Delta_From = '';my $Delta_To = '';my $TestCode;# Whether to parse filenames from the RCS filename, and if so what# prefix to strip.my $RCS_Root;# Whether to output information on the # of lines added and removed# by each file modification.my $Show_Lines_Modified = 0;## end vars set by options.# latest observed times for the start/end tags in delta modemy $Delta_StartTime = 0;my $Delta_EndTime = 0;my $No_Ancestors = 0;my $No_Extra_Indent = 0;my $GroupWithinDate = 0;# ----------------------------------------------------------------------------package CVS::Utils::ChangeLog::EntrySet;sub new {  my $class = shift;  my %self;  bless \%self, $class;}# -------------------------------------sub output_changelog {  my $output_type = $XML_Output ? 'XML' : 'Text';  my $output_class = "CVS::Utils::ChangeLog::EntrySet::Output::${output_type}";  my $output = $output_class->new(follow_branches => \@Follow_Branches,                                  follow_only     => \@Follow_Only,                                  ignore_tags     => \%ignore_tags,                                  show_tags       => \%show_tags,                                 );  $output->output_changelog(@_);}# -------------------------------------sub add_fileentry {  my ($self, $file_full_path, $time, $revision, $state, $lines,      $branch_names, $branch_roots, $branch_numbers,      $symbolic_names, $author, $msg_txt) = @_;      my $qunk =        CVS::Utils::ChangeLog::FileEntry->new($file_full_path, $time, $revision,                                              $state, $lines,                                              $branch_names, $branch_roots,                                              $branch_numbers,                                              $symbolic_names);      # We might be including revision numbers and/or tags and/or      # branch names in the output.  Most of the code from here to      # loop-end deals with organizing these in qunk.      unless ( $Hide_Branch_Additions               and               $msg_txt =~ /file .+ was initially added on branch \S+./ ) {        # Add this file to the list        # (We use many spoonfuls of autovivication magic. Hashes and arrays        # will spring into existence if they aren't there already.)        &main::debug ("(pushing log msg for ". $qunk->dir_key . $qunk->filename . ")\n");        # Store with the files in this commit.  Later we'll loop through        # again, making sure that revisions with the same log message        # and nearby commit times are grouped together as one commit.        $self->{$qunk->dir_key}{$author}{$time}{$msg_txt} =          CVS::Utils::ChangeLog::Message->new($msg_txt)              unless exists $self->{$qunk->dir_key}{$author}{$time}{$msg_txt};        $self->{$qunk->dir_key}{$author}{$time}{$msg_txt}->add_fileentry($qunk);      }}# ----------------------------------------------------------------------------package CVS::Utils::ChangeLog::EntrySet::Output::Text;use base qw( CVS::Utils::ChangeLog::EntrySet::Output );use File::Basename qw( fileparse );sub new {  my $class = shift;  my $self = $class->SUPER::new(@_);}# -------------------------------------sub wday {  my $self = shift; my $class = ref $self;  my ($wday) = @_;  return $Show_Day_Of_Week ? ' ' . $class->weekday_en($wday) : '';}# -------------------------------------sub header_line {  my $self = shift;  my ($time, $author, $lastdate) = @_;  my $header_line = '';  my (undef,$min,$hour,$mday,$mon,$year,$wday)    = $UTC_Times ? gmtime($time) : localtime($time);  my $date = $self->fdatetime($time);  if ($Show_Times) {    $header_line =      sprintf "%s  %s\n\n", $date, $author;  } else {    if ( ! defined $lastdate or $date ne $lastdate or ! $GroupWithinDate ) {      if ( $GroupWithinDate ) {        $header_line = "$date\n\n";      } else {        $header_line = "$date  $author\n\n";      }    } else {      $header_line = '';    }  }}# -------------------------------------sub preprocess_msg_text {  my $self = shift;  my ($text) = @_;  $text = $self->SUPER::preprocess_msg_text($text);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -