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