]> git.mjollnir.org Git - cil.git/commitdiff
Add Attachment functionality, including attach and extract for 'cil.
authorAndrew Chilton <andychilton@gmail.com>
Sat, 21 Jun 2008 13:26:30 +0000 (01:26 +1200)
committerAndrew Chilton <andychilton@gmail.com>
Sat, 21 Jun 2008 13:26:30 +0000 (01:26 +1200)
bin/cil
lib/CIL.pm
lib/CIL/Attachment.pm
lib/CIL/Base.pm
lib/CIL/Comment.pm
lib/CIL/Issue.pm

diff --git a/bin/cil b/bin/cil
index d69f03c50c8c8a7fb7f24a98ff4d1d5bba977bf8..2cea37f86f85aed819f718e5f8bca0a17a1dec5a 100755 (executable)
--- 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 <command> [options]
+Usage: $0 COMMAND [options]
 
 Commands:
-   init    <path>
+   init    PATH
    add
    summary
    list
-   show    <issue>
-   edit    <issue>
-   comment <issue>
+   show    ISSUE
+   edit    ISSUE
+   comment ISSUE
+   attach  ISSUE FILENAME
+   extract ATTACHMENT [TO_FILENAME]
 
 See <http://kapiti.geek.nz/software/cil.html> for further information.
 Report bugs to <andychilton -at- gmail -dot- com>.
index a9d49dfa615f3e0db5651fa37010db0becf5dd1c..b85f2fb506f051eea77fd8e21865893a86ee78d6 100644 (file)
@@ -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;
 ## ----------------------------------------------------------------------------
index 2d27d72c3d198686bc8108c19b503effe53d2353..337ed1aa04e24ddfe23c20fbc4e0218bbbf79f94 100644 (file)
@@ -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;
index 843677fa3419c0c7a2ad82681192a1381dcba636..6ffb09fe2d0586e0c60255a310b33d326e1f3882 100644 (file)
@@ -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 );
 }
 
index 4206ebded30dd06363d8b24191fbaad79ef884e7..9d0398c3d00cdf3a8dc08f89310ec0894a50e13b 100644 (file)
@@ -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;
 ## ----------------------------------------------------------------------------
index 8526b127e000f30dbb82f58dd7aca0808444832e..0dfaf533768dceaea6be54ccb0a96cb1dcd5aa7b 100644 (file)
@@ -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};
 }
 
 ## ----------------------------------------------------------------------------