]> git.donarmstrong.com Git - infobot.git/blob - src/Modules/Freshmeat.pl
- Remaining files that were changed due to removal of $noreply or
[infobot.git] / src / Modules / Freshmeat.pl
1 #
2 # Freshmeat.pl: Frontend to www.freshmeat.net
3 #       Author: dms
4 #      Version: v0.7d (20000923)
5 #      Created: 19990930
6 #
7
8 package Freshmeat;
9
10 use strict;
11
12 ### download compressed version instead?
13
14 my %urls = (
15         'public'  => 'http://www.freshmeat.net/backend/appindex.txt',
16         'private' => 'http://feed.freshmeat.net/appindex/appindex.txt',
17 );
18
19 ####
20 # Usage: &Freshmeat($string);
21 sub Freshmeat {
22     my $sstr    = lc($_[0]);
23     my $refresh = $::param{'freshmeatRefreshInterval'} * 60 * 60;
24
25     my $last_refresh = &::dbGet("freshmeat", "name","_","stable");
26     my $renewtable   = 0;
27
28     if (defined $last_refresh) {
29         $renewtable++ if (time() - $last_refresh > $refresh);
30     } else {
31         $renewtable++;
32     }
33     $renewtable++ if (&::countKeys("freshmeat") < 10);
34
35     if ($renewtable and $$ == $::bot_pid) {
36         &::Forker("freshmeat", sub {
37                 &downloadIndex();
38                 &Freshmeat($sstr);
39         } );
40         # both parent/fork runs here, in case the following looks weird.
41         return if ($$ == $::bot_pid);
42     }
43
44     if (!&showPackage($sstr)) {         # no exact match.
45         my $start_time = &::timeget();
46         my %hash;
47
48         # search by key/NAME first.
49         foreach (&::searchTable("freshmeat", "name","name",$sstr)) {
50             $hash{$_} = 1 unless exists $hash{$_};
51         }
52
53         # search by description line.
54         foreach (&::searchTable("freshmeat", "name","oneliner", $sstr)) {
55             $hash{$_} = 1 unless exists $hash{$_};
56             last if (scalar keys %hash > 15);
57         }
58
59         my @list = keys %hash;
60         # search by value, if we have enough room to do it.
61         if (scalar @list == 1) {
62             &::status("only one match found; showing full info.");
63             &showPackage($list[0]);
64             return;
65         }
66
67         # show how long it took.
68         my $delta_time = &::timedelta($start_time);
69         &::status(sprintf("freshmeat: %.02f sec to complete query.", $delta_time)) if ($delta_time > 0);
70
71         for (@list) {
72             tr/A-Z/a-z/;
73             s/([\,\;]+)/\037$1\037/g;
74         }
75
76         &::performStrictReply( &::formListReply(1, "Freshmeat ", @list) );
77     }
78 }
79
80 sub showPackage {
81     my ($pkg)   = @_;
82     my @fm      = &::dbGet("freshmeat", "name",$pkg,"*");
83
84     if (scalar @fm) {           #1: perfect match of name.
85         my $retval;
86         $retval  = "$fm[0] \002(\002$fm[11]\002)\002, ";
87         $retval .= "section $fm[3], ";
88         $retval .= "is $fm[4]. ";
89         $retval .= "Stable: \002$fm[1]\002, ";
90         $retval .= "Development: \002$fm[2]\002. ";
91         $retval .= $fm[5] || $fm[6];             # fallback to 'download'.
92         $retval .= " deb: ".$fm[8] if ($fm[8] ne ""); # 'deb'.
93         &::performStrictReply($retval);
94         return 1;
95     } else {
96         return 0;
97     }
98 }
99
100 sub randPackage {
101     my @fm      = &::randKey("freshmeat","*");
102
103     if (scalar @fm) {           #1: perfect match of name.
104         my $retval;
105         $retval  = "$fm[0] \002(\002$fm[11]\002)\002, ";
106         $retval .= "section $fm[3], ";
107         $retval .= "is $fm[4]. ";
108         $retval .= "Stable: \002$fm[1]\002, ";
109         $retval .= "Development: \002$fm[2]\002. ";
110         $retval .= $fm[5] || $fm[6];             # fallback to 'download'.
111         $retval .= " deb: ".$fm[8] if ($fm[8] ne ""); # 'deb'.
112
113         return $retval;
114     } else {
115         return;
116     }
117 }
118
119 sub downloadIndex {
120     my $start_time      = &::timeget(); # set the start time.
121     my $idx             = "$::param{tempDir}/fm_index.txt";
122
123     &::msg($::who, "Updating freshmeat index... please wait");
124
125     if (&::isStale($idx, 1)) {
126         &::status("Freshmeat: fetching data.");
127         foreach (keys %urls) {
128             my $retval = &::getURLAsFile($urls{$_}, $idx);
129             next if ($retval =~ /^(403|500)$/);
130
131             &::DEBUG("FM: last! retval => '$retval'.");
132             last;
133         }
134     } else {
135         &::status("Freshmeat: local file hack.");
136     }
137
138     if (! -e $idx) {
139         &::msg($::who, "the freshmeat butcher is closed.");
140         return;
141     }
142
143     if ( -s $idx < 100000) {
144         &::DEBUG("FM: index too small?");
145         unlink $idx;
146         &::msg($::who, "internal error?");
147         return;
148     }
149
150     if ($idx =~ /bz2$/) {
151         open(IN, "bzcat $idx |");
152     } elsif ($idx =~ /gz$/) {
153         open(IN, "gzcat $idx |");
154     } else {
155         open(IN, $idx);
156     }
157
158     # delete the table before we redo it.
159     &::deleteTable("freshmeat");
160
161     ### lets get on with business.
162     # set the last refresh time. fixes multiple spawn bug.
163     &::dbSet("freshmeat", "name","_","stable",time());
164
165     my $i = 0;
166     while (my $line = <IN>) {
167         chop $line;
168         $i++ if ($line eq "%%");
169         last if ($i == 2);
170     }
171
172     &::dbRaw("LOCK", "LOCK TABLES freshmeat WRITE");
173     my @data;
174     my @done;
175     while (my $line = <IN>) {
176         chop $line;
177         if ($line ne "%%") {
178             push(@data,$line);
179             next;
180         }
181
182         if ($i % 200 == 0 and $i != 0) {
183             &::DEBUG("FM: unlocking and locking.");
184             &::dbRaw("UNLOCK", "UNLOCK TABLES");
185             ### another lame hack to "prevent" errors.
186             select(undef, undef, undef, 0.2);
187             &::dbRaw("LOCK", "LOCK TABLES freshmeat WRITE");
188         }
189
190         if (grep /^\Q$data[0]\E$/, @done) {
191             &::DEBUG("dupe? $data[0]");
192             @data = ();
193             next;
194         }
195
196         $i++;
197         pop @data;
198         $data[1] ||= "none";
199         $data[2] ||= "none";
200         &::dbSetRow("freshmeat", @data);
201         push(@done,$data[0]);
202         @data = ();
203     }
204     close IN;
205     &::DEBUG("FM: data ".scalar(@data) );
206     &::dbRaw("UNLOCK", "UNLOCK TABLES");
207
208     my $delta_time = &::timedelta($start_time);
209     &::status(sprintf("Freshmeat: %.02f sec to complete.", $delta_time)) if ($delta_time > 0);
210
211     my $count = &::countKeys("freshmeat");
212     &::status("Freshmeat: $count entries loaded.");
213 }
214
215 sub freshmeatAnnounce {
216     my $file = "$::param{tempDir}/fm_recent.txt";
217     my @old;
218
219     ### if file exists, lets read it.
220     if ( -f $file) {
221         open(IN, $file);
222         while (<IN>) {
223             chop;
224             push(@old,$_);
225         }
226         close IN;
227     }
228
229     my @array = &::getURL("http://core.freshmeat.net/backend/recentnews.txt");
230     my @now;
231
232     while (@array) {
233         my($what,$date,$url) = splice(@array,0,3);
234         push(@now, $what);
235     }
236
237     ### if file does not exist, write new.
238     if (! -f $file) {
239         open(OUT, ">$file");
240         foreach (@now) {
241             print OUT "$_\n";
242         }
243         close OUT;
244
245         return;
246     }
247
248     my @new;
249     for(my $i=0; $i<scalar(@old); $i++) {
250         last if ($now[$i] eq $old[0]);
251         push(@new, $now[$i]);
252     }
253
254     if (!scalar @new) {
255         &::DEBUG("fA: no new items.");
256         return;
257     }
258
259     ### output new file.
260     open(OUT, ">$file");
261     foreach (@now) {
262         print OUT "$_\n";
263     }
264     close OUT;
265
266     return "Freshmeat update: ".join(" \002::\002 ", @new);
267 }
268
269 1;