Mercurial > hg > chronicle
annotate bin/chronicle @ 159:0d86c243c1c0
Include release in static pages too
author | Steve Kemp <steve@steve.org.uk> |
---|---|
date | Sat, 05 Jan 2008 22:45:46 +0000 |
parents | 6c1a70c3c3a8 |
children | 29397985be65 |
rev | line source |
---|---|
1 | 1 #!/usr/bin/perl -w |
2 | |
3 =head1 NAME | |
4 | |
5 chronicle - A blog compiler. | |
6 | |
7 =cut | |
8 | |
9 =head1 SYNOPSIS | |
10 | |
11 | |
36 | 12 Path Options: |
13 | |
85 | 14 --comments Specify the path to the optional comments directory. |
61 | 15 --config Specify a configuration file to read. |
16 --input Specify the input directory to use. | |
17 --output Specify the directory to write output to. | |
18 --theme-dir Specify the path to the theme templates. | |
19 --theme Specify the theme to use. | |
20 --pattern Specify the pattern of files to work with. | |
21 --url-prefix Specify the prefix to the live blog. | |
36 | 22 |
23 | |
24 Pre & Post-Build Commands: | |
25 | |
26 --pre-build Specify a command to execute prior to building the blog. | |
27 --post-build Specify a command to execute once the blog has been built. | |
28 | |
44 | 29 Blog Entry Options: |
30 | |
31 --format Specify the format of your entries, HTML/textile/markdown. | |
36 | 32 |
33 Optional Features: | |
34 | |
46 | 35 --force Force the copying of static files from the blog theme. |
36 | 36 --no-archive Don't create an archive page. |
37 --no-cache Don't use the optional memcached features, even if available. | |
128 | 38 --no-calendar Don't use the optional calendar upon the index. |
36 | 39 --no-tags Don't produce any tag pages. |
40 --lower-case Lower-case all filenames which are output. | |
41 | |
42 | |
1 | 43 Help Options: |
44 | |
45 --help Show the help information for this script. | |
46 --manual Read the manual for this script. | |
47 --verbose Show useful debugging information. | |
48 --version Show the version number and exit. | |
49 | |
50 =cut | |
51 | |
52 | |
53 =head1 ABOUT | |
54 | |
55 Chronicle is a simple tool to convert a collection of text files, | |
33 | 56 located within a single directory, into a blog consisting of static |
57 HTML files. | |
1 | 58 |
59 It supports only the bare minimum of features which are required | |
60 to be useful: | |
61 | |
62 * Tagging support. | |
63 | |
64 * RSS support. | |
65 | |
66 * Archive support. | |
67 | |
68 The obvious deficiencies are: | |
69 | |
85 | 70 * Lack of support for instant commenting. |
1 | 71 |
72 * Lack of pingback/trackback support. | |
73 | |
74 Having said that it is a robust, stable, and useful system. | |
75 | |
76 =cut | |
77 | |
46 | 78 |
44 | 79 =head1 BLOG FORMAT |
80 | |
81 The format of the text files we process is critical to the output | |
82 pages. Each entry should look something like this: | |
83 | |
84 =for example begin | |
85 | |
86 Title: This is the title of the blog post | |
87 Date: 2nd March 2007 | |
88 Tags: one, two, three, long tag | |
89 | |
90 The text of your entry goes here. | |
91 | |
92 =for example end | |
93 | |
94 In this example we can see that the entry itself has been prefaced | |
60 | 95 with a small header. An entry header is contains three optional lines, |
96 if these are not present then there are sensible defaults as described | |
97 below: | |
98 | |
99 =over 8 | |
100 | |
101 =item Title: | |
102 Describes the title of the post. If not present the filename of the entry | |
103 is used instead. | |
104 | |
105 =item Date: | |
106 The date the post was written. If not present the creation time of the | |
107 file is used instead. | |
108 | |
109 =item Tags: | |
110 Any tags which should be associated with the entry, separated by commas. | |
111 | |
112 =back | |
44 | 113 |
114 The text of the entry itself is assumed to be HTML, however if you | |
115 have the optional modules installed you may write it in Markdown or | |
60 | 116 Textile formats - if they are not present you will receive a message |
117 informing you of the names of the required modules. | |
44 | 118 |
60 | 119 You may specify the format of your entries either in the configuration |
120 file, or via the command line flag B<--format>. | |
44 | 121 |
46 | 122 =cut |
123 | |
124 | |
125 =head1 CONFIGURATION | |
126 | |
127 The configuration of the software is minimal, and generally performed | |
128 via the command line arguments. However it is possible to save settings | |
60 | 129 either in the file global /etc/chroniclerc or the per-user ~/.chroniclerc |
46 | 130 file. |
131 | |
60 | 132 If you wish you may pass the name of another configuration file to |
133 the script with the B<--config> flag. This will be read after the | |
134 previous two files, and may override any settings which are present. | |
135 | |
136 The configuration file contains lines like these: | |
46 | 137 |
138 =for example begin | |
139 | |
140 input = /home/me/blog | |
141 | |
142 output = /var/www/blog | |
143 | |
144 format = markdown | |
145 | |
146 =for example end | |
147 | |
148 Keys which are unknown are ignored. | |
44 | 149 |
150 =cut | |
151 | |
152 | |
153 =head1 OPTIONAL CACHING | |
154 | |
60 | 155 To speed the rebuilding of a large blog the compiler may use a local |
156 Memcached deaemon, if installed and available. | |
44 | 157 |
158 To install this, under a Debian GNU/Linux system please run: | |
159 | |
160 =for example begin | |
161 | |
162 apt-get update | |
163 apt-get install memcached libcache-memcached-perl | |
164 | |
165 =for example end | |
166 | |
167 You may disable this caching behaviour with --no-cache, and see the | |
168 effect with --verbose. | |
169 | |
170 =cut | |
171 | |
66
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
172 =head1 OPTIONAL CALENDAR |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
173 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
174 If the 'HTML::CalendarMonthSimple' module is available each blog will |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
175 contain a simple month-view of the current month upon the index. |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
176 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
177 To disable this invoke the program with '--no-calendar'. |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
178 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
179 =cut |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
180 |
1 | 181 |
85 | 182 =head1 OPTIONAL COMMENTING |
183 | |
184 Included with the chronicle code you should find the file | |
185 cgi-bin/comments.cgi. | |
186 | |
187 This file is designed to write submitted comments to the local | |
188 filesystem of your webserver. If you install that, and edit the | |
189 path at the start of teh script you should be able to include | |
190 comments in your blog. | |
191 | |
192 In short there are three things you need to do: | |
193 | |
194 =over 8 | |
195 | |
196 =item Install the CGI script and edit the path at the start. | |
197 | |
198 =item Copy the output comments to your local blog source. | |
199 | |
200 =item Run this script again with --comments=./path/to/comments | |
201 | |
202 =back | |
203 | |
143 | 204 This should include the comments in the static output. More |
205 explicit instructions are provided within the file 'COMMENTS' | |
206 included within the distribution. | |
85 | 207 |
208 =cut | |
209 | |
210 | |
1 | 211 =head1 AUTHOR |
212 | |
213 Steve | |
214 -- | |
215 http://www.steve.org.uk/ | |
216 | |
217 =cut | |
218 | |
219 =head1 LICENSE | |
220 | |
221 Copyright (c) 2007 by Steve Kemp. All rights reserved. | |
222 | |
223 This module is free software; | |
224 you can redistribute it and/or modify it under | |
225 the same terms as Perl itself. | |
226 The LICENSE file contains the full text of the license. | |
227 | |
228 =cut | |
229 | |
230 | |
231 use strict; | |
232 use warnings; | |
45 | 233 |
234 | |
1 | 235 use Date::Parse; |
39 | 236 use Date::Format; |
1 | 237 use File::Copy; |
238 use File::Path; | |
239 use Getopt::Long; | |
240 use HTML::Template; | |
241 use Pod::Usage; | |
45 | 242 use Time::Local; |
1 | 243 |
244 | |
23 | 245 # |
246 # Release number | |
247 # | |
248 # NOTE: Set by 'make release'. | |
249 # | |
67 | 250 my $RELEASE = 'UNRELEASED'; |
1 | 251 |
49 | 252 # |
253 # The names of the months. Posted early to allow i18n users. | |
254 # | |
255 my @names = qw( January February March April May June July August September October November December ); | |
18 | 256 |
1 | 257 # |
258 # Setup default options. | |
259 # | |
33 | 260 my %CONFIG = setupDefaultOptions(); |
1 | 261 |
262 | |
263 # | |
7 | 264 # Read the global and per-user configuration files, if they exist. |
1 | 265 # |
7 | 266 readConfigurationFile( "/etc/chroniclerc" ); |
267 readConfigurationFile( $ENV{'HOME'} . "/.chroniclerc" ); | |
1 | 268 |
269 | |
270 # | |
271 # Parse the command line arguments. | |
272 # | |
273 parseCommandLineArguments(); | |
274 | |
275 | |
276 # | |
59 | 277 # Another configuration file? |
278 # | |
279 readConfigurationFile( $CONFIG{'config'} ) if ( defined $CONFIG{'config'} ); | |
280 | |
281 | |
282 # | |
61 | 283 # Make sure we have arguments which are sane. |
284 # | |
285 # Specifically we want to cope with the "new" 'theme-dir', and 'theme' | |
286 # arguments. | |
287 # | |
288 # | |
289 sanityCheckArguments(); | |
290 | |
291 | |
292 # | |
293 # Listing themes? | |
294 # | |
295 if ( $CONFIG{'list-themes'} ) | |
296 { | |
297 listThemes( $CONFIG{'theme-dir'} ); | |
298 exit; | |
299 } | |
300 | |
1 | 301 # Should we run something before we start? |
302 # | |
303 if ( $CONFIG{'pre-build'} ) | |
304 { | |
305 $CONFIG{'verbose'} && print "Running command: $CONFIG{'pre-build'}\n"; | |
306 | |
307 system($CONFIG{'pre-build'}); | |
308 } | |
309 | |
310 | |
311 # | |
312 # Parse each of the given text files, and build up a datastructure | |
313 # we can use to create our pages. | |
314 # | |
315 # The data-structure is a hash of arrays. The hash key is the blog | |
316 # entry's filename, and the array stored as the hash's value has | |
317 # keys such as: | |
318 # | |
319 # tags => [ 'test', 'testing' ] | |
320 # date => '1st july 2007' | |
321 # title => 'Some title' | |
322 # | |
323 # | |
324 my %data = createDataStructure(); | |
325 | |
326 # | |
18 | 327 # Find each unique tag used within our entries. |
1 | 328 # |
329 my %all_tags; | |
330 %all_tags = findAllTags() unless( $CONFIG{'no-tags'} ); | |
331 | |
332 # | |
333 # Find each unique month + year we've used. | |
334 # | |
39 | 335 my %all_dates; |
1 | 336 %all_dates = findAllMonths() unless( $CONFIG{'no-archive'} ); |
337 | |
338 | |
339 # | |
340 # Now create the global tag + date loops which are used for our | |
341 # sidebar. | |
342 # | |
343 my %CLOUD; | |
344 $CLOUD{'tag'} = createTagCloud( %all_tags ) unless( $CONFIG{'no-tags'} ); | |
345 $CLOUD{'archive'} = createDateCloud( %all_dates ) unless( $CONFIG{'no-archive'} );; | |
346 | |
347 | |
18 | 348 |
349 # | |
39 | 350 # Create the output directories. |
18 | 351 # |
352 mkpath( $CONFIG{'output'}, 0, 0755 ) if ( ! -d $CONFIG{'output'} ); | |
39 | 353 foreach my $tag ( keys %all_tags ) |
354 { | |
355 mkpath( "$CONFIG{'output'}/tags/$tag", 0, 0755 ); | |
356 } | |
357 foreach my $date ( keys %all_dates ) | |
358 { | |
359 next unless ( $date =~ /^([0-9]{4})-([0-9]{2})/ ); | |
360 mkpath( "$CONFIG{'output'}/archive/$1/$2", 0, 0755 ); | |
361 } | |
18 | 362 |
363 | |
1 | 364 # |
365 # Output each static page. | |
366 # | |
367 $CONFIG{'verbose'} && print "Creating static pages:\n"; | |
368 foreach my $file ( keys %data ) | |
369 { | |
370 outputStaticPage( $file ); | |
371 } | |
372 | |
373 | |
374 | |
375 # | |
60 | 376 # Build an output page for every tag which has ever been used. |
1 | 377 # |
378 foreach my $tagName ( sort keys %all_tags ) | |
379 { | |
380 $CONFIG{'verbose'} && print "Creating tag page: $tagName\n"; | |
381 | |
382 outputTagPage( $tagName ); | |
383 } | |
384 | |
385 | |
386 | |
387 # | |
60 | 388 # Now build the archive pages. |
1 | 389 # |
390 foreach my $date ( keys( %all_dates ) ) | |
391 { | |
392 $CONFIG{'verbose'} && print "Creating archive page: $date\n"; | |
393 | |
394 outputArchivePage( $date ); | |
395 } | |
396 | |
397 | |
398 | |
399 # | |
18 | 400 # Finally out the most recent entries for the front-page. |
1 | 401 # |
402 outputIndexPage(); | |
403 | |
404 | |
405 | |
406 # | |
12 | 407 # Copy any static files into place. |
1 | 408 # |
12 | 409 copyStaticFiles(); |
1 | 410 |
411 | |
412 # | |
413 # Post-build command? | |
414 # | |
415 if ( $CONFIG{'post-build'} ) | |
416 { | |
417 $CONFIG{'verbose'} && print "Running command: $CONFIG{'post-build'}\n"; | |
418 | |
419 system($CONFIG{'post-build'}); | |
420 } | |
421 | |
18 | 422 |
1 | 423 # |
424 # All done. | |
425 # | |
426 exit; | |
427 | |
428 | |
429 | |
430 | |
431 | |
18 | 432 |
433 | |
1 | 434 =begin doc |
435 | |
436 Setup the default options we'd expect into our global configuration hash. | |
437 | |
438 =end doc | |
439 | |
440 =cut | |
441 | |
442 sub setupDefaultOptions | |
443 { | |
33 | 444 my %CONFIG; |
445 | |
18 | 446 # |
447 # Text directory. | |
448 # | |
1 | 449 $CONFIG{'input'} = "./blog"; |
85 | 450 $CONFIG{'comments'} = ''; |
18 | 451 |
452 # | |
453 # Output directory. | |
454 # | |
1 | 455 $CONFIG{'output'} = "./output"; |
18 | 456 |
457 # | |
61 | 458 # Theme setup |
18 | 459 # |
61 | 460 $CONFIG{'theme-dir'} = "./themes/"; |
461 $CONFIG{'theme'} = "default"; | |
18 | 462 |
463 # | |
464 # prefix for all links. | |
465 # | |
1 | 466 $CONFIG{'url-prefix'} = ""; |
18 | 467 |
468 # | |
469 # Default input format | |
470 # | |
16 | 471 $CONFIG{'format'} = 'html'; |
18 | 472 |
473 # | |
474 # Entries per-page for the index. | |
475 # | |
476 $CONFIG{'entry-count'} = 10; | |
477 | |
46 | 478 # |
479 # Don't overwrite files by default | |
480 # | |
481 $CONFIG{'force'} = 0; | |
482 | |
33 | 483 return( %CONFIG ); |
1 | 484 } |
485 | |
486 | |
487 | |
18 | 488 |
1 | 489 =begin doc |
490 | |
491 Parse the command line arguments this script was given. | |
492 | |
493 =end doc | |
494 | |
495 =cut | |
496 | |
497 sub parseCommandLineArguments | |
498 { | |
499 my $HELP = 0; | |
500 my $MANUAL = 0; | |
501 my $VERSION = 0; | |
502 | |
503 # | |
504 # Parse options. | |
505 # | |
506 GetOptions( | |
507 # Help options | |
508 "help", \$HELP, | |
509 "manual", \$MANUAL, | |
510 "verbose", \$CONFIG{'verbose'}, | |
511 "version", \$VERSION, | |
61 | 512 "list-themes", \$CONFIG{'list-themes'}, |
1 | 513 |
514 # paths | |
85 | 515 "comments=s", \$CONFIG{'comments'}, |
59 | 516 "config=s", \$CONFIG{'config'}, |
1 | 517 "input=s", \$CONFIG{'input'}, |
518 "output=s", \$CONFIG{'output'}, | |
61 | 519 "theme-dir=s", \$CONFIG{'theme-dir'}, |
520 "theme=s", \$CONFIG{'theme'}, | |
36 | 521 "pattern=s", \$CONFIG{'pattern'}, |
1 | 522 |
523 # optional | |
46 | 524 "force", \$CONFIG{'force'}, |
1 | 525 "no-tags", \$CONFIG{'no-tags'}, |
33 | 526 "no-cache", \$CONFIG{'no-cache'}, |
75
c64a37a823d1
Document, and support, no-calendar.
Steve Kemp <steve@steve.org.uk>
parents:
67
diff
changeset
|
527 "no-calendar", \$CONFIG{'no-calendar'}, |
105 | 528 "no-comments", \$CONFIG{'no-comments'}, |
1 | 529 "no-archive", \$CONFIG{'no-archive'}, |
34 | 530 "lower-case", \$CONFIG{'lower-case'}, |
1 | 531 |
44 | 532 # input format. |
533 "format=s", \$CONFIG{'format'}, | |
534 | |
27 | 535 # prefix |
536 "url-prefix=s", \$CONFIG{'url_prefix'}, | |
537 | |
1 | 538 # commands |
539 "pre-build=s", \$CONFIG{'pre-build'}, | |
540 "post-build=s", \$CONFIG{'post-build'}, | |
541 | |
542 ); | |
543 | |
544 pod2usage(1) if $HELP; | |
545 pod2usage(-verbose => 2 ) if $MANUAL; | |
546 | |
547 if ( $VERSION ) | |
548 { | |
23 | 549 print( "chronicle release $RELEASE\n" ); |
1 | 550 exit; |
551 } | |
552 } | |
553 | |
554 | |
555 | |
556 =begin doc | |
557 | |
558 Create our global datastructure, by reading each of the blog | |
559 files and extracting: | |
560 | |
561 1. The title of the entry. | |
562 | |
563 2. Any tags which might be present. | |
564 | |
565 3. The date upon which it was made. | |
566 | |
567 =end doc | |
568 | |
569 =cut | |
570 | |
571 sub createDataStructure | |
572 { | |
573 my %results; | |
574 | |
575 # | |
576 # Did the user override the default pattern? | |
577 # | |
578 my $pattern = $CONFIG{'pattern'} || "*"; | |
579 | |
580 foreach my $file ( sort( glob( $CONFIG{'input'} . "/" . $pattern ) ) ) | |
581 { | |
7 | 582 # |
583 # Ignore directories. | |
584 # | |
585 next if ( -d $file ); | |
586 | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
587 # |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
588 # Read the entry and store all the data away as a |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
589 # hash element keyed upon the (unique) filename. |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
590 # |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
591 $results{$file} = readBlogEntry( $file); |
1 | 592 } |
593 | |
594 # | |
595 # Make sure we found some entries. | |
596 # | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
597 if ( scalar(keys(%results))< 1 ) |
1 | 598 { |
599 print <<EOF; | |
600 | |
601 There were no text files found in the input directory | |
602 $CONFIG{'input'} which matched the pattern '$pattern'. | |
603 | |
604 Aborting. | |
605 | |
606 EOF | |
607 exit; | |
608 } | |
609 | |
610 return %results; | |
611 } | |
612 | |
613 | |
614 | |
615 =begin doc | |
616 | |
617 Find each distinct tag which has been used within blog entries, | |
618 and the number of times each one has been used. | |
619 | |
620 =end doc | |
621 | |
622 =cut | |
623 | |
624 sub findAllTags | |
625 { | |
626 my %allTags; | |
627 | |
628 foreach my $f ( keys %data ) | |
629 { | |
630 my $h = $data{$f}; | |
631 my $tags = $h->{'tags'} || undef; | |
632 foreach my $t ( @$tags ) | |
633 { | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
634 if ( $t->{'tag'} ) |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
635 { |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
636 $allTags{$t->{'tag'}}+=1; |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
637 } |
1 | 638 } |
639 } | |
640 | |
641 return( %allTags ); | |
642 } | |
643 | |
644 | |
645 | |
646 =begin doc | |
647 | |
648 Create a structure for a tag cloud. | |
649 | |
650 =end doc | |
651 | |
652 =cut | |
653 | |
654 sub createTagCloud | |
655 { | |
656 my( %unique ) = ( @_ ); | |
657 | |
658 my $results; | |
659 | |
660 foreach my $key ( sort keys( %unique ) ) | |
661 { | |
60 | 662 # count. |
27 | 663 my $count = $unique{$key}; |
60 | 664 |
665 # size for the HTML. | |
27 | 666 my $size = 10 + ( $count * 5 ); |
60 | 667 $size = 40 if ( $size >= 40 ); |
27 | 668 |
1 | 669 push( @$results, |
27 | 670 { tag => $key, |
671 count => $count, | |
34 | 672 size => $size } ); |
1 | 673 } |
674 return $results; | |
675 | |
676 } | |
677 | |
678 | |
679 | |
680 =begin doc | |
681 | |
682 Find each of the distinct Month + Year pairs for entries which | |
683 have been created. | |
684 | |
685 =end doc | |
686 | |
687 =cut | |
688 | |
689 sub findAllMonths | |
690 { | |
691 my %allDates; | |
692 foreach my $f ( keys %data ) | |
693 { | |
60 | 694 my $h = $data{$f}; |
1 | 695 next if ( !$h ); |
696 | |
55 | 697 my $date = $h->{'date'}; |
698 | |
699 # | |
60 | 700 # Not a date? Use the ctime of the file. |
55 | 701 # |
702 if ( !defined( $date ) || !length($date) ) | |
703 { | |
704 # | |
705 # Test the file for creation time. | |
706 # | |
707 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, | |
708 $atime,$mtime,$ctime,$blksize,$blocks) | |
709 = stat($f); | |
710 | |
711 $date = localtime( $ctime ); | |
712 } | |
713 | |
714 $date = time2str("%Y-%m", str2time($date)); | |
1 | 715 |
716 $allDates{$date}+=1; | |
717 } | |
718 | |
719 return( %allDates ); | |
720 } | |
721 | |
722 | |
723 | |
724 =begin doc | |
725 | |
726 Create a data structure which can be used for our archive layout. | |
727 | |
728 This is a little messy too. It mostly comes because we want to | |
729 have a nested loop so that we can place our entries in a nice manner. | |
730 | |
731 =end doc | |
732 | |
733 =cut | |
734 | |
735 sub createDateCloud | |
736 { | |
39 | 737 my( %entry_dates ) = ( @_ ); |
1 | 738 |
739 my $results; | |
39 | 740 my $year; |
741 my $months; | |
1 | 742 |
39 | 743 foreach my $date ( sort keys %entry_dates ) |
1 | 744 { |
39 | 745 next unless ( $date =~ /^([0-9]{4})-([0-9]{2})/ ); |
746 | |
747 if ( $year and $1 ne $year ) | |
1 | 748 { |
39 | 749 push( @$results, { year => $year, |
750 months => $months } ); | |
751 undef $months; | |
1 | 752 } |
39 | 753 $year = $1; |
754 | |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
755 push( @$months, { month => $2, |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
756 month_name => $names[$2-1], |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
757 count => $entry_dates{$date} } ); |
39 | 758 |
1 | 759 } |
760 | |
39 | 761 push( @$results, { year => $year, |
762 months => $months } ); | |
1 | 763 |
78 | 764 # |
765 # Make sure this is sorted by reverse chronilogical order. | |
766 # | |
767 my @sorted = sort { $b->{'year'} <=> $a->{'year'} } @$results; | |
768 return \@sorted; | |
1 | 769 } |
770 | |
771 | |
772 | |
773 =begin doc | |
774 | |
775 Sort by date. | |
776 | |
777 =end doc | |
778 | |
779 =cut | |
780 | |
781 sub bywhen | |
782 { | |
37 | 783 # |
784 # Parse and return the date | |
785 # | |
786 my ($ss1,$mm1,$hh1,$day1,$month1,$year1,$zone1) = strptime($a->{'date'}); | |
1 | 787 my ($ss2,$mm2,$hh2,$day2,$month2,$year2,$zone2) = strptime($b->{'date'}); |
788 | |
37 | 789 # |
790 # Abort if we didn't work. | |
791 # | |
66
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
792 die "Couldn't find first year: $a->{'date'}" unless defined($year1); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
793 die "Couldn't find second year: $b->{'date'}" unless defined($year2); |
1 | 794 |
37 | 795 # |
796 # Convert to compare | |
797 # | |
798 my $c = timelocal(0,0,0,$day1,$month1,$year1 + 1900); | |
799 my $d = timelocal(0,0,0,$day2,$month2,$year2 + 1900); | |
800 | |
801 return $d <=> $c; | |
1 | 802 } |
803 | |
804 | |
805 | |
806 | |
807 =begin doc | |
808 | |
809 Output the index page + index RSS feed. | |
810 | |
811 =end doc | |
812 | |
813 =cut | |
814 | |
815 sub outputIndexPage | |
816 { | |
817 | |
818 # | |
819 # Holder for the blog entries. | |
820 # | |
821 my $entries; | |
822 | |
823 # | |
824 # Find all the entries and sort them to be most recent first. | |
825 # | |
826 my $tmp; | |
827 foreach my $file ( keys ( %data ) ) | |
828 { | |
829 my $blog = readBlogEntry( $file ); | |
80
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
830 |
1 | 831 push( @$tmp, $blog ) if (keys( %$blog ) ); |
832 } | |
833 my @tmp2 = sort bywhen @$tmp; | |
834 | |
835 # | |
836 # The number of entries to display upon the index. | |
837 # | |
18 | 838 my $max = $CONFIG{'entry-count'}; |
1 | 839 foreach my $f ( @tmp2 ) |
840 { | |
841 push( @$entries, $f ) if ( $max > 0 ); | |
842 $max -= 1; | |
843 } | |
844 | |
845 # | |
846 # Open the index template. | |
847 # | |
21 | 848 my $template = loadTemplate( "index.template", |
849 die_on_bad_params => 0 ); | |
850 | |
66
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
851 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
852 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
853 # create the calendar if we can. |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
854 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
855 my $calendar = createCalendar(); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
856 if ( defined( $calendar ) ) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
857 { |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
858 my $text = $calendar->as_HTML(); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
859 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
860 $text =~ s/<\/?b>//g; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
861 $text =~ s/<\/?p>//g; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
862 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
863 $template->param( calendar => 1, |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
864 calendar_month => $text ); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
865 } |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
866 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
867 |
21 | 868 # |
869 # The entries. | |
870 # | |
871 $template->param( entries => $entries ) | |
872 if ( $entries ); | |
1 | 873 |
21 | 874 # |
875 # The clouds | |
876 # | |
877 $template->param( tagcloud => $CLOUD{'tag'} ) | |
878 if ( $CLOUD{'tag'} ); | |
879 $template->param( datecloud => $CLOUD{'archive'} ) | |
880 if ( $CLOUD{'archive'} ); | |
881 | |
882 # | |
883 # Blog title and subtitle, if present. | |
884 # | |
885 $template->param( blog_title => $CONFIG{'blog_title'} ) | |
886 if ( $CONFIG{'blog_title'} ); | |
887 $template->param( blog_subtitle => $CONFIG{'blog_subtitle'} ) | |
888 if ( $CONFIG{'blog_subtitle'} ); | |
23 | 889 $template->param( release => $RELEASE ); |
890 | |
1 | 891 |
892 # | |
893 # Page to use | |
894 # | |
895 my $index = $CONFIG{'filename'} || "index.html"; | |
896 | |
39 | 897 outputTemplate( $template, $index ); |
1 | 898 |
899 # | |
900 # Output the RSS feed | |
901 # | |
902 $template = loadTemplate( "index.xml.template", | |
903 die_on_bad_params => 0 ); | |
152
89eef19064e8
Updated to add titles to our RSS feeds.
Steve Kemp <steve@steve.org.uk>
parents:
144
diff
changeset
|
904 $template->param( blog_title => $CONFIG{'blog_title'} ) |
89eef19064e8
Updated to add titles to our RSS feeds.
Steve Kemp <steve@steve.org.uk>
parents:
144
diff
changeset
|
905 if ( $CONFIG{'blog_title'} ); |
89eef19064e8
Updated to add titles to our RSS feeds.
Steve Kemp <steve@steve.org.uk>
parents:
144
diff
changeset
|
906 $template->param( blog_subtitle => $CONFIG{'blog_subtitle'} ) |
89eef19064e8
Updated to add titles to our RSS feeds.
Steve Kemp <steve@steve.org.uk>
parents:
144
diff
changeset
|
907 if ( $CONFIG{'blog_subtitle'} ); |
1 | 908 $template->param( entries => $entries ) if ( $entries ); |
39 | 909 outputTemplate( $template, "index.rss" ); |
1 | 910 } |
911 | |
912 | |
913 | |
914 =begin doc | |
915 | |
916 Write out a /tags/$foo/index.html containing each blog entry which has the | |
917 tag '$foo'. | |
918 | |
919 =end doc | |
920 | |
921 =cut | |
922 | |
923 sub outputTagPage | |
924 { | |
925 my ( $tagName ) = ( @_ ); | |
926 | |
39 | 927 my $dir = "tags/$tagName"; |
1 | 928 |
929 my %allTags; | |
930 my %tagEntries; | |
931 foreach my $f ( keys %data ) | |
932 { | |
933 my $h = $data{$f}; | |
934 my $tags = $h->{'tags'} || undef; | |
935 foreach my $t ( @$tags ) | |
936 { | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
937 my $name = $t->{'tag'}; |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
938 $allTags{$name}+=1; |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
939 my $a = $tagEntries{$name}; |
1 | 940 push @$a, $f ; |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
941 $tagEntries{$name}= $a; |
1 | 942 } |
943 } | |
944 | |
945 my $matching = $tagEntries{$tagName}; | |
946 | |
947 my $entries; | |
948 | |
949 # | |
950 # Now read the matching entries. | |
951 # | |
952 foreach my $f ( sort @$matching ) | |
953 { | |
954 my $blog = readBlogEntry( $f ); | |
955 if (keys( %$blog ) ) | |
956 { | |
957 $CONFIG{'verbose'} && print "\tAdded: $f\n"; | |
958 push( @$entries, $blog ); | |
959 } | |
960 } | |
961 | |
962 # | |
963 # Now write the output as a HTML page. | |
964 # | |
21 | 965 my $template = loadTemplate( "tags.template", |
966 die_on_bad_params => 0 ); | |
967 | |
968 # | |
969 # The entries. | |
970 # | |
1 | 971 $template->param( entries => $entries ) if ( $entries ); |
972 $template->param( tagname => $tagName ); | |
158
6c1a70c3c3a8
Updated so that our templates always get a version included.
Steve Kemp <steve@steve.org.uk>
parents:
152
diff
changeset
|
973 $template->param( release => $RELEASE ); |
21 | 974 |
975 # | |
976 # The clouds | |
977 # | |
978 $template->param( tagcloud => $CLOUD{'tag'} ) | |
979 if ( $CLOUD{'tag'} ); | |
980 $template->param( datecloud => $CLOUD{'archive'} ) | |
981 if ( $CLOUD{'archive'} ); | |
982 | |
983 # | |
984 # Blog title and subtitle, if present. | |
985 # | |
986 $template->param( blog_title => $CONFIG{'blog_title'} ) | |
987 if ( $CONFIG{'blog_title'} ); | |
988 $template->param( blog_subtitle => $CONFIG{'blog_subtitle'} ) | |
989 if ( $CONFIG{'blog_subtitle'} ); | |
990 | |
1 | 991 |
992 # | |
993 # Page to use | |
994 # | |
995 my $index = $CONFIG{'filename'} || "index.html"; | |
996 | |
39 | 997 outputTemplate( $template, "$dir/$index" ); |
1 | 998 |
999 # | |
1000 # Now output the .xml file | |
1001 # | |
1002 $template = loadTemplate( "tags.xml.template", die_on_bad_params => 0 ); | |
152
89eef19064e8
Updated to add titles to our RSS feeds.
Steve Kemp <steve@steve.org.uk>
parents:
144
diff
changeset
|
1003 $template->param( blog_title => $CONFIG{'blog_title'} ) |
89eef19064e8
Updated to add titles to our RSS feeds.
Steve Kemp <steve@steve.org.uk>
parents:
144
diff
changeset
|
1004 if ( $CONFIG{'blog_title'} ); |
1 | 1005 $template->param( entries => $entries ) if ( $entries ); |
1006 $template->param( tagname => $tagName ) if ( $tagName ); | |
39 | 1007 outputTemplate( $template, "$dir/$tagName.rss" ); |
1 | 1008 } |
1009 | |
1010 | |
1011 | |
1012 =begin doc | |
1013 | |
1014 Output the archive page for the given Month + Year. | |
1015 | |
1016 This function is a *mess* and iterates over the data structure much | |
1017 more often than it needs to. | |
1018 | |
1019 =end doc | |
1020 | |
1021 =cut | |
1022 | |
1023 sub outputArchivePage | |
1024 { | |
1025 my( $date ) = ( @_ ); | |
1026 | |
1027 # | |
1028 # Should we abort? | |
1029 # | |
1030 if ( $CONFIG{'no-archive'} ) | |
1031 { | |
1032 $CONFIG{'verbose'} && print "Ignoring archive page, as instructed.\n"; | |
1033 return; | |
1034 } | |
1035 | |
1036 | |
1037 my $year = ''; | |
1038 my $month = ''; | |
39 | 1039 if ( $date =~ /^([0-9]{4})-([0-9]{2})/ ) |
1 | 1040 { |
39 | 1041 $year = $1; |
1042 $month = $2; | |
1 | 1043 } |
1044 | |
1045 # | |
1046 # Make the directory | |
1047 # | |
39 | 1048 my $dir = "archive/$year/$month"; |
1 | 1049 |
1050 my $entries; | |
1051 | |
1052 | |
1053 my %dateEntries; | |
1054 foreach my $f ( keys %data ) | |
1055 { | |
1056 my $h = $data{$f}; | |
55 | 1057 my $date = $h->{'date'}; |
1058 | |
1059 # | |
1060 # Not a date? Use the file. | |
1061 # | |
1062 if ( !defined( $date ) || !length($date) ) | |
1063 { | |
1064 # | |
1065 # Test the file for creation time. | |
1066 # | |
1067 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, | |
1068 $atime,$mtime,$ctime,$blksize,$blocks) | |
1069 = stat($f); | |
1070 | |
1071 $date = localtime( $ctime ); | |
1072 } | |
1073 | |
1074 $date = time2str("%Y-%m", str2time($date)); | |
1 | 1075 |
39 | 1076 push @{$dateEntries{$date}}, $f ; |
1 | 1077 } |
1078 | |
1079 | |
1080 my $matching = $dateEntries{$date}; | |
1081 foreach my $f ( reverse @$matching ) | |
1082 { | |
1083 $CONFIG{'verbose'} && print "\tAdded: $f\n"; | |
1084 | |
1085 my $blog = readBlogEntry( $f ); | |
1086 if (keys( %$blog ) ) | |
1087 { | |
1088 push( @$entries, $blog ); | |
1089 } | |
1090 } | |
1091 | |
1092 # | |
1093 # Now write the output as a HTML page. | |
1094 # | |
21 | 1095 my $template = loadTemplate( "month.template", |
1096 die_on_bad_params => 0 ); | |
158
6c1a70c3c3a8
Updated so that our templates always get a version included.
Steve Kemp <steve@steve.org.uk>
parents:
152
diff
changeset
|
1097 $template->param( release => $RELEASE ); |
21 | 1098 |
48 | 1099 |
21 | 1100 # |
48 | 1101 # The entries |
21 | 1102 # |
1 | 1103 $template->param( entries => $entries ) if ( $entries ); |
48 | 1104 |
1105 # | |
1106 # Output the month + year. | |
1107 # | |
1 | 1108 $template->param( year => $year, month => $month ); |
48 | 1109 $template->param( month_name => $names[$month - 1 ] ); |
21 | 1110 |
1111 # | |
1112 # The clouds | |
1113 # | |
1114 $template->param( tagcloud => $CLOUD{'tag'} ) | |
1115 if ( $CLOUD{'tag'} ); | |
1116 $template->param( datecloud => $CLOUD{'archive'} ) | |
1117 if ( $CLOUD{'archive'} ); | |
1118 | |
1119 # | |
1120 # Blog title and subtitle, if present. | |
1121 # | |
1122 $template->param( blog_title => $CONFIG{'blog_title'} ) | |
1123 if ( $CONFIG{'blog_title'} ); | |
1124 $template->param( blog_subtitle => $CONFIG{'blog_subtitle'} ) | |
1125 if ( $CONFIG{'blog_subtitle'} ); | |
1 | 1126 |
1127 # | |
1128 # Page to use | |
1129 # | |
1130 my $index = $CONFIG{'filename'} || "index.html"; | |
39 | 1131 outputTemplate( $template, "$dir/$index" ); |
1 | 1132 |
1133 # | |
1134 # Now the RSS page. | |
1135 # | |
1136 $template = loadTemplate( "month.xml.template", die_on_bad_params => 0 ); | |
152
89eef19064e8
Updated to add titles to our RSS feeds.
Steve Kemp <steve@steve.org.uk>
parents:
144
diff
changeset
|
1137 $template->param( blog_title => $CONFIG{'blog_title'} ) |
89eef19064e8
Updated to add titles to our RSS feeds.
Steve Kemp <steve@steve.org.uk>
parents:
144
diff
changeset
|
1138 if ( $CONFIG{'blog_title'} ); |
1 | 1139 $template->param( entries => $entries ) if ( $entries ); |
1140 $template->param( month => $month, year => $year ); | |
48 | 1141 $template->param( month_name => $names[$month - 1 ] ); |
39 | 1142 outputTemplate( $template, "$dir/$month.rss" ); |
1 | 1143 } |
1144 | |
1145 | |
1146 | |
1147 | |
1148 =begin doc | |
1149 | |
1150 Output static page. | |
1151 | |
1152 =end doc | |
1153 | |
1154 =cut | |
1155 | |
1156 sub outputStaticPage | |
1157 { | |
1158 my ( $filename ) = ( @_ ); | |
1159 | |
1160 # | |
1161 # Load the template | |
1162 # | |
21 | 1163 my $template = loadTemplate( "entry.template", |
1164 die_on_bad_params => 0 ); | |
159
0d86c243c1c0
Include release in static pages too
Steve Kemp <steve@steve.org.uk>
parents:
158
diff
changeset
|
1165 $template->param( release => $RELEASE ); |
1 | 1166 |
1167 # | |
1168 # Just the name of the file. | |
1169 # | |
1170 my $basename = $filename; | |
1171 if ( $basename =~ /(.*)\/(.*)/ ) | |
1172 { | |
1173 $basename=$2; | |
1174 } | |
57 | 1175 if ( $basename =~ /^(.*)\.(.*)$/ ) |
1176 { | |
1177 $basename = $1; | |
1178 } | |
34 | 1179 |
1 | 1180 # |
1181 # Read the entry | |
1182 # | |
1183 my $static = readBlogEntry( $filename ); | |
1184 | |
34 | 1185 # |
1186 # Get the pieces of information. | |
1187 # | |
1 | 1188 my $title = $static->{'title'} || $basename; |
1189 my $tags = $static->{'tags'}; | |
1190 my $body = $static->{'body'}; | |
55 | 1191 my $date = $static->{'date'}; |
1192 | |
1193 if ( !defined($date) ) | |
1194 { | |
1195 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, | |
1196 $atime,$mtime,$ctime,$blksize,$blocks) | |
1197 = stat($filename); | |
1198 | |
1199 $date = localtime( $ctime ); | |
1200 } | |
1 | 1201 |
1202 $CONFIG{'verbose'} && print "\t$filename\n"; | |
1203 | |
1204 # | |
1205 # Convert to suitable filename. | |
1206 # | |
1207 my $file = fileToTitle($title); | |
1208 | |
85 | 1209 |
1210 # | |
1211 # Get comments, if present. | |
1212 # | |
1213 if( !$CONFIG{'no-comments'} ) | |
1214 { | |
1215 my $comments = getComments( $CONFIG{'comments'}, $file ); | |
1216 | |
1217 if ( defined($comments) ) | |
1218 { | |
132
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1219 my $count = scalar( @$comments ); |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1220 my $plural = 1; |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1221 $plural = 0 if ( $count == 1 ); |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1222 |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1223 $template->param( comments => $comments, |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1224 comment_count => $count, |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1225 comment_plural => $plural ); |
85 | 1226 |
1227 $CONFIG{'verbose'} && print "$file [$filename] has $count comments\n"; | |
1228 } | |
1229 | |
1230 $template->param( comments_enabled => 1 ); | |
1231 } | |
1232 | |
1233 | |
21 | 1234 # |
1235 # The entry. | |
1236 # | |
1 | 1237 $template->param( title => $title ); |
1238 $template->param( tags => $tags ) if ( $tags ); | |
1239 $template->param( date => $date ) if ( $date ); | |
1240 $template->param( body => $body ); | |
92 | 1241 $template->param( link => $static->{'link'} ); |
21 | 1242 |
1243 # | |
1244 # Our clouds | |
1245 # | |
1 | 1246 $template->param( tagcloud => $CLOUD{'tag'} ) if ( $CLOUD{'tag'} ); |
1247 $template->param( datecloud => $CLOUD{'archive'} ) if ( $CLOUD{'archive'} ); | |
21 | 1248 |
1249 # | |
1250 # Blog title and subtitle, if present. | |
1251 # | |
1252 $template->param( blog_title => $CONFIG{'blog_title'} ) | |
1253 if ( $CONFIG{'blog_title'} ); | |
1254 $template->param( blog_subtitle => $CONFIG{'blog_subtitle'} ) | |
1255 if ( $CONFIG{'blog_subtitle'} ); | |
1256 | |
39 | 1257 outputTemplate( $template, $file ); |
1 | 1258 } |
1259 | |
1260 | |
1261 | |
1262 =begin doc | |
1263 | |
1264 Return a hash of interesting data from our blog file. | |
1265 | |
1266 =end doc | |
1267 | |
1268 =cut | |
1269 | |
1270 sub readBlogEntry | |
1271 { | |
1272 my ( $filename ) = ( @_); | |
1273 | |
1274 my %entry; | |
1275 | |
33 | 1276 # |
1277 # Do we have the memcache module available? | |
1278 # | |
1279 my $cache = undef; | |
1280 my $test = "use Cache::Memcached;"; | |
1281 eval( $test ); | |
1282 if ( ( ! $@ ) && ( ! $CONFIG{'no-cache'} ) ) | |
1283 { | |
1284 # create the cache object | |
1285 $cache = new Cache::Memcached {'servers' => ["localhost:11211"] }; | |
1286 | |
1287 # fetch from the cache if it is present. | |
1288 my $cached = $cache->get( "file_$filename" ); | |
1289 if ( defined( $cached ) ) | |
1290 { | |
1291 $CONFIG{'verbose'} && print "memcache-get: $filename\n"; | |
1292 return( \%$cached ) | |
1293 } | |
1294 else | |
1295 { | |
1296 $CONFIG{'verbose'} && print "memcache-fail: $filename\n"; | |
1297 } | |
1298 } | |
1299 | |
1 | 1300 |
18 | 1301 my $title = ""; # entry title. |
1302 my $tags = ""; # entry tags. | |
1303 my $body = ""; # entry body. | |
1304 my $date = ""; # entry date | |
1 | 1305 |
1306 open( ENTRY, "<", $filename ) or die "Failed to read $filename $!"; | |
1307 while( my $line = <ENTRY> ) | |
1308 { | |
1309 # | |
62 | 1310 # Get the tags. |
1 | 1311 # |
62 | 1312 if (( $line =~ /^tags: (.*)/i ) && !length( $tags ) ) |
1 | 1313 { |
62 | 1314 $tags = $1; |
1 | 1315 } |
1316 elsif (( $line =~ /^title: (.*)/i ) && !length($title) ) | |
1317 { | |
62 | 1318 # |
1319 # Get the title | |
1320 # | |
1 | 1321 $title = $1; |
11 | 1322 |
1323 # strip leading and trailing space. | |
1324 $title =~ s/^\s+// if ( length $title ); | |
1325 $title =~ s/\s+$// if ( length $title ); | |
1 | 1326 } |
1327 elsif (( $line =~ /^date: (.*)/i ) && !length($date) ) | |
1328 { | |
62 | 1329 # |
1330 # Get the date. | |
1331 # | |
1 | 1332 $date = $1; |
11 | 1333 |
1334 # strip leading and trailing space. | |
1335 $date =~ s/^\s+// if ( length $date ); | |
1336 $date =~ s/\s+$// if ( length $date ); | |
1337 } | |
1 | 1338 else |
1339 { | |
62 | 1340 # |
1341 # Just a piece of body text. | |
1342 # | |
1 | 1343 $body .= $line; |
1344 } | |
1345 } | |
1346 close( ENTRY ); | |
1347 | |
1348 # | |
44 | 1349 # Determine the input format to use. |
16 | 1350 # |
44 | 1351 my $format = lc($CONFIG{'format'}); |
1352 | |
1353 # | |
1354 # Now process accordingly. | |
1355 # | |
1356 if ( $format eq 'html' ) | |
16 | 1357 { |
1358 # nop | |
1359 } | |
44 | 1360 elsif( $format eq 'markdown' ) |
16 | 1361 { |
1362 $body = markdown2HTML( $body ); | |
1363 } | |
44 | 1364 elsif( $format eq 'textile' ) |
16 | 1365 { |
1366 $body = textile2HTML( $body ); | |
1367 } | |
1368 else | |
1369 { | |
44 | 1370 print "Unkown blog entry format ($CONFIG{'format'}).\n"; |
1371 print "Treating as HTML.\n"; | |
16 | 1372 } |
1373 | |
1374 # | |
1375 # | |
44 | 1376 # If we have tags then we should use them. |
1 | 1377 # |
1378 my $entryTags; | |
1379 | |
1380 foreach my $tag ( split( /,/, $tags ) ) | |
1381 { | |
1382 # strip leading and trailing space. | |
1383 $tag =~ s/^\s+//; | |
1384 $tag =~ s/\s+$//; | |
1385 | |
1386 # skip empty tags. | |
1387 next if ( !length($tag) ); | |
62 | 1388 |
1389 # tags are lowercase. | |
1 | 1390 $tag = lc($tag); |
1391 push ( @$entryTags, { tag => $tag } ); | |
1392 } | |
1393 | |
1394 # | |
1395 # If the date isn't set then use todays. | |
1396 # | |
1397 if ( ! defined($date) ||( !length( $date ) ) ) | |
1398 { | |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1399 my @lt = localtime(time); |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1400 $date = strftime( "%d %B %Y", @lt); |
1 | 1401 } |
1402 | |
1403 # | |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1404 # Make an entry date for the XML feed, if we have a date. |
80
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
1405 # |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1406 my $time = str2time($date); |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1407 if ( $time ) |
80
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
1408 { |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1409 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1410 # Get the details of the file. |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1411 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1412 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1413 $atime,$mtime,$ctime,$blksize,$blocks) |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1414 = stat($filename); |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1415 |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1416 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1417 # Get the modification hours. |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1418 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1419 my ($sec,$min,$hour) = localtime( $mtime ); |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1420 |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1421 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1422 # Pad to two digits for each of the hours, minutes, and seconds. |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1423 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1424 my $hms = sprintf("%02d:%02d:%02d", $hour, $min, $sec ); |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1425 |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1426 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1427 # Store the published date & time away. Collapsing multiple |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1428 # spaces |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1429 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1430 $entry{'pubdate'} = time2str("%a, %e %b %Y $hms GMT", $time ); |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1431 $entry{'pubdate'} =~ s/ +/ /g; |
80
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
1432 } |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1433 else |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1434 { |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1435 print "Failed to parse date: '$date' to generate pubDate of entry.\n"; |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1436 } |
80
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
1437 |
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
1438 # |
1 | 1439 # Store the entry. |
1440 # | |
1441 $entry{'title'} = $title; | |
1442 $entry{'body'} = $body if ( $body ); | |
1443 $entry{'date'} = $date; | |
1444 $entry{'tags'} = $entryTags if ( $entryTags ); | |
33 | 1445 |
85 | 1446 |
33 | 1447 # |
57 | 1448 # No title? |
1449 # | |
1450 if ( !defined($entry{'title'}) || | |
1451 !length($entry{'title'}) ) | |
1452 { | |
1453 my $basename = $filename; | |
1454 if ( $basename =~ /(.*)\/(.*)/ ) | |
1455 { | |
1456 $basename=$2; | |
1457 } | |
1458 if ( $basename =~ /^(.*)\.(.*)$/ ) | |
1459 { | |
1460 $basename = $1; | |
1461 } | |
1462 | |
1463 $entry{'title'} = $basename; | |
1464 } | |
1465 | |
1466 # | |
1467 # Get the link - after ensuring we have a title. | |
1468 # | |
1469 my $link = fileToTitle( $entry{'title'} ); | |
1470 $entry{'link'} = $link; | |
1471 | |
85 | 1472 # |
1473 # Count comments. | |
1474 # | |
1475 $entry{'comment_count' } = countComments( $CONFIG{'comments'}, $entry{'link'} ); | |
132
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1476 if ( defined $entry{'comment_count'} && |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1477 $entry{'comment_count'} != 1 ) |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1478 { |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1479 $entry{'comment_plural'} = 1; |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1480 } |
57 | 1481 |
1482 # | |
33 | 1483 # Store the read file in the cache if we're using it. |
1484 # | |
1485 if ( defined( $cache ) ) | |
1486 { | |
1487 $CONFIG{'verbose'} && print "memcache-set: $filename\n"; | |
1488 $cache->set( "file_$filename", \%entry ); | |
1489 } | |
1 | 1490 return \%entry; |
1491 } | |
1492 | |
1493 | |
1494 | |
1495 =begin doc | |
1496 | |
1497 Create a filename for an URL which does not contain unsafe | |
1498 characters. | |
1499 | |
1500 =end doc | |
1501 | |
1502 =cut | |
1503 | |
1504 sub fileToTitle | |
1505 { | |
1506 my( $file ) = ( @_ ); | |
1507 | |
1508 if ( $file =~ /(.*)\.(.*)/ ) | |
1509 { | |
1510 $file = $1; | |
1511 } | |
1512 $file =~ s/ /_/g; | |
78 | 1513 $file =~ s/'/_/g; |
1514 $file =~ s/!/_/g; | |
1515 $file =~ s/\?/_/g; | |
1 | 1516 $file =~ s/\///g; |
1517 $file =~ s/\\//g; | |
1518 | |
60 | 1519 my $suffix = $CONFIG{'suffix'} || ".html"; |
1520 $file .= $suffix; | |
34 | 1521 |
1522 # | |
1523 # Lower case? | |
1524 # | |
1525 $file = lc($file) if ( $CONFIG{'lower-case'} ); | |
1526 | |
1 | 1527 return( $file ); |
1528 | |
1529 } | |
1530 | |
1531 | |
1532 | |
1533 =begin doc | |
1534 | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1535 Look for comments, for the given entry. Return any found in a format |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1536 suitable for the insertion into the output templates. |
85 | 1537 |
1538 =end doc | |
1539 | |
1540 =cut | |
1541 | |
1542 sub getComments | |
1543 { | |
1544 my( $dir, $title ) = (@_); | |
1545 | |
1546 my $results; | |
1547 | |
1548 if ( $title =~ /^(.*)\.([^.]+)$/ ) | |
1549 { | |
1550 $title = $1; | |
1551 } | |
1552 | |
1553 foreach my $file ( sort( glob( $dir . "/" . $title . "*" ) ) ) | |
1554 { | |
1555 my $date = ""; | |
1556 my $name = ""; | |
1557 my $body = ""; | |
1558 my $mail = ""; | |
1559 | |
1560 if ( $file =~ /^(.*)\.([^.]+)$/ ) | |
1561 { | |
1562 $date = $2; | |
100
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1563 |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1564 if ( $date =~ /(.*)-([0-9:]+)/ ) |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1565 { |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1566 my $d = $1; |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1567 my $t = $2; |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1568 |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1569 $d =~ s/-/ /g; |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1570 $date = "Submitted at $t on $d"; |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1571 } |
85 | 1572 } |
100
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1573 |
85 | 1574 open( COMMENT, "<", $file ) |
1575 or next; | |
1576 | |
1577 foreach my $line ( <COMMENT> ) | |
1578 { | |
1579 next if ( !defined( $line ) ); | |
1580 | |
1581 chomp( $line ); | |
97 | 1582 |
1583 next if ($line =~ /^IP-Address:/ ); | |
1584 next if ($line =~ /^User-Agent:/ ); | |
1585 | |
85 | 1586 if ( !length( $name ) && $line =~ /^Name: (.*)/i ) |
1587 { | |
1588 $name = $1; | |
1589 } | |
1590 elsif ( !length( $mail ) && $line =~ /^Mail: (.*)/i ) | |
1591 { | |
1592 $mail = $1; | |
1593 } | |
1594 else | |
1595 { | |
1596 $body .= $line . "\n"; | |
1597 } | |
1598 } | |
1599 close( COMMENT ); | |
1600 | |
1601 if ( length($name) && | |
1602 length($mail) && | |
1603 length($body) ) | |
1604 { | |
1605 push( @$results, | |
1606 { name => $name, | |
1607 mail => $mail, | |
1608 body => $body, | |
1609 date => $date } ); | |
1610 | |
1611 } | |
1612 } | |
1613 return( $results ); | |
1614 } | |
1615 | |
1616 | |
1617 | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1618 =begin doc |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1619 |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1620 Count the number of comments associated with a given post. |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1621 |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1622 =end doc |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1623 |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1624 =cut |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1625 |
85 | 1626 sub countComments |
1627 { | |
1628 my( $dir, $title ) = (@_); | |
1629 | |
1630 return( 0 ) if ( $CONFIG{'no-comments'} ); | |
1631 | |
1632 if ( $title =~ /^(.*)\.([^.]+)$/ ) | |
1633 { | |
1634 $title = $1; | |
1635 } | |
1636 | |
1637 my $count = 0; | |
1638 foreach my $f ( sort glob( $dir . "/" . $title . "*" ) ) | |
1639 { | |
1640 $count += 1; | |
1641 } | |
1642 | |
1643 return( $count ); | |
1644 } | |
1645 | |
1646 | |
1647 | |
1648 =begin doc | |
1649 | |
1 | 1650 Load a template file. |
1651 | |
1652 =end doc | |
1653 | |
1654 =cut | |
1655 | |
1656 sub loadTemplate | |
1657 { | |
1658 my( $file, %params ) = (@_); | |
1659 | |
1660 # | |
61 | 1661 # Get the directory. |
1662 # | |
1663 my $dir = $CONFIG{'theme-dir'}; | |
1664 | |
1665 # | |
1666 # XML files go in theme-dir/xml/ | |
1667 # | |
1668 if ( $file =~ /\.xml\./i ) | |
1669 { | |
1670 $dir .= "/xml/"; | |
1671 } | |
1672 else | |
1673 { | |
1674 $dir .= "/" . $CONFIG{'theme'} . "/"; | |
1675 } | |
1676 | |
1677 # | |
1 | 1678 # Make sure the file exists. |
1679 # | |
61 | 1680 if ( ! -e $dir . $file ) |
1 | 1681 { |
1682 print <<EOF; | |
1683 | |
61 | 1684 The template file $file was not found in the theme directory. |
1685 | |
62 | 1686 Theme : $CONFIG{'theme'} |
61 | 1687 Theme Directory: $CONFIG{'theme-dir'} |
1688 | |
1689 We expected to find $dir$file; | |
1 | 1690 |
1691 Aborting. | |
1692 EOF | |
1693 exit; | |
1694 } | |
1695 | |
1696 my $t = HTML::Template->new( filename => $file, | |
61 | 1697 path => $dir, |
1 | 1698 loop_context_vars => 1, |
1699 global_vars => 1, | |
1700 %params ); | |
1701 | |
39 | 1702 return( $t ); |
1703 } | |
1704 | |
1705 | |
1706 | |
1707 =begin doc | |
1708 | |
1709 Set URL for top directory and output a template. | |
1710 | |
1711 =end doc | |
1712 | |
1713 =cut | |
1714 | |
1715 sub outputTemplate | |
1716 { | |
1717 my( $template, $path ) = ( @_ ); | |
1718 | |
1 | 1719 # |
39 | 1720 # Select relative/absolute URL prefix. |
1 | 1721 # |
39 | 1722 my $top; |
1 | 1723 if ( $CONFIG{'url_prefix'} ) |
1724 { | |
39 | 1725 $top = $CONFIG{'url_prefix'}; |
1 | 1726 } |
39 | 1727 else |
1728 { | |
1729 $top = $path; | |
1730 $top =~ s'[^/]+/'../'g; | |
1731 $top =~ s'[^/]*$''; | |
1732 } | |
1733 $template->param( top => $top ); | |
1 | 1734 |
39 | 1735 open( OUTPUT, ">", "$CONFIG{'output'}/$path" ); |
1736 print OUTPUT $template->output(); | |
1737 close( OUTPUT ); | |
1 | 1738 } |
1739 | |
1740 | |
1741 | |
1742 =begin doc | |
1743 | |
7 | 1744 Read the specified configuration file if it exists. |
1 | 1745 |
1746 =end doc | |
1747 | |
1748 =cut | |
1749 | |
1750 sub readConfigurationFile | |
1751 { | |
7 | 1752 my( $file ) = ( @_ ); |
1753 | |
1754 # | |
1755 # If it doesn't exist ignore it. | |
1756 # | |
1 | 1757 return if ( ! -e $file ); |
1758 | |
7 | 1759 |
1 | 1760 my $line = ""; |
1761 | |
1762 open( FILE, "<", $file ) or die "Cannot read file '$file' - $!"; | |
1763 while (defined($line = <FILE>) ) | |
1764 { | |
1765 chomp $line; | |
1766 if ($line =~ s/\\$//) | |
1767 { | |
1768 $line .= <FILE>; | |
1769 redo unless eof(FILE); | |
1770 } | |
1771 | |
1772 # Skip lines beginning with comments | |
1773 next if ( $line =~ /^([ \t]*)\#/ ); | |
1774 | |
1775 # Skip blank lines | |
1776 next if ( length( $line ) < 1 ); | |
1777 | |
1778 # Strip trailing comments. | |
1779 if ( $line =~ /(.*)\#(.*)/ ) | |
1780 { | |
1781 $line = $1; | |
1782 } | |
1783 | |
1784 # Find variable settings | |
1785 if ( $line =~ /([^=]+)=([^\n]+)/ ) | |
1786 { | |
1787 my $key = $1; | |
1788 my $val = $2; | |
1789 | |
1790 # Strip leading and trailing whitespace. | |
1791 $key =~ s/^\s+//; | |
1792 $key =~ s/\s+$//; | |
1793 $val =~ s/^\s+//; | |
1794 $val =~ s/\s+$//; | |
1795 | |
1796 # command expansion? | |
1797 if ( $val =~ /(.*)`([^`]+)`(.*)/ ) | |
1798 { | |
1799 # store | |
1800 my $pre = $1; | |
1801 my $cmd = $2; | |
1802 my $post = $3; | |
1803 | |
1804 # get output | |
1805 my $output = `$cmd`; | |
1806 chomp( $output ); | |
1807 | |
1808 # build up replacement. | |
1809 $val = $pre . $output . $post; | |
1810 } | |
1811 | |
1812 # Store value. | |
1813 $CONFIG{ $key } = $val; | |
1814 } | |
1815 } | |
1816 | |
1817 close( FILE ); | |
1818 } | |
1819 | |
1820 | |
1821 | |
1822 =begin doc | |
1823 | |
143 | 1824 Sanity check our arguments, and setup to make sure there is nothing |
1825 obviously broken. | |
61 | 1826 |
1827 =end doc | |
1828 | |
1829 =cut | |
1830 | |
1831 sub sanityCheckArguments | |
1832 { | |
143 | 1833 # |
1834 # Make sure we have an input directory. | |
1835 # | |
1836 if ( ! -d $CONFIG{'input'} ) | |
1837 { | |
1838 print <<EOF; | |
1839 | |
1840 The blog input directory $CONFIG{'input'} does not exist. | |
1841 | |
1842 Aborting. | |
1843 EOF | |
1844 | |
1845 exit; | |
1846 } | |
1847 | |
61 | 1848 if ( !$CONFIG{'theme-dir'} ) |
1849 { | |
1850 print <<EOF; | |
1851 | |
1852 Error - You don't have a theme directory setup. | |
1853 | |
1854 Please specify --theme-dir=/some/path, or add this to your configuration | |
1855 file: | |
1856 | |
1857 theme-dir = /path/to/use/ | |
1858 EOF | |
1859 | |
1860 exit; | |
1861 } | |
1862 | |
1863 if ( ! -d $CONFIG{'theme-dir'} ) | |
1864 { | |
1865 print "The theme directory you specified doesn't exist:\n"; | |
1866 print "\t" . $CONFIG{'theme-dir'} . "\n"; | |
1867 exit; | |
1868 } | |
1869 | |
1870 if ( !$CONFIG{'theme'} ) | |
1871 { | |
1872 print <<EOF; | |
1873 | |
1874 You've not specified a theme. | |
1875 | |
1876 Please specify --theme=xx | |
1877 | |
1878 Or add this to your configuration file: | |
1879 | |
1880 theme = xx | |
1881 | |
1882 | |
1883 [You may list themes with --list-themes] | |
1884 | |
1885 EOF | |
1886 | |
1887 exit; | |
1888 } | |
1889 | |
1890 | |
1891 if ( ! -d $CONFIG{'theme-dir'} . "/" . $CONFIG{'theme'} ) | |
1892 { | |
1893 print "The theme directory you specified doesn't exist in the theme directory:\n"; | |
1894 print "\tTheme :" . $CONFIG{'theme'} . "\n"; | |
1895 print "\tTheme dir:" . $CONFIG{'theme-dir'} . "\n"; | |
1896 print "\tExpected :" . $CONFIG{'theme-dir'} . "/" . $CONFIG{'theme'} . "\n"; | |
1897 exit; | |
1898 } | |
1899 | |
1900 } | |
1901 | |
1902 | |
1903 | |
1904 | |
1905 =begin doc | |
1906 | |
12 | 1907 Copy any static files from the theme directory into the "live" location |
1908 in the output. | |
1909 | |
1910 This only works for a top-level target directory. | |
1 | 1911 |
46 | 1912 Unless --force is specified we skip copying files which already exist. |
1913 | |
1 | 1914 =end doc |
1915 | |
1916 =cut | |
1917 | |
12 | 1918 sub copyStaticFiles |
1 | 1919 { |
12 | 1920 # |
1921 # Soure and destination for the copy | |
1922 # | |
61 | 1923 my $input = $CONFIG{'theme-dir'} . "/" . $CONFIG{'theme'}; |
12 | 1924 my $output = $CONFIG{'output'}; |
1 | 1925 |
12 | 1926 foreach my $pattern ( qw! *.css *.jpg *.gif *.png *.js *.ico ! ) |
1927 { | |
1928 foreach my $file ( glob( $input . "/" . $pattern ) ) | |
1929 { | |
13 | 1930 # |
1931 # Get the name of the file. | |
1932 # | |
1933 if ( $file =~ /(.*)\/(.*)/ ) | |
1934 { | |
1935 $file = $2; | |
1936 } | |
46 | 1937 if ( $CONFIG{'force'} || ( ! -e "$output/$file" ) ) |
12 | 1938 { |
13 | 1939 $CONFIG{'verbose'} && print "Copying static file: $file\n"; |
1940 copy( "$input/$file", "$output/$file" ); | |
12 | 1941 } |
1942 } | |
1943 } | |
1 | 1944 } |
16 | 1945 |
1946 | |
1947 | |
1948 =begin doc | |
1949 | |
1950 Convert from markdown to HTML. | |
1951 | |
1952 =end doc | |
1953 | |
1954 =cut | |
1955 | |
1956 sub markdown2HTML | |
1957 { | |
1958 my( $text ) = (@_); | |
1959 | |
1960 # | |
1961 # Make sure we have the module installed. Use eval to | |
1962 # avoid making this mandatory. | |
1963 # | |
1964 my $test = "use Text::Markdown;"; | |
1965 | |
1966 # | |
1967 # Test loading the module. | |
1968 # | |
1969 eval( $test ); | |
1970 if ( $@ ) | |
1971 { | |
1972 print <<EOF; | |
1973 | |
1974 You have chosen to format your input text via Markdown, but the | |
1975 Perl module Text::Markdown is not installed. | |
1976 | |
1977 Aborting. | |
1978 EOF | |
1979 exit; | |
1980 } | |
1981 | |
1982 # | |
1983 # Convert. | |
1984 # | |
1985 $text = Text::Markdown::Markdown( $text ); | |
1986 return( $text ); | |
1987 } | |
1988 | |
1989 | |
1990 | |
1991 =begin doc | |
1992 | |
1993 Convert from textile to HTML. | |
1994 | |
1995 =end doc | |
1996 | |
1997 =cut | |
1998 | |
1999 sub textile2HTML | |
2000 { | |
2001 my( $text ) = (@_); | |
2002 | |
2003 # | |
2004 # Make sure we have the module installed. Use eval to | |
2005 # avoid making this mandatory. | |
2006 # | |
2007 my $test = "use Text::Textile;"; | |
2008 | |
2009 # | |
2010 # Test loading the module. | |
2011 # | |
2012 eval( $test ); | |
2013 if ( $@ ) | |
2014 { | |
2015 print <<EOF; | |
2016 | |
2017 You have chosen to format your input text via Textile, but the | |
2018 Perl module Text::Textile is not installed. | |
2019 | |
2020 Aborting. | |
2021 EOF | |
2022 exit; | |
2023 } | |
2024 | |
2025 # | |
2026 # Convert. | |
2027 # | |
2028 $text = Text::Textile::textile( $text ); | |
2029 return( $text ); | |
2030 } | |
2031 | |
2032 | |
2033 | |
2034 | |
61 | 2035 sub listThemes |
2036 { | |
2037 my( $dir ) = ( @_ ); | |
2038 | |
2039 $CONFIG{'verbose'} && print "Listhing themes beneath : $dir\n"; | |
2040 | |
2041 foreach my $name ( sort( glob( $dir . "/*" ) ) ) | |
2042 { | |
2043 next unless( -d $name ); | |
2044 | |
2045 next if ( $name =~ /\/xml$/ ); | |
2046 | |
2047 if ( $name =~ /^(.*)\/([^\/\\]*)$/ ) | |
2048 { | |
2049 print $2 . "\n"; | |
2050 } | |
2051 } | |
2052 } | |
66
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2053 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2054 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2055 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2056 =begin doc |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2057 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2058 Create and configure a calendar for the index, if and only iff the |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2059 HTML::CalendarMonthSimple module is installed. |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2060 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2061 =end doc |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2062 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2063 =cut |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2064 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2065 sub createCalendar |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2066 { |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2067 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2068 # Attempt to load the module. |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2069 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2070 my $test = "use HTML::CalendarMonthSimple;"; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2071 eval( $test ); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2072 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2073 # |
128 | 2074 # If there was an error, or the calendar is disabled then |
66
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2075 # return undef. |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2076 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2077 if ( ( $@ ) || ( $CONFIG{'no-calendar'} ) ) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2078 { |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2079 return undef; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2080 } |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2081 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2082 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2083 # Continue |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2084 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2085 my $cal = new HTML::CalendarMonthSimple(); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2086 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2087 # configuration of the calendar |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2088 $cal->border(0); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2089 $cal->weekstartsonmonday(1); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2090 $cal->showweekdayheaders(1); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2091 $cal->sunday('Sun'); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2092 $cal->saturday('Sat'); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2093 $cal->weekdays('Mo','Tue','We','Thu','Fr'); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2094 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2095 # get 4th element from localtime aka month in form of (0..11) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2096 my $curmonth = (localtime)[4] + 1; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2097 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2098 foreach my $f (%data) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2099 { |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2100 my $h = $data{$f}; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2101 next if ( !$h ); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2102 my $entrydate = $h->{'date'}; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2103 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2104 if ( !$entrydate ) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2105 { |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2106 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2107 $atime,$mtime,$ctime,$blksize,$blocks) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2108 = stat($f); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2109 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2110 $entrydate = localtime( $ctime ); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2111 } |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2112 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2113 my $date = time2str("%Y-%m-%d", str2time($entrydate)); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2114 my ($year,$month,$day) = split(/-/,$date); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2115 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2116 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2117 if ($month eq $curmonth) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2118 { |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2119 $cal->setdatehref($day,fileToTitle($data{$f}->{'title'})); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2120 } |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2121 } |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2122 return ($cal); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2123 } |