Merge lp:~ara/ubuntu/lucid/ubuntu-qa-tools/fix_537941 into lp:~ubuntu-branches/ubuntu/lucid/ubuntu-qa-tools/lucid
- Lucid (10.04)
- fix_537941
- Merge into lucid
Proposed by
Ara Pulido
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~ara/ubuntu/lucid/ubuntu-qa-tools/fix_537941 |
Merge into: | lp:~ubuntu-branches/ubuntu/lucid/ubuntu-qa-tools/lucid |
Diff against target: |
995 lines (+557/-389) 4 files modified
debian/changelog (+10/-0) debian/control (+7/-3) dl-ubuntu-test-iso/dl-ubuntu-test-iso (+538/-384) setup.py (+2/-2) |
To merge this branch: | bzr merge lp:~ara/ubuntu/lucid/ubuntu-qa-tools/fix_537941 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach (community) | Approve | ||
Review via email: mp+21222@code.launchpad.net |
Commit message
Description of the change
* dl-ubuntu-test-iso is failing to download lucid images (LP: #537941)
* Fixes some lintian errors due to script naming
* debian/control:
- Removed dependency with python-dev
- Added two existing scripts to the description of the package
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === renamed file 'bugs-mailinglist/ml-fixes-report.py' => 'bugs-mailinglist/ml-fixes-report' |
2 | === renamed file 'bugs-mailinglist/ml-team-fixes-report.py' => 'bugs-mailinglist/ml-team-fixes-report' |
3 | === modified file 'debian/changelog' |
4 | --- debian/changelog 2009-07-14 08:43:29 +0000 |
5 | +++ debian/changelog 2010-03-12 09:50:29 +0000 |
6 | @@ -1,3 +1,13 @@ |
7 | +ubuntu-qa-tools (0.1.4.1) lucid; urgency=low |
8 | + |
9 | + * dl-ubuntu-test-iso is failing to download lucid images (LP: #537941) |
10 | + * Fixes some lintian errors due to script naming |
11 | + * debian/control: |
12 | + - Removed dependency with python-dev |
13 | + - Added two existing scripts to the description of the package |
14 | + |
15 | + -- Ara Pulido <ara@ubuntu.com> Fri, 12 Mar 2010 10:05:58 +0100 |
16 | + |
17 | ubuntu-qa-tools (0.1.4) karmic; urgency=low |
18 | |
19 | * Added three new scripts: |
20 | |
21 | === modified file 'debian/control' |
22 | --- debian/control 2009-02-11 11:27:52 +0000 |
23 | +++ debian/control 2010-03-12 09:50:29 +0000 |
24 | @@ -4,11 +4,11 @@ |
25 | Maintainer: Ubuntu MOTU Developers <ubuntu-motu@lists.ubuntu.com> |
26 | Vcs-Bzr: http://bazaar.launchpad.net/~ubuntu-bugcontrol/ubuntu-qa-tools/packaging |
27 | Vcs-Browser: http://codebrowse.launchpad.net/~ubuntu-bugcontrol/ubuntu-qa-tools/packaging/changes |
28 | -Build-Depends: cdbs (>= 0.4.49), debhelper (>= 6), python-all-dev (>= 2.4) |
29 | +Build-Depends: cdbs (>= 0.4.49), debhelper (>= 6), python-all |
30 | Build-Depends-Indep: python-central (>= 0.5) |
31 | XS-Python-Version: >= 2.5 |
32 | Homepage: https://launchpad.net/ubuntu-qa-tools/ |
33 | -Standards-Version: 3.8.0 |
34 | +Standards-Version: 3.8.4 |
35 | |
36 | Package: ubuntu-qa-tools |
37 | Architecture: all |
38 | @@ -27,10 +27,14 @@ |
39 | . |
40 | * check-needs-packaging - checks for bugs that require new packaging |
41 | * body-searching - search bugs with a particular text |
42 | - * count-senders - quantity of messages sent by individuals to the bug mailinglist |
43 | + * count-senders - quantity of messages sent by individuals |
44 | + to the bug mailinglist |
45 | * tagged-bugs - search for tagged bugs in Launchpad |
46 | * triager-query - search for actions of a particular triager |
47 | * dl-ubuntu-test-iso - downloads ISOs for testing using rsync |
48 | * iso-ripper - rips debs out of downloaded isos |
49 | * debian-bug-search - searches the Debian bug tracking system |
50 | * hugday - simplifies participating on ubuntu hugdays |
51 | + * ml-fixes-report - searches fixes in a bug mailing list |
52 | + * ml-team-fixes-report - searches fixes by team |
53 | + |
54 | |
55 | === modified file 'dl-ubuntu-test-iso/dl-ubuntu-test-iso' |
56 | --- dl-ubuntu-test-iso/dl-ubuntu-test-iso 2009-07-14 08:43:29 +0000 |
57 | +++ dl-ubuntu-test-iso/dl-ubuntu-test-iso 2010-03-12 09:50:29 +0000 |
58 | @@ -1,384 +1,538 @@ |
59 | -#!/bin/sh |
60 | -# |
61 | -# Download, with rsync, Ubuntu ISO images for testing them. |
62 | -# This will use a lot of bandwidth and disk space. |
63 | -# |
64 | -# You can put a configuration file (~/.dl-ubuntu-test-iso) |
65 | -# and set some variables to limit what will be downloaded. |
66 | -# See sample values below. |
67 | -# |
68 | -# * ARCHS: what architectures to download |
69 | -# * FLAVORS: what flavors of Ubuntu? Ubuntu itself, Kubuntu, etc |
70 | -# * VARIANTS: for each flavor, what variants? desktop (= live cd)? |
71 | -# alternate cd? |
72 | -# * OPTS: options for rsync |
73 | -# |
74 | -# You can get sample configuration files at /usr/share/doc/ubuntu-qa-tools/examples/ |
75 | -# |
76 | -# This is based on a script by davmor2 on #ubuntu-testing. Modified and |
77 | -# rewritten to be more easily extensible by Lars Wirzenius. Further |
78 | -# abuse was perpetrated by Steve Beattie. This is probably |
79 | -# too simple to be covered by copyright, but if not: |
80 | -# |
81 | -# Copyright 2008, 2009 Canonical Ltd. |
82 | -# Licensed under the GNU General Public License, version 3. |
83 | - |
84 | -set -e |
85 | - |
86 | -ISOROOT="${HOME}/iso" |
87 | -BASEURL="rsync://cdimage.ubuntu.com/cdimage" |
88 | -RELEASES="karmic hardy" |
89 | -ARCHS="i386 amd64" |
90 | -FLAVORS="ubuntu kubuntu edubuntu xubuntu ubuntu-server" |
91 | -FLAVORS="$FLAVORS ubuntustudio mythbuntu" |
92 | -VARIANTS="desktop alternate server addon dvd" |
93 | -EXCLUDE="" |
94 | -OPTS="-zthhP" |
95 | -QUIET="false" |
96 | -NO_ACT=no |
97 | -VERIFY="true" |
98 | -BUILD="current" |
99 | - |
100 | -RSYNC=rsync |
101 | -ISOINFO=/usr/bin/isoinfo |
102 | -WGET=/usr/bin/wget |
103 | -CURL=/usr/bin/curl |
104 | -CURRENT_RELEASE="karmic" |
105 | -VERSIONS="false" |
106 | -CONFIGFILE="${HOME}/.dl-ubuntu-test-iso" |
107 | - |
108 | -if [ -e "${CONFIGFILE}" ] |
109 | -then |
110 | - . ${CONFIGFILE} |
111 | -elif [ -e "${ISOROOT}/iso.cfg" ] |
112 | -then |
113 | - echo "******" |
114 | - echo "****** ${ISOROOT}/iso.cfg is deprecated, please use ${CONFIGFILE} instead" |
115 | - echo "******" |
116 | - . "${ISOROOT}/iso.cfg" |
117 | -fi |
118 | - |
119 | -setup_dir() |
120 | -{ |
121 | - local dir=$1 |
122 | - |
123 | - [ -d "$dir" ] || mkdir $dir |
124 | - cd $dir |
125 | -} |
126 | - |
127 | -setup_dir $ISOROOT |
128 | - |
129 | -die() |
130 | -{ |
131 | - echo "$@" 1>&2 |
132 | - exit 1 |
133 | -} |
134 | - |
135 | -no_act() |
136 | -{ |
137 | - [ "$NO_ACT" = yes ] |
138 | -} |
139 | - |
140 | -debugify_commands() |
141 | -{ |
142 | - RSYNC="echo $RSYNC" |
143 | - ISOINFO="echo $ISOINFO" |
144 | -} |
145 | - |
146 | -wantflavor() |
147 | -{ |
148 | - echo " $FLAVORS " | grep " $1 " > /dev/null && |
149 | - echo " $EXCLUDE " | grep -v " $1 " > /dev/null |
150 | -} |
151 | - |
152 | -wantvariant() |
153 | -{ |
154 | - echo " $VARIANTS " | grep " $1 " > /dev/null |
155 | -} |
156 | - |
157 | -wantarch() |
158 | -{ |
159 | - local arch="$1" |
160 | - shift |
161 | - echo " $@ " | grep " $arch " > /dev/null |
162 | -} |
163 | - |
164 | -# Dead code, kept around for historical raisins |
165 | -#isold() |
166 | -#{ |
167 | -# if [ ! -e "$1" ] |
168 | -# then |
169 | -# return 0 |
170 | -# else |
171 | -# local mtime=$(stat --printf='%Y\n' "$1") |
172 | -# local old=$(date --date="$MINAGE" +%s) |
173 | -# [ "$mtime" -lt "$old" ] |
174 | -# fi |
175 | -#} |
176 | -# end dead code |
177 | - |
178 | -isquiet() |
179 | -{ |
180 | - [ "$QUIET" = "true" ] |
181 | -} |
182 | - |
183 | -doverify() |
184 | -{ |
185 | - [ "$VERIFY" = "true" ] |
186 | -} |
187 | - |
188 | -doversions() |
189 | -{ |
190 | - [ "$VERSIONS" = "true" ] |
191 | -} |
192 | - |
193 | -computepath() |
194 | -{ |
195 | - local flavor="$1" |
196 | - local release="$2" |
197 | - local dir="$3" |
198 | - |
199 | - local releasepath="" |
200 | - local flavorpath="" |
201 | - if [ "$CURRENT_RELEASE" != "$release" ] |
202 | - then |
203 | - releasepath="$release/" |
204 | - fi |
205 | - |
206 | - if [ "$flavor" != "ubuntu" ] |
207 | - then |
208 | - flavorpath="$flavor/" |
209 | - fi |
210 | - |
211 | - echo "${flavorpath}${releasepath}${dir}" |
212 | -} |
213 | - |
214 | -has_joliet() |
215 | -{ |
216 | - local iso="$1" |
217 | - ! isoinfo -d -i "${iso}" | grep -q "^NO Joliet" |
218 | -} |
219 | - |
220 | -report_versions() |
221 | -{ |
222 | - local dir=$1 |
223 | - |
224 | - if [ ! -x ${ISOINFO} ] |
225 | - then |
226 | - echo "Please install the isoinfo package in order to report iso versions" |
227 | - echo "(On ubuntu, 'sudo apt-get install genisoimage' will get it." |
228 | - exit 1 |
229 | - fi |
230 | - |
231 | - find $dir -name "*.iso" -print | while read isoname |
232 | - do |
233 | - # all ubuntu cds should be joliet, but if non-joliet ones are |
234 | - # stored in the tree as well, it's nice to not report errors due |
235 | - # to that. |
236 | - if has_joliet ${isoname} |
237 | - then |
238 | - DISKINFO=$(${ISOINFO} -J -x "/.disk/info" -i ${isoname} || true) |
239 | - DISKTYPE=$(${ISOINFO} -J -x "/.disk/cd_type" -i ${isoname} || true) |
240 | - fi |
241 | - echo "$isoname ${DISKINFO} ${DISKTYPE}" |
242 | - done |
243 | -} |
244 | - |
245 | -# returns boolean if file exists remotely |
246 | -remote_file_exists() |
247 | -{ |
248 | - local url=$(echo "$1" | sed -e 's/rsync/http/') |
249 | - if [ -x "${WGET}" ] |
250 | - then |
251 | - ${WGET} -q --spider "${url}" |
252 | - elif [ -x "${CURL}" ] |
253 | - then |
254 | - # meh, curl, why are you a pain? |
255 | - local code=$(${CURL} -s -I --write-out "%{http_code}\n" "${url}" | tail -1) |
256 | - [ "${code}" = "200" ] |
257 | - else |
258 | - return 0 |
259 | - fi |
260 | -} |
261 | - |
262 | -get() |
263 | -{ |
264 | - local flavor="$1" |
265 | - local dir="$2" |
266 | - shift 2 |
267 | - |
268 | - local output="" |
269 | - if isquiet |
270 | - then |
271 | - output="> /dev/null" |
272 | - fi |
273 | - |
274 | - for variant in "$@" |
275 | - do |
276 | - if wantflavor "$flavor" && wantvariant "$variant" |
277 | - then |
278 | - [ -d "$flavor" ] || mkdir "$flavor" |
279 | - for arch in $ARCHS |
280 | - do |
281 | - for release in $RELEASES |
282 | - do |
283 | - if wantarch "$arch" "$ARCHS" |
284 | - then |
285 | - local iso="$release-$variant-$arch.iso" |
286 | - local path="$(computepath $flavor $release $dir)" |
287 | - local md5sum="MD5SUMS.$release-$variant" |
288 | - local remote_path="$BASEURL/$path/$iso" |
289 | - if ! remote_file_exists "${remote_path}" |
290 | - then |
291 | - isquiet || echo "Skipping $release $flavor $variant $arch: not on server" |
292 | - else |
293 | - isquiet || echo "Synching $release $flavor $variant $arch ($path/$iso)" |
294 | - if no_act |
295 | - then |
296 | - : |
297 | - # echo "(Not really running rsync because of NO_ACT)" |
298 | - else |
299 | - $RSYNC $OPTS "${remote_path}" "$flavor/$iso" || true |
300 | - doverify && $RSYNC $OPTS "$BASEURL/$path/MD5SUMS" "$flavor/$md5sum" || true |
301 | - fi |
302 | - if doverify |
303 | - then |
304 | - if [ -f "$flavor/$md5sum" ] |
305 | - then |
306 | - local FILEMD5SUM="$(grep "$iso" "$flavor/$md5sum" | sed -e "s/\($iso\)/$flavor\/\\1/")" |
307 | - isquiet || echo -n "Verifying $iso... " |
308 | - eval "echo \"$FILEMD5SUM\" | md5sum -c - $output" || true |
309 | - else |
310 | - isquiet || echo "No checksum file available for $iso, skipping verification" |
311 | - fi |
312 | - fi |
313 | - fi |
314 | - fi |
315 | - done |
316 | - done |
317 | - fi |
318 | - done |
319 | -} |
320 | - |
321 | -print_help() |
322 | -{ |
323 | - echo " |
324 | - ./dl-ubuntu-test-iso [options] |
325 | - |
326 | -You may use the following options: |
327 | - |
328 | - -n, --no-act |
329 | - Do everything, except don't actually run rsync. You can use this |
330 | - to test configuration settings, etc. |
331 | - |
332 | - --debug |
333 | - Similar to --no-act, but echos the actual rsync commands, as you |
334 | - might expect, this is useful for debugging the script or |
335 | - configurations |
336 | - |
337 | - -P Run rsync with the -P option, to get progress reporting. |
338 | - |
339 | - --only flavor, --flavor flavor |
340 | - Only download a specific flavor of Ubuntu. Only the last |
341 | - --only option applies. (You can also set FLAVORS in the |
342 | - configuration file.) --only should probably be considered |
343 | - depricated. |
344 | - |
345 | - --exclude flavor |
346 | - Do not download a specific flavor of Ubuntu. You can use this |
347 | - option multiple times, and none of the specified flavors will be |
348 | - downloaded. (You can also set EXCLUDE in the configuration |
349 | - file.) |
350 | - |
351 | - --release release |
352 | - Only download a specific release target of Ubuntu. Only the last |
353 | - --release option applies. (You can also set RELEASES in the |
354 | - configuration file.) \"hardy\" is the earliest release target |
355 | - |
356 | - --bwlimit kbpslimit |
357 | - Rate limit rsync download to a limit in KBytes/second. |
358 | - " |
359 | -} |
360 | - |
361 | -TEMP=`getopt -o nPqh --long no-act,help,force,debug,quiet,no-verify,versions,only:,exclude:,release:,flavor:,bwlimit:,build: -- "$@"` |
362 | -eval set -- "$TEMP" |
363 | - |
364 | -while true |
365 | -do |
366 | - case "$1" in |
367 | - -n|--no-act) NO_ACT=yes; shift ;; |
368 | - --debug) debugify_commands ; shift;; |
369 | - -q|--quiet) QUIET=true; shift ;; |
370 | - -P) OPTS="$OPTS -P"; shift ;; |
371 | - --only|--flavor) FLAVORS="$2"; shift 2;; |
372 | - --exclude) EXCLUDE="$EXCLUDE $2"; shift 2;; |
373 | - --release) RELEASES="$2"; shift 2;; |
374 | - --bwlimit) OPTS="$OPTS --bwlimit=$2"; shift 2;; |
375 | - --build) BUILD="$2"; shift 2;; |
376 | - --no-verify) VERIFY="FALSE"; shift ;; |
377 | - --versions) VERSIONS="true"; shift ;; |
378 | - -h|--help) print_help ; die ;; |
379 | - --) shift; break ;; |
380 | - *) die "Internal error while parsing command line" |
381 | - esac |
382 | -done |
383 | - |
384 | -if isquiet |
385 | -then |
386 | - OPTS="$OPTS -q" |
387 | -fi |
388 | - |
389 | -isquiet || cat << eof |
390 | -BASEURL=$BASEURL |
391 | -RELEASES=$RELEASES |
392 | -ARCHS=$ARCHS |
393 | -FLAVORS=$FLAVORS |
394 | -VARIANTS=$VARIANTS |
395 | -EXCLUDE=$EXCLUDE |
396 | -OPTS=$OPTS |
397 | -NO_ACT=$NO_ACT |
398 | -VERIFY=$VERIFY |
399 | -BUILD=$BUILD |
400 | -ISOROOT=$ISOROOT |
401 | -QUIET=$QUIET |
402 | - |
403 | -eof |
404 | - |
405 | -if doversions |
406 | -then |
407 | - report_versions $ISOROOT |
408 | - exit 0 |
409 | -fi |
410 | - |
411 | -get ubuntu daily-live/${BUILD} desktop |
412 | -get ubuntu daily/${BUILD} alternate |
413 | -get ubuntu dvd/${BUILD} dvd |
414 | - |
415 | -get ubuntu-server daily/${BUILD} server |
416 | - |
417 | -get kubuntu daily-live/${BUILD} desktop |
418 | -get kubuntu daily/${BUILD} alternate |
419 | -get kubuntu dvd/${BUILD} dvd |
420 | - |
421 | -# deprecated, not enabled by default |
422 | -get kubuntu-kde4 daily-live/${BUILD} desktop |
423 | -get kubuntu-kde4 daily/${BUILD} alternate |
424 | - |
425 | -get edubuntu daily/${BUILD} addon |
426 | - |
427 | -get xubuntu daily-live/${BUILD} desktop |
428 | -get xubuntu daily/${BUILD} alternate |
429 | - |
430 | -get ubuntustudio daily/${BUILD} alternate |
431 | - |
432 | -__ARCHS=$ARCHS |
433 | -# deprecated, not enabled by default |
434 | -ARCHS=i386 get jeos daily/${BUILD} jeos |
435 | -ARCHS=${__ARCHS} |
436 | - |
437 | -# deprecated, not enabled by default |
438 | -get gobuntu daily/${BUILD} alternate |
439 | - |
440 | -# alternate deprecated, should probably be removed |
441 | -get mythbuntu daily/${BUILD} alternate |
442 | -get mythbuntu daily-live/${BUILD} desktop |
443 | +#!/usr/bin/python |
444 | +from __future__ import with_statement # This isn't required in Python 2.6, but must be in the beginning and thus can't be conditional |
445 | + |
446 | +import httplib |
447 | +import urllib2 |
448 | +from time import strptime |
449 | +from datetime import datetime, timedelta |
450 | +from optparse import OptionParser |
451 | +from os import environ |
452 | +import hashlib |
453 | +import os |
454 | +import re |
455 | +import subprocess |
456 | +import sys |
457 | +import stat |
458 | + |
459 | +current_release = 'lucid' |
460 | +releasedict = {} |
461 | +releasedict['hardy'] = [] |
462 | +releasedict['intrepid'] = [] |
463 | +releasedict['jaunty'] = [] |
464 | +releasedict['karmic'] = [] |
465 | +releasedict['lucid'] = [] |
466 | + |
467 | +#allreleases = ['hardy', 'intrepid'] |
468 | +allarchs = ['i386', 'amd64', 'lpia', 'armel'] |
469 | + |
470 | +default = {} |
471 | +default['archs'] = ['i386', 'amd64'] |
472 | +default['variants'] = ['desktop', 'alternate', 'dvd'] |
473 | +default['build'] = 'current' |
474 | +default['host'] = 'cdimage.ubuntu.com' |
475 | +default['releases'] = ['hardy', 'lucid'] |
476 | +default['isoroot'] = environ['HOME'] + '/iso/' |
477 | + |
478 | +zsync_binary = '/usr/bin/zsync' |
479 | + |
480 | +class Flavor: |
481 | + def __init__(self, name, use_prefix=True, releases=default['releases'], |
482 | + variants=default['variants'], archs=default['archs']): |
483 | + self.name = name |
484 | + self.prefix = None |
485 | + if use_prefix: |
486 | + self.prefix = name |
487 | + self.dir = dir |
488 | + self.releases = releases |
489 | + self.variants = variants |
490 | + self.archs = archs |
491 | + for r in releases: |
492 | + releasedict[r].append(self) |
493 | + flavors[name] = self |
494 | + |
495 | +def my_log(x): |
496 | + print x |
497 | + |
498 | +## HTML Header, defines CSS and header image ## |
499 | +def printHeader(): |
500 | + print """ |
501 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" |
502 | +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
503 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> |
504 | +<head> |
505 | + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
506 | + <title>Daily ISO Tracker</title> |
507 | + <style type="text/css"> |
508 | + body { background: #FFFFFF; color: black; } |
509 | + a { text-decoration: none; } |
510 | + table.head { border-style: none none; } |
511 | + table.head td { text-align: center; padding-left: 10px; padding-right: 10px} |
512 | + table.body { background: #efe1c3; border-collapse: collapse; border-style: solid solid; |
513 | + border-width: 3px; margin-bottom: 3ex; empty-cells: show; } |
514 | + table.body th { text-align: left; border-style: none none dotted none; |
515 | + border-width: 1px; padding-right: 10px; } |
516 | + table.body td { text-align: left; border-style: none none dotted none; |
517 | + border-width: 1px; padding-right: 10px; } |
518 | + a { color: blue; } |
519 | + a.verified { color: green; font-weight: bold; } |
520 | + a.testing { color: blue; } |
521 | + pre { white-space: pre-wrap; } |
522 | + </style> |
523 | +</head> |
524 | +<body> |
525 | +<table class="head"> |
526 | + <tr><td width="30%"><a href="http://www.ubuntu.com/"><img src="http://www.ubuntu.com/themes/ubuntu07/images/ubuntulogo.png" border="0" hspace="0" vspace="0" alt="Ubuntu"></a></td> |
527 | + <td><h1>Daily ISO Tracker</h1></td></tr> |
528 | +</table> |
529 | +""" |
530 | + |
531 | +## Print footer ## |
532 | +def printFooter(): |
533 | + time = datetime.datetime.utcnow() |
534 | + print "<p>Last Updated (UTC): %s by <a href=\"https://code.launchpad.net/~sbeattie/sru-tools/sru-buglist\">sru_buglist</a>" % time.ctime() |
535 | + print "written by <a href=\"mailto:sbeattie@ubuntu.com\">Steve Beattie</a>.</p>" |
536 | + print "</body></html>" |
537 | + |
538 | +def dumpHeaders(headers): |
539 | + for header, value in headers: |
540 | + print header + ': ' + value |
541 | + |
542 | +unit_names = {"year" : ("year", "years"), |
543 | + "month" : ("month", "months"), |
544 | + "week" : ("week", "weeks"), |
545 | + "day" : ("day", "days"), |
546 | + "hour" : ("hour", "hours"), |
547 | + "minute" : ("minute", "minutes"), |
548 | + "second" : ("second", "seconds")} |
549 | + |
550 | +def seconds_in_units(seconds): |
551 | + """ |
552 | + Returns a tuple containing the most appropriate unit for the |
553 | + number of seconds supplied and the value in that units form. |
554 | + |
555 | + >>> seconds_in_units(7700) |
556 | + (2, 'hour') |
557 | + """ |
558 | + |
559 | + unit_limits = [("year", 365 * 24 * 3600), |
560 | + ("month", 30 * 24 * 3600), |
561 | + ("week", 7 * 24 * 3600), |
562 | + ("day", 24 * 3600), |
563 | + ("hour", 3600), |
564 | + ("minute", 60)] |
565 | + |
566 | + for unit_name, limit in unit_limits: |
567 | + if seconds >= limit: |
568 | + amount = int(round(float(seconds) / limit)) |
569 | + return amount, unit_name |
570 | + return seconds, "second" |
571 | + |
572 | +def stringify_timedelta(td): |
573 | + """ |
574 | + Converts a timedelta into a nicely readable string. |
575 | + |
576 | + >>> td = timedelta(days = 77, seconds = 5) |
577 | + >>> print readable_timedelta(td) |
578 | + two months |
579 | + """ |
580 | + seconds = td.days * 3600 * 24 + td.seconds |
581 | + amount, unit_name = seconds_in_units(seconds) |
582 | + |
583 | + str_unit = unit_names[unit_name][1] |
584 | + if amount == 1: |
585 | + str_unit = unit_names[unit_name][0] |
586 | + return "%d %s" % (amount, str_unit) |
587 | + |
588 | +def parseDate(date): |
589 | + return datetime.strptime(date, "%a, %d %b %Y %H:%M:%S %Z") |
590 | + |
591 | +def create_dir(path): |
592 | + # XXX: make this more defensive. Sigh. |
593 | + try: |
594 | + stat = os.stat(path) |
595 | + except OSError, e: |
596 | + os.makedirs(path) |
597 | + |
598 | +def read_config(pathname): |
599 | + '''Read the config file, using shell syntax for backwards |
600 | + compatability.''' |
601 | + if not os.path.exists(pathname): |
602 | + return None |
603 | + |
604 | + shell_vars = ['ISOROOT', 'RELEASES', 'FLAVORS', 'VARIANTS', 'EXCLUDE', |
605 | + 'OPTS', 'QUIET', 'NO_ACT', 'VERIFY', 'BUILD', 'BASEURL', 'ARCHS'] |
606 | + command = ". %s; " %(pathname) |
607 | + for var in shell_vars: |
608 | + command += 'if [ ! -z "$%s" ] ; then echo %s=$%s; fi ; ' %(var, var, var) |
609 | + p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) |
610 | + out, err = p.communicate() |
611 | + |
612 | + config = dict() |
613 | + for line in re.split('\n', out): |
614 | + l = re.split('=', line) |
615 | + if not len(l) == 2: |
616 | + continue |
617 | + if l[0] in ['RELEASES', 'FLAVORS', 'VARIANTS', 'EXCLUDE']: |
618 | + l[1] = l[1].lower() |
619 | + config[str.lower(l[0])] = l[1] |
620 | + return config |
621 | + |
622 | +def computepath(wanted, flavor, release, variant): |
623 | + path = '/' |
624 | + if flavor.prefix: |
625 | + path += flavor.prefix + '/' |
626 | + if release != current_release: |
627 | + path += release + '/' |
628 | + path += '%s/%s/' %(variantpaths[variant], wanted['build']) |
629 | + return path |
630 | + |
631 | +def get_status(uri, host, conn=None): |
632 | + close = False |
633 | + result = False, None |
634 | + if not conn: |
635 | + conn = httplib.HTTPConnection(host) |
636 | + conn.set_debuglevel(0) |
637 | + close = True |
638 | + conn.request("HEAD", uri) |
639 | + response = conn.getresponse() |
640 | + if response.status == 200: |
641 | + modified = response.getheader('last-modified') |
642 | + age = datetime.utcnow() - parseDate(modified) |
643 | + result = True, stringify_timedelta(age) |
644 | + else: |
645 | + result = False, response.reason |
646 | + response.read() |
647 | + if close: |
648 | + conn.close() |
649 | + return result |
650 | + |
651 | +def check_status(wanted, config): |
652 | + conn = httplib.HTTPConnection(config.host) |
653 | + conn.set_debuglevel(0) |
654 | + for count, image in enumerate(image_factory(wanted)): |
655 | + release, flavor, variant, arch = image |
656 | + isoname = release + '-' + variant + '-' + arch + '.iso' |
657 | + path = computepath(wanted, flavor, release, variant) |
658 | + uri = path + isoname |
659 | + #print 'Result for ' + uri + ': ' + str(response.status) |
660 | + rc, msg = get_status(uri + '.zsync', config.host, conn=conn) |
661 | + print 'Result for ' + isoname + '.zsync: ' + msg |
662 | + rc, msg = get_status(uri, config.host, conn=conn) |
663 | + print 'Result for ' + isoname + ': ' + msg |
664 | + conn.close() |
665 | + |
666 | +def _do_download(config, source, target): |
667 | + result = True |
668 | + conn = None |
669 | + out = None |
670 | + |
671 | + try: |
672 | + conn = urllib2.urlopen('http://' + config.host + source) |
673 | + out = open(target, 'w') |
674 | + for data in conn: |
675 | + out.write(data) |
676 | + except IOError: |
677 | + result = False |
678 | + finally: |
679 | + if conn: |
680 | + conn.close() |
681 | + if out: |
682 | + out.close() |
683 | + return result |
684 | + |
685 | +def _do_zsync(config, meta, src, target): |
686 | + command = [zsync_binary, '-k', meta, '-o', target, |
687 | + 'http://%s/%s' %(config.host, src)] |
688 | + if config.quiet: |
689 | + command.insert(1, '-q') |
690 | + if config.no_act or config.debug: |
691 | + if config.debug: |
692 | + print ' '.join(command) |
693 | + return True |
694 | + |
695 | + rc = 0 |
696 | + interrupted = False |
697 | + try: |
698 | + rc = subprocess.call(command) |
699 | + # trap external SIGINT death |
700 | + if rc > 128 and rc % 128 == signal.SIGINT: |
701 | + interrupted = True |
702 | + except KeyboardInterrupt: |
703 | + interrupted = True |
704 | + finally: |
705 | + if os.path.exists(target + '.zs-old'): |
706 | + os.remove(target + '.zs-old') |
707 | + if (interrupted or rc != 0) and os.path.exists(target + '.part'): |
708 | + os.rename(target + '.part', target) |
709 | + if os.path.exists(target): |
710 | + os.chmod(target, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) |
711 | + if interrupted: |
712 | + raise KeyboardInterrupt |
713 | + return rc == 0 |
714 | + |
715 | +def do_zsync(config, destination, uri, isoname): |
716 | + zsync_uri = uri + '.zsync' |
717 | + zsync_iso = destination + '/' + isoname |
718 | + zsync_local = destination + '/' |
719 | + # hide zsync files when not mirroring tree structure |
720 | + if not config.mirror: |
721 | + zsync_local += '.' |
722 | + zsync_local += isoname + '.zsync' |
723 | + available, msg = get_status(zsync_uri, config.host) |
724 | + if not available: |
725 | + config._log("control file does not exist, skipping zsync: " + msg) |
726 | + return False |
727 | + |
728 | + # when config.build is set, we could be grabbing an iso older in |
729 | + # time than what we have now. zsync only updates it's local copy |
730 | + # of the meta data if the remote version is dated newer, so we |
731 | + # manually rsync the version we want. |
732 | + if config.build != default['build']: |
733 | + rc = _do_rsync(config, zsync_uri, zsync_local) |
734 | + |
735 | + return _do_zsync(config, zsync_local, zsync_uri, zsync_iso) |
736 | + |
737 | + |
738 | +def _do_rsync(config, source, target): |
739 | + command = ['/usr/bin/rsync', '-zthP', 'rsync://%s/cdimage%s' %(config.host, source), target] |
740 | + if len(config.bwlimit) > 0: |
741 | + command.insert(2, '--bwlimit=' + config.bwlimit) |
742 | + if config.quiet: |
743 | + command.insert(2, '-q') |
744 | + if config.no_act or config.debug: |
745 | + if config.debug: |
746 | + print ' '.join(command) |
747 | + return True |
748 | + rc = subprocess.call(command) |
749 | + return rc == 0 |
750 | + |
751 | +def do_rsync(config, destination, uri, isoname): |
752 | + rsync_local = destination + '/' + isoname |
753 | + #rc = cmd(['/usr/bin/zsync', '-o', zsync_local, 'http://cdimages.ubuntu.com/' + zsync_uri]) |
754 | + return _do_rsync(config, uri, rsync_local) |
755 | + |
756 | +def lookup_hash(path, host): |
757 | + hash_table = { |
758 | + "SHA256" : hashlib.sha256, |
759 | + "SHA1" : hashlib.sha1, |
760 | + "MD5" : hashlib.md5, |
761 | + } |
762 | + conn = httplib.HTTPConnection(host) |
763 | + conn.set_debuglevel(0) |
764 | + for alg in hash_table.keys(): |
765 | + uri = path + alg + 'SUMS' |
766 | + available, msg = get_status(uri, host, conn=conn) |
767 | + if available: |
768 | + conn.close() |
769 | + return alg, hash_table[alg] |
770 | + conn.close() |
771 | + return None, None |
772 | + |
773 | +def do_verify(config, destination, hashsuffix, path, iso): |
774 | + alg, hashfunc = lookup_hash(path, config.host) |
775 | + if not alg: |
776 | + return False |
777 | + |
778 | + uri = path + alg + "SUMS" |
779 | + if config.mirror: |
780 | + local = destination + '/' + alg + "SUMS" |
781 | + else: |
782 | + local = destination + '/' + alg + "SUMS" + hashsuffix |
783 | + rc = _do_download(config, uri, local) |
784 | + if not rc: |
785 | + return False |
786 | + |
787 | + digest = None |
788 | + with open(local) as f: |
789 | + for line in f: |
790 | + if iso in line: |
791 | + digest = re.split('\s+', line)[0] |
792 | + break |
793 | + |
794 | + if not digest: |
795 | + return False |
796 | + |
797 | + m = hashfunc() |
798 | + fd = os.open(destination + '/' + iso, os.O_RDONLY) |
799 | + data = os.read(fd, 16 * 256 * 256) |
800 | + while len(data): |
801 | + m.update(data) |
802 | + data = os.read(fd, 16 * 256 * 256) |
803 | + os.close(fd) |
804 | + result = m.hexdigest() |
805 | + #print digest + ' ' + iso |
806 | + #print result + ' ' + iso |
807 | + |
808 | + return digest == result |
809 | + |
810 | +def iso_download(wanted, config): |
811 | + saved_cwd = os.getcwd() |
812 | + create_dir(wanted['isoroot']) |
813 | + os.chdir(wanted['isoroot']) |
814 | + |
815 | + for count, image in enumerate(image_factory(wanted)): |
816 | + release, flavor, variant, arch = image |
817 | + isoname = release + '-' + variant + '-' + arch + '.iso' |
818 | + hashsuffix = "." + release + '-' + variant |
819 | + path = computepath(wanted, flavor, release, variant) |
820 | + if config.mirror: |
821 | + destination = path[1:-1] |
822 | + else: |
823 | + destination = flavor.name |
824 | + create_dir(destination) |
825 | + uri = path + isoname |
826 | + #print 'Result for ' + uri + ': ' + str(response.status) |
827 | + |
828 | + config._log("Syncing %s %s %s %s" %(release, flavor.name, variant, arch)) |
829 | + available, msg = get_status(uri, config.host) |
830 | + if not available: |
831 | + config._log("iso unavailable from server, skipping: " + msg) |
832 | + continue |
833 | + |
834 | + if not (config.use_zsync and do_zsync(config, destination, uri, isoname)): |
835 | + do_rsync(config, destination, uri, isoname) |
836 | + if config.do_verify: |
837 | + config._log("Verifying " + destination + '/' + isoname) |
838 | + if not (config.debug or config.no_act): |
839 | + if do_verify(config, destination, hashsuffix, path, isoname): |
840 | + config._log("Verification succeeded") |
841 | + else: |
842 | + config._log("!!! Verification failed !!!") |
843 | + |
844 | + os.chdir(saved_cwd) |
845 | + |
846 | +def dump_info(wanted): |
847 | + for count, image in enumerate(image_factory(wanted)): |
848 | + release, flavor, variant, arch = image |
849 | + print "%s %s %s %s %s" %(release, flavor.name, variant, arch, variantpaths[variant]) |
850 | + |
851 | +def image_factory(wanted): |
852 | + for release in releasedict.keys(): |
853 | + if release not in wanted['releases']: |
854 | + continue |
855 | + for flavor in releasedict[release]: |
856 | + if flavor.name not in wanted['flavors']: |
857 | + continue |
858 | + for variant in flavor.variants: |
859 | + if variant not in wanted['variants']: |
860 | + continue |
861 | + for arch in flavor.archs: |
862 | + if arch not in wanted['archs']: |
863 | + continue |
864 | + yield (release, flavor, variant, arch) |
865 | + #print "%s %s %s %s %s" %(release, flavor.name, variant, arch, variantpaths[variant]) |
866 | + |
867 | +def merge_config(cval, file, default, value): |
868 | + ret = None |
869 | + if len(cval) > 0: |
870 | + ret = cval |
871 | + elif file and value in file.keys() and len(file[value]) > 0: |
872 | + ret = file[value] |
873 | + elif value in default.keys(): |
874 | + ret = default[value] |
875 | + return ret |
876 | + |
877 | +def main(): |
878 | + global releasedict, current_release, variantpaths, flavors |
879 | + |
880 | + config = {} |
881 | + wanted = {} |
882 | + flavors = {} |
883 | + variantpaths = {} |
884 | + variantpaths['desktop'] = 'daily-live' |
885 | + variantpaths['alternate'] = 'daily' |
886 | + variantpaths['jeos'] = 'daily' |
887 | + variantpaths['dvd'] = 'dvd' |
888 | + variantpaths['server'] = 'daily' |
889 | + variantpaths['addon'] = 'daily' |
890 | + variantpaths['usb'] = 'daily' |
891 | + variantpaths['netbook-remix'] = 'daily-live' |
892 | + variantpaths['netbook'] = 'daily-live' |
893 | + variantpaths['moblin-remix'] = 'daily-live' |
894 | + |
895 | + Flavor('ubuntu', use_prefix=False) |
896 | + Flavor('ubuntu-server', variants=['server']) |
897 | + Flavor('kubuntu') |
898 | + Flavor('kubuntu-kde4', releases=['hardy'], variants=['desktop', 'alternate']) |
899 | + Flavor('edubuntu', variants=['addon', 'dvd']) |
900 | + Flavor('xubuntu', variants=['desktop', 'alternate']) |
901 | + Flavor('ubuntustudio', variants=['alternate']) |
902 | + Flavor('jeos', releases=['hardy'], variants=['jeos'], archs=['i386']) |
903 | + Flavor('gobuntu', releases=['hardy'], variants=['alternate']) |
904 | + Flavor('mythbuntu', variants=['desktop']) |
905 | + Flavor('ubuntu-mid', variants=['usb'], archs=['lpia']) |
906 | + Flavor('ubuntu-netbook', variants=['netbook'], archs=['i386']) |
907 | + Flavor('kubuntu-netbook', variants=['netbook'], archs=['i386']) |
908 | + Flavor('ubuntu-moblin-remix', variants=['moblin-remix'], archs=['i386']) |
909 | + |
910 | + default['variants'] = variantpaths.keys() |
911 | + default['flavors'] = flavors.keys() |
912 | + |
913 | + parser = OptionParser() |
914 | + parser.add_option('-n', '--no-act', default=False, action='store_true', dest='no_act', help='compute everything but don\'t actually download') |
915 | + parser.add_option('-d', '--debug', default=False, action='store_true') |
916 | + parser.add_option('-q', '--quiet', default=False, action='store_true', help='suppress output except errors') |
917 | + parser.add_option('-P', '--progress', default=False, action='store_true', help='display a progress meter while downloading') |
918 | + parser.add_option('--only', '--flavor', action='append', default=[], dest='flavor', help='select specific flavor to download; multiple --flavor args can be passed') |
919 | + parser.add_option('--exclude', '--exclude-flavor', action='append', default=[], dest='exclude_flavor') |
920 | + parser.add_option('--release', '--only-release', action='append', default=[], dest='release') |
921 | + parser.add_option('--variant', '--only-variant', action='append', default=[], dest='variant') |
922 | + parser.add_option('--exclude-variant', action='append', default=[], dest='exclude_variant') |
923 | + parser.add_option('--arch', '--only-arch', action='append', default=[], dest='arch') |
924 | + parser.add_option('--bwlimit', default='', action="store", type="string", help='rate limit rsync download to BWLIMIT in KBytes/second') |
925 | + parser.add_option('--build', default=default['build'], action="store", type="string") |
926 | + parser.add_option('--no-verify', default=True, action="store_false", dest='do_verify', help='skip comparison against published checksums') |
927 | + parser.add_option('--no-zsync', default=True, action="store_false", dest='use_zsync', help="don't use zsync to download") |
928 | + #parser.add_option('--versions', default=False, action='store_true') |
929 | + parser.add_option('--isoroot', default='', action='store', type='string', help='local directory root to store isos; default is %s' %(default['isoroot'])) |
930 | + parser.add_option('--config', default=environ['HOME'] + '/.dl-ubuntu-test-iso', action='store', type='string', |
931 | + help='choose alternate config file location, default is %default') |
932 | + parser.add_option('--host', default=default['host'], action='store', type='string', help='mirror to pull images from; default is %s' %(default['host'])) |
933 | + parser.add_option('--mirror', default=False, action='store_true', dest='mirror', help='mirror tree structure from cdimages') |
934 | + |
935 | + config, args = parser.parse_args() |
936 | + if len(args) != 0: |
937 | + parser.error("incorrect number of arguments") |
938 | + file_cfg = read_config(config.config) |
939 | + |
940 | + wanted['flavors'] = merge_config(config.flavor, file_cfg, default, 'flavors') |
941 | + if len(config.exclude_flavor) > 0: |
942 | + wanted['flavors'] = filter(lambda x: x not in config.exclude_flavor, wanted['flavors']) |
943 | + |
944 | + wanted['releases'] = merge_config(config.release, file_cfg, default, 'releases') |
945 | + wanted['variants'] = merge_config(config.variant, file_cfg, default, 'variants') |
946 | + if len(config.exclude_variant) > 0: |
947 | + wanted['variants'] = filter(lambda x: x not in config.exclude_variant, wanted['variants']) |
948 | + wanted['build'] = merge_config(config.build, file_cfg, default, 'build') |
949 | + wanted['isoroot'] = merge_config(config.isoroot, file_cfg, default, 'isoroot') |
950 | + |
951 | + wanted['archs'] = merge_config(config.arch, file_cfg, default, 'archs') |
952 | + |
953 | + if not config.no_act and file_cfg != None and 'no_act' in file_cfg.keys(): |
954 | + config.no_act = ('true' == file_cfg['no_act'].lower()) |
955 | + |
956 | + if config.do_verify and file_cfg != None and 'verify' in file_cfg.keys(): |
957 | + config.no_act = ('true' == file_cfg['verify'].lower()) |
958 | + |
959 | + if config.quiet: |
960 | + config._log = lambda x: x |
961 | + else: |
962 | + config._log = my_log |
963 | + |
964 | + if config.use_zsync and not os.path.exists(zsync_binary): |
965 | + config._log("Warning! zsync is not installed, falling back to rsync") |
966 | + config.use_zsync = False |
967 | + |
968 | + if config.use_zsync and len(config.bwlimit) > 0: |
969 | + config._log("Warning! zsync does not support bandwidth limiting") |
970 | + |
971 | + #print file_cfg |
972 | + #print config |
973 | + #print wanted |
974 | + #dump_info(wanted, config) |
975 | + #check_status(wanted, config) |
976 | + iso_download(wanted, config) |
977 | + |
978 | +if __name__ == "__main__": |
979 | + main() |
980 | + |
981 | |
982 | === modified file 'setup.py' |
983 | --- setup.py 2009-07-14 08:43:29 +0000 |
984 | +++ setup.py 2010-03-12 09:50:29 +0000 |
985 | @@ -20,8 +20,8 @@ |
986 | 'bugs-mailinglist/count-senders', |
987 | 'bugs-mailinglist/tagged-bugs', |
988 | 'bugs-mailinglist/triager-query', |
989 | - 'bugs-mailinglist/ml-team-fixes-report.py', |
990 | - 'bugs-mailinglist/ml-fixes-report.py', |
991 | + 'bugs-mailinglist/ml-team-fixes-report', |
992 | + 'bugs-mailinglist/ml-fixes-report', |
993 | 'bugs-mailinglist/new-bug-description-search', |
994 | 'bugtrackers/debian-bug-search', |
995 | 'dl-ubuntu-test-iso/dl-ubuntu-test-iso', |
Good work!