File: directory-as-atom.pl

package info (click to toggle)
libxml-writer-perl 0.900-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 228 kB
  • sloc: perl: 2,609; makefile: 2
file content (148 lines) | stat: -rwxr-xr-x 3,470 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/perl -w

# A full example that presents a directory as an Atom feed
# It demonstrates namespace and formatting control.
# Intended to productise the /junk convention.

# Usage: directory-as-atom.pl <local directory> <public URL> [feed title] [feed subtitle]

# e.g., directory-as-atom.pl /home/user/public_html/junk http://www.example.com/~user/junk/ >index.atom

use strict;

use DirHandle;
use URI::URL;
use DateTime;

use XML::Writer;

my ($dir, $base, $title, $subtitle) = @ARGV;

defined($base) or die "Usage: directory-as-atom.pl <local directory> <public URL> [feed title] [feed subtitle]";

$dir ||= '.';

$title ||= '/junk/';
$subtitle ||= 'ls -ltr $dir | head -10';


my $uid = (stat($dir))[4];

my $dh = DirHandle->new($dir) || die "Unable to opendir $dir: $!";

my @de;

while(my $e = $dh->read()) {
	# Skip dotfiles
	next if ($e =~ /^\./);

	my $n = "$dir/$e";

	next unless (-f $n);

	my ($mtime, $bytes) = (stat($n))[9,7];

	my $desc; # undef, for now

	if (defined($mtime)) {push(@de, [$e, $mtime, $desc, $bytes])};
}

undef($dh);

# Sort into reverse date order...
@de = sort {
	$b->[1] <=> $a->[1];
} @de;

# ...take the most recent ten
if (@de > 10) {
	@de = @de[0..9];
}

# Constants for the namespace URIs
my $ATOM = 'http://www.w3.org/2005/Atom';
my $HTML = 'http://www.w3.org/1999/xhtml';
my $XML = 'http://www.w3.org/XML/1998/namespace';

sub toIsoDate($)
{
	my $t = shift;

	my $d = DateTime->from_epoch(epoch => $t);
	$d->set_time_zone('UTC');

	return $d->iso8601 . "Z";
}

my $w = XML::Writer->new(
	# Use namespaces
	NAMESPACES => 1,
	
	# Write in data mode, with indentation
	DATA_MODE => 1, DATA_INDENT => 1,

	# Use specific namespace prefixes
	PREFIX_MAP => {$ATOM => '', $HTML => 'html'},

	# Force an xmlns:html declaration on the root element
	FORCED_NS_DECLS => [$HTML],

	# Encode text as UTF-8
	ENCODING => 'utf-8'
);

$base = URI::URL->new($base)->abs;

my $feedUrl = URI::URL->new('index.atom', $base);

$w->xmlDecl();

# Start the root element with an xml:base declaration
$w->startTag([$ATOM, 'feed'], [$XML, 'base'] => $base);

$w->dataElement([$ATOM, 'id'], $feedUrl->abs);

# Mandatory Atom feed elements
$w->dataElement([$ATOM, 'title'], $title);
$w->dataElement([$ATOM, 'subtitle'], $subtitle);
$w->dataElement('generator', 'Old-skool directory-based CMS');
$w->emptyTag('link', 'rel' => 'self', 'href' => $feedUrl) if $feedUrl;
$w->dataElement([$ATOM, 'updated'] => toIsoDate(time));

# Find out the directory owner's name
if (my ($name) = (getpwuid($uid))[0]) {
	$w->startTag([$ATOM, 'author']);
	$w->dataElement([$ATOM, 'name'], $name);
	$w->endTag([$ATOM, 'author']);
}

# Write an entry for each file
foreach (@de) {
	my ($n, $mtime, $desc, $bytes) = @{$_};

	my $url = url($n, $base)->abs->as_string;

	$w->startTag([$ATOM, 'entry']);

	$w->dataElement([$ATOM, 'title'], $n);
	$w->dataElement([$ATOM, 'id'], $url);
	$w->emptyTag([$ATOM, 'link'], 'href' => $n);
	$w->dataElement([$ATOM, 'updated'], toIsoDate($mtime));

	# Write atom:content as XHTML; turn off data mode
	#  to control whitespace inside the html:div element
	$w->startTag([$ATOM, 'content'], 'type' => 'xhtml');
	$w->startTag([$HTML, 'div']);
	$w->setDataMode(0);
	$w->dataElement([$HTML, 'code'], $n);
	$w->characters(" - ${bytes} bytes");
	$w->characters(" - ${desc}") if $desc;
	$w->setDataMode(1);
	$w->endTag([$HTML, 'div']);
	$w->endTag([$ATOM, 'content']);

	$w->endTag([$ATOM, 'entry']);
}

$w->endTag([$ATOM, 'feed']);
$w->end();