]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blobdiff - IkiWiki/Plugin/filecheck.pm
Remember to run all the tests before committing!
[git.ikiwiki.info.git] / IkiWiki / Plugin / filecheck.pm
index 27f764e3b344a344ef2d491552824c2c40e6e5f1..4f4e67489a41c51ecae344119362f0ea611d481a 100644 (file)
@@ -3,9 +3,9 @@ package IkiWiki::Plugin::filecheck;
 
 use warnings;
 use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
 
-my %units=( #{{{       # size in bytes
+my %units=(            # size in bytes
        B               => 1,
        byte            => 1,
        KB              => 2 ** 10,
@@ -37,9 +37,22 @@ my %units=( #{{{     # size in bytes
        # ikiwiki, if you find you need larger data quantities, either modify
        # yourself to add them, or travel back in time to 2008 and kill me.
        #   -- Joey
-); #}}}
-
-sub parsesize ($) { #{{{
+);
+
+sub import {
+       hook(type => "getsetup", id => "filecheck",  call => \&getsetup);
+}
+
+sub getsetup () {
+       return
+               plugin => {
+                       safe => 1,
+                       rebuild => undef,
+                       section => "misc",
+               },
+}
+
+sub parsesize ($) {
        my $size=shift;
 
        no warnings;
@@ -51,10 +64,10 @@ sub parsesize ($) { #{{{
                }
        }
        return $base;
-} #}}}
+}
 
 # This is provided for other plugins that want to convert back the other way.
-sub humansize ($) { #{{{
+sub humansize ($) {
        my $size=shift;
 
        foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
@@ -63,21 +76,21 @@ sub humansize ($) { #{{{
                }
        }
        return $size; # near zero, or negative
-} #}}}
+}
 
 package IkiWiki::PageSpec;
 
-sub match_maxsize ($$;@) { #{{{
+sub match_maxsize ($$;@) {
        my $page=shift;
        my $maxsize=eval{IkiWiki::Plugin::filecheck::parsesize(shift)};
        if ($@) {
-               return IkiWiki::FailReason->new("unable to parse maxsize (or number too large)");
+               return IkiWiki::ErrorReason->new("unable to parse maxsize (or number too large)");
        }
 
        my %params=@_;
-       my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+       my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page});
        if (! defined $file) {
-               return IkiWiki::FailReason->new("no file specified");
+               return IkiWiki::ErrorReason->new("file does not exist");
        }
 
        if (-s $file > $maxsize) {
@@ -86,19 +99,19 @@ sub match_maxsize ($$;@) { #{{{
        else {
                return IkiWiki::SuccessReason->new("file not too large");
        }
-} #}}}
+}
 
-sub match_minsize ($$;@) { #{{{
+sub match_minsize ($$;@) {
        my $page=shift;
        my $minsize=eval{IkiWiki::Plugin::filecheck::parsesize(shift)};
        if ($@) {
-               return IkiWiki::FailReason->new("unable to parse minsize (or number too large)");
+               return IkiWiki::ErrorReason->new("unable to parse minsize (or number too large)");
        }
 
        my %params=@_;
-       my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+       my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page});
        if (! defined $file) {
-               return IkiWiki::FailReason->new("no file specified");
+               return IkiWiki::ErrorReason->new("file does not exist");
        }
 
        if (-s $file < $minsize) {
@@ -107,54 +120,68 @@ sub match_minsize ($$;@) { #{{{
        else {
                return IkiWiki::SuccessReason->new("file not too small");
        }
-} #}}}
+}
 
-sub match_mimetype ($$;@) { #{{{
+sub match_mimetype ($$;@) {
        my $page=shift;
        my $wanted=shift;
 
        my %params=@_;
-       my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+       my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page});
        if (! defined $file) {
-               return IkiWiki::FailReason->new("no file specified");
+               return IkiWiki::ErrorReason->new("file does not exist");
        }
 
-       # Use ::magic to get the mime type, the idea is to only trust
-       # data obtained by examining the actual file contents.
+       # Get the mime type.
+       #
+       # First, try File::Mimeinfo. This is fast, but doesn't recognise
+       # all files.
        eval q{use File::MimeInfo::Magic};
-       if ($@) {
-               return IkiWiki::FailReason->new("failed to load File::MimeInfo::Magic ($@); cannot check MIME type");
+       my $mimeinfo_ok=! $@;
+       my $mimetype;
+       if ($mimeinfo_ok) {
+               my $mimetype=File::MimeInfo::Magic::magic($file);
        }
-       my $mimetype=File::MimeInfo::Magic::magic($file);
+
+       # Fall back to using file, which has a more complete
+       # magic database.
        if (! defined $mimetype) {
-               $mimetype=File::MimeInfo::Magic::default($file);
+               open(my $file_h, "-|", "file", "-bi", $file);
+               $mimetype=<$file_h>;
+               chomp $mimetype;
+               close $file_h;
+       }
+       if (! defined $mimetype || $mimetype !~s /;.*//) {
+               # Fall back to default value.
+               $mimetype=File::MimeInfo::Magic::default($file)
+                       if $mimeinfo_ok;
                if (! defined $mimetype) {
                        $mimetype="unknown";
                }
        }
 
        my $regexp=IkiWiki::glob2re($wanted);
-       if ($mimetype!~/^$regexp$/i) {
+       if ($mimetype!~$regexp) {
                return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted");
        }
        else {
                return IkiWiki::SuccessReason->new("file MIME type is $mimetype");
        }
-} #}}}
+}
 
-sub match_virusfree ($$;@) { #{{{
+sub match_virusfree ($$;@) {
        my $page=shift;
        my $wanted=shift;
 
        my %params=@_;
-       my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+       my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page});
        if (! defined $file) {
-               return IkiWiki::FailReason->new("no file specified");
+               return IkiWiki::ErrorReason->new("file does not exist");
        }
 
        if (! exists $IkiWiki::config{virus_checker} ||
            ! length $IkiWiki::config{virus_checker}) {
-               return IkiWiki::FailReason->new("no virus_checker configured");
+               return IkiWiki::ErrorReason->new("no virus_checker configured");
        }
 
        # The file needs to be fed into the virus checker on stdin,
@@ -162,7 +189,7 @@ sub match_virusfree ($$;@) { #{{{
        # used, clamd would fail to read it.
        eval q{use IPC::Open2};
        error($@) if $@;
-       open (IN, "<", $file) || return IkiWiki::FailReason->new("failed to read file");
+       open (IN, "<", $file) || return IkiWiki::ErrorReason->new("failed to read file");
        binmode(IN);
        my $sigpipe=0;
        $SIG{PIPE} = sub { $sigpipe=1 };
@@ -182,9 +209,9 @@ sub match_virusfree ($$;@) { #{{{
        else {
                return IkiWiki::SuccessReason->new("file seems virusfree ($reason)");
        }
-} #}}}
+}
 
-sub match_ispage ($$;@) { #{{{
+sub match_ispage ($$;@) {
        my $filename=shift;
 
        if (defined IkiWiki::pagetype($filename)) {
@@ -193,4 +220,4 @@ sub match_ispage ($$;@) { #{{{
        else {
                return IkiWiki::FailReason->new("file is not a wiki page");
        }
-} #}}}
+}