| 1 |
lucas |
1550 |
#!/usr/bin/ruby -w |
| 2 |
|
|
require 'dbi' |
| 3 |
|
|
require 'cgi' |
| 4 |
|
|
|
| 5 |
lucas |
1693 |
tstart = Time::now |
| 6 |
|
|
|
| 7 |
lucas |
1589 |
class Actions |
| 8 |
|
|
attr_reader :actions, :act_todo, :act_status, :act_comment |
| 9 |
|
|
def initialize |
| 10 |
|
|
@actions = [] |
| 11 |
|
|
@act_status = "" |
| 12 |
|
|
@act_todo = false |
| 13 |
|
|
@act_comment = "" |
| 14 |
|
|
end |
| 15 |
|
|
|
| 16 |
|
|
def add(desc) |
| 17 |
|
|
desc.chomp! |
| 18 |
|
|
date, who, act, comment = desc.split(' ', 4) |
| 19 |
|
|
date = Date::parse(date) |
| 20 |
|
|
if act =~ /^(.+)\((.+)\)$/ |
| 21 |
|
|
act_name, act_arg = $1, $2 |
| 22 |
|
|
if [ 'PROP_RM', 'PROP_RM_O', 'PROP_O', 'O', 'REQ_RM', 'RM', 'SEC_RM', 'O_PROP_RM' ].include?(act_name) |
| 23 |
|
|
# FIXME check bug |
| 24 |
|
|
elsif act_name == 'WAIT' |
| 25 |
|
|
act_arg = act_arg.to_i |
| 26 |
|
|
else |
| 27 |
|
|
puts "Unknown action: #{act} (#{desc})" |
| 28 |
|
|
end |
| 29 |
|
|
@actions << [date, who, [act_name, act_arg], comment] |
| 30 |
|
|
elsif act == 'OK' |
| 31 |
|
|
act_name = 'OK' |
| 32 |
|
|
act_arg = nil |
| 33 |
|
|
@actions << [date, who, [act_name, act_arg], comment] |
| 34 |
|
|
else |
| 35 |
|
|
puts "Unparseable action: #{act} (#{desc})" |
| 36 |
|
|
exit(1) |
| 37 |
|
|
end |
| 38 |
|
|
end |
| 39 |
|
|
|
| 40 |
|
|
def analyze_actions |
| 41 |
|
|
@actions.sort! { |a,b| b[0] <=> a[0] } |
| 42 |
|
|
idx = 0 |
| 43 |
|
|
rm_o = false |
| 44 |
|
|
while idx < @actions.length |
| 45 |
|
|
if @actions[idx][2][0] == 'OK' |
| 46 |
|
|
@act_status = "" |
| 47 |
|
|
@act_comment = @actions[idx][3] if not @actions[idx][3].nil? |
| 48 |
|
|
break |
| 49 |
|
|
elsif @actions[idx][2][0] == 'WAIT' |
| 50 |
|
|
if @actions[idx][0] + @actions[idx][2][1] <= CURDATE |
| 51 |
|
|
idx += 1 |
| 52 |
|
|
next # OK not valid anymore, consider next action |
| 53 |
|
|
else |
| 54 |
|
|
# nothing to do except waiting |
| 55 |
|
|
@act_status = "Waiting until #{@actions[idx][0] + @actions[idx][2][1]}" |
| 56 |
|
|
@act_comment = @actions[idx][3] if not @actions[idx][3].nil? |
| 57 |
|
|
break |
| 58 |
|
|
end |
| 59 |
|
|
elsif @actions[idx][2][0] == 'REQ_RM' or @actions[idx][2][0] == 'RM' |
| 60 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Removal was requested</a>" |
| 61 |
|
|
@act_comment = @actions[idx][3] if not @actions[idx][3].nil? |
| 62 |
|
|
break |
| 63 |
|
|
elsif @actions[idx][2][0] == 'O' |
| 64 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Was orphaned</a>" |
| 65 |
|
|
@act_comment = @actions[idx][3] if not @actions[idx][3].nil? |
| 66 |
|
|
break |
| 67 |
|
|
elsif @actions[idx][2][0] == 'PROP_RM_O' |
| 68 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Was orphaned, will need removal</a>" |
| 69 |
|
|
rm_o = true |
| 70 |
|
|
idx += 1 |
| 71 |
|
|
@act_comment = @actions[idx][3] if not @actions[idx][3].nil? |
| 72 |
|
|
next |
| 73 |
|
|
elsif @actions[idx][2][0] == 'PROP_RM' |
| 74 |
|
|
ok = false |
| 75 |
|
|
if @actions[idx][0] + WAIT_RM_O <= CURDATE and !rm_o |
| 76 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Should be orphaned before removal (since #{@actions[idx][0] + 50})</a>" |
| 77 |
|
|
@act_todo = true |
| 78 |
|
|
ok = true |
| 79 |
|
|
end |
| 80 |
|
|
if @actions[idx][0] + WAIT_RM_RM <= CURDATE |
| 81 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Should be removed (since #{@actions[idx][0] + 100})</a>" |
| 82 |
|
|
@act_todo = true |
| 83 |
|
|
ok = true |
| 84 |
|
|
end |
| 85 |
|
|
if !ok |
| 86 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Removal suggested (since #{@actions[idx][0]})</a>" |
| 87 |
|
|
end |
| 88 |
|
|
@act_comment = @actions[idx][3] if not @actions[idx][3].nil? |
| 89 |
|
|
break |
| 90 |
|
|
elsif @actions[idx][2][0] == 'PROP_O' |
| 91 |
|
|
if @actions[idx][0] + WAIT_O_O <= CURDATE |
| 92 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Should be orphaned (since #{@actions[idx][0] + 50})</a>" |
| 93 |
|
|
@act_todo = true |
| 94 |
|
|
else |
| 95 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Orphaning suggested (since #{@actions[idx][0]})</a>" |
| 96 |
|
|
end |
| 97 |
|
|
@act_comment = @actions[idx][3] if not @actions[idx][3].nil? |
| 98 |
|
|
break |
| 99 |
|
|
elsif @actions[idx][2][0] == 'O_PROP_RM' |
| 100 |
|
|
if @actions[idx][0] + WAIT_ORM_RM <= CURDATE |
| 101 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Should be removed (O pkg) (since #{@actions[idx][0] + 50})</a>" |
| 102 |
|
|
@act_todo = true |
| 103 |
|
|
else |
| 104 |
|
|
@act_status = "<a href=\"http://bugs.debian.org/#{@actions[idx][2][1]}\">Removal suggested (O pkg) (since #{@actions[idx][0]})</a>" |
| 105 |
|
|
end |
| 106 |
|
|
@act_comment = @actions[idx][3] if not @actions[idx][3].nil? |
| 107 |
|
|
break |
| 108 |
|
|
else |
| 109 |
|
|
puts "Unknown act: #{@actions[idx][2][0]}" |
| 110 |
|
|
end |
| 111 |
|
|
end |
| 112 |
|
|
end |
| 113 |
|
|
|
| 114 |
|
|
def Actions::fetch |
| 115 |
|
|
d = IO::popen("svn cat svn://svn.debian.org/collab-qa/bapase/package-actions.txt") |
| 116 |
|
|
f = d.read |
| 117 |
|
|
d.close |
| 118 |
|
|
return Actions::read(f) |
| 119 |
|
|
end |
| 120 |
|
|
|
| 121 |
|
|
def Actions::read(data) |
| 122 |
|
|
pkgs = {} |
| 123 |
|
|
data.each_line do |l| |
| 124 |
|
|
next if l =~/^\s*#/ or l =~/^\s*$/ |
| 125 |
|
|
pkg, rest = l.split(' ',2) |
| 126 |
|
|
if pkgs[pkg].nil? |
| 127 |
|
|
pkgs[pkg] = Actions::new |
| 128 |
|
|
end |
| 129 |
|
|
pkgs[pkg].add(rest) |
| 130 |
|
|
end |
| 131 |
|
|
pkgs.each_pair { |k, v| v.analyze_actions } |
| 132 |
|
|
end |
| 133 |
|
|
end |
| 134 |
|
|
|
| 135 |
lucas |
1550 |
puts "Content-type: text/html\n\n" |
| 136 |
|
|
|
| 137 |
|
|
WAIT_RM_O = 50 |
| 138 |
|
|
WAIT_RM_RM = 100 |
| 139 |
|
|
WAIT_O_O = 50 |
| 140 |
|
|
WAIT_ORM_RM = 50 |
| 141 |
|
|
|
| 142 |
|
|
DATEZERO = Date::parse('0000-01-01') |
| 143 |
|
|
CURDATE = Date::today |
| 144 |
|
|
|
| 145 |
|
|
dbh = DBI::connect('DBI:Pg:dbname=udd;port=5441;host=localhost', 'guest') |
| 146 |
|
|
cgi = CGI.new |
| 147 |
|
|
|
| 148 |
|
|
type = cgi.params['t'] |
| 149 |
|
|
if not type.nil? |
| 150 |
|
|
type = type[0] |
| 151 |
|
|
end |
| 152 |
|
|
|
| 153 |
|
|
if type == 'o' |
| 154 |
|
|
orphaned = true |
| 155 |
|
|
query = "select * from bapase where type is not null order by orphaned_age desc" |
| 156 |
|
|
elsif type == 'nmu' |
| 157 |
|
|
orphaned = true |
| 158 |
|
|
query = "select * from bapase where nmu and nmus > 1 order by nmus desc" |
| 159 |
|
|
elsif type == 'testing' |
| 160 |
|
|
orphaned = true |
| 161 |
lucas |
1575 |
query = "select * from bapase where source not in (select source from sources where distribution='debian' and release='squeeze') order by testing_age desc, first_seen asc" |
| 162 |
|
|
elsif type == 'nodd' |
| 163 |
|
|
orphaned = true |
| 164 |
|
|
query = <<EOF |
| 165 |
lucas |
1693 |
WITH active_emails AS (SELECT email FROM carnivore_emails, active_dds WHERE active_dds.id = carnivore_emails.id) |
| 166 |
lucas |
1575 |
select * from bapase where source in ( |
| 167 |
|
|
SELECT source |
| 168 |
|
|
FROM sources |
| 169 |
|
|
WHERE distribution = 'debian' AND release = 'sid' |
| 170 |
|
|
AND sources.source NOT IN ( |
| 171 |
|
|
SELECT sources.source |
| 172 |
|
|
FROM sources |
| 173 |
|
|
LEFT OUTER JOIN uploaders ON (sources.source = uploaders.source AND sources.version = uploaders.version AND sources.distribution = uploaders.distribution AND sources.release = uploaders.release AND sources.component = uploaders.component) |
| 174 |
|
|
WHERE sources.distribution = 'debian' AND sources.release = 'sid' |
| 175 |
lucas |
1693 |
AND (maintainer_email in (select email from active_emails) |
| 176 |
|
|
OR email in (SELECT email FROM active_emails) |
| 177 |
lucas |
1575 |
OR maintainer_email ~ '.*@lists.(alioth.)?debian.org' |
| 178 |
|
|
OR email ~ '.*@lists.(alioth.)?debian.org')) |
| 179 |
|
|
) order by upload_age desc |
| 180 |
|
|
EOF |
| 181 |
|
|
elsif type == 'maintnmu' |
| 182 |
|
|
orphaned = true |
| 183 |
|
|
query = <<EOF |
| 184 |
|
|
select * from bapase where source in ( |
| 185 |
|
|
select source from sources where distribution='debian' and release='squeeze' and maintainer_email in ( |
| 186 |
|
|
select nmus.email from |
| 187 |
|
|
(select email, count(*) as tot from |
| 188 |
lucas |
1638 |
(select maintainer_email as email, source from sources_uniq |
| 189 |
lucas |
1575 |
where release = 'sid' |
| 190 |
|
|
and distribution = 'debian' |
| 191 |
|
|
and component = 'main' |
| 192 |
|
|
union |
| 193 |
|
|
select email, source from uploaders |
| 194 |
|
|
where release = 'sid' |
| 195 |
|
|
and distribution = 'debian' |
| 196 |
|
|
and component = 'main') as foo |
| 197 |
|
|
group by email) as tot, |
| 198 |
|
|
(select email, count(*) as nmus from |
| 199 |
lucas |
1638 |
(select sources.maintainer_email as email, sources.source from sources_uniq sources, upload_history uh |
| 200 |
lucas |
1575 |
where release = 'sid' |
| 201 |
|
|
and distribution = 'debian' |
| 202 |
|
|
and component = 'main' |
| 203 |
|
|
and sources.source = uh.source and sources.version = uh.version |
| 204 |
|
|
and uh.nmu |
| 205 |
|
|
union |
| 206 |
|
|
select email, uploaders.source from uploaders, upload_history uh |
| 207 |
|
|
where release = 'sid' |
| 208 |
|
|
and distribution = 'debian' |
| 209 |
|
|
and component = 'main' |
| 210 |
|
|
and uploaders.source = uh.source and uploaders.version = uh.version |
| 211 |
|
|
and uh.nmu |
| 212 |
|
|
) as foo |
| 213 |
|
|
group by email) as nmus |
| 214 |
|
|
where nmus * 100 / tot >= 100 |
| 215 |
|
|
and nmus.email = tot.email) |
| 216 |
|
|
union (select source from uploaders where distribution='debian' and release='squeeze' and email in ( |
| 217 |
|
|
select nmus.email from |
| 218 |
|
|
(select email, count(*) as tot from |
| 219 |
lucas |
1638 |
(select maintainer_email as email, source from sources_uniq sources |
| 220 |
lucas |
1575 |
where release = 'sid' |
| 221 |
|
|
and distribution = 'debian' |
| 222 |
|
|
and component = 'main' |
| 223 |
|
|
union |
| 224 |
|
|
select email, source from uploaders |
| 225 |
|
|
where release = 'sid' |
| 226 |
|
|
and distribution = 'debian' |
| 227 |
|
|
and component = 'main') as foo |
| 228 |
|
|
group by email) as tot, |
| 229 |
|
|
(select email, count(*) as nmus from |
| 230 |
lucas |
1638 |
(select sources.maintainer_email as email, sources.source from sources_uniq sources, upload_history uh |
| 231 |
lucas |
1575 |
where release = 'sid' |
| 232 |
|
|
and distribution = 'debian' |
| 233 |
|
|
and component = 'main' |
| 234 |
|
|
and sources.source = uh.source and sources.version = uh.version |
| 235 |
|
|
and uh.nmu |
| 236 |
|
|
union |
| 237 |
|
|
select email, uploaders.source from uploaders, upload_history uh |
| 238 |
|
|
where release = 'sid' |
| 239 |
|
|
and distribution = 'debian' |
| 240 |
|
|
and component = 'main' |
| 241 |
|
|
and uploaders.source = uh.source and uploaders.version = uh.version |
| 242 |
|
|
and uh.nmu |
| 243 |
|
|
) as foo |
| 244 |
|
|
group by email) as nmus |
| 245 |
|
|
where nmus * 100 / tot >= 100 |
| 246 |
|
|
and nmus.email = tot.email |
| 247 |
|
|
))) order by nmus |
| 248 |
|
|
EOF |
| 249 |
lucas |
1550 |
else |
| 250 |
|
|
puts <<-EOF |
| 251 |
lucas |
1598 |
<h1>Bapase</h1> |
| 252 |
|
|
<ul> |
| 253 |
|
|
<li><a href="bapase.cgi?t=o">Orphaned packages</a></li> |
| 254 |
|
|
<li><a href="bapase.cgi?t=nmu">Packages maintained with NMUs</a></li> |
| 255 |
|
|
<li><a href="bapase.cgi?t=testing">Packages not in testing</a></li> |
| 256 |
|
|
<li><a href="bapase.cgi?t=nodd">Packages not maintained by DDs</a></li> |
| 257 |
|
|
<li><a href="bapase.cgi?t=maintnmu">Packages maintained or co-maintained by people with lots of NMUs</a></li> |
| 258 |
|
|
</ul> |
| 259 |
lucas |
1550 |
</body></html> |
| 260 |
|
|
EOF |
| 261 |
|
|
exit(0) |
| 262 |
|
|
end |
| 263 |
|
|
|
| 264 |
|
|
# FIXME add case where type is uknown |
| 265 |
|
|
|
| 266 |
|
|
$actions = Actions::fetch |
| 267 |
|
|
|
| 268 |
|
|
puts <<-EOF |
| 269 |
|
|
<html><head> |
| 270 |
|
|
<style type="text/css"> |
| 271 |
|
|
td, th { |
| 272 |
|
|
border: 1px solid gray; |
| 273 |
|
|
padding-left: 2px; |
| 274 |
|
|
padding-right: 2px; |
| 275 |
|
|
} |
| 276 |
|
|
th { |
| 277 |
|
|
font-size: 8pt; |
| 278 |
|
|
} |
| 279 |
|
|
tr:hover { |
| 280 |
|
|
background-color: #ccc; |
| 281 |
|
|
} |
| 282 |
|
|
table { |
| 283 |
|
|
border-collapse: collapse; |
| 284 |
|
|
} |
| 285 |
|
|
</style> |
| 286 |
|
|
<title>Bapase</title> |
| 287 |
|
|
</head><body> |
| 288 |
|
|
<table border="1"><tr> |
| 289 |
|
|
<th></th><th>Package</th><th>Action</th> |
| 290 |
|
|
EOF |
| 291 |
|
|
puts "<th>Orphaned</th>" if orphaned |
| 292 |
|
|
puts <<-EOF |
| 293 |
|
|
<th>Testing</th> |
| 294 |
|
|
<th>Migrate</th> |
| 295 |
|
|
<th>Popcon</th> |
| 296 |
|
|
<th>Bugs</th> |
| 297 |
|
|
<th>Last upload</th> |
| 298 |
|
|
<th>NMUs</th> |
| 299 |
|
|
<th>Comments</th> |
| 300 |
|
|
</tr> |
| 301 |
|
|
EOF |
| 302 |
lucas |
1693 |
tqs = Time::now |
| 303 |
lucas |
1550 |
sth = dbh.prepare(query) |
| 304 |
|
|
sth.execute |
| 305 |
lucas |
1693 |
tqe = Time::now |
| 306 |
lucas |
1550 |
res = sth.fetch_all |
| 307 |
|
|
n = 0 |
| 308 |
|
|
res.each do |r| |
| 309 |
|
|
n += 1 |
| 310 |
|
|
pkg = r['source'] |
| 311 |
|
|
puts "<tr><td>#{n}</td>" |
| 312 |
|
|
puts "<td><a href=\"http://packages.qa.debian.org/#{pkg}\">#{pkg}</a>" |
| 313 |
|
|
# FIXME removals |
| 314 |
|
|
if $actions[pkg] |
| 315 |
|
|
if $actions[pkg].act_todo |
| 316 |
|
|
puts "<td><b>#{$actions[pkg].act_status}</b></td>" |
| 317 |
|
|
else |
| 318 |
|
|
puts "<td>#{$actions[pkg].act_status}</td>" |
| 319 |
|
|
end |
| 320 |
|
|
else |
| 321 |
|
|
puts "<td></td>" |
| 322 |
|
|
end |
| 323 |
|
|
if orphaned |
| 324 |
|
|
if r['type'] |
| 325 |
|
|
puts "<td><a href=\"http://bugs.debian.org/#{r['bug']}\">#{r['type']}</a> (#{r['orphaned_age']})</td>" |
| 326 |
|
|
else |
| 327 |
|
|
puts "<td></td>" |
| 328 |
|
|
end |
| 329 |
|
|
end |
| 330 |
|
|
if r['testing_age'] and r['testing_age'] > 1 |
| 331 |
|
|
puts "<td>#{r['testing_age']}</td>" |
| 332 |
|
|
else |
| 333 |
|
|
puts "<td></td>" |
| 334 |
|
|
end |
| 335 |
|
|
if r['sync_age'] and r['sync_age'] > 1 |
| 336 |
|
|
puts "<td>#{r['sync_age']}</td>" |
| 337 |
|
|
else |
| 338 |
|
|
puts "<td></td>" |
| 339 |
|
|
end |
| 340 |
|
|
puts "<td>#{r['insts']} / #{r['vote']}</td>" |
| 341 |
|
|
puts "<td><a href=\"http://bugs.debian.org/src:#{pkg}\">#{r['rc_bugs']} / #{r['all_bugs']}</a></td>" |
| 342 |
|
|
puts "<td>#{r['upload_age']}</td>" |
| 343 |
|
|
puts "<td>#{r['nmus']}</td>" |
| 344 |
|
|
puts "<td></td>" |
| 345 |
|
|
if $actions[pkg] |
| 346 |
|
|
comment = $actions[pkg].act_comment.gsub(/#\d+/) do |bug| |
| 347 |
|
|
bugn = bug.gsub(/^#/, '') |
| 348 |
|
|
"<a href=\"http://bugs.debian.org/#{bugn}\">#{bug}</a>" |
| 349 |
|
|
end |
| 350 |
|
|
puts "<td>#{comment}</td>" |
| 351 |
|
|
else |
| 352 |
|
|
puts "<td></td>" |
| 353 |
|
|
end |
| 354 |
|
|
puts "</tr>" |
| 355 |
|
|
end |
| 356 |
|
|
puts "</table>" |
| 357 |
|
|
|
| 358 |
lucas |
1693 |
tstop = Time::now |
| 359 |
|
|
puts " -- #{res.length} packages listed. Page generated in #{tstop - tstart} seconds. Query took #{tqe - tqs} seconds." |
| 360 |
lucas |
1550 |
puts "</body></html>" |
| 361 |
|
|
|
| 362 |
|
|
|
| 363 |
|
|
|
| 364 |
|
|
|
| 365 |
|
|
#sth.finish |