Merge lp:~james-w/linaro-image-tools/fetch-packages into lp:linaro-image-tools/11.11
- fetch-packages
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 64 |
Proposed branch: | lp:~james-w/linaro-image-tools/fetch-packages |
Merge into: | lp:linaro-image-tools/11.11 |
Prerequisite: | lp:~james-w/linaro-image-tools/create-hwpack-skeleton |
Diff against target: |
547 lines (+510/-0) 4 files modified
hwpack/packages.py (+165/-0) hwpack/testing.py (+112/-0) hwpack/tests/__init__.py (+1/-0) hwpack/tests/test_packages.py (+232/-0) |
To merge this branch: | bzr merge lp:~james-w/linaro-image-tools/fetch-packages |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Hudson-Doyle (community) | Approve | ||
Review via email:
|
Commit message
Description of the change
Hi,
Here's the result of my investigations in to how we can fetch packages.
It's small code which I like. It's currently limited to fetching just the
specified packages, as we don't really know what we want there yet. I'm
assuming that if we need to then python-apt can allow us to resolve
dependencies too.
I have two issues with this change, the first being the possible licensing
impact of using python-apt. It is GPL2+ licensed, which I believe would
mean that this code would need to be too, which means getting a TSC
exemption, unless that has already been done for linaro-image-tools.
The second is the growing amount of code in testing.py with no tests.
Should I be testing that code too?
Thanks,
James
- 84. By James Westby
-
Use apt rather than bzrlib, with our own method to avoid the stdout output.
- 85. By James Westby
-
Remove the unneeded ugly code.
- 86. By James Westby
-
Merged create-
hwpack- skeleton into fetch-packages. - 87. By James Westby
-
Use a class as the return value such that we can return name, version and filename.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michael Hudson-Doyle (mwhudson) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Westby (james-w) wrote : | # |
> FWIW about the licensing, http://
> /linaro-
> under GPLv3.
I just saw that too. I guess that means we will have no problem, but I will
check with Loïc.
Thanks,
James
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michael Hudson-Doyle (mwhudson) wrote : | # |
As for the code, I think it's by and large fine, bearing in mind that I don't know how python-apt works.
I don't know if the stuff in testing.py needs tests, but it certainly needs documentation. I also wonder if AptSource should be called AptSourceFixture or something.
DummyProgress could use a docstring. After all that effort going to silencing python-apt, some kind of progress is likely to be desired, I think... I guess this can be carefully added back in later.
fetch_packages doesn't document its return type correctly any more.
All else looks good.
- 88. By James Westby
-
Add some documentation for the Package object.
- 89. By James Westby
-
Make Package in to DummyFetchedPackage to share an interface.
- 90. By James Westby
-
Add more documentation to testing.py and rename AptSource to AptSourceFixture
- 91. By James Westby
-
Tweak docstrings in hwpack.packages. Thanks Michael.
Preview Diff
1 | === added file 'hwpack/packages.py' | |||
2 | --- hwpack/packages.py 1970-01-01 00:00:00 +0000 | |||
3 | +++ hwpack/packages.py 2010-09-02 15:37:46 +0000 | |||
4 | @@ -0,0 +1,165 @@ | |||
5 | 1 | import os | ||
6 | 2 | import shutil | ||
7 | 3 | import tempfile | ||
8 | 4 | |||
9 | 5 | from apt.cache import Cache | ||
10 | 6 | from apt.package import FetchError | ||
11 | 7 | import apt_pkg | ||
12 | 8 | |||
13 | 9 | |||
14 | 10 | class DummyProgress(object): | ||
15 | 11 | """An AcquireProgress that silences all output. | ||
16 | 12 | |||
17 | 13 | This can be used to ensure that apt produces no output | ||
18 | 14 | when fetching files. | ||
19 | 15 | """ | ||
20 | 16 | |||
21 | 17 | def start(self): | ||
22 | 18 | pass | ||
23 | 19 | |||
24 | 20 | def ims_hit(self, item): | ||
25 | 21 | pass | ||
26 | 22 | |||
27 | 23 | def fail(self, item): | ||
28 | 24 | pass | ||
29 | 25 | |||
30 | 26 | def fetch(self, item): | ||
31 | 27 | pass | ||
32 | 28 | |||
33 | 29 | def pulse(self, owner): | ||
34 | 30 | return True | ||
35 | 31 | |||
36 | 32 | def media_change(self): | ||
37 | 33 | return False | ||
38 | 34 | |||
39 | 35 | def stop(self): | ||
40 | 36 | pass | ||
41 | 37 | |||
42 | 38 | |||
43 | 39 | class FetchedPackage(object): | ||
44 | 40 | """The result of fetching packages. | ||
45 | 41 | |||
46 | 42 | :ivar name: the name of the fetched package. | ||
47 | 43 | :type name: str | ||
48 | 44 | :ivar version: the version of the fetched package. | ||
49 | 45 | :type version: str | ||
50 | 46 | :ivar filename: the filename that the package has. | ||
51 | 47 | :type filename: str | ||
52 | 48 | :ivar content: a file that the content of the package can be read from. | ||
53 | 49 | :type content: a file-like object | ||
54 | 50 | :ivar size: the size of the package | ||
55 | 51 | :type size: int | ||
56 | 52 | :ivar md5: the hex representation of the md5sum of the contents of | ||
57 | 53 | the package. | ||
58 | 54 | :type md5: str | ||
59 | 55 | """ | ||
60 | 56 | |||
61 | 57 | def __init__(self, name, version, filename, content, size, md5): | ||
62 | 58 | """Create a FetchedPackage. | ||
63 | 59 | |||
64 | 60 | See the instance variables for the arguments. | ||
65 | 61 | """ | ||
66 | 62 | self.name = name | ||
67 | 63 | self.version = version | ||
68 | 64 | self.filename = filename | ||
69 | 65 | self.content = content | ||
70 | 66 | self.size = size | ||
71 | 67 | self.md5 = md5 | ||
72 | 68 | |||
73 | 69 | def __eq__(self, other): | ||
74 | 70 | return (self.name == other.name | ||
75 | 71 | and self.version == other.version | ||
76 | 72 | and self.filename == other.filename | ||
77 | 73 | and self.content.read() == other.content.read() | ||
78 | 74 | and self.size == other.size | ||
79 | 75 | and self.md5 == other.md5) | ||
80 | 76 | |||
81 | 77 | def __hash__(self): | ||
82 | 78 | return hash( | ||
83 | 79 | (self.name, self.version, self.filename, self.size, self.md5)) | ||
84 | 80 | |||
85 | 81 | |||
86 | 82 | class PackageFetcher(object): | ||
87 | 83 | """A class to fetch packages from a defined list of sources.""" | ||
88 | 84 | |||
89 | 85 | def __init__(self, sources): | ||
90 | 86 | """Create a PackageFetcher. | ||
91 | 87 | |||
92 | 88 | Once created a PackageFetcher should have its `prepare` method | ||
93 | 89 | called before use. | ||
94 | 90 | |||
95 | 91 | :param sources: a list of sources such that they can be prefixed | ||
96 | 92 | with "deb " and fed to apt. | ||
97 | 93 | :type sources: an iterable of str | ||
98 | 94 | """ | ||
99 | 95 | self.sources = sources | ||
100 | 96 | self.tempdir = None | ||
101 | 97 | |||
102 | 98 | def prepare(self): | ||
103 | 99 | """Prepare a PackageFetcher for use. | ||
104 | 100 | |||
105 | 101 | Should be called before use, and after any modification to the list | ||
106 | 102 | of sources. | ||
107 | 103 | """ | ||
108 | 104 | self.cleanup() | ||
109 | 105 | self.tempdir = tempfile.mkdtemp(prefix="hwpack-apt-cache-") | ||
110 | 106 | files = ["var/lib/dpkg/status", | ||
111 | 107 | ] | ||
112 | 108 | dirs = ["var/lib/dpkg", | ||
113 | 109 | "etc/apt/", | ||
114 | 110 | "var/cache/apt/archives/partial", | ||
115 | 111 | "var/lib/apt/lists/partial", | ||
116 | 112 | ] | ||
117 | 113 | for d in dirs: | ||
118 | 114 | os.makedirs(os.path.join(self.tempdir, d)) | ||
119 | 115 | for fn in files: | ||
120 | 116 | with open(os.path.join(self.tempdir, fn), 'w'): | ||
121 | 117 | pass | ||
122 | 118 | sources_list = os.path.join( | ||
123 | 119 | self.tempdir, "etc", "apt", "sources.list") | ||
124 | 120 | with open(sources_list, 'w') as f: | ||
125 | 121 | for source in self.sources: | ||
126 | 122 | f.write("deb %s\n" % source) | ||
127 | 123 | self.cache = Cache(rootdir=self.tempdir, memonly=True) | ||
128 | 124 | self.cache.update() | ||
129 | 125 | self.cache.open() | ||
130 | 126 | |||
131 | 127 | def cleanup(self): | ||
132 | 128 | """Cleanup any remaining artefacts. | ||
133 | 129 | |||
134 | 130 | Should be called on all PackageFetchers when they are finished | ||
135 | 131 | with. | ||
136 | 132 | """ | ||
137 | 133 | if self.tempdir is not None and os.path.exists(self.tempdir): | ||
138 | 134 | shutil.rmtree(self.tempdir) | ||
139 | 135 | |||
140 | 136 | def fetch_packages(self, packages): | ||
141 | 137 | """Fetch the files for the given list of package names. | ||
142 | 138 | |||
143 | 139 | :param packages: a list of package names to install | ||
144 | 140 | :type packages: an iterable of str | ||
145 | 141 | :return: a list of the packages that were fetched, with relevant | ||
146 | 142 | metdata and the contents of the files available. | ||
147 | 143 | :rtype: an iterable of FetchedPackages. | ||
148 | 144 | :raises KeyError: if any of the package names in the list couldn't | ||
149 | 145 | be found. | ||
150 | 146 | """ | ||
151 | 147 | results = [] | ||
152 | 148 | for package in packages: | ||
153 | 149 | candidate = self.cache[package].candidate | ||
154 | 150 | base = os.path.basename(candidate.filename) | ||
155 | 151 | destfile = os.path.join(self.tempdir, base) | ||
156 | 152 | acq = apt_pkg.Acquire(DummyProgress()) | ||
157 | 153 | acqfile = apt_pkg.AcquireFile( | ||
158 | 154 | acq, candidate.uri, candidate.md5, candidate.size, | ||
159 | 155 | base, destfile=destfile) | ||
160 | 156 | acq.run() | ||
161 | 157 | if acqfile.status != acqfile.STAT_DONE: | ||
162 | 158 | raise FetchError( | ||
163 | 159 | "The item %r could not be fetched: %s" % | ||
164 | 160 | (acqfile.destfile, acqfile.error_text)) | ||
165 | 161 | result_package = FetchedPackage( | ||
166 | 162 | candidate.package.name, candidate.version, base, | ||
167 | 163 | open(destfile), candidate.size, candidate.md5) | ||
168 | 164 | results.append(result_package) | ||
169 | 165 | return results | ||
170 | 0 | 166 | ||
171 | === modified file 'hwpack/testing.py' | |||
172 | --- hwpack/testing.py 2010-08-31 15:10:50 +0000 | |||
173 | +++ hwpack/testing.py 2010-09-02 15:37:46 +0000 | |||
174 | @@ -1,8 +1,15 @@ | |||
175 | 1 | from contextlib import contextmanager | 1 | from contextlib import contextmanager |
176 | 2 | import hashlib | ||
177 | 3 | import os | ||
178 | 4 | import shutil | ||
179 | 5 | import tempfile | ||
180 | 2 | from StringIO import StringIO | 6 | from StringIO import StringIO |
181 | 3 | import tarfile | 7 | import tarfile |
182 | 4 | 8 | ||
183 | 9 | from testtools import TestCase | ||
184 | 10 | |||
185 | 5 | from hwpack.better_tarfile import writeable_tarfile | 11 | from hwpack.better_tarfile import writeable_tarfile |
186 | 12 | from hwpack.packages import FetchedPackage | ||
187 | 6 | 13 | ||
188 | 7 | 14 | ||
189 | 8 | @contextmanager | 15 | @contextmanager |
190 | @@ -37,3 +44,108 @@ | |||
191 | 37 | yield tf | 44 | yield tf |
192 | 38 | finally: | 45 | finally: |
193 | 39 | tf.close() | 46 | tf.close() |
194 | 47 | |||
195 | 48 | |||
196 | 49 | class DummyFetchedPackage(FetchedPackage): | ||
197 | 50 | """A FetchedPackage with dummy information. | ||
198 | 51 | |||
199 | 52 | See FetchedPackage for the instance variables. | ||
200 | 53 | """ | ||
201 | 54 | |||
202 | 55 | def __init__(self, name, version): | ||
203 | 56 | """Create a DummyFetchedPackage. | ||
204 | 57 | |||
205 | 58 | :param name: the name of the package. | ||
206 | 59 | :type name: str | ||
207 | 60 | :param version: the version of the package. | ||
208 | 61 | :type version: str | ||
209 | 62 | """ | ||
210 | 63 | self.name = name | ||
211 | 64 | self.version = version | ||
212 | 65 | |||
213 | 66 | @property | ||
214 | 67 | def filename(self): | ||
215 | 68 | return "%s_%s_all.deb" % (self.name, self.version) | ||
216 | 69 | |||
217 | 70 | @property | ||
218 | 71 | def content(self): | ||
219 | 72 | return StringIO("Content of %s" % self.filename) | ||
220 | 73 | |||
221 | 74 | @property | ||
222 | 75 | def size(self): | ||
223 | 76 | return len(self.content.read()) | ||
224 | 77 | |||
225 | 78 | @property | ||
226 | 79 | def md5(self): | ||
227 | 80 | md5sum = hashlib.md5() | ||
228 | 81 | md5sum.update(self.content.read()) | ||
229 | 82 | return md5sum.hexdigest() | ||
230 | 83 | |||
231 | 84 | |||
232 | 85 | class AptSourceFixture(object): | ||
233 | 86 | """A fixture that provides an apt source, with packages and indices. | ||
234 | 87 | |||
235 | 88 | An apt source provides a set of package files, and a Packages file | ||
236 | 89 | that allows apt to determine the contents of the source. | ||
237 | 90 | |||
238 | 91 | :ivar sources_entry: the URI and suite to give to apt to view the | ||
239 | 92 | source (i.e. a sources.list line without the "deb" prefix | ||
240 | 93 | :type sources_entry: str | ||
241 | 94 | """ | ||
242 | 95 | |||
243 | 96 | def __init__(self, packages): | ||
244 | 97 | """Create an AptSourceFixture. | ||
245 | 98 | |||
246 | 99 | :param packages: a list of packages to add to the source | ||
247 | 100 | and index. | ||
248 | 101 | :type packages: an iterable of FetchedPackages | ||
249 | 102 | """ | ||
250 | 103 | self.packages = packages | ||
251 | 104 | |||
252 | 105 | def setUp(self): | ||
253 | 106 | self.rootdir = tempfile.mkdtemp(prefix="hwpack-apt-source-") | ||
254 | 107 | for package in self.packages: | ||
255 | 108 | with open( | ||
256 | 109 | os.path.join(self.rootdir, package.filename), 'wb') as f: | ||
257 | 110 | f.write(package.content.read()) | ||
258 | 111 | with open(os.path.join(self.rootdir, "Packages"), 'wb') as f: | ||
259 | 112 | for package in self.packages: | ||
260 | 113 | f.write('Package: %s\n' % package.name) | ||
261 | 114 | f.write('Version: %s\n' % package.version) | ||
262 | 115 | f.write('Filename: %s\n' % package.filename) | ||
263 | 116 | f.write('Size: %d\n' % package.size) | ||
264 | 117 | f.write('Architecture: all\n') | ||
265 | 118 | f.write('MD5sum: %s\n' % package.md5) | ||
266 | 119 | f.write('\n') | ||
267 | 120 | |||
268 | 121 | def tearDown(self): | ||
269 | 122 | if os.path.exists(self.rootdir): | ||
270 | 123 | shutil.rmtree(self.rootdir) | ||
271 | 124 | |||
272 | 125 | @property | ||
273 | 126 | def sources_entry(self): | ||
274 | 127 | return "file:" + os.path.abspath(self.rootdir) +" ./" | ||
275 | 128 | |||
276 | 129 | |||
277 | 130 | class TestCaseWithFixtures(TestCase): | ||
278 | 131 | """A TestCase with the ability to easily add 'fixtures'. | ||
279 | 132 | |||
280 | 133 | A fixture is an object which can be created and cleaned up, and | ||
281 | 134 | this test case knows how to manage them to ensure that they will | ||
282 | 135 | always be cleaned up at the end of the test. | ||
283 | 136 | """ | ||
284 | 137 | |||
285 | 138 | def useFixture(self, fixture): | ||
286 | 139 | """Make use of a fixture, ensuring that it will be cleaned up. | ||
287 | 140 | |||
288 | 141 | Given a fixture, this method will run the `setUp` method of | ||
289 | 142 | the fixture, and ensure that its `tearDown` method will be | ||
290 | 143 | called at the end of the test, regardless of success or failure. | ||
291 | 144 | |||
292 | 145 | :param fixture: the fixture to use. | ||
293 | 146 | :type fixture: an object with setUp and tearDown methods. | ||
294 | 147 | :return: the fixture that was passed in. | ||
295 | 148 | """ | ||
296 | 149 | self.addCleanup(fixture.tearDown) | ||
297 | 150 | fixture.setUp() | ||
298 | 151 | return fixture | ||
299 | 40 | 152 | ||
300 | === modified file 'hwpack/tests/__init__.py' | |||
301 | --- hwpack/tests/__init__.py 2010-08-31 01:05:12 +0000 | |||
302 | +++ hwpack/tests/__init__.py 2010-09-02 15:37:46 +0000 | |||
303 | @@ -4,6 +4,7 @@ | |||
304 | 4 | module_names = ['hwpack.tests.test_config', | 4 | module_names = ['hwpack.tests.test_config', |
305 | 5 | 'hwpack.tests.test_better_tarfile', | 5 | 'hwpack.tests.test_better_tarfile', |
306 | 6 | 'hwpack.tests.test_hardwarepack', | 6 | 'hwpack.tests.test_hardwarepack', |
307 | 7 | 'hwpack.tests.test_packages', | ||
308 | 7 | 'hwpack.tests.test_tarfile_matchers', | 8 | 'hwpack.tests.test_tarfile_matchers', |
309 | 8 | ] | 9 | ] |
310 | 9 | loader = unittest.TestLoader() | 10 | loader = unittest.TestLoader() |
311 | 10 | 11 | ||
312 | === added file 'hwpack/tests/test_packages.py' | |||
313 | --- hwpack/tests/test_packages.py 1970-01-01 00:00:00 +0000 | |||
314 | +++ hwpack/tests/test_packages.py 2010-09-02 15:37:46 +0000 | |||
315 | @@ -0,0 +1,232 @@ | |||
316 | 1 | import os | ||
317 | 2 | from StringIO import StringIO | ||
318 | 3 | |||
319 | 4 | from testtools import TestCase | ||
320 | 5 | |||
321 | 6 | from hwpack.packages import ( | ||
322 | 7 | FetchedPackage, | ||
323 | 8 | PackageFetcher, | ||
324 | 9 | ) | ||
325 | 10 | from hwpack.testing import ( | ||
326 | 11 | AptSourceFixture, | ||
327 | 12 | DummyFetchedPackage, | ||
328 | 13 | TestCaseWithFixtures, | ||
329 | 14 | ) | ||
330 | 15 | |||
331 | 16 | |||
332 | 17 | class FetchedPackageTests(TestCase): | ||
333 | 18 | |||
334 | 19 | def test_attributes(self): | ||
335 | 20 | package = FetchedPackage( | ||
336 | 21 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
337 | 22 | self.assertEqual("foo", package.name) | ||
338 | 23 | self.assertEqual("1.1", package.version) | ||
339 | 24 | self.assertEqual("foo_1.1.deb", package.filename) | ||
340 | 25 | self.assertEqual("xxxx", package.content.read()) | ||
341 | 26 | self.assertEqual(4, package.size) | ||
342 | 27 | self.assertEqual("aaaa", package.md5) | ||
343 | 28 | |||
344 | 29 | def test_equal(self): | ||
345 | 30 | package1 = FetchedPackage( | ||
346 | 31 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
347 | 32 | package2 = FetchedPackage( | ||
348 | 33 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
349 | 34 | self.assertEqual(package1, package2) | ||
350 | 35 | |||
351 | 36 | def test_not_equal_different_name(self): | ||
352 | 37 | package1 = FetchedPackage( | ||
353 | 38 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
354 | 39 | package2 = FetchedPackage( | ||
355 | 40 | "bar", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
356 | 41 | self.assertNotEqual(package1, package2) | ||
357 | 42 | |||
358 | 43 | def test_not_equal_different_version(self): | ||
359 | 44 | package1 = FetchedPackage( | ||
360 | 45 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
361 | 46 | package2 = FetchedPackage( | ||
362 | 47 | "foo", "1.2", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
363 | 48 | self.assertNotEqual(package1, package2) | ||
364 | 49 | |||
365 | 50 | def test_not_equal_different_filename(self): | ||
366 | 51 | package1 = FetchedPackage( | ||
367 | 52 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
368 | 53 | package2 = FetchedPackage( | ||
369 | 54 | "foo", "1.1", "afoo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
370 | 55 | self.assertNotEqual(package1, package2) | ||
371 | 56 | |||
372 | 57 | def test_not_equal_different_content(self): | ||
373 | 58 | package1 = FetchedPackage( | ||
374 | 59 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
375 | 60 | package2 = FetchedPackage( | ||
376 | 61 | "foo", "1.1", "foo_1.1.deb", StringIO("yyyy"), 4, "aaaa") | ||
377 | 62 | self.assertNotEqual(package1, package2) | ||
378 | 63 | |||
379 | 64 | def test_not_equal_different_size(self): | ||
380 | 65 | package1 = FetchedPackage( | ||
381 | 66 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
382 | 67 | package2 = FetchedPackage( | ||
383 | 68 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 5, "aaaa") | ||
384 | 69 | self.assertNotEqual(package1, package2) | ||
385 | 70 | |||
386 | 71 | def test_not_equal_different_md5(self): | ||
387 | 72 | package1 = FetchedPackage( | ||
388 | 73 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
389 | 74 | package2 = FetchedPackage( | ||
390 | 75 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "bbbb") | ||
391 | 76 | self.assertNotEqual(package1, package2) | ||
392 | 77 | |||
393 | 78 | def test_equal_hash_equal(self): | ||
394 | 79 | package1 = FetchedPackage( | ||
395 | 80 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
396 | 81 | package2 = FetchedPackage( | ||
397 | 82 | "foo", "1.1", "foo_1.1.deb", StringIO("xxxx"), 4, "aaaa") | ||
398 | 83 | self.assertEqual(hash(package1), hash(package2)) | ||
399 | 84 | |||
400 | 85 | |||
401 | 86 | class PackageFetcherTests(TestCaseWithFixtures): | ||
402 | 87 | |||
403 | 88 | def test_cleanup_removes_tempdir(self): | ||
404 | 89 | fetcher = PackageFetcher([]) | ||
405 | 90 | fetcher.prepare() | ||
406 | 91 | tempdir = fetcher.tempdir | ||
407 | 92 | fetcher.cleanup() | ||
408 | 93 | self.assertFalse(os.path.exists(tempdir)) | ||
409 | 94 | |||
410 | 95 | def test_cleanup_ignores_missing_tempdir(self): | ||
411 | 96 | fetcher = PackageFetcher([]) | ||
412 | 97 | fetcher.prepare() | ||
413 | 98 | tempdir = fetcher.tempdir | ||
414 | 99 | fetcher.cleanup() | ||
415 | 100 | # Check that there is no problem removing it again | ||
416 | 101 | fetcher.cleanup() | ||
417 | 102 | |||
418 | 103 | def test_cleanup_before_prepare(self): | ||
419 | 104 | fetcher = PackageFetcher([]) | ||
420 | 105 | # Check that there is no problem cleaning up before we start | ||
421 | 106 | fetcher.cleanup() | ||
422 | 107 | |||
423 | 108 | def test_prepare_creates_tempdir(self): | ||
424 | 109 | fetcher = PackageFetcher([]) | ||
425 | 110 | self.addCleanup(fetcher.cleanup) | ||
426 | 111 | fetcher.prepare() | ||
427 | 112 | self.assertTrue(os.path.isdir(fetcher.tempdir)) | ||
428 | 113 | |||
429 | 114 | def test_prepare_creates_var_lib_dpkg_status_file(self): | ||
430 | 115 | fetcher = PackageFetcher([]) | ||
431 | 116 | self.addCleanup(fetcher.cleanup) | ||
432 | 117 | fetcher.prepare() | ||
433 | 118 | self.assertEqual( | ||
434 | 119 | '', | ||
435 | 120 | open(os.path.join( | ||
436 | 121 | fetcher.tempdir, "var", "lib", "dpkg", "status")).read()) | ||
437 | 122 | |||
438 | 123 | def test_prepare_creates_var_cache_apt_archives_partial_dir(self): | ||
439 | 124 | fetcher = PackageFetcher([]) | ||
440 | 125 | self.addCleanup(fetcher.cleanup) | ||
441 | 126 | fetcher.prepare() | ||
442 | 127 | self.assertTrue( | ||
443 | 128 | os.path.isdir(os.path.join( | ||
444 | 129 | fetcher.tempdir, "var", "cache", "apt", "archives", | ||
445 | 130 | "partial"))) | ||
446 | 131 | |||
447 | 132 | def test_prepare_creates_var_lib_apt_lists_partial_dir(self): | ||
448 | 133 | fetcher = PackageFetcher([]) | ||
449 | 134 | self.addCleanup(fetcher.cleanup) | ||
450 | 135 | fetcher.prepare() | ||
451 | 136 | self.assertTrue( | ||
452 | 137 | os.path.isdir(os.path.join( | ||
453 | 138 | fetcher.tempdir, "var", "lib", "apt", "lists", "partial"))) | ||
454 | 139 | |||
455 | 140 | def test_prepare_creates_etc_apt_sources_list_file(self): | ||
456 | 141 | source1 = self.useFixture(AptSourceFixture([])) | ||
457 | 142 | source2 = self.useFixture(AptSourceFixture([])) | ||
458 | 143 | fetcher = PackageFetcher( | ||
459 | 144 | [source1.sources_entry, source2.sources_entry]) | ||
460 | 145 | self.addCleanup(fetcher.cleanup) | ||
461 | 146 | fetcher.prepare() | ||
462 | 147 | self.assertEqual( | ||
463 | 148 | "deb %s\ndeb %s\n" % ( | ||
464 | 149 | source1.sources_entry, source2.sources_entry), | ||
465 | 150 | open(os.path.join( | ||
466 | 151 | fetcher.tempdir, "etc", "apt", "sources.list")).read()) | ||
467 | 152 | |||
468 | 153 | def get_fetcher(self, sources): | ||
469 | 154 | fetcher = PackageFetcher([s.sources_entry for s in sources]) | ||
470 | 155 | self.addCleanup(fetcher.cleanup) | ||
471 | 156 | fetcher.prepare() | ||
472 | 157 | return fetcher | ||
473 | 158 | |||
474 | 159 | def test_fetch_packages_not_found_because_no_sources(self): | ||
475 | 160 | fetcher = self.get_fetcher([]) | ||
476 | 161 | self.assertRaises(KeyError, fetcher.fetch_packages, ["nothere"]) | ||
477 | 162 | |||
478 | 163 | def test_fetch_packages_not_found_because_not_in_sources(self): | ||
479 | 164 | available_package = DummyFetchedPackage("foo", "1.0") | ||
480 | 165 | source = self.useFixture(AptSourceFixture([available_package])) | ||
481 | 166 | fetcher = self.get_fetcher([source]) | ||
482 | 167 | self.assertRaises(KeyError, fetcher.fetch_packages, ["nothere"]) | ||
483 | 168 | |||
484 | 169 | def test_fetch_packages_not_found_one_of_two_missing(self): | ||
485 | 170 | available_package = DummyFetchedPackage("foo", "1.0") | ||
486 | 171 | source = self.useFixture(AptSourceFixture([available_package])) | ||
487 | 172 | fetcher = self.get_fetcher([source]) | ||
488 | 173 | self.assertRaises( | ||
489 | 174 | KeyError, fetcher.fetch_packages, ["foo", "nothere"]) | ||
490 | 175 | |||
491 | 176 | def test_fetch_packges_fetches_no_packages(self): | ||
492 | 177 | available_package = DummyFetchedPackage("foo", "1.0") | ||
493 | 178 | source = self.useFixture(AptSourceFixture([available_package])) | ||
494 | 179 | fetcher = self.get_fetcher([source]) | ||
495 | 180 | self.assertEqual(0, len(fetcher.fetch_packages([]))) | ||
496 | 181 | |||
497 | 182 | def test_fetch_packges_fetches_single_package(self): | ||
498 | 183 | available_package = DummyFetchedPackage("foo", "1.0") | ||
499 | 184 | source = self.useFixture(AptSourceFixture([available_package])) | ||
500 | 185 | fetcher = self.get_fetcher([source]) | ||
501 | 186 | self.assertEqual(1, len(fetcher.fetch_packages(["foo"]))) | ||
502 | 187 | |||
503 | 188 | def test_fetch_packges_fetches_correct_packge(self): | ||
504 | 189 | available_package = DummyFetchedPackage("foo", "1.0") | ||
505 | 190 | source = self.useFixture(AptSourceFixture([available_package])) | ||
506 | 191 | fetcher = self.get_fetcher([source]) | ||
507 | 192 | self.assertEqual( | ||
508 | 193 | available_package, fetcher.fetch_packages(["foo"])[0]) | ||
509 | 194 | |||
510 | 195 | def test_fetch_packges_fetches_multiple_packages(self): | ||
511 | 196 | available_packages = [ | ||
512 | 197 | DummyFetchedPackage("bar", "1.0"), | ||
513 | 198 | DummyFetchedPackage("foo", "1.0"), | ||
514 | 199 | ] | ||
515 | 200 | source = self.useFixture(AptSourceFixture(available_packages)) | ||
516 | 201 | fetcher = self.get_fetcher([source]) | ||
517 | 202 | self.assertEqual(2, len(fetcher.fetch_packages(["foo", "bar"]))) | ||
518 | 203 | |||
519 | 204 | def test_fetch_packges_fetches_multiple_packages_correctly(self): | ||
520 | 205 | available_packages = [ | ||
521 | 206 | DummyFetchedPackage("foo", "1.0"), | ||
522 | 207 | DummyFetchedPackage("bar", "1.0"), | ||
523 | 208 | ] | ||
524 | 209 | source = self.useFixture(AptSourceFixture(available_packages)) | ||
525 | 210 | fetcher = self.get_fetcher([source]) | ||
526 | 211 | fetched = fetcher.fetch_packages(["foo", "bar"]) | ||
527 | 212 | self.assertEqual(available_packages[0], fetched[0]) | ||
528 | 213 | self.assertEqual(available_packages[1], fetched[1]) | ||
529 | 214 | |||
530 | 215 | def test_fetch_packages_fetches_newest(self): | ||
531 | 216 | available_packages = [ | ||
532 | 217 | DummyFetchedPackage("bar", "1.0"), | ||
533 | 218 | DummyFetchedPackage("bar", "1.1"), | ||
534 | 219 | ] | ||
535 | 220 | source = self.useFixture(AptSourceFixture(available_packages)) | ||
536 | 221 | fetcher = self.get_fetcher([source]) | ||
537 | 222 | fetched = fetcher.fetch_packages(["bar"]) | ||
538 | 223 | self.assertEqual(available_packages[1], fetched[0]) | ||
539 | 224 | |||
540 | 225 | def test_fetch_packages_fetches_newest_from_multiple_sources(self): | ||
541 | 226 | old_source_packages = [DummyFetchedPackage("bar", "1.0")] | ||
542 | 227 | new_source_packages = [DummyFetchedPackage("bar", "1.1")] | ||
543 | 228 | old_source = self.useFixture(AptSourceFixture(old_source_packages)) | ||
544 | 229 | new_source = self.useFixture(AptSourceFixture(new_source_packages)) | ||
545 | 230 | fetcher = self.get_fetcher([old_source, new_source]) | ||
546 | 231 | fetched = fetcher.fetch_packages(["bar"]) | ||
547 | 232 | self.assertEqual(new_source_packages[0], fetched[0]) |
FWIW about the licensing, http:// bazaar. launchpad. net/~linaro- maintainers/ linaro- image-tools/ linaro- image-tools/ revision/ 44 put linaro-media-create under GPLv3.