2 package IkiWiki::Plugin::amazon_s3;
5 no warnings 'redefine';
11 # Store references to real subs before overriding them.
14 foreach my $sub (qw{IkiWiki::writefile IkiWiki::prune}) {
20 hook(type => "checkconfig", id => "amazon_s3", call => \&checkconfig);
23 sub checkconfig { #{{{
24 foreach my $field (qw{amazon_s3_key_id amazon_s3_key_file
26 if (! exists $config{$field} || ! defined $config{$field}) {
27 error(sprintf(gettext("Must specify %s"), $field));
30 if (! exists $config{amazon_s3_prefix} ||
31 ! defined $config{amazon_s3_prefix}) {
32 $config{amazon_s3_prefix}="wiki/";
39 return $bucket if defined $bucket;
41 open(IN, "<", $config{amazon_s3_key_file}) || error($config{amazon_s3_key_file}.": ".$!);
46 my $s3=Net::Amazon::S3->new({
47 aws_access_key_id => $config{amazon_s3_key_id},
48 aws_secret_access_key => $key,
52 # make sure the bucket exists
53 if (exists $config{amazon_s3_location}) {
54 $bucket=$s3->add_bucket({
55 bucket => $config{amazon_s3_bucket},
56 location_constraint => $config{amazon_s3_location},
60 $bucket=$s3->add_bucket({
61 bucket => $config{amazon_s3_bucket},
66 error(gettext("Failed to create bucket in S3: ").
67 $s3->err.": ".$s3->errstr."\n");
78 # This is a wrapper around the real writefile.
79 sub writefile ($$$;$$) { #{{{
86 # First, write the file to disk.
87 my $ret=$IkiWiki::Plugin::amazon_s3::subs{'IkiWiki::writefile'}->($file, $destdir, $content, $binary, $writer);
89 # Now, determine if the file was written to the destdir.
90 # writefile might be used for writing files elsewhere.
91 # Also, $destdir might be set to a subdirectory of the destdir.
93 if ($destdir eq $config{destdir}) {
96 elsif ("$destdir/$file" =~ /^\Q$config{destdir}\/\E(.*)/) {
100 # Store the data in S3.
102 $key=$config{amazon_s3_prefix}.$key;
103 my $bucket=IkiWiki::Plugin::amazon_s3::getbucket();
105 # The http layer tries to downgrade utf-8
106 # content, but that can fail (see
107 # http://rt.cpan.org/Ticket/Display.html?id=35710),
108 # so force convert it to bytes.
109 $content=encode_utf8($content) if defined $content;
111 if (defined $content && ! length $content) {
112 # S3 doesn't allow storing empty files!
117 acl_short => 'public-read',
118 content_type => mimetype("$destdir/$file"),
122 $res=$bucket->add_key($key, $content, \%opts);
125 # read back in the file that the writer emitted
126 $res=$bucket->add_key_filename($key, "$destdir/$file", \%opts);
128 if ($res && $key=~/(^|\/)index.$config{htmlext}$/) {
129 # index.html files are a special case. Since S3 is
130 # not a normal web server, it won't serve up
131 # foo/index.html when foo/ is requested. So the
132 # file has to be stored twice. (This is bad news
133 # when usedirs is enabled!)
134 $key=~s/index.$config{htmlext}$//;
136 $res=$bucket->add_key($key, $content, \%opts);
139 $res=$bucket->add_key_filename($key, "$destdir/$file", \%opts);
143 error(gettext("Failed to save file to S3: ").
144 $bucket->err.": ".$bucket->errstr."\n");
151 # This is a wrapper around the real prune.
155 my $bucket=IkiWiki::Plugin::amazon_s3::getbucket();
156 print STDERR "wrapped prune\n";
158 return $IkiWiki::Plugin::amazon_s3::subs{'IkiWiki::writefile'}->($file);