Merge lp:~sil2100/ubuntu-cdimage/cdimage-to-livefs-map into lp:ubuntu-cdimage

Proposed by Łukasz Zemczak
Status: Merged
Merged at revision: 1948
Proposed branch: lp:~sil2100/ubuntu-cdimage/cdimage-to-livefs-map
Merge into: lp:ubuntu-cdimage
Diff against target: 474 lines (+224/-58)
5 files modified
etc/cdimage-to-livecd-rootfs-map (+13/-0)
lib/cdimage/config.py (+64/-0)
lib/cdimage/livefs.py (+18/-44)
lib/cdimage/tests/test_config.py (+100/-0)
lib/cdimage/tests/test_livefs.py (+29/-14)
To merge this branch: bzr merge lp:~sil2100/ubuntu-cdimage/cdimage-to-livefs-map
Reviewer Review Type Date Requested Status
Dimitri John Ledkov (community) Approve
Ubuntu CD Image Team Pending
Review via email: mp+404310@code.launchpad.net

Commit message

Add a etc/cdimage-to-livefs-map mapping config file to streamline all the various cdimage->livefs mappings done implicitly in code. We also add the mapping bits for generic arm64 and amd64 images while at it.

Description of the change

Add a etc/cdimage-to-livefs-map mapping config file to streamline all the various cdimage->livefs mappings done implicitly in code. We also add the mapping bits for generic arm64 and amd64 images while at it.

This was proposed by xnox when we originally discussed the generic image changes. I personally HATE that right now we have all those weird differences between ubuntu-cdimage and live-build SUBARCH, PROJECT and SUBPROJECT definitions. In my mind, since we own both projects, we should simply be consistent across both projects and always plan in such a way to not confuse people by doing some translations from like one subarch to another. But I know all this requires refactoring of both cdimage and livecd-rootfs.

What I hate even more is implicitness of such mappings. I am a fan of code that's consistent and easy to read, without having to know specific hidden 'quirks'. This is why today I decided to go on with Dimitri's idea of having an explicit cdimage -> live mapping file where any custom mappings like these can go. This way new developers will know about what differences are and why (as we can leave comments for those there).

I added some unit tests for the new functionality which now passes and made sure existing test also pass. Well, the ones that should pass. There are some unrelated unit test failures which I'd like to fix with some other MP.

To post a comment you must log in.
Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Please note that this was written in a heat of the moment in a very fast pace, so it might not be perfect. So a review is more than welcome!

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Please add "SERIES" filter column. Such that we can have correct per-series mappings defined.

Not sure about "cdimage-to-livefs-map" name, maybe it is "cdimage-to-livecd-rootfs-map".

Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Thanks for the review! I'll change the name and add a SERIES column, since it seems like we need it for impish right now at least.

1948. By Łukasz Zemczak

Rename the mapping file to something that makes more sense, handle '-' in the target subarch name and add 'series' (DIST) column to the mapping file.

Revision history for this message
Dimitri John Ledkov (xnox) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'etc/cdimage-to-livecd-rootfs-map'
2--- etc/cdimage-to-livecd-rootfs-map 1970-01-01 00:00:00 +0000
3+++ etc/cdimage-to-livecd-rootfs-map 2021-06-25 10:12:21 +0000
4@@ -0,0 +1,13 @@
5+# PROJECT IMAGE_TYPE DIST ARCH SUBARCH LIVEFS_PROJECT LIVEFS_CPUARCH LIVEFS_SUBARCH
6+# Put more specific matches first.
7+# Like etc/default-arches, "PROJECT" is in fact PROJECT[-SUBPROJECT][-LOCALE]. "-" means 'empty'.
8+
9+ubuntu-server daily-preinstalled * riscv64 unleashed ubuntu-cpc * sifive_fu540
10+ubuntu-server daily-preinstalled * riscv64 unmatched ubuntu-cpc * sifive_hifive_unmatched_fu740
11+# XXX: We should probably get rid of this once we start building unleased+unmatched image pairs for focal, as this is here
12+# only for focal legacy reasons.
13+ubuntu-server daily-preinstalled focal riscv64 - ubuntu-cpc * hifive
14+ubuntu-server daily-preinstalled * * - ubuntu-cpc * generic
15+ubuntu-server daily-preinstalled * * * ubuntu-cpc * *
16+ubuntu-appliance * * * * ubuntu-core * *
17+livecd-base * * * * base * *
18
19=== modified file 'lib/cdimage/config.py'
20--- lib/cdimage/config.py 2021-04-23 10:48:40 +0000
21+++ lib/cdimage/config.py 2021-06-25 10:12:21 +0000
22@@ -285,6 +285,7 @@
23 for key, value in kwargs.items():
24 self[key] = value
25 config_path = os.path.join(self.root, "etc", "config")
26+ self.livefs_arch_mapping = {}
27 if read:
28 if os.path.exists(config_path):
29 self.read(config_path)
30@@ -305,6 +306,7 @@
31 self.set_default_arches()
32 if "CPUARCHES" not in self:
33 self.set_default_cpuarches()
34+ self.set_livefs_mapping()
35
36 def __setitem__(self, key, value):
37 config_value = value
38@@ -393,6 +395,58 @@
39 return arches
40 return None
41
42+ def set_livefs_mapping(self):
43+ self.livefs_arch_mapping = {}
44+ mapping = os.path.join(self.root, "etc", "cdimage-to-livecd-rootfs-map")
45+ if not os.path.exists(mapping):
46+ return
47+ want_project_bits = [self.project]
48+ if self.subproject:
49+ want_project_bits.append(self.subproject)
50+ if self["UBUNTU_DEFAULTS_LOCALE"]:
51+ want_project_bits.append(self["UBUNTU_DEFAULTS_LOCALE"])
52+ want_project = "-".join(want_project_bits)
53+ with open(mapping) as f:
54+ mapping_file = f.readlines()
55+ for arch in self.arches:
56+ (want_cpuarch, _, want_subarch) = arch.partition("+")
57+ for line in mapping_file:
58+ line = line.strip()
59+ if not line or line.startswith("#"):
60+ continue
61+ try:
62+ (project, image_type, series, cpuarch, subarch,
63+ livefs_project, livefs_cpuarch, livefs_subarch) = \
64+ line.split(None, 7)
65+ except ValueError:
66+ continue
67+ if not fnmatch.fnmatchcase(want_project, project):
68+ continue
69+ if not fnmatch.fnmatchcase(self.image_type, image_type):
70+ continue
71+ if not self.match_series(series):
72+ continue
73+ if not fnmatch.fnmatchcase(want_cpuarch, cpuarch):
74+ continue
75+ # - means 'no subarch'
76+ if subarch == "-":
77+ if want_subarch:
78+ continue
79+ elif not fnmatch.fnmatchcase(want_subarch, subarch):
80+ continue
81+ # * means 'no change'
82+ if livefs_project == "*":
83+ livefs_project = self.project
84+ if livefs_cpuarch == "*":
85+ livefs_cpuarch = want_cpuarch
86+ if livefs_subarch == "*":
87+ livefs_subarch = want_subarch
88+ elif livefs_subarch == "-":
89+ livefs_subarch = None
90+ livefs_arch = ("%s+%s" % (livefs_cpuarch, livefs_subarch)
91+ if livefs_subarch else livefs_cpuarch)
92+ self.livefs_arch_mapping[arch] = (livefs_project, livefs_arch)
93+
94 def set_default_cpuarches(self):
95 self["CPUARCHES"] = " ".join(
96 sorted(set(arch.split("+")[0] for arch in self.arches)))
97@@ -457,6 +511,16 @@
98 return '22'
99 return None
100
101+ def livefs_project_for_arch(self, arch):
102+ if arch not in self.livefs_arch_mapping:
103+ return self.project
104+ return self.livefs_arch_mapping[arch][0]
105+
106+ def livefs_arch_for_arch(self, arch):
107+ if arch not in self.livefs_arch_mapping:
108+ return arch
109+ return self.livefs_arch_mapping[arch][1]
110+
111 def export(self):
112 ret = dict(os.environ)
113 for key, value in self.items():
114
115=== modified file 'lib/cdimage/livefs.py'
116--- lib/cdimage/livefs.py 2021-03-11 10:51:35 +0000
117+++ lib/cdimage/livefs.py 2021-06-25 10:12:21 +0000
118@@ -67,34 +67,20 @@
119 pass
120
121
122-def split_arch(arch):
123- arch_bits = arch.split("+", 1)
124+def split_arch(config, arch):
125+ # To make sure we're compatible with everything before, we need to do the
126+ # arch -> livefs_arch mapping here. This way we're consistent with how it
127+ # worked previously
128+ live_arch = config.livefs_arch_for_arch(arch)
129+ arch_bits = live_arch.split("+", 1)
130 if len(arch_bits) == 1:
131 arch_bits.append("")
132 cpuarch, subarch = arch_bits
133-
134- if cpuarch == "amd64" and subarch == "mac":
135- # Use normal amd64 live image on amd64+mac.
136- subarch = ""
137-
138- if cpuarch == "riscv64":
139- # need to specify subarch to get raw.xz instead of qcow2
140- # originally, no subarch was the unleashed image. Add support
141- # for user-friendly subarch names and translate them to u-boot
142- # target names for livecd-rootfs maybe the two will be able to
143- # merge but at the moment, they are very different SOCs.
144- if subarch == "":
145- subarch = "hifive" # for focal
146- elif subarch == "unleashed":
147- subarch = "sifive_fu540"
148- elif subarch == "unmatched":
149- subarch = "sifive_hifive_unmatched_fu740"
150-
151 return cpuarch, subarch
152
153
154 def live_builder(config, arch):
155- cpuarch, subarch = split_arch(arch)
156+ cpuarch, subarch = split_arch(config, arch)
157 project = config.project
158
159 path = os.path.join(config.root, "production", "livefs-builders")
160@@ -126,7 +112,7 @@
161 def live_build_options(config, arch):
162 options = []
163
164- cpuarch, subarch = split_arch(arch)
165+ cpuarch, subarch = split_arch(config, arch)
166 if (cpuarch in ("armel", "armhf") and
167 config.image_type == "daily-preinstalled"):
168 if subarch in ("mx5", "omap", "omap4"):
169@@ -149,22 +135,10 @@
170
171
172 def live_project(config, arch):
173- project = config.project
174-
175- if project == "livecd-base":
176- liveproject = "base"
177- elif (project == "ubuntu-server" and
178- config.image_type == "daily-preinstalled"):
179- liveproject = "ubuntu-cpc"
180- elif project == "ubuntu-appliance":
181- liveproject = "ubuntu-core"
182- else:
183- liveproject = project
184-
185- cpuarch, subarch = split_arch(arch)
186+ liveproject = config.livefs_project_for_arch(arch)
187
188 if config["CDIMAGE_DVD"]:
189- if project in ("ubuntu", "kubuntu", "edubuntu", "ubuntustudio"):
190+ if config.project in ("ubuntu", "kubuntu", "edubuntu", "ubuntustudio"):
191 liveproject += "-dvd"
192
193 return liveproject
194@@ -183,7 +157,7 @@
195
196 command.extend(live_build_options(config, arch))
197
198- cpuarch, subarch = split_arch(arch)
199+ cpuarch, subarch = split_arch(config, arch)
200 if cpuarch:
201 command.extend(["-A", cpuarch])
202 if subarch:
203@@ -202,7 +176,7 @@
204
205
206 def live_build_lp_kwargs(config, lp, lp_livefs, arch):
207- cpuarch, subarch = split_arch(arch)
208+ cpuarch, subarch = split_arch(config, arch)
209 kwargs = {}
210 metadata_override = {}
211
212@@ -254,7 +228,7 @@
213 bits = [config.project]
214 if config.subproject:
215 bits.append(config.subproject)
216- cpuarch, subarch = split_arch(arch)
217+ cpuarch, subarch = split_arch(config, arch)
218 bits.append(cpuarch)
219 if subarch:
220 bits.append(subarch)
221@@ -273,7 +247,7 @@
222 livefs_id_bits = [project]
223 if config.subproject:
224 livefs_id_bits.append(config.subproject)
225- cpuarch, subarch = split_arch(arch)
226+ cpuarch, subarch = split_arch(config, arch)
227 if subarch:
228 livefs_id_bits.append(subarch)
229 if config["UBUNTU_DEFAULTS_LOCALE"]:
230@@ -304,7 +278,7 @@
231
232
233 def live_lp_info(config, arch):
234- cpuarch, subarch = split_arch(arch)
235+ cpuarch, subarch = split_arch(config, arch)
236 want_project_bits = [config.project]
237 if config.subproject:
238 want_project_bits.append(config.subproject)
239@@ -462,7 +436,7 @@
240 if config["LIVECD_BASE"]:
241 return config["LIVECD_BASE"]
242
243- cpuarch, subarch = split_arch(arch)
244+ cpuarch, subarch = split_arch(config, arch)
245 series = config["DIST"]
246
247 if config["LIVECD"]:
248@@ -482,7 +456,7 @@
249
250
251 def flavours(config, arch):
252- cpuarch, subarch = split_arch(arch)
253+ cpuarch, subarch = split_arch(config, arch)
254 project = config.project
255 series = config["DIST"]
256
257@@ -550,7 +524,7 @@
258 if item == "ltsp-squashfs" and arch == "amd64":
259 # use i386 LTSP image on amd64 too
260 arch = "i386"
261- cpuarch, subarch = split_arch(arch)
262+ cpuarch, subarch = split_arch(config, arch)
263 project = config.project
264 series = config["DIST"]
265 liveproject = live_project(config, arch)
266
267=== modified file 'lib/cdimage/tests/test_config.py'
268--- lib/cdimage/tests/test_config.py 2020-12-02 17:05:14 +0000
269+++ lib/cdimage/tests/test_config.py 2021-06-25 10:12:21 +0000
270@@ -164,6 +164,91 @@
271 config = Config(SUBPROJECT="wubi", IMAGE_TYPE="wubi")
272 self.assertEqual("amd64 i386", config["ARCHES"])
273
274+ def test_livefs_mapping(self):
275+ os.environ["CDIMAGE_ROOT"] = self.use_temp_dir()
276+ os.environ["ARCHES"] = "arm64 arm64+unleashed"
277+ etc_dir = os.path.join(self.temp_dir, "etc")
278+ with mkfile(os.path.join(etc_dir, "config")) as f:
279+ print(dedent("""\
280+ #! /bin/sh
281+ PROJECT=ubuntu-server
282+ DIST=focal
283+ """), file=f)
284+ with mkfile(os.path.join(etc_dir, "cdimage-to-livecd-rootfs-map")) as f:
285+ print("ubuntu-server\tdaily-preinstalled\t*\tarm64\tunleashed\t"
286+ "ubuntu-cpc\t*\tsifive_fu540", file=f)
287+ config = Config(IMAGE_TYPE="daily-preinstalled")
288+ # Check if project and arch got overriden
289+ self.assertEqual(
290+ "ubuntu-cpc", config.livefs_project_for_arch("arm64+unleashed"))
291+ self.assertEqual(
292+ "arm64+sifive_fu540",
293+ config.livefs_arch_for_arch("arm64+unleashed"))
294+ # And if no mapping entries present, no changes should be made
295+ self.assertEqual(
296+ "ubuntu-server", config.livefs_project_for_arch("arm64"))
297+ self.assertEqual(
298+ "arm64", config.livefs_arch_for_arch("arm64"))
299+
300+ def test_livefs_mapping_empty_subarch(self):
301+ os.environ["CDIMAGE_ROOT"] = self.use_temp_dir()
302+ os.environ["ARCHES"] = "arm64 arm64+unleashed"
303+ etc_dir = os.path.join(self.temp_dir, "etc")
304+ with mkfile(os.path.join(etc_dir, "config")) as f:
305+ print(dedent("""\
306+ #! /bin/sh
307+ PROJECT=ubuntu-server
308+ DIST=focal
309+ """), file=f)
310+ with mkfile(os.path.join(etc_dir, "cdimage-to-livecd-rootfs-map")) as f:
311+ print("ubuntu-server\tdaily-preinstalled\t*\tarm64\t-\t"
312+ "ubuntu-cpc\t*\tgeneric\n"
313+ "ubuntu-server\tdaily-preinstalled\t*\tarm64\tunleashed\t"
314+ "ubuntu-cpc\t*\t-\n", file=f)
315+ config = Config(IMAGE_TYPE="daily-preinstalled")
316+ # Check if no subarch is converted to a subarch
317+ self.assertEqual(
318+ "ubuntu-cpc", config.livefs_project_for_arch("arm64"))
319+ self.assertEqual(
320+ "arm64+generic",
321+ config.livefs_arch_for_arch("arm64"))
322+ # ...and other way around, subarch case to no subarch
323+ self.assertEqual(
324+ "ubuntu-cpc", config.livefs_project_for_arch("arm64+unleashed"))
325+ self.assertEqual(
326+ "arm64",
327+ config.livefs_arch_for_arch("arm64+unleashed"))
328+
329+ def test_livefs_mapping_series(self):
330+ os.environ["CDIMAGE_ROOT"] = self.use_temp_dir()
331+ os.environ["ARCHES"] = "arm64 arm64+unleashed"
332+ etc_dir = os.path.join(self.temp_dir, "etc")
333+ with mkfile(os.path.join(etc_dir, "config")) as f:
334+ print(dedent("""\
335+ #! /bin/sh
336+ PROJECT=ubuntu-server
337+ DIST=groovy
338+ """), file=f)
339+ with mkfile(os.path.join(etc_dir,
340+ "cdimage-to-livecd-rootfs-map")) as f:
341+ print("ubuntu-server\tdaily-preinstalled\tfocal-\tarm64\t-\t"
342+ "ubuntu-cpc\t*\tgeneric\n"
343+ "ubuntu-server\tdaily-preinstalled\impish\tarm64\t"
344+ "unleashed\tubuntu-cpc\t*\tsifive_unleashed\n", file=f)
345+ config = Config(IMAGE_TYPE="daily-preinstalled")
346+ # This should be matched by series
347+ self.assertEqual(
348+ "ubuntu-cpc", config.livefs_project_for_arch("arm64"))
349+ self.assertEqual(
350+ "arm64+generic",
351+ config.livefs_arch_for_arch("arm64"))
352+ # ...this not
353+ self.assertEqual(
354+ "ubuntu-server", config.livefs_project_for_arch("arm64+unleashed"))
355+ self.assertEqual(
356+ "arm64+unleashed",
357+ config.livefs_arch_for_arch("arm64+unleashed"))
358+
359 def test_read_shell(self):
360 os.environ["CDIMAGE_ROOT"] = self.use_temp_dir()
361 with mkfile(os.path.join(self.temp_dir, "etc", "config")) as f:
362@@ -329,6 +414,21 @@
363 config["IMAGE_TYPE"] = "daily-live"
364 self.assertEqual("daily-live", config.image_type)
365
366+ def test_livefs_project_for_arch(self):
367+ config = Config(read=False)
368+ config["PROJECT"] = "ubuntu-server"
369+ config.livefs_arch_mapping = {"amd64+generic": ("ubuntu-cpc", "amd64")}
370+ self.assertEqual("ubuntu-cpc",
371+ config.livefs_project_for_arch("amd64+generic"))
372+ self.assertEqual("ubuntu-server",
373+ config.livefs_project_for_arch("amd64"))
374+
375+ def test_livefs_arch_for_arch(self):
376+ config = Config(read=False)
377+ config.livefs_arch_mapping = {"amd64": ("ubuntu-cpc", "amd64+generic")}
378+ self.assertEqual("amd64+generic", config.livefs_arch_for_arch("amd64"))
379+ self.assertEqual("arm64", config.livefs_arch_for_arch("arm64"))
380+
381 def test_all_projects(self):
382 config = Config(read=False)
383 self.assertEqual([], config.all_projects)
384
385=== modified file 'lib/cdimage/tests/test_livefs.py'
386--- lib/cdimage/tests/test_livefs.py 2020-12-10 17:32:42 +0000
387+++ lib/cdimage/tests/test_livefs.py 2021-06-25 10:12:21 +0000
388@@ -148,27 +148,38 @@
389
390 class TestSplitArch(TestCase):
391 def test_amd64(self):
392- self.assertEqual(("amd64", ""), split_arch("amd64"))
393-
394- def test_amd64_mac(self):
395- self.assertEqual(("amd64", ""), split_arch("amd64+mac"))
396+ config = Config(read=False)
397+ self.assertEqual(("amd64", ""), split_arch(config, "amd64"))
398
399 def test_arm64_raspi(self):
400- self.assertEqual(("arm64", "raspi"), split_arch("arm64+raspi"))
401+ config = Config(read=False)
402+ self.assertEqual(("arm64", "raspi"), split_arch(config, "arm64+raspi"))
403
404 def test_armhf_omap4(self):
405- self.assertEqual(("armhf", "omap4"), split_arch("armhf+omap4"))
406+ config = Config(read=False)
407+ self.assertEqual(("armhf", "omap4"), split_arch(config, "armhf+omap4"))
408
409 def test_i386(self):
410- self.assertEqual(("i386", ""), split_arch("i386"))
411+ config = Config(read=False)
412+ self.assertEqual(("i386", ""), split_arch(config, "i386"))
413
414
415 class TestLiveProject(TestCase):
416 def assertProjectEqual(self, expected, project, series, arch="i386",
417 **kwargs):
418- config = Config(read=False)
419- config["PROJECT"] = project
420- config["DIST"] = series
421+ os.environ["CDIMAGE_ROOT"] = self.use_temp_dir()
422+ os.environ["ARCHES"] = arch
423+ etc_dir = os.path.join(self.temp_dir, "etc")
424+ with mkfile(os.path.join(etc_dir, "config")) as f:
425+ print(dedent("""\
426+ #! /bin/sh
427+ PROJECT=%s
428+ DIST=%s
429+ """ % (project, series)), file=f)
430+ with mkfile(os.path.join(etc_dir, "cdimage-to-livecd-rootfs-map")) as f:
431+ print("ubuntu-appliance\t*\t*\t*\t*\tubuntu-core\t*\t*\n"
432+ "livecd-base\t*\t*\t*\t*\tbase\t*\t*", file=f)
433+ config = Config()
434 for key, value in kwargs.items():
435 config[key.upper()] = value
436 self.assertEqual(expected, live_project(config, arch))
437@@ -179,22 +190,23 @@
438 def test_ubuntu_dvd(self):
439 for series in all_series[7:]:
440 self.assertProjectEqual(
441- "ubuntu-dvd", "ubuntu", series, cdimage_dvd="1")
442+ "ubuntu-dvd", "ubuntu", series.full_name, cdimage_dvd="1")
443
444 def test_kubuntu_dvd(self):
445 for series in all_series[7:]:
446 self.assertProjectEqual(
447- "kubuntu-dvd", "kubuntu", series, cdimage_dvd="1")
448+ "kubuntu-dvd", "kubuntu", series.full_name, cdimage_dvd="1")
449
450 def test_edubuntu_dvd(self):
451 for series in all_series[10:]:
452 self.assertProjectEqual(
453- "edubuntu-dvd", "edubuntu", series, cdimage_dvd="1")
454+ "edubuntu-dvd", "edubuntu", series.full_name, cdimage_dvd="1")
455
456 def test_ubuntustudio_dvd(self):
457 for series in all_series[15:]:
458 self.assertProjectEqual(
459- "ubuntustudio-dvd", "ubuntustudio", series, cdimage_dvd="1")
460+ "ubuntustudio-dvd", "ubuntustudio", series.full_name,
461+ cdimage_dvd="1")
462
463 def test_ubuntu_appliance(self):
464 # We currently only support ubuntu-appliances for bionic (UC18)
465@@ -1103,6 +1115,9 @@
466 self.config["PROJECT"] = "ubuntu-server"
467 self.config["DIST"] = "xenial"
468 self.config["IMAGE_TYPE"] = "daily-preinstalled"
469+ self.config.livefs_arch_mapping = {
470+ "armhf+raspi2": ("ubuntu-cpc", "armhf+raspi2")
471+ }
472 self.assertTrue(download_live_items(self.config, "armhf+raspi2",
473 "disk1.img.xz"))
474 mock_fetch.assert_called_once_with(

Subscribers

People subscribed via source and target branches