Mercurial > hg > chronicle
annotate bin/chronicle @ 144:571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
author | Steve Kemp <steve@steve.org.uk> |
---|---|
date | Wed, 26 Dec 2007 15:28:45 +0000 |
parents | 55c15e6aebd6 |
children | 89eef19064e8 |
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 ); | |
904 $template->param( entries => $entries ) if ( $entries ); | |
39 | 905 outputTemplate( $template, "index.rss" ); |
1 | 906 } |
907 | |
908 | |
909 | |
910 =begin doc | |
911 | |
912 Write out a /tags/$foo/index.html containing each blog entry which has the | |
913 tag '$foo'. | |
914 | |
915 =end doc | |
916 | |
917 =cut | |
918 | |
919 sub outputTagPage | |
920 { | |
921 my ( $tagName ) = ( @_ ); | |
922 | |
39 | 923 my $dir = "tags/$tagName"; |
1 | 924 |
925 my %allTags; | |
926 my %tagEntries; | |
927 foreach my $f ( keys %data ) | |
928 { | |
929 my $h = $data{$f}; | |
930 my $tags = $h->{'tags'} || undef; | |
931 foreach my $t ( @$tags ) | |
932 { | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
933 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
|
934 $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
|
935 my $a = $tagEntries{$name}; |
1 | 936 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
|
937 $tagEntries{$name}= $a; |
1 | 938 } |
939 } | |
940 | |
941 my $matching = $tagEntries{$tagName}; | |
942 | |
943 my $entries; | |
944 | |
945 # | |
946 # Now read the matching entries. | |
947 # | |
948 foreach my $f ( sort @$matching ) | |
949 { | |
950 my $blog = readBlogEntry( $f ); | |
951 if (keys( %$blog ) ) | |
952 { | |
953 $CONFIG{'verbose'} && print "\tAdded: $f\n"; | |
954 push( @$entries, $blog ); | |
955 } | |
956 } | |
957 | |
958 # | |
959 # Now write the output as a HTML page. | |
960 # | |
21 | 961 my $template = loadTemplate( "tags.template", |
962 die_on_bad_params => 0 ); | |
963 | |
964 # | |
965 # The entries. | |
966 # | |
1 | 967 $template->param( entries => $entries ) if ( $entries ); |
968 $template->param( tagname => $tagName ); | |
21 | 969 |
970 # | |
971 # The clouds | |
972 # | |
973 $template->param( tagcloud => $CLOUD{'tag'} ) | |
974 if ( $CLOUD{'tag'} ); | |
975 $template->param( datecloud => $CLOUD{'archive'} ) | |
976 if ( $CLOUD{'archive'} ); | |
977 | |
978 # | |
979 # Blog title and subtitle, if present. | |
980 # | |
981 $template->param( blog_title => $CONFIG{'blog_title'} ) | |
982 if ( $CONFIG{'blog_title'} ); | |
983 $template->param( blog_subtitle => $CONFIG{'blog_subtitle'} ) | |
984 if ( $CONFIG{'blog_subtitle'} ); | |
985 | |
1 | 986 |
987 # | |
988 # Page to use | |
989 # | |
990 my $index = $CONFIG{'filename'} || "index.html"; | |
991 | |
39 | 992 outputTemplate( $template, "$dir/$index" ); |
1 | 993 |
994 # | |
995 # Now output the .xml file | |
996 # | |
997 $template = loadTemplate( "tags.xml.template", die_on_bad_params => 0 ); | |
998 $template->param( entries => $entries ) if ( $entries ); | |
999 $template->param( tagname => $tagName ) if ( $tagName ); | |
39 | 1000 outputTemplate( $template, "$dir/$tagName.rss" ); |
1 | 1001 } |
1002 | |
1003 | |
1004 | |
1005 =begin doc | |
1006 | |
1007 Output the archive page for the given Month + Year. | |
1008 | |
1009 This function is a *mess* and iterates over the data structure much | |
1010 more often than it needs to. | |
1011 | |
1012 =end doc | |
1013 | |
1014 =cut | |
1015 | |
1016 sub outputArchivePage | |
1017 { | |
1018 my( $date ) = ( @_ ); | |
1019 | |
1020 # | |
1021 # Should we abort? | |
1022 # | |
1023 if ( $CONFIG{'no-archive'} ) | |
1024 { | |
1025 $CONFIG{'verbose'} && print "Ignoring archive page, as instructed.\n"; | |
1026 return; | |
1027 } | |
1028 | |
1029 | |
1030 my $year = ''; | |
1031 my $month = ''; | |
39 | 1032 if ( $date =~ /^([0-9]{4})-([0-9]{2})/ ) |
1 | 1033 { |
39 | 1034 $year = $1; |
1035 $month = $2; | |
1 | 1036 } |
1037 | |
1038 # | |
1039 # Make the directory | |
1040 # | |
39 | 1041 my $dir = "archive/$year/$month"; |
1 | 1042 |
1043 my $entries; | |
1044 | |
1045 | |
1046 my %dateEntries; | |
1047 foreach my $f ( keys %data ) | |
1048 { | |
1049 my $h = $data{$f}; | |
55 | 1050 my $date = $h->{'date'}; |
1051 | |
1052 # | |
1053 # Not a date? Use the file. | |
1054 # | |
1055 if ( !defined( $date ) || !length($date) ) | |
1056 { | |
1057 # | |
1058 # Test the file for creation time. | |
1059 # | |
1060 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, | |
1061 $atime,$mtime,$ctime,$blksize,$blocks) | |
1062 = stat($f); | |
1063 | |
1064 $date = localtime( $ctime ); | |
1065 } | |
1066 | |
1067 $date = time2str("%Y-%m", str2time($date)); | |
1 | 1068 |
39 | 1069 push @{$dateEntries{$date}}, $f ; |
1 | 1070 } |
1071 | |
1072 | |
1073 my $matching = $dateEntries{$date}; | |
1074 foreach my $f ( reverse @$matching ) | |
1075 { | |
1076 $CONFIG{'verbose'} && print "\tAdded: $f\n"; | |
1077 | |
1078 my $blog = readBlogEntry( $f ); | |
1079 if (keys( %$blog ) ) | |
1080 { | |
1081 push( @$entries, $blog ); | |
1082 } | |
1083 } | |
1084 | |
1085 # | |
1086 # Now write the output as a HTML page. | |
1087 # | |
21 | 1088 my $template = loadTemplate( "month.template", |
1089 die_on_bad_params => 0 ); | |
1090 | |
48 | 1091 |
21 | 1092 # |
48 | 1093 # The entries |
21 | 1094 # |
1 | 1095 $template->param( entries => $entries ) if ( $entries ); |
48 | 1096 |
1097 # | |
1098 # Output the month + year. | |
1099 # | |
1 | 1100 $template->param( year => $year, month => $month ); |
48 | 1101 $template->param( month_name => $names[$month - 1 ] ); |
21 | 1102 |
1103 # | |
1104 # The clouds | |
1105 # | |
1106 $template->param( tagcloud => $CLOUD{'tag'} ) | |
1107 if ( $CLOUD{'tag'} ); | |
1108 $template->param( datecloud => $CLOUD{'archive'} ) | |
1109 if ( $CLOUD{'archive'} ); | |
1110 | |
1111 # | |
1112 # Blog title and subtitle, if present. | |
1113 # | |
1114 $template->param( blog_title => $CONFIG{'blog_title'} ) | |
1115 if ( $CONFIG{'blog_title'} ); | |
1116 $template->param( blog_subtitle => $CONFIG{'blog_subtitle'} ) | |
1117 if ( $CONFIG{'blog_subtitle'} ); | |
1 | 1118 |
1119 # | |
1120 # Page to use | |
1121 # | |
1122 my $index = $CONFIG{'filename'} || "index.html"; | |
39 | 1123 outputTemplate( $template, "$dir/$index" ); |
1 | 1124 |
1125 # | |
1126 # Now the RSS page. | |
1127 # | |
1128 $template = loadTemplate( "month.xml.template", die_on_bad_params => 0 ); | |
1129 $template->param( entries => $entries ) if ( $entries ); | |
1130 $template->param( month => $month, year => $year ); | |
48 | 1131 $template->param( month_name => $names[$month - 1 ] ); |
39 | 1132 outputTemplate( $template, "$dir/$month.rss" ); |
1 | 1133 } |
1134 | |
1135 | |
1136 | |
1137 | |
1138 =begin doc | |
1139 | |
1140 Output static page. | |
1141 | |
1142 =end doc | |
1143 | |
1144 =cut | |
1145 | |
1146 sub outputStaticPage | |
1147 { | |
1148 my ( $filename ) = ( @_ ); | |
1149 | |
1150 # | |
1151 # Load the template | |
1152 # | |
21 | 1153 my $template = loadTemplate( "entry.template", |
1154 die_on_bad_params => 0 ); | |
1 | 1155 |
1156 # | |
1157 # Just the name of the file. | |
1158 # | |
1159 my $basename = $filename; | |
1160 if ( $basename =~ /(.*)\/(.*)/ ) | |
1161 { | |
1162 $basename=$2; | |
1163 } | |
57 | 1164 if ( $basename =~ /^(.*)\.(.*)$/ ) |
1165 { | |
1166 $basename = $1; | |
1167 } | |
34 | 1168 |
1 | 1169 # |
1170 # Read the entry | |
1171 # | |
1172 my $static = readBlogEntry( $filename ); | |
1173 | |
34 | 1174 # |
1175 # Get the pieces of information. | |
1176 # | |
1 | 1177 my $title = $static->{'title'} || $basename; |
1178 my $tags = $static->{'tags'}; | |
1179 my $body = $static->{'body'}; | |
55 | 1180 my $date = $static->{'date'}; |
1181 | |
1182 if ( !defined($date) ) | |
1183 { | |
1184 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, | |
1185 $atime,$mtime,$ctime,$blksize,$blocks) | |
1186 = stat($filename); | |
1187 | |
1188 $date = localtime( $ctime ); | |
1189 } | |
1 | 1190 |
1191 $CONFIG{'verbose'} && print "\t$filename\n"; | |
1192 | |
1193 # | |
1194 # Convert to suitable filename. | |
1195 # | |
1196 my $file = fileToTitle($title); | |
1197 | |
85 | 1198 |
1199 # | |
1200 # Get comments, if present. | |
1201 # | |
1202 if( !$CONFIG{'no-comments'} ) | |
1203 { | |
1204 my $comments = getComments( $CONFIG{'comments'}, $file ); | |
1205 | |
1206 if ( defined($comments) ) | |
1207 { | |
132
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1208 my $count = scalar( @$comments ); |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1209 my $plural = 1; |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1210 $plural = 0 if ( $count == 1 ); |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1211 |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1212 $template->param( comments => $comments, |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1213 comment_count => $count, |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1214 comment_plural => $plural ); |
85 | 1215 |
1216 $CONFIG{'verbose'} && print "$file [$filename] has $count comments\n"; | |
1217 } | |
1218 | |
1219 $template->param( comments_enabled => 1 ); | |
1220 } | |
1221 | |
1222 | |
21 | 1223 # |
1224 # The entry. | |
1225 # | |
1 | 1226 $template->param( title => $title ); |
1227 $template->param( tags => $tags ) if ( $tags ); | |
1228 $template->param( date => $date ) if ( $date ); | |
1229 $template->param( body => $body ); | |
92 | 1230 $template->param( link => $static->{'link'} ); |
21 | 1231 |
1232 # | |
1233 # Our clouds | |
1234 # | |
1 | 1235 $template->param( tagcloud => $CLOUD{'tag'} ) if ( $CLOUD{'tag'} ); |
1236 $template->param( datecloud => $CLOUD{'archive'} ) if ( $CLOUD{'archive'} ); | |
21 | 1237 |
1238 # | |
1239 # Blog title and subtitle, if present. | |
1240 # | |
1241 $template->param( blog_title => $CONFIG{'blog_title'} ) | |
1242 if ( $CONFIG{'blog_title'} ); | |
1243 $template->param( blog_subtitle => $CONFIG{'blog_subtitle'} ) | |
1244 if ( $CONFIG{'blog_subtitle'} ); | |
1245 | |
39 | 1246 outputTemplate( $template, $file ); |
1 | 1247 } |
1248 | |
1249 | |
1250 | |
1251 =begin doc | |
1252 | |
1253 Return a hash of interesting data from our blog file. | |
1254 | |
1255 =end doc | |
1256 | |
1257 =cut | |
1258 | |
1259 sub readBlogEntry | |
1260 { | |
1261 my ( $filename ) = ( @_); | |
1262 | |
1263 my %entry; | |
1264 | |
33 | 1265 # |
1266 # Do we have the memcache module available? | |
1267 # | |
1268 my $cache = undef; | |
1269 my $test = "use Cache::Memcached;"; | |
1270 eval( $test ); | |
1271 if ( ( ! $@ ) && ( ! $CONFIG{'no-cache'} ) ) | |
1272 { | |
1273 # create the cache object | |
1274 $cache = new Cache::Memcached {'servers' => ["localhost:11211"] }; | |
1275 | |
1276 # fetch from the cache if it is present. | |
1277 my $cached = $cache->get( "file_$filename" ); | |
1278 if ( defined( $cached ) ) | |
1279 { | |
1280 $CONFIG{'verbose'} && print "memcache-get: $filename\n"; | |
1281 return( \%$cached ) | |
1282 } | |
1283 else | |
1284 { | |
1285 $CONFIG{'verbose'} && print "memcache-fail: $filename\n"; | |
1286 } | |
1287 } | |
1288 | |
1 | 1289 |
18 | 1290 my $title = ""; # entry title. |
1291 my $tags = ""; # entry tags. | |
1292 my $body = ""; # entry body. | |
1293 my $date = ""; # entry date | |
1 | 1294 |
1295 open( ENTRY, "<", $filename ) or die "Failed to read $filename $!"; | |
1296 while( my $line = <ENTRY> ) | |
1297 { | |
1298 # | |
62 | 1299 # Get the tags. |
1 | 1300 # |
62 | 1301 if (( $line =~ /^tags: (.*)/i ) && !length( $tags ) ) |
1 | 1302 { |
62 | 1303 $tags = $1; |
1 | 1304 } |
1305 elsif (( $line =~ /^title: (.*)/i ) && !length($title) ) | |
1306 { | |
62 | 1307 # |
1308 # Get the title | |
1309 # | |
1 | 1310 $title = $1; |
11 | 1311 |
1312 # strip leading and trailing space. | |
1313 $title =~ s/^\s+// if ( length $title ); | |
1314 $title =~ s/\s+$// if ( length $title ); | |
1 | 1315 } |
1316 elsif (( $line =~ /^date: (.*)/i ) && !length($date) ) | |
1317 { | |
62 | 1318 # |
1319 # Get the date. | |
1320 # | |
1 | 1321 $date = $1; |
11 | 1322 |
1323 # strip leading and trailing space. | |
1324 $date =~ s/^\s+// if ( length $date ); | |
1325 $date =~ s/\s+$// if ( length $date ); | |
1326 } | |
1 | 1327 else |
1328 { | |
62 | 1329 # |
1330 # Just a piece of body text. | |
1331 # | |
1 | 1332 $body .= $line; |
1333 } | |
1334 } | |
1335 close( ENTRY ); | |
1336 | |
1337 # | |
44 | 1338 # Determine the input format to use. |
16 | 1339 # |
44 | 1340 my $format = lc($CONFIG{'format'}); |
1341 | |
1342 # | |
1343 # Now process accordingly. | |
1344 # | |
1345 if ( $format eq 'html' ) | |
16 | 1346 { |
1347 # nop | |
1348 } | |
44 | 1349 elsif( $format eq 'markdown' ) |
16 | 1350 { |
1351 $body = markdown2HTML( $body ); | |
1352 } | |
44 | 1353 elsif( $format eq 'textile' ) |
16 | 1354 { |
1355 $body = textile2HTML( $body ); | |
1356 } | |
1357 else | |
1358 { | |
44 | 1359 print "Unkown blog entry format ($CONFIG{'format'}).\n"; |
1360 print "Treating as HTML.\n"; | |
16 | 1361 } |
1362 | |
1363 # | |
1364 # | |
44 | 1365 # If we have tags then we should use them. |
1 | 1366 # |
1367 my $entryTags; | |
1368 | |
1369 foreach my $tag ( split( /,/, $tags ) ) | |
1370 { | |
1371 # strip leading and trailing space. | |
1372 $tag =~ s/^\s+//; | |
1373 $tag =~ s/\s+$//; | |
1374 | |
1375 # skip empty tags. | |
1376 next if ( !length($tag) ); | |
62 | 1377 |
1378 # tags are lowercase. | |
1 | 1379 $tag = lc($tag); |
1380 push ( @$entryTags, { tag => $tag } ); | |
1381 } | |
1382 | |
1383 # | |
1384 # If the date isn't set then use todays. | |
1385 # | |
1386 if ( ! defined($date) ||( !length( $date ) ) ) | |
1387 { | |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1388 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
|
1389 $date = strftime( "%d %B %Y", @lt); |
1 | 1390 } |
1391 | |
1392 # | |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1393 # 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
|
1394 # |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1395 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
|
1396 if ( $time ) |
80
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
1397 { |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1398 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1399 # 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
|
1400 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1401 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
|
1402 $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
|
1403 = stat($filename); |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1404 |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1405 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1406 # 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
|
1407 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1408 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
|
1409 |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1410 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1411 # 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
|
1412 # |
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1413 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
|
1414 |
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 # 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
|
1417 # spaces |
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 $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
|
1420 $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
|
1421 } |
84
c7f71166bc90
Simplified the handling of dates & times a little via Date::Format.
Steve Kemp <steve@steve.org.uk>
parents:
83
diff
changeset
|
1422 else |
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 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
|
1425 } |
80
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
1426 |
5379f7e3f7de
Updated so that we have pubDate attributes for our RDF
Steve Kemp <steve@steve.org.uk>
parents:
78
diff
changeset
|
1427 # |
1 | 1428 # Store the entry. |
1429 # | |
1430 $entry{'title'} = $title; | |
1431 $entry{'body'} = $body if ( $body ); | |
1432 $entry{'date'} = $date; | |
1433 $entry{'tags'} = $entryTags if ( $entryTags ); | |
33 | 1434 |
85 | 1435 |
33 | 1436 # |
57 | 1437 # No title? |
1438 # | |
1439 if ( !defined($entry{'title'}) || | |
1440 !length($entry{'title'}) ) | |
1441 { | |
1442 my $basename = $filename; | |
1443 if ( $basename =~ /(.*)\/(.*)/ ) | |
1444 { | |
1445 $basename=$2; | |
1446 } | |
1447 if ( $basename =~ /^(.*)\.(.*)$/ ) | |
1448 { | |
1449 $basename = $1; | |
1450 } | |
1451 | |
1452 $entry{'title'} = $basename; | |
1453 } | |
1454 | |
1455 # | |
1456 # Get the link - after ensuring we have a title. | |
1457 # | |
1458 my $link = fileToTitle( $entry{'title'} ); | |
1459 $entry{'link'} = $link; | |
1460 | |
85 | 1461 # |
1462 # Count comments. | |
1463 # | |
1464 $entry{'comment_count' } = countComments( $CONFIG{'comments'}, $entry{'link'} ); | |
132
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1465 if ( defined $entry{'comment_count'} && |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1466 $entry{'comment_count'} != 1 ) |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1467 { |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1468 $entry{'comment_plural'} = 1; |
7a05117f1bc3
Show plural comments correctly.
Steve Kemp <steve@steve.org.uk>
parents:
128
diff
changeset
|
1469 } |
57 | 1470 |
1471 # | |
33 | 1472 # Store the read file in the cache if we're using it. |
1473 # | |
1474 if ( defined( $cache ) ) | |
1475 { | |
1476 $CONFIG{'verbose'} && print "memcache-set: $filename\n"; | |
1477 $cache->set( "file_$filename", \%entry ); | |
1478 } | |
1 | 1479 return \%entry; |
1480 } | |
1481 | |
1482 | |
1483 | |
1484 =begin doc | |
1485 | |
1486 Create a filename for an URL which does not contain unsafe | |
1487 characters. | |
1488 | |
1489 =end doc | |
1490 | |
1491 =cut | |
1492 | |
1493 sub fileToTitle | |
1494 { | |
1495 my( $file ) = ( @_ ); | |
1496 | |
1497 if ( $file =~ /(.*)\.(.*)/ ) | |
1498 { | |
1499 $file = $1; | |
1500 } | |
1501 $file =~ s/ /_/g; | |
78 | 1502 $file =~ s/'/_/g; |
1503 $file =~ s/!/_/g; | |
1504 $file =~ s/\?/_/g; | |
1 | 1505 $file =~ s/\///g; |
1506 $file =~ s/\\//g; | |
1507 | |
60 | 1508 my $suffix = $CONFIG{'suffix'} || ".html"; |
1509 $file .= $suffix; | |
34 | 1510 |
1511 # | |
1512 # Lower case? | |
1513 # | |
1514 $file = lc($file) if ( $CONFIG{'lower-case'} ); | |
1515 | |
1 | 1516 return( $file ); |
1517 | |
1518 } | |
1519 | |
1520 | |
1521 | |
1522 =begin doc | |
1523 | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1524 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
|
1525 suitable for the insertion into the output templates. |
85 | 1526 |
1527 =end doc | |
1528 | |
1529 =cut | |
1530 | |
1531 sub getComments | |
1532 { | |
1533 my( $dir, $title ) = (@_); | |
1534 | |
1535 my $results; | |
1536 | |
1537 if ( $title =~ /^(.*)\.([^.]+)$/ ) | |
1538 { | |
1539 $title = $1; | |
1540 } | |
1541 | |
1542 foreach my $file ( sort( glob( $dir . "/" . $title . "*" ) ) ) | |
1543 { | |
1544 my $date = ""; | |
1545 my $name = ""; | |
1546 my $body = ""; | |
1547 my $mail = ""; | |
1548 | |
1549 if ( $file =~ /^(.*)\.([^.]+)$/ ) | |
1550 { | |
1551 $date = $2; | |
100
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1552 |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1553 if ( $date =~ /(.*)-([0-9:]+)/ ) |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1554 { |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1555 my $d = $1; |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1556 my $t = $2; |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1557 |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1558 $d =~ s/-/ /g; |
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1559 $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
|
1560 } |
85 | 1561 } |
100
19148729b491
Updated the formatting of date++time on comments
Steve Kemp <steve@steve.org.uk>
parents:
97
diff
changeset
|
1562 |
85 | 1563 open( COMMENT, "<", $file ) |
1564 or next; | |
1565 | |
1566 foreach my $line ( <COMMENT> ) | |
1567 { | |
1568 next if ( !defined( $line ) ); | |
1569 | |
1570 chomp( $line ); | |
97 | 1571 |
1572 next if ($line =~ /^IP-Address:/ ); | |
1573 next if ($line =~ /^User-Agent:/ ); | |
1574 | |
85 | 1575 if ( !length( $name ) && $line =~ /^Name: (.*)/i ) |
1576 { | |
1577 $name = $1; | |
1578 } | |
1579 elsif ( !length( $mail ) && $line =~ /^Mail: (.*)/i ) | |
1580 { | |
1581 $mail = $1; | |
1582 } | |
1583 else | |
1584 { | |
1585 $body .= $line . "\n"; | |
1586 } | |
1587 } | |
1588 close( COMMENT ); | |
1589 | |
1590 if ( length($name) && | |
1591 length($mail) && | |
1592 length($body) ) | |
1593 { | |
1594 push( @$results, | |
1595 { name => $name, | |
1596 mail => $mail, | |
1597 body => $body, | |
1598 date => $date } ); | |
1599 | |
1600 } | |
1601 } | |
1602 return( $results ); | |
1603 } | |
1604 | |
1605 | |
1606 | |
144
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1607 =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
|
1608 |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1609 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
|
1610 |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1611 =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
|
1612 |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1613 =cut |
571c8d4310f0
Removed redundent reading of entries, to speed up and simplify the code.
Steve Kemp <steve@steve.org.uk>
parents:
143
diff
changeset
|
1614 |
85 | 1615 sub countComments |
1616 { | |
1617 my( $dir, $title ) = (@_); | |
1618 | |
1619 return( 0 ) if ( $CONFIG{'no-comments'} ); | |
1620 | |
1621 if ( $title =~ /^(.*)\.([^.]+)$/ ) | |
1622 { | |
1623 $title = $1; | |
1624 } | |
1625 | |
1626 my $count = 0; | |
1627 foreach my $f ( sort glob( $dir . "/" . $title . "*" ) ) | |
1628 { | |
1629 $count += 1; | |
1630 } | |
1631 | |
1632 return( $count ); | |
1633 } | |
1634 | |
1635 | |
1636 | |
1637 =begin doc | |
1638 | |
1 | 1639 Load a template file. |
1640 | |
1641 =end doc | |
1642 | |
1643 =cut | |
1644 | |
1645 sub loadTemplate | |
1646 { | |
1647 my( $file, %params ) = (@_); | |
1648 | |
1649 # | |
61 | 1650 # Get the directory. |
1651 # | |
1652 my $dir = $CONFIG{'theme-dir'}; | |
1653 | |
1654 # | |
1655 # XML files go in theme-dir/xml/ | |
1656 # | |
1657 if ( $file =~ /\.xml\./i ) | |
1658 { | |
1659 $dir .= "/xml/"; | |
1660 } | |
1661 else | |
1662 { | |
1663 $dir .= "/" . $CONFIG{'theme'} . "/"; | |
1664 } | |
1665 | |
1666 # | |
1 | 1667 # Make sure the file exists. |
1668 # | |
61 | 1669 if ( ! -e $dir . $file ) |
1 | 1670 { |
1671 print <<EOF; | |
1672 | |
61 | 1673 The template file $file was not found in the theme directory. |
1674 | |
62 | 1675 Theme : $CONFIG{'theme'} |
61 | 1676 Theme Directory: $CONFIG{'theme-dir'} |
1677 | |
1678 We expected to find $dir$file; | |
1 | 1679 |
1680 Aborting. | |
1681 EOF | |
1682 exit; | |
1683 } | |
1684 | |
1685 my $t = HTML::Template->new( filename => $file, | |
61 | 1686 path => $dir, |
1 | 1687 loop_context_vars => 1, |
1688 global_vars => 1, | |
1689 %params ); | |
1690 | |
39 | 1691 return( $t ); |
1692 } | |
1693 | |
1694 | |
1695 | |
1696 =begin doc | |
1697 | |
1698 Set URL for top directory and output a template. | |
1699 | |
1700 =end doc | |
1701 | |
1702 =cut | |
1703 | |
1704 sub outputTemplate | |
1705 { | |
1706 my( $template, $path ) = ( @_ ); | |
1707 | |
1 | 1708 # |
39 | 1709 # Select relative/absolute URL prefix. |
1 | 1710 # |
39 | 1711 my $top; |
1 | 1712 if ( $CONFIG{'url_prefix'} ) |
1713 { | |
39 | 1714 $top = $CONFIG{'url_prefix'}; |
1 | 1715 } |
39 | 1716 else |
1717 { | |
1718 $top = $path; | |
1719 $top =~ s'[^/]+/'../'g; | |
1720 $top =~ s'[^/]*$''; | |
1721 } | |
1722 $template->param( top => $top ); | |
1 | 1723 |
39 | 1724 open( OUTPUT, ">", "$CONFIG{'output'}/$path" ); |
1725 print OUTPUT $template->output(); | |
1726 close( OUTPUT ); | |
1 | 1727 } |
1728 | |
1729 | |
1730 | |
1731 =begin doc | |
1732 | |
7 | 1733 Read the specified configuration file if it exists. |
1 | 1734 |
1735 =end doc | |
1736 | |
1737 =cut | |
1738 | |
1739 sub readConfigurationFile | |
1740 { | |
7 | 1741 my( $file ) = ( @_ ); |
1742 | |
1743 # | |
1744 # If it doesn't exist ignore it. | |
1745 # | |
1 | 1746 return if ( ! -e $file ); |
1747 | |
7 | 1748 |
1 | 1749 my $line = ""; |
1750 | |
1751 open( FILE, "<", $file ) or die "Cannot read file '$file' - $!"; | |
1752 while (defined($line = <FILE>) ) | |
1753 { | |
1754 chomp $line; | |
1755 if ($line =~ s/\\$//) | |
1756 { | |
1757 $line .= <FILE>; | |
1758 redo unless eof(FILE); | |
1759 } | |
1760 | |
1761 # Skip lines beginning with comments | |
1762 next if ( $line =~ /^([ \t]*)\#/ ); | |
1763 | |
1764 # Skip blank lines | |
1765 next if ( length( $line ) < 1 ); | |
1766 | |
1767 # Strip trailing comments. | |
1768 if ( $line =~ /(.*)\#(.*)/ ) | |
1769 { | |
1770 $line = $1; | |
1771 } | |
1772 | |
1773 # Find variable settings | |
1774 if ( $line =~ /([^=]+)=([^\n]+)/ ) | |
1775 { | |
1776 my $key = $1; | |
1777 my $val = $2; | |
1778 | |
1779 # Strip leading and trailing whitespace. | |
1780 $key =~ s/^\s+//; | |
1781 $key =~ s/\s+$//; | |
1782 $val =~ s/^\s+//; | |
1783 $val =~ s/\s+$//; | |
1784 | |
1785 # command expansion? | |
1786 if ( $val =~ /(.*)`([^`]+)`(.*)/ ) | |
1787 { | |
1788 # store | |
1789 my $pre = $1; | |
1790 my $cmd = $2; | |
1791 my $post = $3; | |
1792 | |
1793 # get output | |
1794 my $output = `$cmd`; | |
1795 chomp( $output ); | |
1796 | |
1797 # build up replacement. | |
1798 $val = $pre . $output . $post; | |
1799 } | |
1800 | |
1801 # Store value. | |
1802 $CONFIG{ $key } = $val; | |
1803 } | |
1804 } | |
1805 | |
1806 close( FILE ); | |
1807 } | |
1808 | |
1809 | |
1810 | |
1811 =begin doc | |
1812 | |
143 | 1813 Sanity check our arguments, and setup to make sure there is nothing |
1814 obviously broken. | |
61 | 1815 |
1816 =end doc | |
1817 | |
1818 =cut | |
1819 | |
1820 sub sanityCheckArguments | |
1821 { | |
143 | 1822 # |
1823 # Make sure we have an input directory. | |
1824 # | |
1825 if ( ! -d $CONFIG{'input'} ) | |
1826 { | |
1827 print <<EOF; | |
1828 | |
1829 The blog input directory $CONFIG{'input'} does not exist. | |
1830 | |
1831 Aborting. | |
1832 EOF | |
1833 | |
1834 exit; | |
1835 } | |
1836 | |
61 | 1837 if ( !$CONFIG{'theme-dir'} ) |
1838 { | |
1839 print <<EOF; | |
1840 | |
1841 Error - You don't have a theme directory setup. | |
1842 | |
1843 Please specify --theme-dir=/some/path, or add this to your configuration | |
1844 file: | |
1845 | |
1846 theme-dir = /path/to/use/ | |
1847 EOF | |
1848 | |
1849 exit; | |
1850 } | |
1851 | |
1852 if ( ! -d $CONFIG{'theme-dir'} ) | |
1853 { | |
1854 print "The theme directory you specified doesn't exist:\n"; | |
1855 print "\t" . $CONFIG{'theme-dir'} . "\n"; | |
1856 exit; | |
1857 } | |
1858 | |
1859 if ( !$CONFIG{'theme'} ) | |
1860 { | |
1861 print <<EOF; | |
1862 | |
1863 You've not specified a theme. | |
1864 | |
1865 Please specify --theme=xx | |
1866 | |
1867 Or add this to your configuration file: | |
1868 | |
1869 theme = xx | |
1870 | |
1871 | |
1872 [You may list themes with --list-themes] | |
1873 | |
1874 EOF | |
1875 | |
1876 exit; | |
1877 } | |
1878 | |
1879 | |
1880 if ( ! -d $CONFIG{'theme-dir'} . "/" . $CONFIG{'theme'} ) | |
1881 { | |
1882 print "The theme directory you specified doesn't exist in the theme directory:\n"; | |
1883 print "\tTheme :" . $CONFIG{'theme'} . "\n"; | |
1884 print "\tTheme dir:" . $CONFIG{'theme-dir'} . "\n"; | |
1885 print "\tExpected :" . $CONFIG{'theme-dir'} . "/" . $CONFIG{'theme'} . "\n"; | |
1886 exit; | |
1887 } | |
1888 | |
1889 } | |
1890 | |
1891 | |
1892 | |
1893 | |
1894 =begin doc | |
1895 | |
12 | 1896 Copy any static files from the theme directory into the "live" location |
1897 in the output. | |
1898 | |
1899 This only works for a top-level target directory. | |
1 | 1900 |
46 | 1901 Unless --force is specified we skip copying files which already exist. |
1902 | |
1 | 1903 =end doc |
1904 | |
1905 =cut | |
1906 | |
12 | 1907 sub copyStaticFiles |
1 | 1908 { |
12 | 1909 # |
1910 # Soure and destination for the copy | |
1911 # | |
61 | 1912 my $input = $CONFIG{'theme-dir'} . "/" . $CONFIG{'theme'}; |
12 | 1913 my $output = $CONFIG{'output'}; |
1 | 1914 |
12 | 1915 foreach my $pattern ( qw! *.css *.jpg *.gif *.png *.js *.ico ! ) |
1916 { | |
1917 foreach my $file ( glob( $input . "/" . $pattern ) ) | |
1918 { | |
13 | 1919 # |
1920 # Get the name of the file. | |
1921 # | |
1922 if ( $file =~ /(.*)\/(.*)/ ) | |
1923 { | |
1924 $file = $2; | |
1925 } | |
46 | 1926 if ( $CONFIG{'force'} || ( ! -e "$output/$file" ) ) |
12 | 1927 { |
13 | 1928 $CONFIG{'verbose'} && print "Copying static file: $file\n"; |
1929 copy( "$input/$file", "$output/$file" ); | |
12 | 1930 } |
1931 } | |
1932 } | |
1 | 1933 } |
16 | 1934 |
1935 | |
1936 | |
1937 =begin doc | |
1938 | |
1939 Convert from markdown to HTML. | |
1940 | |
1941 =end doc | |
1942 | |
1943 =cut | |
1944 | |
1945 sub markdown2HTML | |
1946 { | |
1947 my( $text ) = (@_); | |
1948 | |
1949 # | |
1950 # Make sure we have the module installed. Use eval to | |
1951 # avoid making this mandatory. | |
1952 # | |
1953 my $test = "use Text::Markdown;"; | |
1954 | |
1955 # | |
1956 # Test loading the module. | |
1957 # | |
1958 eval( $test ); | |
1959 if ( $@ ) | |
1960 { | |
1961 print <<EOF; | |
1962 | |
1963 You have chosen to format your input text via Markdown, but the | |
1964 Perl module Text::Markdown is not installed. | |
1965 | |
1966 Aborting. | |
1967 EOF | |
1968 exit; | |
1969 } | |
1970 | |
1971 # | |
1972 # Convert. | |
1973 # | |
1974 $text = Text::Markdown::Markdown( $text ); | |
1975 return( $text ); | |
1976 } | |
1977 | |
1978 | |
1979 | |
1980 =begin doc | |
1981 | |
1982 Convert from textile to HTML. | |
1983 | |
1984 =end doc | |
1985 | |
1986 =cut | |
1987 | |
1988 sub textile2HTML | |
1989 { | |
1990 my( $text ) = (@_); | |
1991 | |
1992 # | |
1993 # Make sure we have the module installed. Use eval to | |
1994 # avoid making this mandatory. | |
1995 # | |
1996 my $test = "use Text::Textile;"; | |
1997 | |
1998 # | |
1999 # Test loading the module. | |
2000 # | |
2001 eval( $test ); | |
2002 if ( $@ ) | |
2003 { | |
2004 print <<EOF; | |
2005 | |
2006 You have chosen to format your input text via Textile, but the | |
2007 Perl module Text::Textile is not installed. | |
2008 | |
2009 Aborting. | |
2010 EOF | |
2011 exit; | |
2012 } | |
2013 | |
2014 # | |
2015 # Convert. | |
2016 # | |
2017 $text = Text::Textile::textile( $text ); | |
2018 return( $text ); | |
2019 } | |
2020 | |
2021 | |
2022 | |
2023 | |
61 | 2024 sub listThemes |
2025 { | |
2026 my( $dir ) = ( @_ ); | |
2027 | |
2028 $CONFIG{'verbose'} && print "Listhing themes beneath : $dir\n"; | |
2029 | |
2030 foreach my $name ( sort( glob( $dir . "/*" ) ) ) | |
2031 { | |
2032 next unless( -d $name ); | |
2033 | |
2034 next if ( $name =~ /\/xml$/ ); | |
2035 | |
2036 if ( $name =~ /^(.*)\/([^\/\\]*)$/ ) | |
2037 { | |
2038 print $2 . "\n"; | |
2039 } | |
2040 } | |
2041 } | |
66
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2042 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2043 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2044 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2045 =begin doc |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2046 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2047 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
|
2048 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
|
2049 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2050 =end doc |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2051 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2052 =cut |
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 sub createCalendar |
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 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2057 # 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
|
2058 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2059 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
|
2060 eval( $test ); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2061 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2062 # |
128 | 2063 # 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
|
2064 # return undef. |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2065 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2066 if ( ( $@ ) || ( $CONFIG{'no-calendar'} ) ) |
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 return undef; |
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 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2071 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2072 # Continue |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2073 # |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2074 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
|
2075 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2076 # configuration of the calendar |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2077 $cal->border(0); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2078 $cal->weekstartsonmonday(1); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2079 $cal->showweekdayheaders(1); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2080 $cal->sunday('Sun'); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2081 $cal->saturday('Sat'); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2082 $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
|
2083 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2084 # 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
|
2085 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
|
2086 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2087 foreach my $f (%data) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2088 { |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2089 my $h = $data{$f}; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2090 next if ( !$h ); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2091 my $entrydate = $h->{'date'}; |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2092 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2093 if ( !$entrydate ) |
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 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
|
2096 $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
|
2097 = stat($f); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2098 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2099 $entrydate = localtime( $ctime ); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2100 } |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2101 |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2102 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
|
2103 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
|
2104 |
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 if ($month eq $curmonth) |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2107 { |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2108 $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
|
2109 } |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2110 } |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2111 return ($cal); |
fbeda752caa7
Updated so that there is a calander optionally available.
Steve Kemp <steve@steve.org.uk>
parents:
65
diff
changeset
|
2112 } |