28af9f6cd6b153b5212a9edbeec7888f8aa13d2d
[privoxy.git] / utils / create-package-feed.pl
1 #!/usr/local/bin/perl
2
3 ############################################################################
4 # Copyright (c) 2016 "Unknown", Fabian Keil <fk@fabiankeil.de>
5 #
6 # Permission to use, copy, modify, and distribute this software for any
7 # purpose with or without fee is hereby granted, provided that the above
8 # copyright notice and this permission notice appear in all copies.
9 #
10 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 ############################################################################
18
19 use warnings;
20 use strict;
21 use Digest::SHA;
22 my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
23 my @days   = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
24
25 my $base_dlurl = 'https://www.privoxy.org/sf-download-mirror/';
26 my $max_advertised_files = 100;
27
28 sub generate_rss_item($$$$) {
29     my ($target, $target_uri, $target_time, $target_sha256) = @_;
30
31     my $rss_item;
32     my $escaped_target_uri = $target_uri;
33     $escaped_target_uri =~ s@ @%20@g;
34
35     # RSS line
36     $rss_item =
37         '<item><title><![CDATA[' . $target_uri . ']]></title>';
38     $rss_item .=
39         '<description><![CDATA['
40         . $target_uri
41         . ' (SHA-256: '
42         . $target_sha256
43         . ')]]></description>';
44     $rss_item .=
45         '<link>'
46         . $base_dlurl
47         . $escaped_target_uri
48         . '</link><guid>'
49         . $base_dlurl
50         . $escaped_target_uri
51         . '</guid>';
52     $rss_item .= '<pubDate>';
53     my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
54         gmtime($target_time);
55     $rss_item .= sprintf("%s, %s %s %d %.2d:%.2d:%.2d GMT",
56                          $days[$wday], $mday, $months[$mon], ($year + 1900),
57                          $hour, $min, $sec);
58     $rss_item .= '</pubDate></item>';
59     $rss_item .= "\n";
60
61     return $rss_item;
62 }
63
64 sub get_sha256_sum($) {
65     my $file = shift;
66
67     open(my $fd, "<", $file)
68         or die "Can't open '$file' to generate checksum $!";
69     my $sha256 = Digest::SHA->new("SHA-256");
70     $sha256->addfile($fd);
71     close($fd);
72
73     return $sha256->hexdigest;
74 }
75
76 sub get_released_files($) {
77     my $scan_dir = shift;
78
79     my @Array = ();
80     my $i     = 0;
81     my $target;
82     my $target_sha256;
83     my $target_uri;
84     my $target_time;
85     my $target_line;
86
87     opendir(my $D1, $scan_dir) or die "Can't open 1st directory! /";
88     while (my $fi1 = readdir($D1)) {
89         next if ($fi1 =~ m/^\./);
90         next if ($fi1 eq 'OldFiles' or $fi1 eq 'pkgsrc');
91
92         opendir(my $D2, $scan_dir . $fi1 . '/')
93             or die "Can't open 2nd directory! /$fi1";
94         while (my $fi2 = readdir($D2)) {
95             next if ($fi2 =~ m/^\./);
96
97             # Start listing /OS/Version/FILE
98             opendir(my $D3, $scan_dir . $fi1 . '/' . $fi2 . '/')
99                 or die "Can't open 3rd directory! /$fi1/$fi2";
100             while (my $fi3 = readdir($D3)) {
101                 next if ($fi3 =~ m/^\./);
102                 $target = $scan_dir . $fi1 . '/' . $fi2 . '/' . $fi3;
103                 next if (!-e $target);    # skip if file is not exist
104
105                 $target_uri  = $fi1 . '/' . $fi2 . '/' . $fi3;
106                 $target_time = (stat $target)[9];
107
108                 $Array[$i] = ([$target_time, $target, $target_uri]);
109
110                 $i++;
111             }
112             closedir($D3);
113         }
114         closedir($D2);
115     }
116     closedir($D1);
117
118     return sort { @$a[0] <=> @$b[0] } @Array;
119 }
120
121 sub generate_feed($) {
122     my $scan_dir = shift;
123
124     # Result = Full XML Codes
125     my $result = '<?xml version="1.0" encoding="utf-8"?>
126  <rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
127   <channel>
128    <title>Privoxy Releases</title>
129    <link>https://www.privoxy.org/announce.txt</link>
130    <description><![CDATA[Privoxy Releases RSS feed]]></description>
131    <pubDate>';
132     my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = gmtime();
133     $result .=
134         "$days[$wday], $mday $months[$mon] "
135         . ($year + 1900)
136         . " $hour:$min:$sec GMT";
137     $result .= '</pubDate>';
138     $result .= "\n";
139
140     my @resArray = get_released_files($scan_dir);
141     my $i = @resArray - 1;
142     while ($max_advertised_files-- > 0 && $i >= 0) {
143         my $target_time =  $resArray[$i][0];
144         my $target = $resArray[$i][1];
145         my $target_uri =  $resArray[$i][2];
146
147         my $target_sha256 = get_sha256_sum($target);
148
149         my $rss_item = generate_rss_item($target, $target_uri, $target_time, $target_sha256);
150
151         $result .= $rss_item;
152         $i--;
153     }
154     $result .= '  </channel>
155    </rss>';
156
157     return $result;
158 }
159
160 sub main() {
161     my $scan_dir = shift(@ARGV)
162         or die "Local package directory not specified (first argument)\n";
163     my $save_rss_file = shift(@ARGV)
164         or die "RSS output file path not specified (second argument)\n";
165
166     my $result = generate_feed($scan_dir);
167
168     open(my $XMLF, ">", $save_rss_file) or die "Failed to write XML file";
169     print $XMLF $result;
170     close($XMLF);
171 }
172
173 main();