curtin-dev team mailing list archive
-
curtin-dev team
-
Mailing list archive
-
Message #01766
[Merge] ~dbungert/curtin:command-apt-libapt-v3 into curtin:master
Dan Bungert has proposed merging ~dbungert/curtin:command-apt-libapt-v3 into curtin:master.
Commit message:
commands/apt_config: use python3-apt, support disable_components
Add usage of python3-apt to replace the homegrown parser. This is most ok,
but python3-apt currently has only partial support for the options listed
in a sources.list line, so there are some workarounds in place to minize
the effect of that.
Use the above to add support for disable_components, with the goal of
supporting with subiquity a 'free software' option that disables
multiverse and restricted.
Requested reviews:
Michael Hudson-Doyle (mwhudson)
For more details, see:
https://code.launchpad.net/~dbungert/curtin/+git/curtin/+merge/407565
--
Your team curtin developers is subscribed to branch curtin:master.
diff --git a/curtin/commands/apt_config.py b/curtin/commands/apt_config.py
index e7d84c0..8220bfa 100644
--- a/curtin/commands/apt_config.py
+++ b/curtin/commands/apt_config.py
@@ -11,6 +11,8 @@ import os
import re
import sys
+from aptsources.sourceslist import SourceEntry
+
from curtin.log import LOG
from curtin import (config, distro, gpg, paths, util)
@@ -211,22 +213,7 @@ def rename_apt_lists(new_mirrors, target=None):
LOG.warn("Failed to rename apt list:", exc_info=True)
-def mirror_to_placeholder(tmpl, mirror, placeholder):
- """ mirror_to_placeholder
- replace the specified mirror in a template with a placeholder string
- Checks for existance of the expected mirror and warns if not found
- """
- if mirror not in tmpl:
- if mirror.endswith("/") and mirror[:-1] in tmpl:
- LOG.debug("mirror_to_placeholder: '%s' did not exist in tmpl, "
- "did without a trailing /. Accomodating.", mirror)
- mirror = mirror[:-1]
- else:
- LOG.warn("Expected mirror '%s' not found in: %s", mirror, tmpl)
- return tmpl.replace(mirror, placeholder)
-
-
-def map_known_suites(suite):
+def map_known_suites(suite, release):
"""there are a few default names which will be auto-extended.
This comes at the inability to use those names literally as suites,
but on the other hand increases readability of the cfg quite a lot"""
@@ -236,10 +223,10 @@ def map_known_suites(suite):
'proposed': '$RELEASE-proposed',
'release': '$RELEASE'}
try:
- retsuite = mapping[suite]
+ template_suite = mapping[suite]
except KeyError:
- retsuite = suite
- return retsuite
+ template_suite = suite
+ return util.render_string(template_suite, {'RELEASE': release})
def disable_suites(disabled, src, release):
@@ -248,36 +235,86 @@ def disable_suites(disabled, src, release):
if not disabled:
return src
- retsrc = src
+ suites_to_disable = []
for suite in disabled:
- suite = map_known_suites(suite)
- releasesuite = util.render_string(suite, {'RELEASE': release})
- LOG.debug("Disabling suite %s as %s", suite, releasesuite)
+ release_suite = map_known_suites(suite, release)
+ LOG.debug("Disabling suite %s as %s", suite, release_suite)
+ suites_to_disable.append(release_suite)
+
+ output = []
+ for entry in src:
+ if entry.dist in suites_to_disable and not entry.disabled:
+ # handle commenting ourselves - it handles lines with
+ # options better
+ entry = SourceEntry('# ' + str(entry))
+ output.append(entry)
+ return output
+
+
+def disable_components(disabled, entries):
+ """reads the config for components to be disabled and remove those
+ from the entries"""
+ if not disabled:
+ return entries
+
+ # purposefully skip disabling the main component
+ comps_to_disable = [comp for comp in disabled if comp != 'main']
+
+ output = []
+ for entry in entries:
+ if any(comp in comps_to_disable for comp in entry.comps) \
+ and not entry.disabled:
+ # handle commenting ourselves - it handles lines with
+ # options better
+ comment = SourceEntry('# ' + str(entry))
+ output.append(comment)
+
+ entry.comps = [comp for comp in entry.comps
+ if comp not in comps_to_disable]
+ if entry.comps:
+ output.append(entry)
+ else:
+ output.append(entry)
+ return output
- newsrc = ""
- for line in retsrc.splitlines(True):
- if line.startswith("#"):
- newsrc += line
- continue
- # sources.list allow options in cols[1] which can have spaces
- # so the actual suite can be [2] or later. example:
- # deb [ arch=amd64,armel k=v ] http://example.com/debian
- cols = line.split()
- if len(cols) > 1:
- pcol = 2
- if cols[1].startswith("["):
- for col in cols[1:]:
- pcol += 1
- if col.endswith("]"):
- break
+def update_dist(entries, release):
+ for entry in entries:
+ entry.dist = util.render_string(entry.dist, {'RELEASE': release})
+ return entries
- if cols[pcol] == releasesuite:
- line = '# suite disabled by curtin: %s' % line
- newsrc += line
- retsrc = newsrc
- return retsrc
+def mirror_to_placeholder(entries, mirror, placeholder):
+ """ mirror_to_placeholder
+ replace the specified mirror in a template with a placeholder string
+ Checks for existance of the expected mirror and warns if not found
+ """
+ mirrors = [mirror]
+ if mirror[-1] == '/':
+ mirrors.append(mirror[:-1])
+
+ for entry in entries:
+ if entry.uri in mirrors:
+ entry.uri = placeholder
+
+
+def update_uri(entries, mirrors, target, from_file):
+ defaults = get_default_mirrors(distro.get_architecture(target))
+ if from_file:
+ # when loading from an existing file, we also replace default
+ # URIs with configured mirrors
+ mirror_to_placeholder(entries, defaults['PRIMARY'],
+ mirrors["MIRROR"])
+ mirror_to_placeholder(entries, defaults['SECURITY'],
+ mirrors["SECURITY"])
+
+ for entry in entries:
+ entry.uri = util.render_string(entry.uri, mirrors)
+ return entries
+
+
+def entries_to_str(entries):
+ return ''.join([str(entry) + '\n' for entry in entries])
def generate_sources_list(cfg, release, mirrors, target=None):
@@ -285,34 +322,27 @@ def generate_sources_list(cfg, release, mirrors, target=None):
create a source.list file based on a custom or default template
by replacing mirrors and release in the template
"""
- default_mirrors = get_default_mirrors(distro.get_architecture(target))
aptsrc = "/etc/apt/sources.list"
- params = {'RELEASE': release}
- for k in mirrors:
- params[k] = mirrors[k]
tmpl = cfg.get('sources_list', None)
+ from_file = False
if tmpl is None:
LOG.info("No custom template provided, fall back to modify"
"mirrors in %s on the target system", aptsrc)
tmpl = util.load_file(paths.target_path(target, aptsrc))
- # Strategy if no custom template was provided:
- # - Only replacing mirrors
- # - no reason to replace "release" as it is from target anyway
- # - The less we depend upon, the more stable this is against changes
- # - warn if expected original content wasn't found
- tmpl = mirror_to_placeholder(tmpl, default_mirrors['PRIMARY'],
- "$MIRROR")
- tmpl = mirror_to_placeholder(tmpl, default_mirrors['SECURITY'],
- "$SECURITY")
+ from_file = True
+
+ entries = [SourceEntry(line) for line in tmpl.splitlines(True)]
+ entries = update_uri(entries, mirrors, target, from_file)
+ entries = update_dist(entries, release)
+ entries = disable_suites(cfg.get('disable_suites'), entries, release)
+ entries = disable_components(cfg.get('disable_components'), entries)
+ output = entries_to_str(entries)
orig = paths.target_path(target, aptsrc)
if os.path.exists(orig):
os.rename(orig, orig + ".curtin.old")
-
- rendered = util.render_string(tmpl, params)
- disabled = disable_suites(cfg.get('disable_suites'), rendered, release)
- util.write_file(paths.target_path(target, aptsrc), disabled, mode=0o644)
+ util.write_file(paths.target_path(target, aptsrc), output, mode=0o644)
def apply_preserve_sources_list(target):
diff --git a/doc/topics/apt_source.rst b/doc/topics/apt_source.rst
index f996c53..cf0f8bd 100644
--- a/doc/topics/apt_source.rst
+++ b/doc/topics/apt_source.rst
@@ -35,6 +35,8 @@ Features
- disabling suites (=pockets)
+ - disabling components (multiverse, universe, restricted)
+
- per architecture mirror definition
diff --git a/examples/apt-source.yaml b/examples/apt-source.yaml
index 695c696..a3ff8b0 100644
--- a/examples/apt-source.yaml
+++ b/examples/apt-source.yaml
@@ -27,8 +27,8 @@ apt:
#
# This is an empty list by default, so nothing is disabled.
#
- # If given, those suites are removed from sources.list after all other
- # modifications have been made.
+ # If given, those suites are removed from sources.list after most other
+ # modifications have been made, but before component removal.
# Suites are even disabled if no other modification was made,
# but not if is preserve_sources_list is active.
# There is a special alias “$RELEASE” as in the sources that will be replace
@@ -45,12 +45,26 @@ apt:
# There is no harm in specifying a suite to be disabled that is not found in
# the source.list file (just a no-op then)
#
- # Note: Lines don’t get deleted, but disabled by being converted to a comment.
# The following example disables all usual defaults except $RELEASE-security.
# On top it disables a custom suite called "mysuite"
disable_suites: [$RELEASE-updates, backports, $RELEASE, mysuite]
- # 1.3 primary/security
+ # 1.3 disable_components
+ #
+ # This is an empty list by default, so nothing is disabled.
+ #
+ # If given, those components are removed from sources.list after all other
+ # modifications have been made.
+ # Components are even disabled if no other modification was made,
+ # but not if is preserve_sources_list is active.
+ #
+ # There is no harm in specifying a component to be disabled that is not found
+ # in the source.list file (just a no-op then)
+ #
+ # The following example disables all usual default components except main.
+ disable_components: [restricted, universe, multiverse]
+
+ # 1.4 primary/security
#
# define a custom (e.g. localized) mirror that will be used in sources.list
# and any custom sources entries for deb / deb-src lines.
@@ -90,7 +104,7 @@ apt:
# primary: http://archive.ubuntu.com/ubuntu
# security: http://security.ubuntu.com/ubuntu
- # 1.4 sources_list
+ # 1.5 sources_list
#
# Provide a custom template for rendering sources.list
# without one provided curtin will try to modify the sources.list it finds
@@ -105,7 +119,7 @@ apt:
deb $PRIMARY $RELEASE universe restricted
deb $SECURITY $RELEASE-security multiverse
- # 1.5 conf
+ # 1.6 conf
#
# Any apt config string that will be made available to apt
# see the APT.CONF(5) man page for details what can be specified
@@ -117,7 +131,7 @@ apt:
};
};
- # 1.6 (http_|ftp_|https_)proxy
+ # 1.7 (http_|ftp_|https_)proxy
#
# Proxies are the most common apt.conf option, so that for simplified use
# there is a shortcut for those. Those get automatically translated into the
@@ -129,7 +143,7 @@ apt:
ftp_proxy: ftp://[[user][:pass]@]host[:port]/
https_proxy: https://[[user][:pass]@]host[:port]/
- # 1.7 add_apt_repo_match
+ # 1.8 add_apt_repo_match
#
# 'source' entries in apt-sources that match this python regex
# expression will be passed to add-apt-repository
diff --git a/tests/unittests/test_apt_source.py b/tests/unittests/test_apt_source.py
index 6556399..9c1d828 100644
--- a/tests/unittests/test_apt_source.py
+++ b/tests/unittests/test_apt_source.py
@@ -7,11 +7,14 @@ import glob
import os
import re
import socket
+import tempfile
import mock
from mock import call
+from aptsources.sourceslist import SourceEntry
+
from curtin import distro
from curtin import gpg
from curtin import util
@@ -63,6 +66,18 @@ class PseudoChrootableTarget(util.ChrootableTarget):
ChrootableTargetStr = "curtin.commands.apt_config.util.ChrootableTarget"
+def entryify(data):
+ return [SourceEntry(line) for line in data.splitlines()]
+
+
+def lineify(entries):
+ out = apt_config.entries_to_str(entries)
+ # the tests are written without the trailing newline,
+ # but we don't want to remove multiple of them
+ out = out[:-1] if len(out) > 0 and out[-1] == '\n' else out
+ return out
+
+
class TestAptSourceConfig(CiTestCase):
""" TestAptSourceConfig
Main Class to test apt configs
@@ -758,6 +773,7 @@ class TestAptSourceConfig(CiTestCase):
def test_disable_suites(self):
"""test_disable_suites - disable_suites with many configurations"""
release = "xenial"
+
orig = """deb http://ubuntu.com//ubuntu xenial main
deb http://ubuntu.com//ubuntu xenial-updates main
deb http://ubuntu.com//ubuntu xenial-security main
@@ -771,39 +787,38 @@ deb http://ubuntu.com//ubuntu xenial-updates main
deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# single disable release suite
disabled = ["$RELEASE"]
- expect = """\
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial main
+ expect = """# deb http://ubuntu.com//ubuntu xenial main
deb http://ubuntu.com//ubuntu xenial-updates main
deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# single disable other suite
disabled = ["$RELEASE-updates"]
expect = """deb http://ubuntu.com//ubuntu xenial main
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-updates main
+# deb http://ubuntu.com//ubuntu xenial-updates main
deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# multi disable
disabled = ["$RELEASE-updates", "$RELEASE-security"]
expect = """deb http://ubuntu.com//ubuntu xenial main
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-updates main
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-security main
+# deb http://ubuntu.com//ubuntu xenial-updates main
+# deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# multi line disable (same suite multiple times in input)
disabled = ["$RELEASE-updates", "$RELEASE-security"]
@@ -815,14 +830,14 @@ deb http://UBUNTU.com//ubuntu xenial-updates main
deb http://UBUNTU.COM//ubuntu xenial-updates main
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
expect = """deb http://ubuntu.com//ubuntu xenial main
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-updates main
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-security main
+# deb http://ubuntu.com//ubuntu xenial-updates main
+# deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
-# suite disabled by curtin: deb http://UBUNTU.com//ubuntu xenial-updates main
-# suite disabled by curtin: deb http://UBUNTU.COM//ubuntu xenial-updates main
+# deb http://UBUNTU.com//ubuntu xenial-updates main
+# deb http://UBUNTU.COM//ubuntu xenial-updates main
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# comment in input
disabled = ["$RELEASE-updates", "$RELEASE-security"]
@@ -835,15 +850,15 @@ deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://UBUNTU.COM//ubuntu xenial-updates main
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
expect = """deb http://ubuntu.com//ubuntu xenial main
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-updates main
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-security main
+# deb http://ubuntu.com//ubuntu xenial-updates main
+# deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
#foo
-#deb http://UBUNTU.com//ubuntu xenial-updates main
-# suite disabled by curtin: deb http://UBUNTU.COM//ubuntu xenial-updates main
+# deb http://UBUNTU.com//ubuntu xenial-updates main
+# deb http://UBUNTU.COM//ubuntu xenial-updates main
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# single disable custom suite
disabled = ["foobar"]
@@ -854,9 +869,9 @@ deb http://ubuntu.com/ubuntu/ foobar main"""
expect = """deb http://ubuntu.com//ubuntu xenial main
deb http://ubuntu.com//ubuntu xenial-updates main
deb http://ubuntu.com//ubuntu xenial-security main
-# suite disabled by curtin: deb http://ubuntu.com/ubuntu/ foobar main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+# deb http://ubuntu.com/ubuntu/ foobar main"""
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# single disable non existing suite
disabled = ["foobar"]
@@ -868,8 +883,8 @@ deb http://ubuntu.com/ubuntu/ notfoobar main"""
deb http://ubuntu.com//ubuntu xenial-updates main
deb http://ubuntu.com//ubuntu xenial-security main
deb http://ubuntu.com/ubuntu/ notfoobar main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# single disable suite with option
disabled = ["$RELEASE-updates"]
@@ -879,12 +894,12 @@ deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
expect = """deb http://ubuntu.com//ubuntu xenial main
-# suite disabled by curtin: deb [a=b] http://ubu.com//ubu xenial-updates main
+# deb [a=b] http://ubu.com//ubu xenial-updates main
deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# single disable suite with more options and auto $RELEASE expansion
disabled = ["updates"]
@@ -894,13 +909,12 @@ deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
expect = """deb http://ubuntu.com//ubuntu xenial main
-# suite disabled by curtin: deb [a=b c=d] \
-http://ubu.com//ubu xenial-updates main
+# deb [a=b c=d] http://ubu.com//ubu xenial-updates main
deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
# single disable suite while options at others
disabled = ["$RELEASE-security"]
@@ -911,25 +925,168 @@ deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
expect = """deb http://ubuntu.com//ubuntu xenial main
deb [arch=foo] http://ubuntu.com//ubuntu xenial-updates main
-# suite disabled by curtin: deb http://ubuntu.com//ubuntu xenial-security main
+# deb http://ubuntu.com//ubuntu xenial-security main
deb-src http://ubuntu.com//ubuntu universe multiverse
deb http://ubuntu.com/ubuntu/ xenial-proposed main"""
- result = apt_config.disable_suites(disabled, orig, release)
- self.assertEqual(expect, result)
+ result = apt_config.disable_suites(disabled, entryify(orig), release)
+ self.assertEqual(expect, lineify(result))
def test_disable_suites_blank_lines(self):
"""test_disable_suites_blank_lines - ensure blank lines allowed"""
- lines = ["deb %(repo)s %(rel)s main universe",
- "",
- "deb %(repo)s %(rel)s-updates main universe",
- " # random comment",
- "#comment here",
- ""]
rel = "trusty"
- repo = 'http://example.com/mirrors/ubuntu'
- orig = "\n".join(lines) % {'repo': repo, 'rel': rel}
- self.assertEqual(
- orig, apt_config.disable_suites(["proposed"], orig, rel))
+
+ orig = """
+deb http://example.com/mirrors/ubuntu trusty main universe
+
+deb http://example.com/mirrors/ubuntu trusty-updates main universe
+
+deb http://example.com/mirrors/ubuntu trusty-proposed main universe
+
+#comment here"""
+ expect = """
+deb http://example.com/mirrors/ubuntu trusty main universe
+
+deb http://example.com/mirrors/ubuntu trusty-updates main universe
+
+# deb http://example.com/mirrors/ubuntu trusty-proposed main universe
+
+#comment here"""
+ disabled = ["proposed"]
+ result = apt_config.disable_suites(disabled, entryify(orig), rel)
+ self.assertEqual(expect, lineify(result))
+
+ def test_disable_components(self):
+ orig = """\
+deb http://ubuntu.com/ubuntu xenial main restricted universe multiverse
+deb http://ubuntu.com/ubuntu xenial-updates main restricted universe multiverse
+deb http://ubuntu.com/ubuntu xenial-security \
+main restricted universe multiverse
+deb-src http://ubuntu.com/ubuntu xenial main restricted universe multiverse
+deb http://ubuntu.com/ubuntu/ xenial-proposed \
+main restricted universe multiverse"""
+ expect = orig
+
+ # no-op
+ disabled = []
+ result = apt_config.disable_components(disabled, entryify(orig))
+ self.assertEqual(expect, lineify(result))
+
+ # no-op 2
+ disabled = None
+ result = apt_config.disable_components(disabled, entryify(orig))
+ self.assertEqual(expect, lineify(result))
+
+ # we don't disable main
+ disabled = ('main', )
+ result = apt_config.disable_components(disabled, entryify(orig))
+ self.assertEqual(expect, lineify(result))
+
+ # nonsense
+ disabled = ('asdf', )
+ result = apt_config.disable_components(disabled, entryify(orig))
+ self.assertEqual(expect, lineify(result))
+
+ # free-only
+ expect = """\
+# deb http://ubuntu.com/ubuntu xenial main restricted universe multiverse
+deb http://ubuntu.com/ubuntu xenial main universe
+# deb http://ubuntu.com/ubuntu xenial-updates main restricted \
+universe multiverse
+deb http://ubuntu.com/ubuntu xenial-updates main universe
+# deb http://ubuntu.com/ubuntu xenial-security main restricted \
+universe multiverse
+deb http://ubuntu.com/ubuntu xenial-security main universe
+# deb-src http://ubuntu.com/ubuntu xenial main restricted universe multiverse
+deb-src http://ubuntu.com/ubuntu xenial main universe
+# deb http://ubuntu.com/ubuntu/ xenial-proposed main restricted \
+universe multiverse
+deb http://ubuntu.com/ubuntu/ xenial-proposed main universe"""
+ disabled = ('restricted', 'multiverse')
+ result = apt_config.disable_components(disabled, entryify(orig))
+ self.assertEqual(expect, lineify(result))
+
+ # skip line when this component is the last
+ orig = """\
+deb http://ubuntu.com/ubuntu xenial main universe multiverse
+deb http://ubuntu.com/ubuntu xenial-updates universe
+deb http://ubuntu.com/ubuntu xenial-security universe multiverse"""
+ expect = """\
+# deb http://ubuntu.com/ubuntu xenial main universe multiverse
+deb http://ubuntu.com/ubuntu xenial main
+# deb http://ubuntu.com/ubuntu xenial-updates universe
+# deb http://ubuntu.com/ubuntu xenial-security universe multiverse"""
+ disabled = ('universe', 'multiverse')
+ result = apt_config.disable_components(disabled, entryify(orig))
+ self.assertEqual(expect, lineify(result))
+
+ # comment everything
+ orig = """\
+deb http://ubuntu.com/ubuntu xenial-security universe multiverse"""
+ expect = """\
+# deb http://ubuntu.com/ubuntu xenial-security universe multiverse"""
+ disabled = ('universe', 'multiverse')
+ result = apt_config.disable_components(disabled, entryify(orig))
+ self.assertEqual(expect, lineify(result))
+
+ # double-hash comment
+ orig = """\
+
+## Major bug fix updates produced after the final release of the
+## distribution.
+
+deb http://archive.ubuntu.com/ubuntu/ impish-updates main restricted
+# deb http://archive.ubuntu.com/ubuntu/ impish-updates main restricted"""
+ expect = """\
+
+## Major bug fix updates produced after the final release of the
+## distribution.
+
+# deb http://archive.ubuntu.com/ubuntu/ impish-updates main restricted
+deb http://archive.ubuntu.com/ubuntu/ impish-updates main
+# deb http://archive.ubuntu.com/ubuntu/ impish-updates main restricted"""
+ disabled = ('restricted', )
+ result = apt_config.disable_components(disabled, entryify(orig))
+ self.assertEqual(expect, lineify(result))
+
+
+ @mock.patch("curtin.util.write_file")
+ @mock.patch("curtin.distro.get_architecture")
+ def test_generate_with_options(self, get_arch, write_file):
+ get_arch.return_value = "amd64"
+ orig = """deb http://ubuntu.com//ubuntu $RELEASE main
+# stuff things
+
+deb http://ubuntu.com//ubuntu $RELEASE-updates main
+deb http://ubuntu.com//ubuntu $RELEASE-security main
+deb-src http://ubuntu.com//ubuntu $RELEASE universe multiverse
+# deb http://ubuntu.com/ubuntu/ $RELEASE-proposed main
+deb [a=b] http://ubuntu.com/ubuntu/ $RELEASE-backports main
+"""
+ expect = """deb http://ubuntu.com//ubuntu xenial main
+# stuff things
+
+deb http://ubuntu.com//ubuntu xenial-updates main
+deb http://ubuntu.com//ubuntu xenial-security main
+deb-src http://ubuntu.com//ubuntu xenial universe multiverse
+# deb http://ubuntu.com/ubuntu/ xenial-proposed main
+# deb [a=b] http://ubuntu.com/ubuntu/ $RELEASE-backports main
+"""
+ # $RELEASE in backports doesn't get expanded because the line is
+ # considered invalid because of the options. So when the line
+ # gets commented out, it comments out the original line, not
+ # what we've modifed it to.
+ rel = 'xenial'
+ mirrors = {'PRIMARY': 'http://ubuntu.com/ubuntu/'}
+
+ cfg = {
+ 'preserve_sources_list': False,
+ 'sources_list': orig,
+ 'disable_suites': ['backports'],
+ }
+ with tempfile.TemporaryDirectory() as trgt:
+ apt_config.generate_sources_list(cfg, rel, mirrors, trgt)
+ filepath = os.path.join(trgt, 'etc/apt/sources.list')
+ write_file.assert_called_with(filepath, expect, mode=0o644)
class TestDebconfSelections(CiTestCase):
diff --git a/tests/vmtests/__init__.py b/tests/vmtests/__init__.py
index 0b19d8f..fd6c246 100644
--- a/tests/vmtests/__init__.py
+++ b/tests/vmtests/__init__.py
@@ -1631,6 +1631,9 @@ class VMBaseClass(TestCase):
def check_file_regex(self, filename, regex):
self.assertRegex(self.load_collect_file(filename), regex)
+ def not_file_regex(self, filename, regex):
+ self.assertNotRegex(self.load_collect_file(filename), regex)
+
# To get rid of deprecation warning in python 3.
def assertRegex(self, s, r):
try:
@@ -1640,6 +1643,14 @@ class VMBaseClass(TestCase):
# Python 2.
self.assertRegexpMatches(s, r)
+ def assertNotRegex(self, s, r):
+ try:
+ # Python 3.
+ super(VMBaseClass, self).assertNotRegex(s, r)
+ except AttributeError:
+ # Python 2.
+ self.assertNotRegexpMatches(s, r)
+
def get_blkid_data(self, blkid_file):
data = self.load_collect_file(blkid_file)
ret = {}
diff --git a/tests/vmtests/test_apt_source.py b/tests/vmtests/test_apt_source.py
index a090ffa..9d00dc8 100644
--- a/tests/vmtests/test_apt_source.py
+++ b/tests/vmtests/test_apt_source.py
@@ -164,9 +164,8 @@ class TestAptSrcDisablePockets(TestAptSrcAbs):
r"deb.*us.archive.ubuntu.com")
self.check_file_regex("sources.list",
r"deb.*security.ubuntu.com")
- # updates disabled
- self.check_file_regex("sources.list",
- r"# suite disabled by curtin:.*-updates")
+ # updates disabled and not present
+ self.not_file_regex("sources.list", r"# .*-updates")
class TestAptSrcModifyArches(TestAptSrcModify):
Follow ups