| Arch documentation | Contained in the Arch distribution. |
Arch::Log - class representing Arch patch-log
use Arch::Log;
my $log = Arch::Log->new($rfc2822_message_string);
printf "Patch log date: %s\n", $log->header('standard_date');
print $log->dump;
my $first_new_file = $log->get_headers->{new_files}->[0];
This class represents the patch-log concept in Arch and provides some useful methods.
The following class methods are available:
get_message, get_headers, header, get_changes, split_version, get_version, get_revision, get_revision_kind, get_revision_desc, dump.
Return the original message with that the object was constructed.
Return the hashref of all headers including body, see also header method.
Get or set the named header. The special name 'body' represents the message body (the text following the headers).
This is just a shortcut for header('method'). However unlike
header('method'), method fails instead of returning undef if the log
does not have the given header name.
Return a list of changes in the corresponding changeset.
ATTENTION! Patch logs do not distinguish metadata (ie permission) changes from ordinary content changes. Permission changes will be represented with a change type of 'M'. This is different from Arch::Changeset::get_changes and Arch::Tree::get_changes.
Return a list of 2 strings: full version and patch-level.
Return the full version name, not unlike split_version.
Return the full revision name. This is currently a concatination of headers Archive and Revision with '/' separator.
Return one of the strings 'tag', 'import' or 'cset' depending on the revision kind this log represents.
Return revision description hashref with the keys: name, version, summary, creator, email, date, kind.
Returns the object dump using Data::Dumper.
Awaiting for your reports.
Mikhael Goikhman (migo@homemail.com--Perl-GPL/arch-perl--devel).
For more information, see tla, Arch::Session, Arch::Library, Arch::Changes.
| Arch documentation | Contained in the Arch distribution. |
# Arch Perl library, Copyright (C) 2004 Mikhael Goikhman # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use 5.005; use strict; package Arch::Log; use Arch::Changes qw(:type); use Arch::Util qw(standardize_date parse_creator_email date2age); sub new ($$%) { my $class = shift; my $message = shift || die "Arch::Log::new: no message\n"; my %init = @_; my $self = { message => $message, headers => undef, hide_ids => $init{hide_ids}, }; return bless $self, $class; } sub get_message ($) { my $self = shift; return $self->{message}; } use vars qw($SPECIAL_HEADERS); $SPECIAL_HEADERS = { modified_directories => 1, modified_files => 1, new_directories => 1, new_files => 1, new_patches => -1, removed_directories => 1, removed_files => 1, renamed_directories => 2, renamed_files => 2, }; sub get_headers ($) { my $self = shift; return $self->{headers} if defined $self->{headers}; my $message = $self->{message}; my ($headers_str, $body) = $message =~ /^(.*?\n)\n(.*)$/s or die "Incorrect message:\n\n$message\n\n- No body delimeter\n"; my $headers = { body => $body }; $headers_str =~ s{^([\w-]+):[ \t]*(.*\n(?:[ \t]+.*\n)*)}{ my ($header, $value) = (lc($1), $2); $header =~ s/-/_/sg; die "Duplicate header $header in message:\n\n$message\n" if exists $headers->{$header}; chomp($value); # handle special headers (lists, lists of pairs, files but ids) my $type = $SPECIAL_HEADERS->{$header}; if ($type) { $value = [ split(/[ \n]+/, $value) ]; $value = [ grep { !m:(^|/).arch-ids/: } @$value ] if $type > 0 && $self->{hide_ids}; if ($type == 2) { my @pairs = (); push @pairs, [ splice @$value, 0, 2 ] while @$value; $value = \@pairs; } } $headers->{$header} = $value; "" }meg; #print "*** $_: $headers->{$_} ***\n" foreach keys %$headers; return $self->{headers} = $headers; } sub header ($$;$) { my $self = shift; my $header = shift; return $self->get_headers->{$header} unless @_; $self->get_headers->{$header} = shift; } sub get_changes ($) { my $self = shift; my $changes = Arch::Changes->new; # make a workaround for tla bug: missing New-directories in import log; # still, there is no way to figure out empty directory added on import my @import_dirs = (); if ($self->get_revision_kind eq 'import' && !$self->header('new_directories')) { my %import_dirs = (); foreach (@{$self->header('new_files') || []}) { my $file = $_; $import_dirs{$1} = 1 while $file =~ s!^(.+)/.+$!$1!; } @import_dirs = sort keys %import_dirs; } # new dirs foreach my $path (@{$self->header('new_directories') || []}, @import_dirs) { $changes->add(ADD, 1, $path); } # new files foreach my $path (@{$self->header('new_files') || []}) { $changes->add(ADD, 0, $path); } # removed dirs foreach my $path (@{$self->header('removed_directories') || []}) { $changes->add(DELETE, 1, $path); } # removed files foreach my $path (@{$self->header('removed_files') || []}) { $changes->add(DELETE, 0, $path); } # modified dirs foreach my $path (@{$self->header('modified_directories') || []}) { # directories cannot be MODIFY'ed $changes->add(META_MODIFY, 1, $path); } # modified files foreach my $path (@{$self->header('modified_files') || []}) { # logs don't distinguish MODIFY and META_MODIFY $changes->add(MODIFY, 0, $path); } # moved dirs foreach my $paths (@{$self->header('renamed_directories') || []}) { $changes->add(RENAME, 1, @{$paths}); } # moved files foreach my $paths (@{$self->header('renamed_files') || []}) { $changes->add(RENAME, 0, @{$paths}); } return $changes; } sub split_version ($) { my $self = shift; my $full_revision = $self->get_revision; die "Invalid archive/revision ($full_revision) in log:\n$self->{message}" unless $full_revision =~ /^(.+)--(.+)/; return ($1, $2); } sub get_version ($) { my $self = shift; ($self->split_version)[0]; } sub get_revision ($) { my $self = shift; $self->header('archive') . "/" . $self->header('revision'); } sub get_revision_kind ($) { my $self = shift; return $self->header('continuation_of')? 'tag': $self->header('revision') =~ /--base-0$/? 'import': 'cset'; } sub get_revision_desc ($) { my $self = shift; my ($version, $name) = $self->split_version; my $summary = $self->header('summary') || '(none)'; my ($creator, $email, $username) = parse_creator_email($self->header('creator') || "N.O.Body"); my $date = $self->header('standard_date') || standardize_date($self->header('date') || "no-date"); my $age = date2age($date); my $kind = $self->get_revision_kind; return { name => $name, version => $version, summary => $summary, creator => $creator, email => $email, username => $username, date => $date, age => $age, kind => $kind, }; } sub dump ($) { my $self = shift; my $headers = $self->get_headers; require Data::Dumper; my $dumper = Data::Dumper->new([$headers]); $dumper->Sortkeys(1) if $dumper->can('Sortkeys'); return $dumper->Quotekeys(0)->Indent(1)->Terse(1)->Dump; } sub AUTOLOAD ($@) { my $self = shift; my @params = @_; my $method = $Arch::Log::AUTOLOAD; # remove the package name $method =~ s/.*://; # DESTROY messages should never be propagated return if $method eq 'DESTROY'; if (exists $self->get_headers->{$method}) { $self->header($method, @_); } else { die "Arch::Log: no such header or method ($method)\n"; } } 1; __END__