Merge lp:~jml/pkgme-service/add-download-file into lp:pkgme-service

Proposed by Jonathan Lange
Status: Merged
Approved by: James Westby
Approved revision: 141
Merged at revision: 141
Proposed branch: lp:~jml/pkgme-service/add-download-file
Merge into: lp:pkgme-service
Diff against target: 261 lines (+188/-3)
3 files modified
src/djpkgme/osutils.py (+80/-0)
src/djpkgme/tasks.py (+1/-3)
src/djpkgme/tests/test_osutils.py (+107/-0)
To merge this branch: bzr merge lp:~jml/pkgme-service/add-download-file
Reviewer Review Type Date Requested Status
James Westby (community) Approve
Review via email: mp+134127@code.launchpad.net

Commit message

Add download_file from pkgme-devportal

Description of the change

I wrote a useful message here before, but the Internet ate it.

pkgme-service uses download_file, but pkgme-devportal does not. This branch
copies download_file into pkgme-service so it can be removed from devportalbinary.

To post a comment you must log in.
Revision history for this message
James Westby (james-w) :
review: Approve
Revision history for this message
ISD Branch Mangler (isd-branches-mangler) wrote :
Download full text (6.1 KiB)

The attempt to merge lp:~jml/pkgme-service/add-download-file into lp:pkgme-service failed. Below is the output from the failed tests.

python2.7 bootstrap.py --distribute --version 1.5.1 \
    --download-base=download-cache/dist --eggs=eggs \
    --setup-source distribute_setup.py
touch --no-create bin/buildout
./bin/buildout
Develop: '/tmp/tmpHkM6lC/.'
Updating scripts.
Updating filetemplates.
touch --no-create bin/py
./bin/py django_project/manage.py test djpkgme
Creating test database for alias 'default'...
Destroying test database for alias 'default'...

Tree is up to date at revision 44 of branch bzr+ssh://bazaar.launchpad.net/+branch/ca-download-cache
..............................E...............................
======================================================================
ERROR: test_gtk (djpkgme.tests.test_integration.TestEndToEnd)
djpkgme.tests.test_integration.TestEndToEnd.test_gtk
----------------------------------------------------------------------
_StringException: Empty attachments:
  twisted-log

celery-log: {{{
[2012-11-13 22:31:00,675: WARNING/MainProcess] -------------- <email address hidden> v2.5.0
---- **** -----
--- * *** * -- [Configuration]
-- * - **** --- . broker: djkombu.transport.DatabaseTransport:////
- ** ---------- . loader: djcelery.loaders.DjangoLoader
- ** ---------- . logfile: <email address hidden>@WARNING
- ** ---------- . concurrency: 1
- ** ---------- . events: ON
- *** --- * --- . beat: OFF
-- ******* ----
--- ***** ----- [Queues]
 -------------- . celery: exchange:celery (direct) binding:celery
[2012-11-13 22:31:00,687: WARNING/MainProcess] <email address hidden> has started.
[2012-11-13 22:31:06,258: INFO/PoolWorker-1] ['tar', '--force-local', '--no-same-owner', '--no-same-permissions', '-xf', u'/tmp/tmp7kivhZ/download/package-name4.tar.gz', '-C', '/tmp/tmp7kivhZ/working'] finished in 0.445s
[2012-11-13 22:31:07,815: INFO/PoolWorker-1] ['/tmp/eggs/pkgme_devportal-0.4.10-py2.7.egg/devportalbinary/backends/python-stub/want'] finished in 1.555s
[2012-11-13 22:31:09,035: INFO/PoolWorker-1] ['/tmp/eggs/pkgme_devportal-0.4.10-py2.7.egg/devportalbinary/backends/diff/want'] finished in 1.220s
[2012-11-13 22:31:09,937: INFO/PoolWorker-1] ['/tmp/eggs/pkgme_devportal-0.4.10-py2.7.egg/devportalbinary/backends/pdf/want'] finished in 0.900s
[2012-11-13 22:31:11,504: INFO/PoolWorker-1] ['/tmp/eggs/pkgme_devportal-0.4.10-py2.7.egg/devportalbinary/backends/deb-bin/want'] finished in 1.567s
[2012-11-13 22:31:13,235: INFO/PoolWorker-1] ['/tmp/eggs/pkgme_devportal-0.4.10-py2.7.egg/devportalbinary/backends/exe/want'] finished in 1.730s
[2012-11-13 22:31:14,021: INFO/PoolWorker-1] ['/tmp/eggs/pkgme_devportal-0.4.10-py2.7.egg/devportalbinary/backends/deb-src/want'] finished in 0.785s
[2012-11-13 22:31:15,127: INFO/PoolWorker-1] ['/tmp/eggs/pkgme_devportal-0.4.10-py2.7.egg/devportalbinary/backends/text/want'] finished in 1.106s
[2012-11-13 22:31:17,969: INFO/PoolWorker-1] ['/tmp/eggs/pkgme_devportal-0.4.10-py2.7.egg/devportalbinary/backends/image/want'] finished in 2.840s
[2012-11-13 ...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/djpkgme/osutils.py'
--- src/djpkgme/osutils.py 2012-09-20 16:11:44 +0000
+++ src/djpkgme/osutils.py 2012-11-13 15:21:25 +0000
@@ -10,8 +10,16 @@
10import os10import os
11import shutil11import shutil
12import tarfile12import tarfile
13import tempfile
14from urllib2 import (
15 HTTPError,
16 Request,
17 URLError,
18 urlopen,
19 )
13import zipfile20import zipfile
1421
22from bzrlib import urlutils
15from pkgme.run_script import (23from pkgme.run_script import (
16 run_subprocess,24 run_subprocess,
17 ScriptFailed,25 ScriptFailed,
@@ -130,3 +138,75 @@
130 finally:138 finally:
131 t.close()139 t.close()
132 return destination140 return destination
141
142
143def _open_file_for_writing(url, directory=None, name=None, working_dir=None):
144 """Open a file for writing.
145
146 If neither 'directory' nor 'name' are specified then make a secure
147 tempfile with 'mkstemp'. If directory is specified, then opens a file in
148 that directory, either with 'name' or the trailing segment of the URL. If
149 directory is not specified and name is specified, then opens the file in a
150 temporary directory.
151
152 If 'working_dir' is specified, then all temporary files or directories
153 will be created inside that directory.
154 """
155 if directory is None:
156 if name is None:
157 fd, path = tempfile.mkstemp(dir=working_dir)
158 else:
159 return _open_file_for_writing(
160 url, tempfile.mkdtemp(dir=working_dir), name, working_dir)
161 else:
162 if name is None:
163 name = urlutils.unescape(urlutils.basename(url))
164 path = os.path.join(directory, name)
165 fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_EXCL)
166 return fd, path
167
168
169def _wrap_urlopen(request):
170 """urlopen with better error messages."""
171 url = request.get_full_url()
172 try:
173 return urlopen(request)
174 except HTTPError, original:
175 raise HTTPError(
176 original.url,
177 original.code,
178 '%s: <%s>' % (original.msg, url),
179 original.hdrs,
180 original.fp,
181 )
182 except URLError, original:
183 if original.args:
184 message = '%s: %s' % (str(original.args[0]), url)
185 else:
186 message = url
187 e = URLError(message)
188 e.original = original
189 raise e
190
191
192def download_file(url, directory=None, name=None, working_dir=None,
193 bufsize=4 * 2 ** 10, headers=None):
194 """Download 'url' into 'directory'."""
195 # XXX: download_file is no longer used within pkgme-devportal
196 request = Request(url)
197 if headers is not None:
198 for h in headers:
199 request.add_header(h, headers[h])
200 download = _wrap_urlopen(request)
201 try:
202 fd, path = _open_file_for_writing(url, directory, name, working_dir)
203 try:
204 while True:
205 data = download.read(bufsize)
206 if not data:
207 return path
208 os.write(fd, data)
209 finally:
210 os.close(fd)
211 finally:
212 download.close()
133213
=== modified file 'src/djpkgme/tasks.py'
--- src/djpkgme/tasks.py 2012-09-18 12:34:40 +0000
+++ src/djpkgme/tasks.py 2012-11-13 15:21:25 +0000
@@ -12,9 +12,6 @@
12from oops_dictconfig import config_from_dict12from oops_dictconfig import config_from_dict
1313
14from devportalbinary.metadata import MetadataBackend14from devportalbinary.metadata import MetadataBackend
15from devportalbinary.database import (
16 download_file,
17 )
18from fixtures import (15from fixtures import (
19 TempDir,16 TempDir,
20 )17 )
@@ -33,6 +30,7 @@
33 submit_pkgme_info,30 submit_pkgme_info,
34 )31 )
35from .osutils import (32from .osutils import (
33 download_file,
36 make_tarball,34 make_tarball,
37 prepare_file,35 prepare_file,
38 )36 )
3937
=== modified file 'src/djpkgme/tests/test_osutils.py'
--- src/djpkgme/tests/test_osutils.py 2012-09-20 16:55:57 +0000
+++ src/djpkgme/tests/test_osutils.py 2012-11-13 15:21:25 +0000
@@ -1,19 +1,27 @@
1import errno1import errno
2import os2import os
3from StringIO import StringIO
3import subprocess4import subprocess
4import tarfile5import tarfile
6from urllib2 import (
7 HTTPError,
8 URLError,
9 )
5import zipfile10import zipfile
611
7from fixtures import TempDir12from fixtures import TempDir
8from testtools import TestCase13from testtools import TestCase
9from testtools.matchers import (14from testtools.matchers import (
10 DirExists,15 DirExists,
16 Equals,
11 FileContains,17 FileContains,
12 HasPermissions,18 HasPermissions,
19 Matcher,
13 Not,20 Not,
14 TarballContains,21 TarballContains,
15 )22 )
16from treeshape import (23from treeshape import (
24 CONTENT,
17 from_rough_spec,25 from_rough_spec,
18 HasFileTree,26 HasFileTree,
19 FileTree,27 FileTree,
@@ -21,7 +29,9 @@
21 )29 )
2230
23from ..osutils import (31from ..osutils import (
32 _open_file_for_writing,
24 DEFAULT_WORKING_DIRECTORY_NAME,33 DEFAULT_WORKING_DIRECTORY_NAME,
34 download_file,
25 make_tarball,35 make_tarball,
26 prepare_file,36 prepare_file,
27 try_extract_with_tar_command,37 try_extract_with_tar_command,
@@ -223,3 +233,100 @@
223 self.assertEqual(233 self.assertEqual(
224 destination,234 destination,
225 os.path.join(destination_dir, '%s-2.tar.gz' % (package_name,)))235 os.path.join(destination_dir, '%s-2.tar.gz' % (package_name,)))
236
237
238class IsChildPath(Matcher):
239
240 def __init__(self, parent_path):
241 super(IsChildPath, self).__init__()
242 self._parent_path = parent_path
243
244 def match(self, child_path):
245 parent_segments = os.path.abspath(self._parent_path).split(os.sep)
246 child_segments = os.path.abspath(child_path).split(os.sep)
247 return Equals(parent_segments).match(
248 child_segments[:len(parent_segments)])
249
250
251class TestOpenForWriting(TestCase):
252
253 def assertIsWriteable(self, fd, path):
254 contents = self.getUniqueString()
255 os.write(fd, contents)
256 os.close(fd)
257 self.assertThat(path, FileContains(contents))
258
259 def test_default(self):
260 fd, path = _open_file_for_writing('http://example.org/foo')
261 self.addCleanup(os.unlink, path)
262 self.assertIsWriteable(fd, path)
263
264 def test_directory_provided(self):
265 temp_path = self.useFixture(TempDir()).path
266 fd, path = _open_file_for_writing(
267 'http://example.org/foo', temp_path)
268 self.assertIsWriteable(fd, path)
269 self.assertEqual(os.path.join(temp_path, 'foo'), path)
270
271 def test_name_provided(self):
272 fd, path = _open_file_for_writing(
273 'http://example.org/foo', name='bar')
274 self.addCleanup(os.unlink, path)
275 self.assertIsWriteable(fd, path)
276 self.assertEqual('bar', os.path.basename(path))
277
278 def test_directory_and_name_provided(self):
279 temp_path = self.useFixture(TempDir()).path
280 fd, path = _open_file_for_writing(
281 'http://example.org/foo', temp_path, name='bar')
282 self.assertIsWriteable(fd, path)
283 self.assertEqual(os.path.join(temp_path, 'bar'), path)
284
285 def test_working_directory_no_name(self):
286 working_dir = self.useFixture(TempDir()).path
287 fd, path = _open_file_for_writing(
288 'http://example.org/foo', working_dir=working_dir)
289 self.assertIsWriteable(fd, path)
290 self.assertThat(path, IsChildPath(working_dir))
291
292 def test_working_directory_name(self):
293 working_dir = self.useFixture(TempDir()).path
294 fd, path = _open_file_for_writing(
295 'http://example.org/foo', name='bar', working_dir=working_dir)
296 self.assertIsWriteable(fd, path)
297 self.assertEqual('bar', os.path.basename(path))
298 self.assertThat(path, IsChildPath(working_dir))
299
300
301class TestDownloadFile(TestCase):
302
303 def test_saves_file(self):
304 from djpkgme import osutils
305 contents = self.getUniqueString()
306 def urlopen(url):
307 return StringIO(contents)
308 self.patch(osutils, 'urlopen', urlopen)
309 path = download_file('http://example.org/foo')
310 self.assertThat(path, FileContains(contents))
311
312 def test_url_error_includes_url(self):
313 from djpkgme import osutils
314 def urlopen(url):
315 raise URLError("whatever")
316 self.patch(osutils, 'urlopen', urlopen)
317 url = 'http://example.org/foo'
318 e = self.assertRaises(URLError, download_file, url)
319 self.assertEqual("<urlopen error whatever: %s>" % (url,), str(e))
320
321 def test_http_error_includes_url(self):
322 from djpkgme import osutils
323 url = 'http://example.org/foo'
324 # HTTPError must get a valid fp, otherwise it won't store the URL.
325 tree = self.useFixture(FileTree({'thing.txt': {CONTENT: 'whatever'}}))
326 fp = open(os.path.join(tree.path, 'thing.txt'), 'r')
327 def urlopen(url):
328 raise HTTPError(url, 404, 'whatever dude', {}, fp)
329 self.patch(osutils, 'urlopen', urlopen)
330 e = self.assertRaises(HTTPError, download_file, url)
331 self.assertEqual(
332 "HTTP Error 404: whatever dude: <%s>" % (url,), str(e))

Subscribers

People subscribed via source and target branches