Merge lp:~vorlon/ddeb-retriever/python3 into lp:ddeb-retriever

Proposed by Steve Langasek on 2017-05-18
Status: Merged
Merged at revision: 173
Proposed branch: lp:~vorlon/ddeb-retriever/python3
Merge into: lp:ddeb-retriever
Diff against target: 515 lines (+110/-84)
3 files modified
archive_tools.py (+97/-79)
ddeb-retriever (+1/-1)
ddeb_retriever.py (+12/-4)
To merge this branch: bzr merge lp:~vorlon/ddeb-retriever/python3
Reviewer Review Type Date Requested Status
Brian Murray (community) 2017-05-18 Approve on 2017-07-10
Colin Watson 2017-05-18 Approve on 2017-05-23
Review via email: mp+324233@code.launchpad.net

Description of the Change

Since germanium is running 16.04 already, we should use python3 rather than python2, so move this over in one go. Also, use urllib.request.urlopen() and getcode to avoid publishing error pages as ddebs.

To post a comment you must log in.
Brian Murray (brian-murray) wrote :

Is there a reason the shebang in ddeb_retriever.py wasn't changed to python3 also?

I also have one nitpicky comment which you can find in-line.

review: Needs Information
Steve Langasek (vorlon) wrote :

didn't notice ddeb_retriever.py had a shebang since it wasn't executable. thanks, fixed. also fixed the whitespace consistency issue.

lp:~vorlon/ddeb-retriever/python3 updated on 2017-05-23
175. By Steve Langasek on 2017-05-23

also fix shebang in ddeb_retriever.py (though unused)

176. By Steve Langasek on 2017-05-23

spacing consistency

review: Approve
Colin Watson (cjwatson) :
review: Approve
lp:~vorlon/ddeb-retriever/python3 updated on 2017-07-10
177. By Steve Langasek on 2017-05-23

better python3ing of hash sorting

178. By Steve Langasek on 2017-05-23

with gzip.open

179. By Steve Langasek on 2017-07-10

Write to a temporary file, to avoid truncated downloads on interrupt

Brian Murray (brian-murray) wrote :

I approve the new changes to this branch.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'archive_tools.py'
2--- archive_tools.py 2017-04-22 23:07:59 +0000
3+++ archive_tools.py 2017-07-10 17:23:38 +0000
4@@ -11,7 +11,6 @@
5 '''
6
7 import apt_pkg
8-import urllib2
9 import urllib
10 import os
11 import gzip
12@@ -25,7 +24,7 @@
13 import subprocess
14 import glob
15 import logging
16-from cStringIO import StringIO
17+from io import StringIO
18
19 apt_pkg.init_system()
20
21@@ -42,13 +41,13 @@
22 if url.startswith('http://') or url.startswith('ftp://') or \
23 url.startswith('https://') or url.startswith('file://'):
24 data = tempfile.NamedTemporaryFile()
25- src = urllib2.urlopen(url, timeout=60)
26+ src = urllib.request.urlopen(url, timeout=60)
27 data.write(src.read())
28 src.close()
29 data.flush()
30 data.seek(0)
31 else:
32- data = open(url)
33+ data = open(url, mode='rb')
34
35 tagfile = tempfile.TemporaryFile()
36 if url.endswith('.gz'):
37@@ -158,8 +157,7 @@
38 if cmp(max.get(parser.section[group_by], ('', ''))[0], parser.section[sort_key]) < 0:
39 max[parser.section[group_by]] = (parser.section[sort_key], str(parser.section))
40
41- ks = max.keys()
42- ks.sort()
43+ ks = sorted(max)
44 first = True
45 for k in ks:
46 if first:
47@@ -169,7 +167,7 @@
48 outfile.write(max[k][1])
49
50
51-def install_pool(archive_root, file_url, component, source):
52+def install_pool(archive_root, file_path, component, source):
53 '''Install given file into the pool, with the given component and source
54 package name.
55
56@@ -181,13 +179,14 @@
57 hash = source[0]
58
59 destdir = os.path.join(archive_root, 'pool', component, hash, source)
60- destfile = os.path.join(destdir, os.path.basename(file_url))
61+ destfile = os.path.join(destdir, os.path.basename(file_path))
62 if os.path.exists(destfile):
63 return False
64 if not os.path.isdir(destdir):
65 os.makedirs(destdir)
66
67- urllib.urlretrieve(file_url, destfile)
68+ with open(file_path, 'rb') as infile, open(destfile, 'wb') as outfile:
69+ outfile.write(infile.read())
70
71 return True
72
73@@ -213,8 +212,8 @@
74 raise NotImplementedError('create_index() does not support source packages with a reference_archive')
75
76 # create configuration file
77- conf = tempfile.NamedTemporaryFile()
78- print >> conf, '''Dir {
79+ conf = tempfile.NamedTemporaryFile(mode='w+')
80+ print('''Dir {
81 ArchiveDir ".";
82 CacheDir ".cache";
83 FileListDir "./lists";
84@@ -237,7 +236,7 @@
85 Tree "dists/%s" {
86 Sections "%s";
87 Architectures "%s";
88-}''' % (ext, pocket, ' '.join(components), ' '.join(archs))
89+}''' % (ext, pocket, ' '.join(components), ' '.join(archs)), file=conf)
90 conf.flush()
91
92 old_cwd = os.getcwd()
93@@ -307,9 +306,8 @@
94 stdout=subprocess.PIPE, stderr=stderr)
95 out = apt_ftparchive.communicate()[0]
96 assert apt_ftparchive.returncode == 0
97- r = open('Release', 'w')
98- r.write(out)
99- r.close()
100+ with open('Release', 'wb') as r:
101+ r.write(out)
102 if gpg_sign:
103 try:
104 os.unlink('Release.gpg')
105@@ -330,18 +328,21 @@
106 def _packages_files(path, files):
107 '''Add all files from given Packages path to the 'files' set.'''
108
109- parser = apt_pkg.TagFile(open(path))
110+ with open(path) as f:
111+ parser = apt_pkg.TagFile(f)
112 while parser.step():
113 f = parser.section['Filename']
114 if f.startswith('./'):
115 f = f[2:]
116 files.add(f)
117+ parser.close()
118
119
120 def _sources_files(path, files):
121 '''Add all files from given Sources path to the 'files' set.'''
122
123- parser = apt_pkg.TagFile(open(path))
124+ with open(path) as f:
125+ parser = apt_pkg.TagFile(f)
126 while parser.step():
127 d = parser.section.get('Directory')
128 for l in parser.section['Files'].splitlines():
129@@ -351,6 +352,7 @@
130 files.add(os.path.join(d, fields[2]))
131 else:
132 files.add(fields[2])
133+ parser.close()
134
135
136 def archive_cleanup(archive_root, keep_days=0):
137@@ -428,7 +430,7 @@
138 z = gzip.open(dest + '.new', 'w', 9)
139 elif dest.endswith('.bz2'):
140 z = bz2.BZ2File(dest + '.new', 'w')
141- f = open(src)
142+ f = open(src, 'rb')
143 while True:
144 block = f.read(10240)
145 if not block:
146@@ -454,7 +456,8 @@
147 for root, dirs, files in os.walk(distroot):
148 if 'Packages' in files:
149 path = os.path.join(root, 'Packages')
150- debcontrol_dominate(open(path), open(path + '.new', 'w'))
151+ with open(path) as old, open(path + '.new', 'w') as new:
152+ debcontrol_dominate(old, new)
153
154 # regenerate compressed files
155 if 'Packages.gz' in files:
156@@ -468,7 +471,8 @@
157
158 if 'Sources' in files:
159 path = os.path.join(root, 'Sources')
160- debcontrol_dominate(open(path), open(path + '.new', 'w'))
161+ with open(path) as old, open(path + '.new', 'w') as new:
162+ debcontrol_dominate(old, new)
163
164 # regenerate compressed files
165 if 'Sources.gz' in files:
166@@ -504,7 +508,8 @@
167
168 d = tempfile.mkdtemp()
169 os.mkdir(os.path.join(d, 'DEBIAN'))
170- open(os.path.join(d, 'DEBIAN', 'control'), 'w').write('''Package: %s
171+ with open(os.path.join(d, 'DEBIAN', 'control'), 'w') as file:
172+ file.write('''Package: %s
173 Version: %s
174 Priority: optional
175 Section: devel
176@@ -534,10 +539,9 @@
177 d = os.path.join(self.workdir, repo, 'dists', pocket, component, 'binary-' + arch)
178 if not os.path.isdir(d):
179 os.makedirs(d)
180- f = gzip.GzipFile(os.path.join(d, 'Packages.gz'), mode='w')
181- for (name, version) in packages:
182- f.write('Package: %s\nVersion: %s\n\n' % (name, version))
183- f.close()
184+ with gzip.open(os.path.join(d, 'Packages.gz'), mode='wt') as f:
185+ for (name, version) in packages:
186+ f.write('Package: %s\nVersion: %s\n\n' % (name, version))
187
188
189 #
190@@ -555,8 +559,8 @@
191
192 self.tmpfiles = set(os.listdir('/tmp'))
193
194- self.sources = tempfile.NamedTemporaryFile()
195- print >> self.sources, '''Package: aalib
196+ self.sources = tempfile.NamedTemporaryFile(mode='w')
197+ print('''Package: aalib
198 Binary: libaa-bin, libaa1-dev, libaa1
199 Version: 1.4p5-30
200 Directory: pool/main/a/aalib
201@@ -566,11 +570,11 @@
202
203 Package: abiword
204 Binary: abiword-plugins, abiword-plugins-gnome, abiword-help, abiword, abiword-common, abiword-gnome
205-Version: 2.4.4-0ubuntu5'''
206+Version: 2.4.4-0ubuntu5''', file=self.sources)
207 self.sources.flush()
208
209- self.packages = tempfile.NamedTemporaryFile()
210- print >> self.packages, '''Package: abiword
211+ self.packages = tempfile.NamedTemporaryFile(mode='w')
212+ print('''Package: abiword
213 Architecture: amd64
214 Version: 2.4.4-0ubuntu5
215 Description: Short
216@@ -579,7 +583,7 @@
217
218 Package: abiword-common
219 Source: abiword
220-Version: 2.4.4-0ubuntu5'''
221+Version: 2.4.4-0ubuntu5''', file=self.packages)
222 self.packages.flush()
223
224 def tearDown(self):
225@@ -710,8 +714,7 @@
226 '''Return string with space-separated sorted list of keys of a
227 dictionary.'''
228
229- k = map.keys()
230- k.sort()
231+ k = sorted(map)
232 return ' '.join(k)
233
234
235@@ -749,22 +752,26 @@
236 os.chdir(d)
237
238 os.makedirs(os.path.join(package, 'debian'))
239- open(os.path.join(package, 'README'), 'w').write('hello\n')
240- open(os.path.join(package, 'debian', 'control'), 'w').write('''\
241+ with open(os.path.join(package, 'README'), 'w') as f:
242+ f.write('hello\n')
243+ with open(os.path.join(package, 'debian', 'control'), 'w') as f:
244+ f.write('''\
245 Source: %s
246 Maintainer: Joe <joe@ubuntu.com>
247
248 Package: %s
249 Architecture: all
250 ''' % (package, package))
251- open(os.path.join(package, 'debian', 'changelog'), 'w').write('''\
252+ with open(os.path.join(package, 'debian', 'changelog'), 'w') as f:
253+ f.write('''\
254 %s (%s) dummy; urgency=low
255
256 * Dummy package.
257
258 -- Joe <joe@joe.com> Fri, 22 Sep 2006 13:07:40 +0200
259 ''' % (package, version))
260- open(os.path.join(package, 'debian', 'rules'), 'w')
261+ with open(os.path.join(package, 'debian', 'rules'), 'w') as f:
262+ pass
263
264 if not native:
265 upstreamver = '-'.join(version.split('-')[:-1])
266@@ -811,14 +818,14 @@
267 def test_install_pool(self):
268 '''install_pool()'''
269
270- f = tempfile.NamedTemporaryFile()
271- print >> f, 'hello'
272+ f = tempfile.NamedTemporaryFile(mode='w')
273+ print('hello', file=f)
274 f.flush()
275
276 self.assertTrue(install_pool(self.archivedir, f.name, 'main', 'src1'))
277 self.assertTrue(install_pool(self.archivedir, f.name, 'main', 'src2'))
278 self.assertTrue(install_pool(self.archivedir, f.name, 'main', 'libsrc'))
279- self.assertTrue(install_pool(self.archivedir, 'file://' + f.name, 'universe', 'src'))
280+ self.assertTrue(install_pool(self.archivedir, f.name, 'universe', 'src'))
281 self.assertFalse(install_pool(self.archivedir, f.name, 'universe', 'src'))
282
283 self.assertEqual(_ls(os.path.join(self.archivedir, 'pool')), 'main universe')
284@@ -827,9 +834,9 @@
285 self.assertEqual(_ls(os.path.join(self.archivedir, 'pool', 'main', 'libs')), 'libsrc')
286 self.assertEqual(_ls(os.path.join(self.archivedir, 'pool', 'main', 'libs', 'libsrc')),
287 os.path.basename(f.name))
288- self.assertEqual(open(os.path.join(
289- self.archivedir, 'pool', 'main', 'libs', 'libsrc', os.path.basename(f.name))).read(),
290- 'hello\n')
291+ with open(os.path.join(self.archivedir, 'pool', 'main', 'libs',
292+ 'libsrc', os.path.basename(f.name))) as f:
293+ self.assertEqual(f.read(), 'hello\n')
294
295 f.close()
296
297@@ -876,20 +883,21 @@
298 self.archivedir, 'dists', 'edgy', 'main', 'binary-powerpc', 'Packages.xz'))
299 self.assertEqual(map, xzmap)
300
301- self.assertEqual(open(os.path.join(
302- self.archivedir, 'dists', 'edgy', 'main', 'binary-i386', 'Packages')).read(),
303- '')
304- self.assertEqual(open(os.path.join(
305- self.archivedir, 'dists', 'edgy', 'universe', 'binary-powerpc', 'Packages')).read(),
306- '')
307- self.assertEqual(open(os.path.join(
308- self.archivedir, 'dists', 'edgy', 'main', 'binary-amd64', 'Packages')).read(),
309- '')
310- self.assertEqual(open(os.path.join(
311- self.archivedir, 'dists', 'edgy', 'universe', 'binary-amd64', 'Packages')).read(),
312- '')
313+ with open(os.path.join(self.archivedir, 'dists', 'edgy', 'main',
314+ 'binary-i386', 'Packages')) as f:
315+ self.assertEqual(f.read(), '')
316+ with open(os.path.join(self.archivedir, 'dists', 'edgy', 'universe',
317+ 'binary-powerpc', 'Packages')) as f:
318+ self.assertEqual(f.read(), '')
319+ with open(os.path.join(self.archivedir, 'dists', 'edgy', 'main',
320+ 'binary-amd64', 'Packages')) as f:
321+ self.assertEqual(f.read(), '')
322+ with open(os.path.join(self.archivedir, 'dists', 'edgy', 'universe',
323+ 'binary-amd64', 'Packages')) as f:
324+ self.assertEqual(f.read(), '')
325
326- rel = open(os.path.join(self.archivedir, 'dists', 'edgy', 'Release')).read()
327+ with open(os.path.join(self.archivedir, 'dists', 'edgy', 'Release')) as f:
328+ rel = f.read()
329 self.assertIn('\nSuite: edgy\n', rel)
330 self.assertIn('Architectures: amd64 i386 powerpc\n', rel)
331 self.assertIn('\nComponents: main restricted universe\n', rel)
332@@ -924,8 +932,9 @@
333 self.assertEqual(_ls(os.path.join(
334 self.archivedir, 'dists', 'edgy', 'main', 'source')),
335 'Sources Sources.gz Sources.xz')
336- self.assertEqual(open(os.path.join(
337- self.archivedir, 'dists', 'edgy', 'main', 'binary-i386', 'Packages')).read(), '')
338+ with open(os.path.join(self.archivedir, 'dists', 'edgy', 'main',
339+ 'binary-i386', 'Packages')) as f:
340+ self.assertEqual(f.read(), '')
341 map = debcontrol_map(os.path.join(
342 self.archivedir, 'dists', 'edgy', 'main', 'source', 'Sources'))
343
344@@ -987,9 +996,9 @@
345 self.archivedir, 'dists', 'edgy', 'universe', 'binary-i386', 'Packages.xz'))
346 self.assertEqual(map, xzmap)
347
348- self.assertEqual(open(os.path.join(self.archivedir, 'dists', 'edgy',
349- 'main', 'binary-i386', 'Packages')).read(),
350- '')
351+ with open(os.path.join(self.archivedir, 'dists', 'edgy',
352+ 'main', 'binary-i386', 'Packages')) as f:
353+ self.assertEqual(f.read(),'')
354
355 self.assertGreater(os.path.getsize(
356 os.path.join(self.archivedir, 'dists', 'edgy', 'Release')), 0)
357@@ -998,11 +1007,11 @@
358 '''performance of create_indexes()'''
359
360 # install some test debs
361- for i in xrange(1000):
362+ for i in range(1000):
363 install_pool(self.archivedir, TestArchive.create_deb(
364 str(i), '1-1', 'i386', self.testfiles_dir), 'main', str(i))
365
366- print '[setup done]',
367+ print('[setup done]')
368 sys.stdout.flush()
369
370 # call create_indexes()
371@@ -1011,8 +1020,8 @@
372 t2 = time.time()
373
374 pkg = os.path.join(self.archivedir, 'dists', 'edgy', 'main', 'binary-i386', 'Packages')
375- print 'Packages:', os.path.getsize(pkg), 'Packages.gz:', os.path.getsize(pkg + '.gz'),
376- print '%.1f seconds ' % (t2 - t1),
377+ print('Packages:', os.path.getsize(pkg), 'Packages.gz:', os.path.getsize(pkg + '.gz'))
378+ print('%.1f seconds ' % (t2 - t1))
379 sys.stdout.flush()
380
381 def test_create_indexes_refarchive(self):
382@@ -1088,25 +1097,25 @@
383 map = debcontrol_map(os.path.join(
384 self.archivedir, 'dists', 'dapper', 'universe', 'binary-i386', 'Packages.gz'),
385 'Version')
386- self.assertEqual(map.keys(), ['1-1'])
387+ self.assertEqual(list(map.keys()), ['1-1'])
388 self.assertEqual(map['1-1']['Package'], 'foo-dbgsym')
389
390 map = debcontrol_map(os.path.join(
391 self.archivedir, 'dists', 'dapper', 'main', 'binary-powerpc', 'Packages.gz'),
392 'Version')
393- self.assertEqual(map.keys(), ['2-2'])
394+ self.assertEqual(list(map.keys()), ['2-2'])
395 self.assertEqual(map['2-2']['Package'], 'bar1-dbgsym')
396
397 map = debcontrol_map(os.path.join(
398 self.archivedir, 'dists', 'edgy', 'universe', 'binary-i386', 'Packages.gz'),
399 'Version')
400- self.assertEqual(map.keys(), ['1-2'])
401+ self.assertEqual(list(map.keys()), ['1-2'])
402 self.assertEqual(map['1-2']['Package'], 'foo-dbgsym')
403
404 map = debcontrol_map(os.path.join(
405 self.archivedir, 'dists', 'edgy', 'main', 'binary-powerpc', 'Packages.gz'),
406 'Version')
407- self.assertEqual(map.keys(), ['2-2ubuntu1'])
408+ self.assertEqual(list(map.keys()), ['2-2ubuntu1'])
409 self.assertEqual(map['2-2ubuntu1']['Package'], 'bar1-dbgsym')
410
411 finally:
412@@ -1115,7 +1124,7 @@
413 def test_debcontrol_dominate(self):
414 '''debcontrol_dominate()'''
415
416- i = tempfile.NamedTemporaryFile()
417+ i = tempfile.NamedTemporaryFile(mode='w')
418 i.write('''Package: foo
419 Version: 1-0
420 Description: oldest foo
421@@ -1202,11 +1211,16 @@
422 def test_archive_cleanup_customlayout(self):
423 '''archive_cleanup() with a non-standard archive structure'''
424
425- open(os.path.join(self.archivedir, 'foo_1_i386.deb'), 'w').write('foo_1')
426- open(os.path.join(self.archivedir, 'foo_2_i386.deb'), 'w').write('foo_2')
427- open(os.path.join(self.archivedir, 'bar_1_i386.deb'), 'w').write('bar_1')
428- open(os.path.join(self.archivedir, 'cruft_3_i386.deb'), 'w').write('cruft')
429- open(os.path.join(self.archivedir, 'Packages'), 'w').write('''Package: foo
430+ with open(os.path.join(self.archivedir, 'foo_1_i386.deb'), 'w') as f:
431+ f.write('foo_1')
432+ with open(os.path.join(self.archivedir, 'foo_2_i386.deb'), 'w') as f:
433+ f.write('foo_2')
434+ with open(os.path.join(self.archivedir, 'bar_1_i386.deb'), 'w') as f:
435+ f.write('bar_1')
436+ with open(os.path.join(self.archivedir, 'cruft_3_i386.deb'), 'w') as f:
437+ f.write('cruft')
438+ with open(os.path.join(self.archivedir, 'Packages'), 'w') as f:
439+ f.write('''Package: foo
440 Version: 2
441 Filename: foo_2_i386.deb
442
443@@ -1280,16 +1294,20 @@
444 # check that Packages.gz and Sources.gz are re-created properly
445 s = os.path.join(self.archivedir, 'dists', 'dapper', 'main',
446 'source', 'Sources')
447- self.assertEqual(open(s).read(), gzip.open(s + '.gz').read())
448+ with open(s, mode='rb') as f:
449+ self.assertEqual(f.read(), gzip.open(s + '.gz').read())
450 s = os.path.join(self.archivedir, 'dists', 'dapper', 'main',
451 'binary-i386', 'Packages')
452- self.assertEqual(open(s).read(), gzip.open(s + '.gz').read())
453+ with open(s, mode='rb') as f:
454+ self.assertEqual(f.read(), gzip.open(s + '.gz').read())
455 s = os.path.join(self.archivedir, 'dists', 'edgy', 'universe',
456 'source', 'Sources')
457- self.assertEqual(open(s).read(), gzip.open(s + '.gz').read())
458+ with open(s, mode='rb') as f:
459+ self.assertEqual(f.read(), gzip.open(s + '.gz').read())
460 s = os.path.join(self.archivedir, 'dists', 'edgy', 'universe',
461 'binary-i386', 'Packages')
462- self.assertEqual(open(s).read(), gzip.open(s + '.gz').read())
463+ with open(s, mode='rb') as f:
464+ self.assertEqual(f.read(), gzip.open(s + '.gz').read())
465
466 def test_archive_dominate_flat(self):
467 '''archive_dominate() with a flat tree'''
468
469=== modified file 'ddeb-retriever'
470--- ddeb-retriever 2014-07-17 07:40:31 +0000
471+++ ddeb-retriever 2017-07-10 17:23:38 +0000
472@@ -1,4 +1,4 @@
473-#!/usr/bin/python
474+#!/usr/bin/python3
475 import ddeb_retriever
476
477 ddeb_retriever.main()
478
479=== modified file 'ddeb_retriever.py'
480--- ddeb_retriever.py 2017-04-22 23:07:59 +0000
481+++ ddeb_retriever.py 2017-07-10 17:23:38 +0000
482@@ -1,5 +1,5 @@
483-#!/usr/bin/python
484-import os.path
485+#!/usr/bin/python3
486+import os
487 import logging
488 import urllib
489 import argparse
490@@ -76,7 +76,7 @@
491 Return True if it was installed successfully or already present,
492 otherwise False.
493 '''
494- ddeb = urllib.unquote(os.path.basename(url))
495+ ddeb = urllib.parse.unquote(os.path.basename(url))
496 try:
497 (dbgsymname, version, arch) = ddeb.split('_')
498 assert arch.endswith('.ddeb')
499@@ -107,7 +107,15 @@
500 os.makedirs(destdir)
501 except OSError:
502 pass
503- urllib.urlretrieve(url, dest)
504+ with urllib.request.urlopen(url) as req:
505+ if req.getcode() != 200:
506+ logging.error('URL %s failed with code %u', req.geturl(), code)
507+ return False
508+ response = req.read()
509+ with open(dest + '.new', 'wb') as handle:
510+ handle.write(response)
511+ os.rename(dest + '.new', dest)
512+
513 logging.debug('Downloaded %s into %s', ddeb, os.path.dirname(dest))
514
515 return True

Subscribers

People subscribed via source and target branches