Add the 'fsck' command along with relevant refactorings.
authorAndrew Chilton <andychilton@gmail.com>
Fri, 27 Jun 2008 23:51:14 +0000 (11:51 +1200)
committerAndrew Chilton <andychilton@gmail.com>
Fri, 27 Jun 2008 23:51:14 +0000 (11:51 +1200)
bin/cil
issues/c_81dc204c.cil [new file with mode: 0644]
issues/i_c6a8d865.cil
lib/CIL.pm
lib/CIL/Base.pm
lib/CIL/Issue.pm

diff --git a/bin/cil b/bin/cil
index 4bc39fede69ffbebce84b4403f709d8b7b56d96d..9e9604b4caead3f28e92d5530b680bfdb3c49c46 100755 (executable)
--- a/bin/cil
+++ b/bin/cil
@@ -247,7 +247,7 @@ sub cmd_add {
             $edit = 'n';
         }
         else {
-            print $issue->error(), "\n";
+            msg($_) foreach @{ $issue->errors };
             print 'Would you like to re-edit (y/n): ';
             $edit = <STDIN>;
             chomp $edit;
@@ -288,7 +288,7 @@ sub cmd_edit {
             $edit = 'n';
         }
         else {
-            print $issue->error(), "\n";
+            msg($_) foreach @{ $issue->errors };
             print 'Would you like to re-edit (y/n): ';
             $edit = <STDIN>;
             chomp $edit;
@@ -333,7 +333,7 @@ sub cmd_comment {
             $edit = 'n';
         }
         else {
-            print $comment->error(), "\n";
+            msg($_) foreach @{ $issue->errors };
             print 'Would you like to re-edit (y/n): ';
             $edit = <STDIN>;
             chomp $edit;
@@ -422,6 +422,128 @@ sub cmd_extract {
     write_file( $filename, $attachment->as_binary );
 }
 
+sub cmd_fsck {
+    my ($cil, $args) = @_;
+
+    # this looks at all the issues it can find and checks for:
+    # * validity
+    # * all the comments are there
+    # * all the attachments are there
+    # then it checks each individual comment/attachment for:
+    # * ToDo: validity
+    # * it's parent exists
+
+    check_paths($cil);
+
+    # find all the issues, comments and attachments
+    my $issues = $cil->get_issues();
+    my $issue = {};
+    foreach my $i ( @$issues ) {
+        $issue->{$i->name} = $i;
+    }
+    my $comments = $cil->get_comments();
+    my $comment = {};
+    foreach my $c ( @$comments ) {
+        $comment->{$c->name} = $c;
+    }
+    my $attachments = $cil->get_attachments();
+    my $attachment = {};
+    foreach my $a ( @$attachments ) {
+        $attachment->{$a->name} = $a;
+    }
+
+    my $errors = {};
+
+    if ( @$issues ) {
+        foreach my $i ( sort { $a->Inserted cmp $b->Inserted } @$issues ) {
+            my $name = $i->name;
+
+            unless ( $i->is_valid($cil) ) {
+                foreach ( @{ $i->errors } ) {
+                    push @{$errors->{$name}}, $_;
+                }
+            }
+
+            # check that all it's comments are there and that they have this parent
+            my $comments = $i->Comments;
+            foreach my $c ( @$comments ) {
+                # see if this comment exists at all
+                if ( exists $comment->{$c} ) {
+                    # check the parent is this issue
+                    push @{$errors->{$name}}, "comment '$c' is listed under issue '" . $i->name . "' but does not reciprocate"
+                        unless $comment->{$c}->Issue eq $i->name;
+                }
+                else {
+                    push @{$errors->{$name}}, "comment '$c' listed in issue '" . $i->name . "' does not exist";
+                }
+            }
+
+            # check that all it's attachments are there and that they have this parent
+            my $attachments = $i->Attachments;
+            foreach my $a ( @$attachments ) {
+                # see if this attachment exists at all
+                if ( exists $attachment->{$a} ) {
+                    # check the parent is this issue
+                    push @{$errors->{$name}}, "attachment '$a' is listed under issue '" . $i->name . "' but does not reciprocate"
+                        unless $attachment->{$a}->Issue eq $i->name;
+                }
+                else {
+                    push @{$errors->{$name}}, "attachment '$a' listed in issue '" . $i->name . "' does not exist";
+                }
+            }
+        }
+    }
+
+    print_fsck_errors('Issue', $errors);
+
+    # comments
+    $errors = {};
+
+    # loop through all the comments
+    if ( @$comments ) {
+        # check that their parent issues exist
+        foreach my $c ( sort { $a->Inserted cmp $b->Inserted } @$comments ) {
+            # check that the parent of each comment exists
+            unless ( exists $issue->{$c->Issue} ) {
+                push @{$errors->{$c->name}}, "comment '" . $c->name . "' refers to issue '" . $c->Issue . "' but issue does not exist";
+            }
+        }
+    }
+
+    print_fsck_errors('Comment', $errors);
+
+    # attachments
+    $errors = {};
+
+    # loop through all the attachments
+    if ( @$attachments ) {
+        # check that their parent issues exist
+        foreach my $a ( sort { $a->Inserted cmp $b->Inserted } @$attachments ) {
+            # check that the parent of each attachment exists
+            unless ( exists $issue->{$a->Issue} ) {
+                push @{$errors->{$a->name}}, "attachment '" . $a->name . "' refers to issue '" . $a->Issue . "' but issue does not exist";
+            }
+        }
+    }
+
+    print_fsck_errors('Attachment', $errors);
+
+    # nothing more to do
+    separator();
+}
+
+sub print_fsck_errors {
+    my ($entity, $errors) = @_;
+
+    separator();
+    foreach my $issue_name ( keys %$errors ) {
+        title( "$entity $issue_name ");
+        foreach my $error ( @{$errors->{$issue_name}} ) {
+            msg("* $error");
+        }
+    }
+}
+
 ## ----------------------------------------------------------------------------
 
 sub check_paths {
diff --git a/issues/c_81dc204c.cil b/issues/c_81dc204c.cil
new file mode 100644 (file)
index 0000000..7d3b708
--- /dev/null
@@ -0,0 +1,9 @@
+Issue: c6a8d865
+CreatedBy: Andrew Chilton <andychilton@gmail.com>
+Inserted: 2008-06-27T23:39:55
+Updated: 2008-06-27T23:40:49
+
+Added the command 'fsck'. Currently it works okay but it might need looking at
+in the future for functionality and possible refactoring.
+
+Closing issue.
index dfff5885469b543e6a3d5a8d2cfb24ff396e60fe..9e46130ba7a862315298ee52213606963cf4d4e5 100644 (file)
@@ -1,11 +1,12 @@
 Summary: Add a 'fsck' command
-Status: New
+Status: Finished
 CreatedBy: Andrew Chilton <andychilton@gmail.com>
 AssignedTo: Andrew Chilton <andychilton@gmail.com>
 Label: Milestone-v0.3
 Label: Type-Enhancement
+Comment: 81dc204c
 Inserted: 2008-06-27T13:39:48
-Updated: 2008-06-27T23:27:54
+Updated: 2008-06-27T23:40:49
 
 When we add issues and their comments and attachments, there is the possibility
 that you don't actually check in the correct files at the same time. This
index 2a4f9d5822056738b05787165008a3d0fd6a3757..e2be890cfdaa36a1fee0967ff59b64f322c15682 100644 (file)
@@ -58,21 +58,39 @@ sub new {
     return $self;
 }
 
-sub list_issues {
-    my ($self) = @_;
+sub list_entities {
+    my ($self, $prefix) = @_;
 
-    my $globpath = $self->IssueDir . "/i_*.cil";
+    my $globpath = $self->IssueDir . "/${prefix}_*.cil";
     my @filenames = bsd_glob($globpath);
 
-    my @issues;
+    my @entities;
     foreach my $filename ( sort @filenames ) {
-        my ($name) = $filename =~ m{/i_(.*)\.cil$}xms;
-        push @issues, {
+        my ($name) = $filename =~ m{/${prefix}_(.*)\.cil$}xms;
+        push @entities, {
             name => $name,
             filename => $filename,
         };
     }
-    return \@issues;
+    return \@entities;
+}
+
+sub list_issues {
+    my ($self) = @_;
+
+    return $self->list_entities('i');
+}
+
+sub list_comments {
+    my ($self) = @_;
+
+    return $self->list_entities('c');
+}
+
+sub list_attachments {
+    my ($self) = @_;
+
+    return $self->list_entities('a');
 }
 
 sub get_issues {
@@ -87,6 +105,30 @@ sub get_issues {
     return \@issues;
 }
 
+sub get_comments {
+    my ($self) = @_;
+
+    my $comment_list = $self->list_comments();
+
+    my @comments;
+    foreach my $comment ( @$comment_list ) {
+        push @comments, CIL::Comment->new_from_name( $self, $comment->{name} );
+    }
+    return \@comments;
+}
+
+sub get_attachments {
+    my ($self) = @_;
+
+    my $attachment_list = $self->list_attachments();
+
+    my @attachments;
+    foreach my $attachment ( @$attachment_list ) {
+        push @attachments, CIL::Attachment->new_from_name( $self, $attachment->{name} );
+    }
+    return \@attachments;
+}
+
 sub get_comments_for {
     my ($self, $issue) = @_;
 
index b08ebd8d89b5ccce2e5371d547b0eaf5dbdc2422..f9b932f7cf719716450b79ae9667286eddc11c69 100644 (file)
@@ -215,12 +215,12 @@ sub name {
     return $self->{name};
 }
 
-sub error {
+sub errors {
     my $self = shift;
     if( @_ ) {
-        $self->{error} = $_[0];
+        $self->{errors} = $_[0];
     }
-    return $self->{error};
+    return $self->{errors};
 }
 
 ## ----------------------------------------------------------------------------
index 904a93b10aa98889114ad316f988a799bb076aa5..d44626e874e8a89e0ada95f2dc4c79b16b05ab60 100644 (file)
@@ -93,17 +93,17 @@ sub last_field {
 sub is_valid {
     my ($self, $cil) = @_;
 
+    my @errors;
+
     # issues should have a Summary
     unless ( defined defined $self->Summary and length $self->Summary ) {
-        $self->error( 'You must provide a summary.' );
-        return;
+        push @errors, 'Issue does not have a summary';
     }
 
     # see if we only allow certain Statuses
     if ( $cil->StatusStrict ) {
         unless ( exists $cil->StatusAllowed()->{$self->Status} ) {
-            $self->error( "You have 'StatusStrict' turned on but this status (" . $self->Status . ") is not in the 'StatusAllowedList'" );
-            return;
+            push @errors, "StatusStrict is turned on but this issue has an invalid status '" . $self->Status . "'";
         }
     }
 
@@ -112,13 +112,13 @@ sub is_valid {
         my @labels = @{$self->Labels};
         foreach my $label ( @labels ) {
             unless ( exists $cil->LabelAllowed()->{$label} ) {
-                $self->error( "You have 'LabelStrict' turned on but this label ($label) is not in the 'LabelAllowedList'" );
-                return;
+                push @errors, "LabelStrict is turned on but this issue has an invalid label '$label'";
             }
         }
     }
 
-    return 1;
+    $self->errors( \@errors );
+    return @errors ? 0 : 1;
 }
 
 sub add_label {