From bddee613a0989a3a0c52e459e1877a1f1dfdda59 Mon Sep 17 00:00:00 2001 From: Andrew Chilton Date: Sun, 22 Jun 2008 01:26:30 +1200 Subject: [PATCH] Add Attachment functionality, including attach and extract for 'cil. --- bin/cil | 107 ++++++++++++++++++++++++++++++++++++++---- lib/CIL.pm | 17 ++++++- lib/CIL/Attachment.pm | 70 ++++++++++++++++++++++++++- lib/CIL/Base.pm | 6 +-- lib/CIL/Comment.pm | 8 +++- lib/CIL/Issue.pm | 22 +++++++-- 6 files changed, 211 insertions(+), 19 deletions(-) diff --git a/bin/cil b/bin/cil index d69f03c..2cea37f 100755 --- a/bin/cil +++ b/bin/cil @@ -26,10 +26,12 @@ use Digest::MD5 qw(md5_hex); use File::Touch; use File::Glob ':glob'; use File::Basename; +use File::Slurp qw(read_file write_file); use Term::CallEditor qw(solicit); use CIL; use CIL::Issue; use CIL::Comment; +use CIL::Attachment; my $COMMANDS = { init => 1, @@ -39,6 +41,8 @@ my $COMMANDS = { show => 1, edit => 1, comment => 1, + attach => 1, + extract => 1, }; my $gan = $ENV{GIT_AUTHOR_NAME} || 'Your Name'; @@ -103,6 +107,16 @@ EOF my ($issue_name) = @ARGV; comment($cil, $issue_name); + } + elsif ( $command eq 'attach' ) { + my ($issue_name, $filename) = @ARGV; + attach($cil, $issue_name, $filename); + + } + elsif ( $command eq 'extract' ) { + my ($issue_name, $attachment_name, $filename) = @ARGV; + extract($cil, $issue_name, $attachment_name, $filename); + } else { @@ -157,8 +171,8 @@ sub list { # find all the issues my $issues = $cil->get_issues(); if ( @$issues ) { - separator(); foreach my $issue ( sort { $a->Inserted cmp $b->Inserted } @$issues ) { + separator(); display_issue_headers($cil, $issue); } separator(); @@ -266,6 +280,70 @@ sub comment { display_issue_full($cil, $issue); } +sub attach { + my ($cil, $issue_name, $filename) = @_; + + my $issue = CIL::Issue->new_from_name($cil, $issue_name); + unless ( defined $issue ) { + fatal("couldn't load issue '$issue_name'"); + } + + # check to see if the file exists + unless ( -r $filename ) { + fatal("couldn't read file '$filename'"); + } + + my $basename = basename( $filename ); + + my $add_attachment_text = <<"EOF"; +Filename : $basename +CreatedBy : $gan <$gae> + +File goes here ... this will be overwritten. +EOF + + # read in the new issue text + my $fh = solicit( $add_attachment_text ); + + my $attachment = CIL::Attachment->new_from_fh( 'tmp', $fh ); + unless ( defined $attachment ) { + fatal("could not create new attachment"); + } + + # now add the file itself + my $contents = read_file( $filename ); + $attachment->set_file_contents( $contents ); + + # set the size + my ($size) = (stat($filename))[7]; + $attachment->Size( $size ); + + # we've got the attachment, so let's name it + my $unique_str = $attachment->Inserted . $attachment->File; + $attachment->set_name( substr(md5_hex($unique_str), 0, 8) ); + + # finally, tell it who it's parent is and then save + $attachment->Issue( $issue->name ); + $attachment->save($cil); + + # add the comment to the issue, update it's timestamp and save it out + $issue->add_attachment( $attachment ); + $issue->save($cil); + display_issue_full($cil, $issue); +} + +sub extract { + my ($cil, $attachment_name, $filename) = @_; + + my $attachment = CIL::Attachment->new_from_name($cil, $attachment_name); + unless ( defined $attachment ) { + fatal("Couldn't load attachment '$attachment_name'"); + } + + $filename ||= $attachment->Filename(); + write_file( $filename, $attachment->as_binary ); +} + ## ---------------------------------------------------------------------------- sub check_paths { @@ -339,7 +417,6 @@ sub display_issue_full { field( 'Inserted', $issue->Inserted() ); field( 'Updated', $issue->Inserted() ); text('Description', $issue->Description()); - separator(); my $comments = $cil->get_comments_for( $issue ); foreach my $comment ( @$comments ) { @@ -348,8 +425,20 @@ sub display_issue_full { field( 'Inserted', $comment->Inserted() ); field( 'Updated', $comment->Inserted() ); text('Description', $comment->Description()); - separator(); } + + my $attachments = $cil->get_attachments_for( $issue ); + print Dumper(); + foreach my $attachment ( @$attachments ) { + title( 'Attachment ' . $attachment->name() ); + field( 'Filename', $attachment->Filename() ); + field( 'CreatedBy', $attachment->CreatedBy() ); + field( 'Inserted', $attachment->Inserted() ); + field( 'Updated', $attachment->Inserted() ); + msg(); + } + + separator(); } sub msg { @@ -399,16 +488,18 @@ sub fatal { sub usage { print <<"END_USAGE"; -Usage: $0 [options] +Usage: $0 COMMAND [options] Commands: - init + init PATH add summary list - show - edit - comment + show ISSUE + edit ISSUE + comment ISSUE + attach ISSUE FILENAME + extract ATTACHMENT [TO_FILENAME] See for further information. Report bugs to . diff --git a/lib/CIL.pm b/lib/CIL.pm index a9d49df..b85f2fb 100644 --- a/lib/CIL.pm +++ b/lib/CIL.pm @@ -83,7 +83,7 @@ sub get_comments_for { my ($self, $issue) = @_; my @comments; - foreach my $comment_name ( @{$issue->Comment} ) { + foreach my $comment_name ( @{$issue->Comments} ) { my $comment = CIL::Comment->new_from_name( $self, $comment_name ); push @comments, $comment; } @@ -94,6 +94,21 @@ sub get_comments_for { return \@comments; } +sub get_attachments_for { + my ($self, $issue) = @_; + + my @attachments; + foreach my $attachment_name ( @{$issue->Attachments} ) { + my $attachment = CIL::Attachment->new_from_name( $self, $attachment_name ); + push @attachments, $attachment; + } + + # sort them in cronological order + @attachments = sort { $a->Inserted cmp $b->Inserted } @attachments; + + return \@attachments; +} + ## ---------------------------------------------------------------------------- 1; ## ---------------------------------------------------------------------------- diff --git a/lib/CIL/Attachment.pm b/lib/CIL/Attachment.pm index 2d27d72..337ed1a 100644 --- a/lib/CIL/Attachment.pm +++ b/lib/CIL/Attachment.pm @@ -23,9 +23,75 @@ package CIL::Attachment; use strict; use warnings; +use Carp; -use base qw(Class::Accessor); -__PACKAGE__->mk_accessors(qw(filename)); +use MIME::Base64; + +use base qw(CIL::Base); + +# fields specific to Attachment +__PACKAGE__->mk_accessors(qw(Issue Filename Size File)); + +# all fields +my @FIELDS = ( qw(Issue Filename Size CreatedBy Inserted Updated File) ); + +## ---------------------------------------------------------------------------- + +sub new { + my ($proto, $name) = @_; + + croak 'please provide an attachment name' + unless defined $name; + + my $class = ref $proto || $proto; + my $self = {}; + bless $self, $class; + + $self->set_name( $name ); + $self->{data} = { + Issue => '', + Filename => '', + Size => '', + CreatedBy => '', + Inserted => '', + Updated => '', + File => '', + }; + $self->{Changed} = 0; + + $self->set_inserted_now; + + return $self; +} + +sub set_file_contents { + my ($self, $contents) = @_; + + # $contents will be binary + $self->{data}{File} = encode_base64( $contents ); +} + +sub as_binary { + my ($self) = @_; + + return decode_base64( $self->{data}{File} ); +} + +sub prefix { + return 'a'; +} + +sub fields { + return \@FIELDS; +} + +sub array_fields { + return {}; +} + +sub last_field { + return 'File'; +} ## ---------------------------------------------------------------------------- 1; diff --git a/lib/CIL/Base.pm b/lib/CIL/Base.pm index 843677f..6ffb09f 100644 --- a/lib/CIL/Base.pm +++ b/lib/CIL/Base.pm @@ -27,7 +27,7 @@ use Carp; use DateTime; use base qw(Class::Accessor); -__PACKAGE__->mk_accessors(qw(CreatedBy Inserted Updated Description)); +__PACKAGE__->mk_accessors(qw(CreatedBy Inserted Updated)); ## ---------------------------------------------------------------------------- @@ -41,7 +41,7 @@ sub new_from_name { croak "filename '$filename' does no exist" unless -f $filename; - my $data = CIL::Utils->parse_cil_file($filename, 'Description'); + my $data = CIL::Utils->parse_cil_file($filename, $class->last_field); my $issue = $class->new_from_data( $name, $data ); return $issue; } @@ -83,7 +83,7 @@ sub new_from_fh { croak 'please provide name' unless defined $name; - my $data = CIL::Utils->parse_from_fh( $fh, 'Description' ); + my $data = CIL::Utils->parse_from_fh( $fh, $class->last_field ); return $class->new_from_data( $name, $data ); } diff --git a/lib/CIL/Comment.pm b/lib/CIL/Comment.pm index 4206ebd..9d0398c 100644 --- a/lib/CIL/Comment.pm +++ b/lib/CIL/Comment.pm @@ -26,7 +26,9 @@ use warnings; use Carp; use base qw(CIL::Base); -__PACKAGE__->mk_accessors(qw(Issue)); + +# fields specific to Comment +__PACKAGE__->mk_accessors(qw(Issue Description)); my @FIELDS = ( qw(Issue CreatedBy Inserted Updated Description) ); @@ -69,6 +71,10 @@ sub array_fields { return {}; } +sub last_field { + return 'Description'; +} + ## ---------------------------------------------------------------------------- 1; ## ---------------------------------------------------------------------------- diff --git a/lib/CIL/Issue.pm b/lib/CIL/Issue.pm index 8526b12..0dfaf53 100644 --- a/lib/CIL/Issue.pm +++ b/lib/CIL/Issue.pm @@ -29,7 +29,9 @@ use CIL; use CIL::Utils; use base qw(CIL::Base); -__PACKAGE__->mk_accessors(qw(Summary Status AssignedTo Label Comment Attachment)); + +# fields specific to Issue +__PACKAGE__->mk_accessors(qw(Summary Status AssignedTo Label Comment Attachment Description)); my @FIELDS = ( qw(Summary Status CreatedBy AssignedTo Label Comment Attachment Inserted Updated Description) ); my $cfg = { @@ -84,6 +86,10 @@ sub array_fields { return $cfg->{array}; } +sub last_field { + return 'Description'; +} + sub add_label { my ($self, $label) = @_; @@ -109,10 +115,13 @@ sub add_comment { sub add_attachment { my ($self, $attachment) = @_; - croak "can only add comments of type CIL::Attachment" - unless ref $attachment eq 'CIL::Attachment'; + croak "can only add attachments of type CIL::Attachment" + unless $attachment->isa( 'CIL::Attachment' ); + # add the attachment name and set this issue's updated time push @{$self->{data}{Attachment}}, $attachment->name; + $self->Updated( $attachment->Updated ); + $self->flag_as_updated(); } sub as_output { @@ -122,7 +131,12 @@ sub as_output { sub Comments { my ($self) = @_; - return $self->{Comment}; + return $self->{data}{Comment}; +} + +sub Attachments { + my ($self) = @_; + return $self->{data}{Attachment}; } ## ---------------------------------------------------------------------------- -- 2.39.5