Merge ~dbungert/curtin:command-apt-libapt-v4 into curtin:master

Proposed by Dan Bungert
Status: Merged
Approved by: Dan Bungert
Approved revision: 7193cf40c5f65bd52d615eb19199d2e468f13030
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~dbungert/curtin:command-apt-libapt-v4
Merge into: curtin:master
Diff against target: 530 lines (+195/-112)
5 files modified
curtin/commands/apt_config.py (+68/-59)
tests/unittests/test_apt_source.py (+113/-50)
tests/vmtests/__init__.py (+11/-0)
tests/vmtests/test_apt_source.py (+2/-3)
tox.ini (+1/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Michael Hudson-Doyle Approve
Review via email: mp+408383@code.launchpad.net

Commit message

commands/apt: use python-apt for sources.list

Start using python{,3}-apt for sources.list handling.
generate_sources_list now operates in a pipeline-like model, where each
stage performs one specific transformation on the list of entries.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
0cf5057... by Dan Bungert

tox: +sitepackages for py27-pylint

Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Very nice. Just one suggestion, feel free to act on or ignore that and then merge, no further review required.

review: Approve
7193cf4... by Dan Bungert

commands/apt: uri update simplification

Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/curtin/commands/apt_config.py b/curtin/commands/apt_config.py
2index e7d84c0..ef4a34c 100644
3--- a/curtin/commands/apt_config.py
4+++ b/curtin/commands/apt_config.py
5@@ -11,6 +11,8 @@ import os
6 import re
7 import sys
8
9+from aptsources.sourceslist import SourceEntry
10+
11 from curtin.log import LOG
12 from curtin import (config, distro, gpg, paths, util)
13
14@@ -211,22 +213,38 @@ def rename_apt_lists(new_mirrors, target=None):
15 LOG.warn("Failed to rename apt list:", exc_info=True)
16
17
18-def mirror_to_placeholder(tmpl, mirror, placeholder):
19- """ mirror_to_placeholder
20- replace the specified mirror in a template with a placeholder string
21- Checks for existance of the expected mirror and warns if not found
22- """
23- if mirror not in tmpl:
24- if mirror.endswith("/") and mirror[:-1] in tmpl:
25- LOG.debug("mirror_to_placeholder: '%s' did not exist in tmpl, "
26- "did without a trailing /. Accomodating.", mirror)
27- mirror = mirror[:-1]
28- else:
29- LOG.warn("Expected mirror '%s' not found in: %s", mirror, tmpl)
30- return tmpl.replace(mirror, placeholder)
31+def update_default_mirrors(entries, mirrors, target):
32+ """replace existing default repos with the configured mirror"""
33+
34+ defaults = get_default_mirrors(distro.get_architecture(target))
35+ mirrors_replacement = {
36+ defaults['PRIMARY']: mirrors["MIRROR"],
37+ defaults['SECURITY']: mirrors["SECURITY"],
38+ }
39+
40+ # allow original file URIs without the trailing slash to match mirror
41+ # specifications that have it
42+ noslash = {}
43+ for key in mirrors_replacement.keys():
44+ if key[-1] == '/':
45+ noslash[key[:-1]] = mirrors_replacement[key]
46+
47+ mirrors_replacement.update(noslash)
48+
49+ for entry in entries:
50+ entry.uri = mirrors_replacement.get(entry.uri, entry.uri)
51+ return entries
52+
53
54+def update_mirrors(entries, mirrors):
55+ """perform template replacement of mirror placeholders with configured
56+ values"""
57+ for entry in entries:
58+ entry.uri = util.render_string(entry.uri, mirrors)
59+ return entries
60
61-def map_known_suites(suite):
62+
63+def map_known_suites(suite, release):
64 """there are a few default names which will be auto-extended.
65 This comes at the inability to use those names literally as suites,
66 but on the other hand increases readability of the cfg quite a lot"""
67@@ -236,10 +254,10 @@ def map_known_suites(suite):
68 'proposed': '$RELEASE-proposed',
69 'release': '$RELEASE'}
70 try:
71- retsuite = mapping[suite]
72+ template_suite = mapping[suite]
73 except KeyError:
74- retsuite = suite
75- return retsuite
76+ template_suite = suite
77+ return util.render_string(template_suite, {'RELEASE': release})
78
79
80 def disable_suites(disabled, src, release):
81@@ -248,36 +266,30 @@ def disable_suites(disabled, src, release):
82 if not disabled:
83 return src
84
85- retsrc = src
86+ suites_to_disable = []
87 for suite in disabled:
88- suite = map_known_suites(suite)
89- releasesuite = util.render_string(suite, {'RELEASE': release})
90- LOG.debug("Disabling suite %s as %s", suite, releasesuite)
91+ release_suite = map_known_suites(suite, release)
92+ LOG.debug("Disabling suite %s as %s", suite, release_suite)
93+ suites_to_disable.append(release_suite)
94+
95+ output = []
96+ for entry in src:
97+ if entry.dist in suites_to_disable and not entry.disabled:
98+ # handle commenting ourselves - it handles lines with
99+ # options better
100+ entry = SourceEntry('# ' + str(entry))
101+ output.append(entry)
102+ return output
103
104- newsrc = ""
105- for line in retsrc.splitlines(True):
106- if line.startswith("#"):
107- newsrc += line
108- continue
109
110- # sources.list allow options in cols[1] which can have spaces
111- # so the actual suite can be [2] or later. example:
112- # deb [ arch=amd64,armel k=v ] http://example.com/debian
113- cols = line.split()
114- if len(cols) > 1:
115- pcol = 2
116- if cols[1].startswith("["):
117- for col in cols[1:]:
118- pcol += 1
119- if col.endswith("]"):
120- break
121+def update_dist(entries, release):
122+ for entry in entries:
123+ entry.dist = util.render_string(entry.dist, {'RELEASE': release})
124+ return entries
125
126- if cols[pcol] == releasesuite:
127- line = '# suite disabled by curtin: %s' % line
128- newsrc += line
129- retsrc = newsrc
130
131- return retsrc
132+def entries_to_str(entries):
133+ return ''.join([str(entry) + '\n' for entry in entries])
134
135
136 def generate_sources_list(cfg, release, mirrors, target=None):
137@@ -285,34 +297,31 @@ def generate_sources_list(cfg, release, mirrors, target=None):
138 create a source.list file based on a custom or default template
139 by replacing mirrors and release in the template
140 """
141- default_mirrors = get_default_mirrors(distro.get_architecture(target))
142 aptsrc = "/etc/apt/sources.list"
143- params = {'RELEASE': release}
144- for k in mirrors:
145- params[k] = mirrors[k]
146
147 tmpl = cfg.get('sources_list', None)
148+ from_file = False
149 if tmpl is None:
150 LOG.info("No custom template provided, fall back to modify"
151 "mirrors in %s on the target system", aptsrc)
152 tmpl = util.load_file(paths.target_path(target, aptsrc))
153- # Strategy if no custom template was provided:
154- # - Only replacing mirrors
155- # - no reason to replace "release" as it is from target anyway
156- # - The less we depend upon, the more stable this is against changes
157- # - warn if expected original content wasn't found
158- tmpl = mirror_to_placeholder(tmpl, default_mirrors['PRIMARY'],
159- "$MIRROR")
160- tmpl = mirror_to_placeholder(tmpl, default_mirrors['SECURITY'],
161- "$SECURITY")
162+ from_file = True
163+
164+ entries = [SourceEntry(line) for line in tmpl.splitlines(True)]
165+ if from_file:
166+ # when loading from an existing file, we also replace default
167+ # URIs with configured mirrors
168+ entries = update_default_mirrors(entries, mirrors, target)
169+
170+ entries = update_mirrors(entries, mirrors)
171+ entries = update_dist(entries, release)
172+ entries = disable_suites(cfg.get('disable_suites'), entries, release)
173+ output = entries_to_str(entries)
174
175 orig = paths.target_path(target, aptsrc)
176 if os.path.exists(orig):
177 os.rename(orig, orig + ".curtin.old")
178-
179- rendered = util.render_string(tmpl, params)
180- disabled = disable_suites(cfg.get('disable_suites'), rendered, release)
181- util.write_file(paths.target_path(target, aptsrc), disabled, mode=0o644)
182+ util.write_file(paths.target_path(target, aptsrc), output, mode=0o644)
183
184
185 def apply_preserve_sources_list(target):
186diff --git a/tests/unittests/test_apt_source.py b/tests/unittests/test_apt_source.py
187index 6556399..01e70ad 100644
188--- a/tests/unittests/test_apt_source.py
189+++ b/tests/unittests/test_apt_source.py
190@@ -12,6 +12,8 @@ import socket
191 import mock
192 from mock import call
193
194+from aptsources.sourceslist import SourceEntry
195+
196 from curtin import distro
197 from curtin import gpg
198 from curtin import util
199@@ -63,6 +65,18 @@ class PseudoChrootableTarget(util.ChrootableTarget):
200 ChrootableTargetStr = "curtin.commands.apt_config.util.ChrootableTarget"
201
202
203+def entryify(data):
204+ return [SourceEntry(line) for line in data.splitlines()]
205+
206+
207+def lineify(entries):
208+ out = apt_config.entries_to_str(entries)
209+ # the tests are written without the trailing newline,
210+ # but we don't want to remove multiple of them
211+ out = out[:-1] if len(out) > 0 and out[-1] == '\n' else out
212+ return out
213+
214+
215 class TestAptSourceConfig(CiTestCase):
216 """ TestAptSourceConfig
217 Main Class to test apt configs
218@@ -77,6 +91,7 @@ class TestAptSourceConfig(CiTestCase):
219 self.matcher = re.compile(ADD_APT_REPO_MATCH).search
220 self.add_patch('curtin.util.subp', 'm_subp')
221 self.m_subp.return_value = ('s390x', '')
222+ self.target = self.tmp_dir()
223
224 @staticmethod
225 def _add_apt_sources(*args, **kwargs):
226@@ -758,6 +773,7 @@ class TestAptSourceConfig(CiTestCase):
227 def test_disable_suites(self):
228 """test_disable_suites - disable_suites with many configurations"""
229 release = "xenial"
230+
231 orig = """deb http://ubuntu.com//ubuntu xenial main
232 deb http://ubuntu.com//ubuntu xenial-updates main
233 deb http://ubuntu.com//ubuntu xenial-security main
234@@ -771,39 +787,38 @@ deb http://ubuntu.com//ubuntu xenial-updates main
235 deb http://ubuntu.com//ubuntu xenial-security main
236 deb-src http://ubuntu.com//ubuntu universe multiverse
237 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
238- result = apt_config.disable_suites(disabled, orig, release)
239- self.assertEqual(expect, result)
240+ result = apt_config.disable_suites(disabled, entryify(orig), release)
241+ self.assertEqual(expect, lineify(result))
242
243 # single disable release suite
244 disabled = ["$RELEASE"]
245- expect = """\
246-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial main
247+ expect = """# deb http://ubuntu.com//ubuntu xenial main
248 deb http://ubuntu.com//ubuntu xenial-updates main
249 deb http://ubuntu.com//ubuntu xenial-security main
250 deb-src http://ubuntu.com//ubuntu universe multiverse
251 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
252- result = apt_config.disable_suites(disabled, orig, release)
253- self.assertEqual(expect, result)
254+ result = apt_config.disable_suites(disabled, entryify(orig), release)
255+ self.assertEqual(expect, lineify(result))
256
257 # single disable other suite
258 disabled = ["$RELEASE-updates"]
259 expect = """deb http://ubuntu.com//ubuntu xenial main
260-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-updates main
261+# deb http://ubuntu.com//ubuntu xenial-updates main
262 deb http://ubuntu.com//ubuntu xenial-security main
263 deb-src http://ubuntu.com//ubuntu universe multiverse
264 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
265- result = apt_config.disable_suites(disabled, orig, release)
266- self.assertEqual(expect, result)
267+ result = apt_config.disable_suites(disabled, entryify(orig), release)
268+ self.assertEqual(expect, lineify(result))
269
270 # multi disable
271 disabled = ["$RELEASE-updates", "$RELEASE-security"]
272 expect = """deb http://ubuntu.com//ubuntu xenial main
273-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-updates main
274-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-security main
275+# deb http://ubuntu.com//ubuntu xenial-updates main
276+# deb http://ubuntu.com//ubuntu xenial-security main
277 deb-src http://ubuntu.com//ubuntu universe multiverse
278 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
279- result = apt_config.disable_suites(disabled, orig, release)
280- self.assertEqual(expect, result)
281+ result = apt_config.disable_suites(disabled, entryify(orig), release)
282+ self.assertEqual(expect, lineify(result))
283
284 # multi line disable (same suite multiple times in input)
285 disabled = ["$RELEASE-updates", "$RELEASE-security"]
286@@ -815,14 +830,14 @@ deb http://UBUNTU.com//ubuntu xenial-updates main
287 deb http://UBUNTU.COM//ubuntu xenial-updates main
288 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
289 expect = """deb http://ubuntu.com//ubuntu xenial main
290-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-updates main
291-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-security main
292+# deb http://ubuntu.com//ubuntu xenial-updates main
293+# deb http://ubuntu.com//ubuntu xenial-security main
294 deb-src http://ubuntu.com//ubuntu universe multiverse
295-# suite disabled by curtin: deb http://UBUNTU.com//ubuntu xenial-updates main
296-# suite disabled by curtin: deb http://UBUNTU.COM//ubuntu xenial-updates main
297+# deb http://UBUNTU.com//ubuntu xenial-updates main
298+# deb http://UBUNTU.COM//ubuntu xenial-updates main
299 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
300- result = apt_config.disable_suites(disabled, orig, release)
301- self.assertEqual(expect, result)
302+ result = apt_config.disable_suites(disabled, entryify(orig), release)
303+ self.assertEqual(expect, lineify(result))
304
305 # comment in input
306 disabled = ["$RELEASE-updates", "$RELEASE-security"]
307@@ -835,15 +850,15 @@ deb-src http://ubuntu.com//ubuntu universe multiverse
308 deb http://UBUNTU.COM//ubuntu xenial-updates main
309 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
310 expect = """deb http://ubuntu.com//ubuntu xenial main
311-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-updates main
312-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-security main
313+# deb http://ubuntu.com//ubuntu xenial-updates main
314+# deb http://ubuntu.com//ubuntu xenial-security main
315 deb-src http://ubuntu.com//ubuntu universe multiverse
316 #foo
317-#deb http://UBUNTU.com//ubuntu xenial-updates main
318-# suite disabled by curtin: deb http://UBUNTU.COM//ubuntu xenial-updates main
319+# deb http://UBUNTU.com//ubuntu xenial-updates main
320+# deb http://UBUNTU.COM//ubuntu xenial-updates main
321 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
322- result = apt_config.disable_suites(disabled, orig, release)
323- self.assertEqual(expect, result)
324+ result = apt_config.disable_suites(disabled, entryify(orig), release)
325+ self.assertEqual(expect, lineify(result))
326
327 # single disable custom suite
328 disabled = ["foobar"]
329@@ -854,9 +869,9 @@ deb http://ubuntu.com/ubuntu/ foobar main"""
330 expect = """deb http://ubuntu.com//ubuntu xenial main
331 deb http://ubuntu.com//ubuntu xenial-updates main
332 deb http://ubuntu.com//ubuntu xenial-security main
333-# suite disabled by curtin: deb http://ubuntu.com/ubuntu/ foobar main"""
334- result = apt_config.disable_suites(disabled, orig, release)
335- self.assertEqual(expect, result)
336+# deb http://ubuntu.com/ubuntu/ foobar main"""
337+ result = apt_config.disable_suites(disabled, entryify(orig), release)
338+ self.assertEqual(expect, lineify(result))
339
340 # single disable non existing suite
341 disabled = ["foobar"]
342@@ -868,8 +883,8 @@ deb http://ubuntu.com/ubuntu/ notfoobar main"""
343 deb http://ubuntu.com//ubuntu xenial-updates main
344 deb http://ubuntu.com//ubuntu xenial-security main
345 deb http://ubuntu.com/ubuntu/ notfoobar main"""
346- result = apt_config.disable_suites(disabled, orig, release)
347- self.assertEqual(expect, result)
348+ result = apt_config.disable_suites(disabled, entryify(orig), release)
349+ self.assertEqual(expect, lineify(result))
350
351 # single disable suite with option
352 disabled = ["$RELEASE-updates"]
353@@ -879,12 +894,12 @@ deb http://ubuntu.com//ubuntu xenial-security main
354 deb-src http://ubuntu.com//ubuntu universe multiverse
355 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
356 expect = """deb http://ubuntu.com//ubuntu xenial main
357-# suite disabled by curtin: deb [a=b] http://ubu.com//ubu xenial-updates main
358+# deb [a=b] http://ubu.com//ubu xenial-updates main
359 deb http://ubuntu.com//ubuntu xenial-security main
360 deb-src http://ubuntu.com//ubuntu universe multiverse
361 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
362- result = apt_config.disable_suites(disabled, orig, release)
363- self.assertEqual(expect, result)
364+ result = apt_config.disable_suites(disabled, entryify(orig), release)
365+ self.assertEqual(expect, lineify(result))
366
367 # single disable suite with more options and auto $RELEASE expansion
368 disabled = ["updates"]
369@@ -894,13 +909,12 @@ deb http://ubuntu.com//ubuntu xenial-security main
370 deb-src http://ubuntu.com//ubuntu universe multiverse
371 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
372 expect = """deb http://ubuntu.com//ubuntu xenial main
373-# suite disabled by curtin: deb [a=b c=d] \
374-http://ubu.com//ubu xenial-updates main
375+# deb [a=b c=d] http://ubu.com//ubu xenial-updates main
376 deb http://ubuntu.com//ubuntu xenial-security main
377 deb-src http://ubuntu.com//ubuntu universe multiverse
378 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
379- result = apt_config.disable_suites(disabled, orig, release)
380- self.assertEqual(expect, result)
381+ result = apt_config.disable_suites(disabled, entryify(orig), release)
382+ self.assertEqual(expect, lineify(result))
383
384 # single disable suite while options at others
385 disabled = ["$RELEASE-security"]
386@@ -911,25 +925,74 @@ deb-src http://ubuntu.com//ubuntu universe multiverse
387 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
388 expect = """deb http://ubuntu.com//ubuntu xenial main
389 deb [arch=foo] http://ubuntu.com//ubuntu xenial-updates main
390-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-security main
391+# deb http://ubuntu.com//ubuntu xenial-security main
392 deb-src http://ubuntu.com//ubuntu universe multiverse
393 deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
394- result = apt_config.disable_suites(disabled, orig, release)
395- self.assertEqual(expect, result)
396+ result = apt_config.disable_suites(disabled, entryify(orig), release)
397+ self.assertEqual(expect, lineify(result))
398
399 def test_disable_suites_blank_lines(self):
400 """test_disable_suites_blank_lines - ensure blank lines allowed"""
401- lines = ["deb %(repo)s %(rel)s main universe",
402- "",
403- "deb %(repo)s %(rel)s-updates main universe",
404- " # random comment",
405- "#comment here",
406- ""]
407 rel = "trusty"
408- repo = 'http://example.com/mirrors/ubuntu'
409- orig = "\n".join(lines) % {'repo': repo, 'rel': rel}
410- self.assertEqual(
411- orig, apt_config.disable_suites(["proposed"], orig, rel))
412+
413+ orig = """
414+deb http://example.com/mirrors/ubuntu trusty main universe
415+
416+deb http://example.com/mirrors/ubuntu trusty-updates main universe
417+
418+deb http://example.com/mirrors/ubuntu trusty-proposed main universe
419+
420+#comment here"""
421+ expect = """
422+deb http://example.com/mirrors/ubuntu trusty main universe
423+
424+deb http://example.com/mirrors/ubuntu trusty-updates main universe
425+
426+# deb http://example.com/mirrors/ubuntu trusty-proposed main universe
427+
428+#comment here"""
429+ disabled = ["proposed"]
430+ result = apt_config.disable_suites(disabled, entryify(orig), rel)
431+ self.assertEqual(expect, lineify(result))
432+
433+ @mock.patch("curtin.util.write_file")
434+ @mock.patch("curtin.distro.get_architecture")
435+ def test_generate_with_options(self, get_arch, write_file):
436+ get_arch.return_value = "amd64"
437+ orig = """deb http://ubuntu.com//ubuntu $RELEASE main
438+# stuff things
439+
440+deb http://ubuntu.com//ubuntu $RELEASE-updates main
441+deb http://ubuntu.com//ubuntu $RELEASE-security main
442+deb-src http://ubuntu.com//ubuntu $RELEASE universe multiverse
443+# deb http://ubuntu.com/ubuntu/ $RELEASE-proposed main
444+deb [a=b] http://ubuntu.com/ubuntu/ $RELEASE-backports main
445+"""
446+ expect = """deb http://ubuntu.com//ubuntu xenial main
447+# stuff things
448+
449+deb http://ubuntu.com//ubuntu xenial-updates main
450+deb http://ubuntu.com//ubuntu xenial-security main
451+deb-src http://ubuntu.com//ubuntu xenial universe multiverse
452+# deb http://ubuntu.com/ubuntu/ xenial-proposed main
453+# deb [a=b] http://ubuntu.com/ubuntu/ $RELEASE-backports main
454+"""
455+ # $RELEASE in backports doesn't get expanded because the line is
456+ # considered invalid because of the options. So when the line
457+ # gets commented out, it comments out the original line, not
458+ # what we've modifed it to.
459+ rel = 'xenial'
460+ mirrors = {'PRIMARY': 'http://ubuntu.com/ubuntu/'}
461+
462+ cfg = {
463+ 'preserve_sources_list': False,
464+ 'sources_list': orig,
465+ 'disable_suites': ['backports'],
466+ }
467+
468+ apt_config.generate_sources_list(cfg, rel, mirrors, self.target)
469+ filepath = os.path.join(self.target, 'etc/apt/sources.list')
470+ write_file.assert_called_with(filepath, expect, mode=0o644)
471
472
473 class TestDebconfSelections(CiTestCase):
474diff --git a/tests/vmtests/__init__.py b/tests/vmtests/__init__.py
475index 0b19d8f..fd6c246 100644
476--- a/tests/vmtests/__init__.py
477+++ b/tests/vmtests/__init__.py
478@@ -1631,6 +1631,9 @@ class VMBaseClass(TestCase):
479 def check_file_regex(self, filename, regex):
480 self.assertRegex(self.load_collect_file(filename), regex)
481
482+ def not_file_regex(self, filename, regex):
483+ self.assertNotRegex(self.load_collect_file(filename), regex)
484+
485 # To get rid of deprecation warning in python 3.
486 def assertRegex(self, s, r):
487 try:
488@@ -1640,6 +1643,14 @@ class VMBaseClass(TestCase):
489 # Python 2.
490 self.assertRegexpMatches(s, r)
491
492+ def assertNotRegex(self, s, r):
493+ try:
494+ # Python 3.
495+ super(VMBaseClass, self).assertNotRegex(s, r)
496+ except AttributeError:
497+ # Python 2.
498+ self.assertNotRegexpMatches(s, r)
499+
500 def get_blkid_data(self, blkid_file):
501 data = self.load_collect_file(blkid_file)
502 ret = {}
503diff --git a/tests/vmtests/test_apt_source.py b/tests/vmtests/test_apt_source.py
504index a090ffa..9d00dc8 100644
505--- a/tests/vmtests/test_apt_source.py
506+++ b/tests/vmtests/test_apt_source.py
507@@ -164,9 +164,8 @@ class TestAptSrcDisablePockets(TestAptSrcAbs):
508 r"deb.*us.archive.ubuntu.com")
509 self.check_file_regex("sources.list",
510 r"deb.*security.ubuntu.com")
511- # updates disabled
512- self.check_file_regex("sources.list",
513- r"# suite disabled by curtin:.*-updates")
514+ # updates disabled and not present
515+ self.not_file_regex("sources.list", r"# .*-updates")
516
517
518 class TestAptSrcModifyArches(TestAptSrcModify):
519diff --git a/tox.ini b/tox.ini
520index f27dfbc..d9437c5 100644
521--- a/tox.ini
522+++ b/tox.ini
523@@ -71,6 +71,7 @@ commands = {envpython} -m pylint --errors-only {posargs:curtin tests/vmtests}
524 [testenv:py27-pylint]
525 # set basepython because tox 1.6 (trusty) does not support generated environments
526 basepython = python2.7
527+sitepackages = true
528 deps = {[testenv]deps}
529 {[testenv:py27]deps}
530 pylint==1.8.1

Subscribers

People subscribed via source and target branches