$edit = 'n';
}
else {
- print $issue->error(), "\n";
+ msg($_) foreach @{ $issue->errors };
print 'Would you like to re-edit (y/n): ';
$edit = <STDIN>;
chomp $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;
$edit = 'n';
}
else {
- print $comment->error(), "\n";
+ msg($_) foreach @{ $issue->errors };
print 'Would you like to re-edit (y/n): ';
$edit = <STDIN>;
chomp $edit;
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 {
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 {
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) = @_;
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 . "'";
}
}
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 {