← Back to team overview

curtin-dev team mailing list archive

[Merge] ~dbungert/curtin:command-apt-components into curtin:master

 

Dan Bungert has proposed merging ~dbungert/curtin:command-apt-components into curtin:master with ~dbungert/curtin:command-apt-libapt-v4 as a prerequisite.

Commit message:
command/apt: disable_components

Add the ability to disable components in source.list.
Intentionally refuses to not disable the main component.

Requested reviews:
  curtin developers (curtin-dev)

For more details, see:
https://code.launchpad.net/~dbungert/curtin/+git/curtin/+merge/408391
-- 
Your team curtin developers is requested to review the proposed merge of ~dbungert/curtin:command-apt-components into curtin:master.
diff --git a/curtin/commands/apt_config.py b/curtin/commands/apt_config.py
index 1082c63..cd5548e 100644
--- a/curtin/commands/apt_config.py
+++ b/curtin/commands/apt_config.py
@@ -283,6 +283,33 @@ def disable_suites(disabled, src, release):
     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
+
+
 def update_dist(entries, release):
     for entry in entries:
         entry.dist = util.render_string(entry.dist, {'RELEASE': release})
@@ -317,6 +344,7 @@ def generate_sources_list(cfg, release, mirrors, target=None):
     entries = update_mirrors(entries, mirrors)
     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)
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 01e70ad..48fb820 100644
--- a/tests/unittests/test_apt_source.py
+++ b/tests/unittests/test_apt_source.py
@@ -955,6 +955,99 @@ deb http://example.com/mirrors/ubuntu trusty-updates main universe
         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):

Follow ups