summaryrefslogtreecommitdiffstats
path: root/tests/test_aptsources.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_aptsources.py')
-rw-r--r--tests/test_aptsources.py1573
1 files changed, 1573 insertions, 0 deletions
diff --git a/tests/test_aptsources.py b/tests/test_aptsources.py
new file mode 100644
index 0000000..1e04552
--- /dev/null
+++ b/tests/test_aptsources.py
@@ -0,0 +1,1573 @@
+#!/usr/bin/python3
+
+import copy
+import os
+import tempfile
+import unittest
+
+import apt_pkg
+import testcommon
+
+import aptsources.distro
+import aptsources.sourceslist
+
+
+class TestAptSources(testcommon.TestCase):
+ def setUp(self):
+ testcommon.TestCase.setUp(self)
+ if apt_pkg.config["APT::Architecture"] not in ("i386", "amd64"):
+ apt_pkg.config.set("APT::Architecture", "i386")
+ apt_pkg.config.set("Dir::Etc", os.getcwd())
+ apt_pkg.config.set("Dir::Etc::sourceparts", tempfile.mkdtemp())
+ if os.path.exists("./build/data/templates"):
+ self.templates = os.path.abspath("./build/data/templates")
+ elif os.path.exists("../build/data/templates"):
+ self.templates = os.path.abspath("../build/data/templates")
+ else:
+ self.templates = "/usr/share/python-apt/templates/"
+
+ def tearDown(self):
+ aptsources.distro._OSRelease.OS_RELEASE_FILE = (
+ aptsources.distro._OSRelease.DEFAULT_OS_RELEASE_FILE
+ )
+ if "LSB_ETC_LSB_RELEASE" in os.environ:
+ del os.environ["LSB_ETC_LSB_RELEASE"]
+
+ def testIsMirror(self):
+ """aptsources: Test mirror detection."""
+ yes = aptsources.sourceslist.is_mirror(
+ "http://archive.ubuntu.com", "http://de.archive.ubuntu.com"
+ )
+ no = aptsources.sourceslist.is_mirror(
+ "http://archive.ubuntu.com", "http://ftp.debian.org"
+ )
+ self.assertTrue(yes)
+ self.assertFalse(no)
+
+ def testSourcesListReading(self):
+ """aptsources: Test sources.list parsing."""
+ apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates)
+ self.assertEqual(len(sources.list), 10)
+ # test load
+ sources.list = []
+ sources.load("data/aptsources/sources.list")
+ self.assertEqual(len(sources.list), 10)
+
+ def testSourcesListReading_deb822(self):
+ """aptsources: Test sources.list parsing."""
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ self.assertEqual(len(sources.list), 5)
+ # test load
+ sources.list = []
+ sources.load("data/aptsources/sources.list.d/main.sources")
+ self.assertEqual(len(sources.list), 5)
+
+ for entry in sources.list:
+ self.assertFalse(entry.invalid)
+ self.assertFalse(entry.disabled)
+ self.assertEqual(entry.types, ["deb"])
+ self.assertEqual(entry.type, "deb")
+ self.assertEqual(entry.uris, ["http://de.archive.ubuntu.com/ubuntu/"])
+ self.assertEqual(entry.uri, "http://de.archive.ubuntu.com/ubuntu/")
+
+ self.assertEqual(sources.list[0].comps, ["main"])
+ self.assertEqual(sources.list[1].comps, ["restricted"])
+ self.assertEqual(sources.list[2].comps, ["universe"])
+ self.assertEqual(sources.list[3].comps, ["main"])
+ self.assertEqual(sources.list[4].comps, ["main"])
+
+ for entry in sources.list[:-1]:
+ self.assertIsNone(entry.trusted)
+
+ self.assertTrue(sources.list[-1].trusted)
+
+ for entry in sources.list[:-2]:
+ self.assertEqual(entry.architectures, [])
+ self.assertEqual(entry.suites, ["edgy"])
+ self.assertEqual(entry.dist, "edgy")
+
+ for entry in sources.list[-2:]:
+ self.assertEqual(entry.suites, ["natty"])
+ self.assertEqual(entry.dist, "natty")
+ self.assertEqual(entry.architectures, ["amd64", "i386"])
+
+ def testSourcesListWriting_deb822(self):
+ """aptsources: Test sources.list parsing."""
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ with tempfile.TemporaryDirectory() as tmpdir:
+ for entry in sources.list:
+ entry.file = os.path.join(tmpdir, os.path.basename(entry.file))
+
+ sources.save()
+
+ maxDiff = self.maxDiff
+ self.maxDiff = None
+ for file in os.listdir("data/aptsources/sources.list.d"):
+ with open(os.path.join("data/aptsources/sources.list.d", file)) as a:
+ with open(os.path.join(tmpdir, file)) as b:
+ self.assertEqual(a.read(), b.read(), f"file {file}")
+ self.maxDiff = maxDiff
+
+ def testSourcesListAdding(self):
+ """aptsources: Test additions to sources.list"""
+ apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates)
+ # test to add something that is already there (main)
+ before = copy.deepcopy(sources)
+ sources.add("deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["main"])
+ self.assertTrue(sources.list == before.list)
+ # test to add something that is already there (restricted)
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["restricted"]
+ )
+ self.assertTrue(sources.list == before.list)
+
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "natty",
+ ["main"],
+ architectures=["amd64", "i386"],
+ )
+ self.assertTrue(sources.list == before.list)
+
+ # test to add something new: multiverse
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["multiverse"]
+ )
+ found = False
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ and "multiverse" in entry.comps
+ ):
+ found = True
+ break
+ self.assertTrue(found)
+
+ # add a new natty entry without architecture specification
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "natty", ["multiverse"]
+ )
+ found = False
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "natty"
+ and entry.architectures == []
+ and "multiverse" in entry.comps
+ ):
+ found = True
+ break
+ self.assertTrue(found)
+
+ # Add universe to existing multi-arch line
+ sources.add(
+ "deb",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "natty",
+ ["universe"],
+ architectures=["i386", "amd64"],
+ )
+ found = False
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "natty"
+ and set(entry.architectures) == {"amd64", "i386"}
+ and set(entry.comps) == {"main", "universe"}
+ ):
+ found = True
+ break
+ self.assertTrue(found)
+ # test to add something new: multiverse *and*
+ # something that is already there
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["universe", "something"],
+ )
+ found_universe = 0
+ found_something = 0
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ ):
+ for c in entry.comps:
+ if c == "universe":
+ found_universe += 1
+ if c == "something":
+ found_something += 1
+ # print "\n".join([s.str() for s in sources])
+ self.assertEqual(found_something, 1)
+ self.assertEqual(found_universe, 1)
+
+ def testSourcesListAdding_deb822(self):
+ """aptsources: Test additions to sources.list"""
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ # test to add something that is already there (main)
+ before = copy.deepcopy(sources)
+ sources.add("deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["main"])
+ self.assertEqual(sources.list, before.list)
+ # test to add something that is already there (restricted)
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["restricted"]
+ )
+ self.assertTrue(sources.list == before.list)
+
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "natty",
+ ["main"],
+ architectures=["amd64", "i386"],
+ )
+ self.assertEqual(
+ [e.str() for e in sources.list], [e.str() for e in before.list]
+ )
+
+ # test to add something new: multiverse
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["multiverse"]
+ )
+ found = False
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ and "multiverse" in entry.comps
+ ):
+ found = True
+ break
+ self.assertTrue(found)
+
+ # add a new natty entry without architecture specification
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "natty", ["multiverse"]
+ )
+ found = False
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "natty"
+ and entry.architectures == []
+ and "multiverse" in entry.comps
+ ):
+ found = True
+ break
+ self.assertTrue(found)
+
+ # Add universe to existing multi-arch line
+ sources.add(
+ "deb",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "natty",
+ ["universe"],
+ architectures=["i386", "amd64"],
+ )
+ found = False
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "natty"
+ and set(entry.architectures) == {"amd64", "i386"}
+ and set(entry.comps) == {"main", "universe"}
+ ):
+ found = True
+ break
+ self.assertTrue(found)
+ # test to add something new: multiverse *and*
+ # something that is already there
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["universe", "something"],
+ )
+ found_universe = 0
+ found_something = 0
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ ):
+ for c in entry.comps:
+ if c == "universe":
+ found_universe += 1
+ if c == "something":
+ found_something += 1
+ # print "\n".join([s.str() for s in sources])
+ self.assertEqual(found_something, 1)
+ self.assertEqual(found_universe, 1)
+
+ def testAddingWithComment_deb822(self):
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+ self._commonTestAddingWithComment()
+
+ def testAddingWithComment_short(self):
+ apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list")
+ self._commonTestAddingWithComment()
+
+ def _commonTestAddingWithComment(self):
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+
+ # test to add something that is already there (main); loses comment
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["main"],
+ comment="this will be lost",
+ )
+ self.assertTrue(sources.list == before.list)
+ for entry in sources:
+ self.assertNotEqual(entry.comment, "this will be lost")
+
+ # test to add component to existing entry: multiverse; loses comment
+ sources.add(
+ "deb",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["multiverse"],
+ comment="this will be lost",
+ )
+ for entry in sources:
+ self.assertNotEqual(entry.comment, "this will be lost")
+
+ before = copy.deepcopy(sources)
+ # test to add entirely new entry; retains comment
+ sources.add(
+ "deb-src",
+ "http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["main"],
+ comment="this will appear",
+ file=sources.list[0].file, # make sure we test the deb822 code path
+ )
+ self.assertNotEqual(sources.list, before.list)
+ self.assertEqual(len(sources.list), len(before.list) + 1)
+ found = False
+ for entry in sources:
+ if (
+ entry.type == "deb-src"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ and entry.comment == "this will appear"
+ and "main" in entry.comps
+ ):
+ found = True
+ break
+ self.assertTrue(found)
+
+ def testInsertion_deb822(self):
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+
+ # test to insert something that is already there (universe); does not
+ # move existing entry (remains at index 2)
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["universe"], pos=0
+ )
+ self.assertTrue(sources.list == before.list)
+ entry = list(sources)[2]
+ self.assertEqual(entry.type, "deb")
+ self.assertEqual(entry.uri, "http://de.archive.ubuntu.com/ubuntu/")
+ self.assertEqual(entry.dist, "edgy")
+ self.assertIn("universe", entry.comps)
+
+ # test add component to existing entry: multiverse; does not move
+ # entry to which it is appended (remains at index 0)
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["multiverse"], pos=2
+ )
+ entry = list(sources)[0]
+ self.assertTrue(
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ and {"main", "multiverse"} <= set(entry.comps)
+ )
+
+ # test to add entirely new entry; inserted at 0
+ sources.add(
+ "deb-src", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["main"], pos=0
+ )
+ entry = list(sources)[0]
+ self.assertTrue(
+ entry.type == "deb-src"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ and "main" in entry.comps
+ )
+
+ def testInsertion(self):
+ apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates)
+
+ # test to insert something that is already there (universe); does not
+ # move existing entry (remains at index 2)
+ before = copy.deepcopy(sources)
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["universe"], pos=0
+ )
+ self.assertTrue(sources.list == before.list)
+ entry = list(sources)[5]
+ self.assertTrue(
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ and "universe" in entry.comps
+ )
+
+ # test add component to existing entry: multiverse; does not move
+ # entry to which it is appended (remains at index 0)
+ sources.add(
+ "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["multiverse"], pos=2
+ )
+ entry = list(sources)[1]
+ self.assertTrue(
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ and {"main", "multiverse"} <= set(entry.comps)
+ )
+
+ # test to add entirely new entry; inserted at 0
+ sources.add(
+ "deb-src", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["main"], pos=0
+ )
+ entry = list(sources)[0]
+ self.assertTrue(
+ entry.type == "deb-src"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and entry.dist == "edgy"
+ and "main" in entry.comps
+ )
+
+ def testDuplication_short(self):
+ apt_pkg.config.set(
+ "Dir::Etc::sourcelist", "data/aptsources/sources.list.testDuplication"
+ )
+ return self.commonTestDuplication()
+
+ def testDuplication_deb822(self):
+ apt_pkg.config.set(
+ "Dir::Etc::sourceparts", "data/aptsources/sources.list.d.testDuplication"
+ )
+ return self.commonTestDuplication()
+
+ def commonTestDuplication(self):
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ test_url = "http://ppa.launchpad.net/me/myproject/ubuntu"
+ # test to add something that is already there (enabled)
+ before = copy.deepcopy(sources)
+ sources.add("deb", test_url, "xenial", ["main"])
+ self.assertEqual(sources.list, before.list)
+ # test to add something that is already there (disabled)
+ sources.add("# deb-src", test_url, "xenial", ["main"])
+ self.assertEqual(sources.list, before.list)
+ # test to enable something that is already there
+ sources.add("deb-src", test_url, "xenial", ["main"])
+ found = False
+ self.assertEqual(len(sources.list), 2)
+ for entry in sources:
+ if (
+ entry.type == "deb-src"
+ and not entry.disabled
+ and entry.uri == test_url
+ and entry.dist == "xenial"
+ and entry.architectures == []
+ and entry.comps == ["main"]
+ ):
+ found = True
+ break
+ self.assertTrue(found)
+
+ def testMatcher_short(self):
+ """aptsources: Test matcher"""
+ apt_pkg.config.set(
+ "Dir::Etc::sourcelist", "data/aptsources/" "sources.list.testDistribution"
+ )
+ return self.commonTestMatcher()
+
+ def testMatcher_deb822(self):
+ """aptsources: Test matcher"""
+ apt_pkg.config.set(
+ "Dir::Etc::sourceparts",
+ "data/aptsources/" "sources.list.d.testDistribution",
+ )
+ return self.commonTestMatcher()
+
+ def commonTestMatcher(self):
+ """aptsources: Test matcher"""
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu",
+ codename="bionic",
+ description="Ubuntu 18.04 LTS",
+ release="18.04",
+ )
+ distro.get_sources(sources)
+ # test if all suits of the current distro were detected correctly
+ self.assertNotEqual(sources.list, [])
+ for s in sources:
+ if not s.template:
+ self.fail("source entry '%s' has no matcher" % s)
+
+ # Hack in a check for splitting of fields here.
+ if sources.list[-1].file.endswith(".sources"):
+ self.assertEqual(
+ sources.list[-1].uris, ["cdrom:[Ubuntu 8.04 _Hardy Heron_]"]
+ )
+ self.assertEqual(sources.list[-1].uri, "cdrom:[Ubuntu 8.04 _Hardy Heron_]")
+
+ def testMultiArch(self):
+ """aptsources: Test multi-arch parsing"""
+
+ apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ assert not sources.list[8].invalid
+ assert sources.list[8].type == "deb"
+ assert sources.list[8].architectures == ["amd64", "i386"]
+ assert sources.list[8].uri == "http://de.archive.ubuntu.com/ubuntu/"
+ assert sources.list[8].dist == "natty"
+ assert sources.list[8].comps == ["main"]
+ assert sources.list[8].line.strip() == str(sources.list[8])
+ assert sources.list[8].trusted is None
+
+ def testMultiArch_deb822(self):
+ """aptsources: Test multi-arch parsing"""
+
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ assert not sources.list[3].invalid
+ assert sources.list[3].type == "deb"
+ assert sources.list[3].architectures == ["amd64", "i386"]
+ assert sources.list[3].uri == "http://de.archive.ubuntu.com/ubuntu/"
+ assert sources.list[3].dist == "natty"
+ assert sources.list[3].comps == ["main"]
+ self.assertEqual(sources.list[3].line.strip(), str(sources.list[3]))
+ self.assertIsNone(sources.list[3].trusted)
+
+ def testMultipleOptions(self):
+ """aptsources: Test multi-arch parsing"""
+
+ apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates)
+ assert sources.list[9].invalid is False
+ assert sources.list[9].type == "deb"
+ assert sources.list[9].architectures == ["amd64", "i386"]
+ self.assertEqual(sources.list[9].uri, "http://de.archive.ubuntu.com/ubuntu/")
+ assert sources.list[9].dist == "natty"
+ assert sources.list[9].comps == ["main"]
+ assert sources.list[9].trusted
+ assert sources.list[9].line.strip() == str(sources.list[9])
+
+ def testMultipleOptions_deb822(self):
+ """aptsources: Test multi-arch parsing"""
+
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ assert sources.list[4].invalid is False
+ assert sources.list[4].type == "deb"
+ assert sources.list[4].architectures == ["amd64", "i386"]
+ self.assertEqual(sources.list[4].uri, "http://de.archive.ubuntu.com/ubuntu/")
+ assert sources.list[4].dist == "natty"
+ assert sources.list[4].comps == ["main"]
+ assert sources.list[4].trusted
+ assert sources.list[4].line.strip() == str(sources.list[4])
+
+ def test_enable_component(self):
+ target = "./data/aptsources/sources.list.enable_comps"
+ line = "deb http://archive.ubuntu.com/ubuntu lucid main\n"
+ with open(target, "w") as target_file:
+ target_file.write(line)
+ apt_pkg.config.set("Dir::Etc::sourcelist", target)
+ sources = aptsources.sourceslist.SourcesList(True, self.templates)
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04"
+ )
+ # and get the sources
+ distro.get_sources(sources)
+ # test enable_component
+ comp = "multiverse"
+ distro.enable_component(comp)
+ comps = set()
+ for entry in sources:
+ comps = comps.union(set(entry.comps))
+ self.assertTrue("multiverse" in comps)
+ self.assertTrue("universe" in comps)
+
+ def test_enable_component_deb822(self):
+ target = (
+ apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources"
+ )
+ line = "Types: deb\nURIs: http://archive.ubuntu.com/ubuntu\nSuites: lucid\nComponents: main\n"
+ with open(target, "w") as target_file:
+ target_file.write(line)
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04"
+ )
+ # and get the sources
+ distro.get_sources(sources)
+ # test enable_component
+ comp = "multiverse"
+ distro.enable_component(comp)
+ comps = set()
+ for entry in sources:
+ comps = comps.union(set(entry.comps))
+ self.assertTrue("multiverse" in comps)
+ self.assertTrue("universe" in comps)
+
+ def test_enable_component_deb822_multi(self):
+ apt_pkg.config.set("Dir::Etc::sourcelist", "/dev/null")
+
+ target = (
+ apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources"
+ )
+ line = "Types: deb\nURIs: http://archive.ubuntu.com/ubuntu\nSuites: lucid lucid-updates\nComponents: main\n"
+ with open(target, "w") as target_file:
+ target_file.write(line)
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04"
+ )
+ # and get the sources
+ distro.get_sources(sources)
+ self.assertEqual(len(distro.main_sources), 1)
+ self.assertEqual(len(sources.list), 1)
+ # test enable_component
+ comp = "multiverse"
+ distro.enable_component(comp)
+ self.assertEqual(len(sources.list), 2) # split into two
+
+ self.assertEqual(
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu\n"
+ "Suites: lucid\n"
+ "Components: main multiverse universe",
+ str(sources.list[0]),
+ )
+ self.assertEqual(
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu\n"
+ "Suites: lucid-updates\n"
+ "Components: main multiverse universe",
+ str(sources.list[1]),
+ )
+
+ comps = set()
+ for entry in sources:
+ comps = comps.union(set(entry.comps))
+ self.assertTrue("multiverse" in comps)
+ self.assertTrue("universe" in comps)
+
+ sources.save()
+ self.assertEqual(
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu\n"
+ "Suites: lucid lucid-updates\n"
+ "Components: main multiverse universe",
+ str(sources.list[0]),
+ )
+
+ def test_enable_component_deb822_multi_mixed_origin(self):
+ apt_pkg.config.set("Dir::Etc::sourcelist", "/dev/null")
+
+ target = (
+ apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources"
+ )
+ line = "Types: deb\nURIs: http://archive.ubuntu.com/ubuntu http://example.com/\nSuites: lucid\nComponents: main\n"
+ with open(target, "w") as target_file:
+ target_file.write(line)
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04"
+ )
+ # and get the sources
+ distro.get_sources(sources)
+ self.assertEqual(len(distro.main_sources), 2)
+ self.assertEqual(len(sources.list), 1)
+ # test enable_component
+ comp = "multiverse"
+ distro.enable_component(comp)
+ self.assertEqual(len(sources.list), 2) # split into two
+
+ self.assertEqual(
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu\n"
+ "Suites: lucid\n"
+ "Components: main multiverse universe",
+ str(sources.list[0]),
+ )
+ self.assertEqual(
+ "Types: deb\n"
+ "URIs: http://example.com/\n"
+ "Suites: lucid\n"
+ "Components: main",
+ str(sources.list[1]),
+ )
+
+ sources.save()
+ self.assertEqual(
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu\n"
+ "Suites: lucid\n"
+ "Components: main multiverse universe",
+ str(sources.list[0]),
+ )
+ self.assertEqual(
+ "Types: deb\n"
+ "URIs: http://example.com/\n"
+ "Suites: lucid\n"
+ "Components: main",
+ str(sources.list[1]),
+ )
+
+ def test_enable_component_deb822_multi_mixed_ultimate(self):
+ apt_pkg.config.set("Dir::Etc::sourcelist", "/dev/null")
+
+ target = (
+ apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources"
+ )
+ line = "Types: deb deb-src\nURIs: http://archive.ubuntu.com/ubuntu http://example.com/\nSuites: lucid lucid-updates notalucid\nComponents: main\n"
+ with open(target, "w") as target_file:
+ target_file.write(line)
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04"
+ )
+ # and get the sources
+ distro.get_sources(sources)
+ self.assertEqual(len(distro.main_sources), 1)
+ self.assertEqual(len(sources.list), 1)
+ self.assertEqual(len(sources.exploded_list()), 12)
+ # test enable_component
+ comp = "multiverse"
+ distro.enable_component(comp)
+ self.assertEqual(len(sources.list), 12) # split into two
+
+ expected = []
+ for typ in "deb", "deb-src":
+ for uri in "http://archive.ubuntu.com/ubuntu", "http://example.com/":
+ for suite in "lucid", "lucid-updates", "notalucid":
+ comps = "main multiverse universe"
+ # unofficial source ends up without enablement
+ if uri == "http://example.com/" or suite == "notalucid":
+ comps = "main"
+ expected.append(
+ f"Types: {typ}\n"
+ f"URIs: {uri}\n"
+ f"Suites: {suite}\n"
+ f"Components: {comps}"
+ )
+
+ self.maxDiff = None
+ self.assertEqual(expected, list(map(str, sources.list)))
+ sources.save()
+
+ expected = [
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu\n"
+ "Suites: lucid lucid-updates\n"
+ "Components: main multiverse universe",
+ # unofficial suite
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu http://example.com/\n"
+ "Suites: notalucid\n"
+ "Components: main",
+ # unofficial mirror, FIXME: We'd rather merge the notalucid into here
+ "Types: deb deb-src\n"
+ "URIs: http://example.com/\n"
+ "Suites: lucid lucid-updates\n"
+ "Components: main",
+ ]
+ self.maxDiff = None
+ self.assertEqual(expected, list(map(str, sources.list)))
+
+ def test_deb822_explode(self):
+ apt_pkg.config.set("Dir::Etc::sourcelist", "/dev/null")
+ target = (
+ apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources"
+ )
+ line = "Types: deb\nURIs: http://archive.ubuntu.com/ubuntu\nSuites: lucid\nComponents: main\n"
+ with open(target, "w") as target_file:
+ target_file.write(line)
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+
+ self.assertEqual(len(sources.list), 1)
+ self.assertEqual(len(sources.exploded_list()), 1)
+ self.assertIsInstance(
+ sources.exploded_list()[0], aptsources.sourceslist.Deb822SourceEntry
+ )
+
+ sources.list[0].suites += ["fakesuite"]
+ self.assertEqual(len(sources.list), 1)
+ self.assertEqual(len(sources.exploded_list()), 2)
+ self.assertIsInstance(
+ sources.exploded_list()[0], aptsources.sourceslist.ExplodedDeb822SourceEntry
+ )
+ self.assertIsInstance(
+ sources.exploded_list()[1], aptsources.sourceslist.ExplodedDeb822SourceEntry
+ )
+ self.assertEqual(sources.list[0].suites, ["lucid", "fakesuite"])
+ sources.remove(sources.exploded_list()[1])
+ self.assertEqual(len(sources.list), 1)
+ self.assertEqual(len(sources.exploded_list()), 1)
+ self.assertEqual(sources.list[0].suites, ["lucid"])
+
+ sources.list[0].types += ["deb-src"]
+ self.assertEqual(len(sources.list), 1)
+ self.assertEqual(len(sources.exploded_list()), 2)
+ self.assertIsInstance(
+ sources.exploded_list()[0], aptsources.sourceslist.ExplodedDeb822SourceEntry
+ )
+ self.assertIsInstance(
+ sources.exploded_list()[1], aptsources.sourceslist.ExplodedDeb822SourceEntry
+ )
+ self.assertEqual(sources.list[0].types, ["deb", "deb-src"])
+ sources.remove(sources.exploded_list()[1])
+ self.assertEqual(len(sources.list), 1)
+ self.assertEqual(len(sources.exploded_list()), 1)
+ self.assertEqual(sources.list[0].types, ["deb"])
+
+ sources.list[0].uris += ["http://example.com"]
+ self.assertEqual(len(sources.list), 1)
+ self.assertEqual(len(sources.exploded_list()), 2)
+ self.assertIsInstance(
+ sources.exploded_list()[0], aptsources.sourceslist.ExplodedDeb822SourceEntry
+ )
+ self.assertIsInstance(
+ sources.exploded_list()[1], aptsources.sourceslist.ExplodedDeb822SourceEntry
+ )
+ self.assertEqual(
+ sources.list[0].uris,
+ ["http://archive.ubuntu.com/ubuntu", "http://example.com"],
+ )
+ sources.remove(sources.exploded_list()[1])
+ self.assertEqual(len(sources.list), 1)
+ self.assertEqual(len(sources.exploded_list()), 1)
+ self.assertEqual(sources.list[0].uris, ["http://archive.ubuntu.com/ubuntu"])
+
+ # test setting attributes
+ sources.list[0].uris += ["http://example.com"]
+ with self.assertRaises(AttributeError):
+ sources.exploded_list()[0].types = ["does not work"]
+ with self.assertRaises(AttributeError):
+ sources.exploded_list()[0].uris = ["does not work"]
+ with self.assertRaises(AttributeError):
+ sources.exploded_list()[0].suites = ["does not work"]
+ with self.assertRaises(AttributeError):
+ sources.exploded_list()[0].doesnotexist = ["does not work"]
+
+ # test overriding
+ sources.exploded_list()[0].type = "faketype"
+ self.assertEqual(sources.list[0].type, "faketype")
+ self.assertEqual(sources.list[1].type, "deb")
+ sources.exploded_list()[0].type = "deb"
+ self.assertEqual(sources.list[0].type, "deb")
+ self.assertEqual(sources.list[1].type, "deb")
+ sources.save()
+ self.assertEqual(len(sources.list), 1)
+
+ def testDistribution_short(self):
+ """aptsources: Test distribution detection."""
+ apt_pkg.config.set(
+ "Dir::Etc::sourcelist", "data/aptsources/" "sources.list.testDistribution"
+ )
+ return self.commonTestDistribution()
+
+ def testDistribution_deb822(self):
+ """aptsources: Test distribution detection."""
+ apt_pkg.config.set(
+ "Dir::Etc::sourceparts",
+ "data/aptsources/" "sources.list.d.testDistribution",
+ )
+ return self.commonTestDistribution()
+
+ def commonTestDistribution(self):
+ """aptsources: Test distribution detection."""
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu",
+ codename="bionic",
+ description="Ubuntu 18.04 LTS",
+ release="18.04",
+ )
+ distro.get_sources(sources)
+ # test if all suits of the current distro were detected correctly
+ dist_templates = set()
+ for s in sources:
+ if s.template:
+ dist_templates.add(s.template.name)
+ # print dist_templates
+ for d in (
+ "hardy",
+ "hardy-security",
+ "hardy-updates",
+ "intrepid",
+ "hardy-backports",
+ ):
+ self.assertTrue(d in dist_templates)
+ # test enable
+ comp = "restricted"
+ distro.enable_component(comp)
+ found = {}
+ for entry in sources:
+ if (
+ entry.type == "deb"
+ and entry.uri == "http://de.archive.ubuntu.com/ubuntu/"
+ and "edgy" in entry.dist
+ ):
+ for c in entry.comps:
+ if c == comp:
+ if entry.dist not in found:
+ found[entry.dist] = 0
+ found[entry.dist] += 1
+ # print "".join([s.str() for s in sources])
+ for key in found:
+ self.assertEqual(found[key], 1)
+
+ # add a not-already available component
+ comp = "multiverse"
+ distro.enable_component(comp)
+ found = {}
+ for entry in sources:
+ if entry.type == "deb" and entry.template and entry.template.name == "edgy":
+ for c in entry.comps:
+ if c == comp:
+ if entry.dist not in found.has_key:
+ found[entry.dist] = 0
+ found[entry.dist] += 1
+ # print "".join([s.str() for s in sources])
+ for key in found:
+ self.assertEqual(found[key], 1)
+
+ @unittest.skip("lsb-release test broken when it was added")
+ def test_os_release_distribution(self):
+ """os-release file can be read and is_like is populated accordingly"""
+ os.environ["LSB_ETC_LSB_RELEASE"] = os.path.abspath(
+ "./data/aptsources/lsb-release"
+ )
+ aptsources.distro._OSRelease.OS_RELEASE_FILE = os.path.abspath(
+ "./data/aptsources/os-release"
+ )
+ distro = aptsources.distro.get_distro()
+ # Everything but is_like comes from lsb_release, see TODO in
+ # get_distro.
+ self.assertEqual("Ubuntu", distro.id)
+ self.assertEqual("xenial", distro.codename)
+ self.assertEqual("Ubuntu 16.04.1 LTS", distro.description)
+ self.assertEqual("16.04", distro.release)
+ self.assertEqual(["ubuntu", "debian"], distro.is_like)
+
+ def test_enable_disabled_short(self):
+ """LP: #1042916: Test enabling disabled entry."""
+ apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list")
+ return self.common_test_enable_disabled()
+
+ def test_enable_disabled_deb822(self):
+ """LP: #1042916: Test enabling disabled entry."""
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+ return self.common_test_enable_disabled()
+
+ def common_test_enable_disabled(self):
+ """LP: #1042916: Test enabling disabled entry."""
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ disabled = sources.add(
+ "deb",
+ "http://fi.archive.ubuntu.com/ubuntu/",
+ "precise",
+ ["main"],
+ file=sources.list[0].file, # if we use deb822, enable deb822
+ )
+ disabled.set_enabled(False)
+ enabled = sources.add(
+ "deb",
+ "http://fi.archive.ubuntu.com/ubuntu/",
+ "precise",
+ ["main"],
+ file=sources.list[0].file, # if we use deb822, enable deb822
+ )
+ self.assertEqual(disabled, enabled)
+ self.assertFalse(disabled.disabled)
+
+ def test_duplicate_uri_with_trailing_slash_short(self):
+ """Test replacing entry with same uri except trailing slash"""
+ apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list")
+ return self.common_test_duplicate_uri_with_trailing_slash()
+
+ def test_duplicate_uri_with_trailing_slash_deb822(self):
+ """Test replacing entry with same uri except trailing slash"""
+ apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d")
+ return self.common_test_duplicate_uri_with_trailing_slash()
+
+ def common_test_duplicate_uri_with_trailing_slash(self):
+ """Test replacing entry with same uri except trailing slash"""
+ sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True)
+ line_wslash = "deb http://rslash.ubuntu.com/ubuntu/ precise main"
+ line_woslash = "deb http://rslash.ubuntu.com/ubuntu precise main"
+ entry_wslash = aptsources.sourceslist.SourceEntry(line_wslash)
+ entry_woslash = aptsources.sourceslist.SourceEntry(line_woslash)
+ self.assertEqual(entry_wslash, entry_woslash)
+ count = len(sources.list)
+ sourceslist_wslash = sources.add(
+ entry_wslash.type, entry_wslash.uri, entry_wslash.dist, entry_wslash.comps
+ )
+ self.assertEqual(count + 1, len(sources.list))
+ count = len(sources.list)
+ sourceslist_woslash = sources.add(
+ entry_woslash.type,
+ entry_woslash.uri,
+ entry_woslash.dist,
+ entry_woslash.comps,
+ )
+ self.assertEqual(count, len(sources.list))
+ self.assertEqual(sourceslist_wslash, sourceslist_woslash)
+
+ def test_deb822_distro_enable_disable_component(self):
+ """Test enabling and disabling a component in the distro sources.
+
+ This ensures reasonable behavior when enabling and then disabling a component"""
+ with tempfile.NamedTemporaryFile("w", suffix=".sources") as file:
+ file.write(
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ )
+ file.flush()
+
+ apt_pkg.config.set("Dir::Etc::sourcelist", file.name)
+ sources = aptsources.sourceslist.SourcesList(
+ True, self.templates, deb822=True
+ )
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu",
+ codename="noble",
+ description="Ubuntu 24.04 LTS",
+ release="24.04",
+ )
+
+ self.assertEqual(len(sources.list), 2)
+ distro.get_sources(sources)
+ distro.enable_component("multiverse")
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe multiverse\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe multiverse\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ # Disable it again
+ # FIXME: The child entries will no longer be valid at this point, so we have to call
+ # get_sources(), but it's not clear whether this should be considered a bug -
+ # there may have been other changes rendering entries no longer valid that distro
+ # is holding on to.
+ distro.get_sources(sources)
+ distro.disable_component("multiverse")
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ # Disable universe as well
+ distro.get_sources(sources)
+ distro.disable_component("universe")
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ def test_deb822_distro_enable_disable_component_mixed_origin(self):
+ """Test enabling and disabling a component in the distro sources, with mixed origin
+
+ Here we ensure that we still get idempotent behavior of disable after enable even if the
+ entry we were modifying also had a non-official repository in it."""
+ with tempfile.NamedTemporaryFile("w", suffix=".sources") as file:
+ file.write(
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ )
+ file.flush()
+
+ apt_pkg.config.set("Dir::Etc::sourcelist", file.name)
+ sources = aptsources.sourceslist.SourcesList(
+ True, self.templates, deb822=True
+ )
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu",
+ codename="noble",
+ description="Ubuntu 24.04 LTS",
+ release="24.04",
+ )
+
+ self.assertEqual(len(sources.list), 2)
+ distro.get_sources(sources)
+ distro.enable_component("multiverse")
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe multiverse\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe multiverse\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ # Disable it again
+ # FIXME: The child entries will no longer be valid at this point, so we have to call
+ # get_sources(), but it's not clear whether this should be considered a bug -
+ # there may have been other changes rendering entries no longer valid that distro
+ # is holding on to.
+ distro.get_sources(sources)
+ distro.disable_component("multiverse")
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ # Disable universe too. The behaviour here is interesting: Distro only disables
+ # universe for the official source, so we end up with the non-official source split out.
+ distro.get_sources(sources)
+ distro.disable_component("universe")
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# main archive\n" # note it keeps the comment on the split out child
+ "Types: deb deb-src\n"
+ "URIs: http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ def test_deb822_distro_enable_disable_child_source_mixed_origins(self):
+ """Test enabling and disabling a child source (proposed) in the distro sources, with mixed origin
+
+ Here we ensure that we still get idempotent behavior of disable after enable even if the
+ entry we were modifying also had a non-official repository in it."""
+ with tempfile.NamedTemporaryFile("w", suffix=".sources") as file:
+ file.write(
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ )
+ file.flush()
+
+ apt_pkg.config.set("Dir::Etc::sourcelist", file.name)
+ sources = aptsources.sourceslist.SourcesList(
+ True, self.templates, deb822=True
+ )
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu",
+ codename="noble",
+ description="Ubuntu 24.04 LTS",
+ release="24.04",
+ )
+
+ self.assertEqual(len(sources.list), 2)
+ distro.get_sources(sources)
+ distro.get_source_code = True
+ distro.add_source(dist="noble-proposed")
+
+ # FIXME: Component ordering is not stable right now
+ for entry in sources.list:
+ entry.comps = sorted(entry.comps)
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+
+ # FIXME: In an optimal world it would look like this
+ self.assertNotEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble noble-updates noble-proposed\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ # Sadly our merge algorithm does not always produce optimal merges, because it merges the unofficial entry first
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble-proposed\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ # Disable it again
+ # FIXME: The child entries will no longer be valid at this point, so we have to call
+ # get_sources(), but it's not clear whether this should be considered a bug -
+ # there may have been other changes rendering entries no longer valid that distro
+ # is holding on to.
+ distro.get_sources(sources)
+ for child in distro.child_sources + distro.source_code_sources:
+ if child.dist.endswith("proposed"):
+ sources.remove(child)
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb deb-src\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb deb-src\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ def test_deb822_distro_enable_disable_child_source_mixed_origins_no_source_code(
+ self,
+ ):
+ """Test enabling and disabling a child source (proposed) in the distro sources, with mixed origin
+
+ Here we ensure that we still get idempotent behavior of disable after enable even if the
+ entry we were modifying also had a non-official repository in it."""
+ with tempfile.NamedTemporaryFile("w", suffix=".sources") as file:
+ file.write(
+ "# main archive\n"
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ )
+ file.flush()
+
+ apt_pkg.config.set("Dir::Etc::sourcelist", file.name)
+ sources = aptsources.sourceslist.SourcesList(
+ True, self.templates, deb822=True
+ )
+ distro = aptsources.distro.get_distro(
+ id="Ubuntu",
+ codename="noble",
+ description="Ubuntu 24.04 LTS",
+ release="24.04",
+ )
+
+ self.assertEqual(len(sources.list), 2)
+ distro.get_sources(sources)
+ self.assertEqual(
+ [(s.type, s.uri, s.dist, s.comps) for s in distro.main_sources]
+ + ["separator"]
+ + [(s.type, s.uri, s.dist, s.comps) for s in distro.child_sources],
+ [
+ (
+ "deb",
+ "http://archive.ubuntu.com/ubuntu/",
+ "noble",
+ ["main", "universe"],
+ ),
+ "separator",
+ (
+ "deb",
+ "http://archive.ubuntu.com/ubuntu/",
+ "noble-updates",
+ ["main", "universe"],
+ ),
+ (
+ "deb",
+ "http://security.ubuntu.com/ubuntu/",
+ "noble-security",
+ ["main", "universe"],
+ ),
+ ],
+ )
+ distro.add_source(dist="noble-proposed")
+
+ # FIXME: Component ordering is not stable right now
+ for entry in sources.list:
+ entry.comps = sorted(entry.comps)
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+
+ # FIXME: In an optimal world it would look like this
+ self.assertNotEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble noble-updates noble-proposed\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# main archive\n"
+ "Types: deb\n"
+ "URIs: http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ # Sadly our merge algorithm does not always produce optimal merges, because it merges the unofficial entry first
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/\n"
+ "Suites: noble-proposed\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+ # Disable it again
+ # FIXME: The child entries will no longer be valid at this point, so we have to call
+ # get_sources(), but it's not clear whether this should be considered a bug -
+ # there may have been other changes rendering entries no longer valid that distro
+ # is holding on to.
+ distro.get_sources(sources)
+ for child in distro.child_sources + distro.source_code_sources:
+ if child.dist.endswith("proposed"):
+ sources.remove(child)
+ sources.save()
+
+ with open(file.name) as readonly:
+ self.maxDiff = None
+ self.assertEqual(
+ readonly.read(),
+ "# main archive\n"
+ "Types: deb\n"
+ "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n"
+ "Suites: noble noble-updates\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n"
+ "\n"
+ "# security\n"
+ "Types: deb\n"
+ "URIs: http://security.ubuntu.com/ubuntu/\n"
+ "Suites: noble-security\n"
+ "Components: main universe\n"
+ "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n",
+ )
+
+
+if __name__ == "__main__":
+ os.chdir(os.path.dirname(__file__))
+ unittest.main()