[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1064620: firmware-nonfree: suggestions for the packaging, gencontrol.py and debian/rules



Source: firmware-nonfree
Version: 20230210-5
Severity: wishlist
Tags: patch

Hello.

The source package builds with the attached changes (2 to 10), and
debdiff finds no difference in the resulting debs for
firmware-{linux,linux-nonfree,qcom-media} (testing do_extra in gencontrol.py)
firmware-realtek (testing an example of do_main in gencontrol.py)

Commit 2 to 9 are cosmetic.

Commit 10 simplifies the build system in my opinion, and may improve
the handling of spaces in file names (1#1035505).

This is a complex package and I miss context, so I may of course split
10 in separate commits or revert parts of it depending on your answer.
>From 798e5b247db70dc24ce6736a4eba7b5ae17ca41d Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Fri, 23 Feb 2024 17:10:17 +0100
Subject: [PATCH 02/10] d/README.Debian: typo

---
 debian/README.source | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/debian/README.source b/debian/README.source
index 15c11bf..43e897a 100644
--- a/debian/README.source
+++ b/debian/README.source
@@ -85,7 +85,7 @@ Optional per-file metadata:
 
 [<filename>_base] desc: One-line description for this file, used in
                         package description
-[<filename>_base] version: Verson number for this file, used in package
+[<filename>_base] version: Version number for this file, used in package
                            description
 
 To re-generate debian/control (and other files) based on these
-- 
2.39.2

>From c525da983a782b3d58e7ba4f793930e197fc05d7 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Fri, 23 Feb 2024 17:11:31 +0100
Subject: [PATCH 03/10] d/clean: instead of complexity in d/rules

---
 debian/clean | 2 ++
 debian/rules | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 debian/clean

diff --git a/debian/clean b/debian/clean
new file mode 100644
index 0000000..b0bff90
--- /dev/null
+++ b/debian/clean
@@ -0,0 +1,2 @@
+debian/build/
+debian/lib/python/__pycache__/
diff --git a/debian/rules b/debian/rules
index 5867d9f..ccd41a7 100755
--- a/debian/rules
+++ b/debian/rules
@@ -15,7 +15,6 @@ build-indep build-arch build: debian/control
 
 clean: debian/control
 	dh_testdir
-	rm -rf debian/build debian/lib/python/__pycache__
 	dh_clean
 
 binary-indep: build-indep
-- 
2.39.2

>From d193cb90f02e2c669c1ad2fb91759f4d9c3591e8 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Fri, 23 Feb 2024 17:28:04 +0100
Subject: [PATCH 04/10] d/rules: use dpkg pkg-info.mk snippet instead of
 reinventing it

---
 debian/rules | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/debian/rules b/debian/rules
index ccd41a7..d9a2d38 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,10 +1,9 @@
 #!/usr/bin/make -f
 SHELL := sh -e
-SOURCE := $(shell dpkg-parsechangelog -SSource)
-VERSION := $(shell dpkg-parsechangelog -SVersion)
-VERSION_UPSTREAM := $(shell echo "$(VERSION)" | sed -e 's,-[^-]*$$,,')
-VERSION_BINNMU := $(shell echo "$(VERSION)" | sed -rne 's,.*\+b([0-9]+)$$,\1,p')
-VERSION_SOURCE := $(patsubst %+b$(VERSION_BINNMU),%,$(VERSION))
+
+include /usr/share/dpkg/pkg-info.mk
+VERSION_BINNMU := $(shell echo "$(DEB_VERSION)" | sed -rne 's,.*\+b([0-9]+)$$,\1,p')
+VERSION_SOURCE := $(patsubst %+b$(VERSION_BINNMU),%,$(DEB_VERSION))
 
 include debian/rules.defs
 
@@ -35,7 +34,7 @@ CONTROL_FILES += debian/bin/gencontrol.py debian/config/defines $(wildcard debia
 # in the checksum.
 debian/build/version-info: debian/changelog
 	mkdir -p $(@D)
-	printf >$@ 'Source: %s\nVersion: %s\n' $(SOURCE) $(VERSION_SOURCE)
+	printf >$@ 'Source: %s\nVersion: %s\n' $(DEB_SOURCE) $(VERSION_SOURCE)
 
 debian/control debian/rules.gen: $(GENCONTROL) $(CONTROL_FILES)
 ifeq ($(wildcard debian/control.md5sum),)
@@ -59,8 +58,8 @@ debian/control-real: $(GENCONTROL) $(CONTROL_FILES)
 	@echo
 	exit 1
 
-DIR_ORIG = ../orig/$(SOURCE)-$(VERSION_UPSTREAM)
-TAR_ORIG_NAME = $(SOURCE)_$(VERSION_UPSTREAM).orig.tar.xz
+DIR_ORIG = ../orig/$(DEB_SOURCE)-$(DEB_VERSION_UPSTREAM)
+TAR_ORIG_NAME = $(DEB_SOURCE)_$(DEB_VERSION_UPSTREAM).orig.tar.xz
 TAR_ORIG = $(firstword $(wildcard ../$(TAR_ORIG_NAME)) $(wildcard ../orig/$(TAR_ORIG_NAME)))
 
 orig: $(DIR_ORIG)
-- 
2.39.2

>From 1327a9f8e15b602e7f3df768758f478b548dbd50 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Fri, 23 Feb 2024 17:28:38 +0100
Subject: [PATCH 05/10] d/rules: expand GENCONTROL instead of duplicating its
 contents

---
 debian/rules | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/debian/rules b/debian/rules
index d9a2d38..f455e5e 100755
--- a/debian/rules
+++ b/debian/rules
@@ -26,9 +26,9 @@ binary-arch: build-arch
 binary:	binary-indep binary-arch
 
 CONTROL_FILES = debian/build/version-info $(wildcard debian/templates/*.in)
-CONTROL_FILES += debian/bin/gencontrol.py debian/config/defines $(wildcard debian/config/*/defines) debian/modinfo.json
+CONTROL_FILES += $(GENCONTROL) debian/config/defines $(wildcard debian/config/*/defines) debian/modinfo.json
 
-# debian/bin/gencontrol.py uses debian/changelog as input, but the
+# GENCONTROL uses debian/changelog as input, but the
 # output only depends on the source name and version.  To avoid
 # frequent changes to debian/control.md5sum, include only those fields
 # in the checksum.
-- 
2.39.2

>From 568294221c5a8ba01a92952744ea96b6eda464db Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Fri, 23 Feb 2024 17:36:45 +0100
Subject: [PATCH 06/10] d/watch: update format to version 4, add spaces for
 readability

---
 debian/watch | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/debian/watch b/debian/watch
index f09afbf..1e4102e 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,4 +1,10 @@
-version=3
-opts="mode=git, gitmode=shallow, pgpmode=gittag" \
+version=4
+
+opts="\
+  mode=git,\
+  gitmode=shallow,\
+  pgpmode=gittag,\
+" \
 https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git \
-refs/tags/(.*) debian
+refs/tags/(.*) \
+debian
-- 
2.39.2

>From 94edbc25117933a9e71db715333f29be54f110bf Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Fri, 23 Feb 2024 17:22:19 +0100
Subject: [PATCH 07/10] gencontrol.py: open files with context managers

---
 debian/bin/gencontrol.py | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/debian/bin/gencontrol.py b/debian/bin/gencontrol.py
index 293432b..11249d0 100755
--- a/debian/bin/gencontrol.py
+++ b/debian/bin/gencontrol.py
@@ -258,18 +258,21 @@ class GenControl(debian_linux.gencontrol.Gencontrol):
 
         if 'initramfs-tools' in config_entry.get('support', []):
             postinst = self.templates.get('postinst.initramfs-tools')
-            open("debian/firmware-%s.postinst" % package, 'w').write(self.substitute(postinst, vars))
+            with open(f'debian/firmware-{package}.postinst', 'w') as postint_f:
+                postint_f.write(self.substitute(postinst, vars))
 
         if 'license-accept' in config_entry:
-            license = open("%s/LICENSE.install" % package_dir, 'r').read()
+            with open(f'{package_dir}/LICENSE.install', 'r') as license_f:
+                license = license_f.read()
             preinst = self.templates.get('preinst.license')
             preinst_filename = "debian/firmware-%s.preinst" % package
-            open(preinst_filename, 'w').write(self.substitute(preinst, vars))
+            with open(preinst_filename, 'w') as preinst_f:
+                preinst_f.write(self.substitute(preinst, vars))
 
             templates = self.templates.get_templates_control('templates.license', vars)
             templates[0]['Description'].append(re.sub('\n\n', '\n.\n', license))
             templates_filename = "debian/firmware-%s.templates" % package
-            self.write_rfc822(open(templates_filename, 'w'), templates)
+            self.write_rfc822(templates_filename, templates)
 
             desc = packages_binary[0]['Description']
             desc.append(
@@ -290,7 +293,8 @@ You must agree to the terms of this license before it is installed."""
         vars['longdesc-metainfo'] = re.sub(r'\s+', ' ', vars['longdesc'])
         package_meta_temp = self.templates.get("metainfo.xml", {})
         # XXX Might need to escape some characters
-        open("debian/firmware-%s.metainfo.xml" % package, 'w').write(self.substitute(package_meta_temp, vars))
+        with open(f'debian/firmware-{package}.metainfo.xml', 'w') as meta_f:
+            meta_f.write(self.substitute(package_meta_temp, vars))
 
     def process_template(self, in_entry, vars):
         e = Template()
@@ -324,18 +328,18 @@ You must agree to the terms of this license before it is installed."""
         self.write_makefile(makefile)
 
     def write_control(self, list):
-        self.write_rfc822(open("debian/control", 'w'), list)
+        self.write_rfc822('debian/control', list)
 
     def write_makefile(self, makefile):
-        f = open("debian/rules.gen", 'w')
-        makefile.write(f)
-        f.close()
-
-    def write_rfc822(self, f, list):
-        for entry in list:
-            for key, value in entry.items():
-                f.write("%s: %s\n" % (key, value))
-            f.write('\n')
+        with open('debian/rules.gen', 'w') as f:
+            makefile.write(f)
+
+    def write_rfc822(self, path, list):
+        with open(path, 'w') as f:
+            for entry in list:
+                for key, value in entry.items():
+                    f.write("%s: %s\n" % (key, value))
+                f.write('\n')
 
 if __name__ == '__main__':
     GenControl()()
-- 
2.39.2

>From ab600a244f3ca4b12c124c01c04f775a77adc699 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Sun, 25 Feb 2024 01:07:44 +0100
Subject: [PATCH 08/10] gencontrol.py: import standard library before local
 modules

---
 debian/bin/gencontrol.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/debian/bin/gencontrol.py b/debian/bin/gencontrol.py
index 11249d0..1f5b574 100755
--- a/debian/bin/gencontrol.py
+++ b/debian/bin/gencontrol.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python3
 
+from collections import OrderedDict
 import io
 import json
 import locale
@@ -18,7 +19,6 @@ import debian_linux.gencontrol
 from debian_linux.gencontrol import Makefile, MakeFlags, PackagesList
 from debian_linux.utils import TextWrapper
 from debian_linux.utils import Templates as TemplatesBase
-from collections import OrderedDict
 
 class PackageDescription(PackageDescriptionBase):
     __slots__ = ()
-- 
2.39.2

>From fdadbaf724a06a554ee19da02bf8d6434aa516d6 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Sun, 25 Feb 2024 01:16:09 +0100
Subject: [PATCH 09/10] gencontrol.py: remove unused process_template methods

---
 debian/bin/gencontrol.py | 17 -----------------
 1 file changed, 17 deletions(-)

diff --git a/debian/bin/gencontrol.py b/debian/bin/gencontrol.py
index 1f5b574..fdaaf6b 100755
--- a/debian/bin/gencontrol.py
+++ b/debian/bin/gencontrol.py
@@ -296,23 +296,6 @@ You must agree to the terms of this license before it is installed."""
         with open(f'debian/firmware-{package}.metainfo.xml', 'w') as meta_f:
             meta_f.write(self.substitute(package_meta_temp, vars))
 
-    def process_template(self, in_entry, vars):
-        e = Template()
-        for key, value in in_entry.items():
-            if isinstance(value, PackageDescription):
-                e[key] = self.process_description(value, vars)
-            elif key[:2] == 'X-':
-                pass
-            else:
-                e[key] = self.substitute(value, vars)
-        return e
-
-    def process_templates(self, in_entries, vars):
-        entries = []
-        for i in in_entries:
-            entries.append(self.process_template(i, vars))
-        return entries
-
     def substitute(self, s, vars):
         if isinstance(s, (list, tuple)):
             return [self.substitute(i, vars) for i in s]
-- 
2.39.2

>From e9ac0ac9976f9c05206f492c3cfcece7981887b9 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas@debian.org>
Date: Sun, 25 Feb 2024 01:26:35 +0100
Subject: [PATCH 10/10] Simplify gencontrol.py and its interaction with
 debian/rules

Before:
  d/bin/gencontrol.py
    encodes a list of files and links to install as Make variables
    generates d/rules.gen as a Makefile running d/rules.real
  d/rules
    invokes 'make -f d/rules.gen' recursively
  d/rules.real
    installs things (and displays its actions)
    runs debhelper tools
After:
  d/bin/gencontrol.py
    generates d/rules.gen as a shell script installing files and links
  d/rules:
    uses the dh driver and debhelper overrides in the usual way
    (displays and) executes d/rules.gen

In gencontrol.py
 * remove the GenControl class.
   The ancestor class was unused, and the attributes are more explicit
   as parameters in procedure calls.
 * Move modinfo and firmware_modules from main() to the more specific
   do_main().
 * Rename the templates local variable to avoid a clash with the
   argument.
 * Add a append_to_rules_gen procedure in charge of the generation.
---
 debian/bin/gencontrol.py | 469 +++++++++++++++++++--------------------
 debian/rules             |  29 ++-
 debian/rules.real        |  45 ----
 3 files changed, 251 insertions(+), 292 deletions(-)
 delete mode 100644 debian/rules.real

diff --git a/debian/bin/gencontrol.py b/debian/bin/gencontrol.py
index fdaaf6b..162ae9a 100755
--- a/debian/bin/gencontrol.py
+++ b/debian/bin/gencontrol.py
@@ -15,8 +15,7 @@ locale.setlocale(locale.LC_CTYPE, "C.UTF-8")
 from config import Config
 from debian_linux.debian import BinaryPackage, PackageRelation, _ControlFileDict
 from debian_linux.debian import PackageDescription as PackageDescriptionBase
-import debian_linux.gencontrol
-from debian_linux.gencontrol import Makefile, MakeFlags, PackagesList
+from debian_linux.gencontrol import PackagesList
 from debian_linux.utils import TextWrapper
 from debian_linux.utils import Templates as TemplatesBase
 
@@ -70,259 +69,259 @@ class Templates(TemplatesBase):
         return Template.read_rfc822(io.StringIO(self.get(key, context)))
 
 
-class GenControl(debian_linux.gencontrol.Gencontrol):
-    def __init__(self):
-        self.config = Config()
-        self.templates = Templates()
+def main():
+    config = Config()
+    templates = Templates()
+    packages = PackagesList()
+    do_source(templates, packages)
+    do_extra(config, templates, packages)
+    do_main(config, templates, packages)
+    write_rfc822('debian/control', packages.values())
 
-        with open('debian/modinfo.json', 'r') as f:
-            self.modinfo = json.load(f)
 
-        # Make another dict keyed by firmware names
-        self.firmware_modules = {}
-        for name, info  in self.modinfo.items():
-            for firmware_filename in info['firmware']:
-                self.firmware_modules.setdefault(firmware_filename, []) \
-                                     .append(name)
+def do_source(templates, packages):
+    packages['source'] = templates.get_source_control("control.source", {})[0]
 
-    def __call__(self):
-        packages = PackagesList()
-        makefile = Makefile()
 
-        self.do_source(packages)
-        self.do_extra(packages, makefile)
-        self.do_main(packages, makefile)
+def do_extra(config, templates, packages):
+    config_entry = config['base',]
+    vars = {}
+    vars.update(config_entry)
 
-        self.write(packages, makefile)
+    for package_binary in templates.get_control("control.extra", {}):
+        assert package_binary['Package'].startswith('firmware-')
 
-    def do_source(self, packages):
-        packages['source'] = self.templates.get_source_control("control.source", {})[0]
+        packages.append(package_binary)
 
-    def do_extra(self, packages, makefile):
-        config_entry = self.config['base',]
-        vars = {}
-        vars.update(config_entry)
 
-        for package_binary in self.templates.get_control("control.extra", {}):
-            assert package_binary['Package'].startswith('firmware-')
-            package = package_binary['Package'].replace('firmware-', '')
+def do_main(config, templates, packages):
 
-            makeflags = MakeFlags()
-            makeflags['FILES'] = ''
-            makeflags['PACKAGE'] = package
-            makefile.add_cmds('binary-indep', ["$(MAKE) -f debian/rules.real binary-indep %s" % makeflags])
+    with open('debian/modinfo.json', 'r') as f:
+        modinfo: dict[str, dict[str, list[str]]] = json.load(f)
 
-            packages.append(package_binary)
+    # Make another dict keyed by firmware names
+    firmware_modules: dict[str, list[str]] = {}
+    for name, info in modinfo.items():
+        for firmware_filename in info['firmware']:
+            firmware_modules.setdefault(firmware_filename, []) \
+                            .append(name)
 
-    def do_main(self, packages, makefile):
-        config_entry = self.config['base',]
-        vars = {}
-        vars.update(config_entry)
-
-        makeflags = MakeFlags()
-
-        for i in ('build', 'binary-arch', 'setup'):
-            makefile.add_cmds("%s_%%" % i, ["@true"])
+    config_entry = config['base',]
+    vars = {}
+    vars.update(config_entry)
 
+    with open('debian/rules.gen', 'w') as rules_gen:
         for package in config_entry['packages']:
-            self.do_package(packages, makefile, package, vars.copy(), makeflags.copy())
-
-    def do_package(self, packages, makefile, package, vars, makeflags):
-        config_entry = self.config['base', package]
-        vars.update(config_entry)
-        vars['package'] = package
-        vars['package-env-prefix'] = 'FIRMWARE_' + package.upper().replace('-', '_')
-
-        makeflags['PACKAGE'] = package
-
-        # Those might be absent, set them to empty string for replacement to work:
-        empty_list = ['replaces', 'conflicts', 'breaks', 'provides', 'recommends']
-        for optional in ['replaces', 'conflicts', 'breaks', 'provides', 'recommends']:
-            if optional not in vars:
-                vars[optional] = ''
-
-        package_dir = "debian/config/%s" % package
-
+            do_package(config, templates, modinfo, firmware_modules,
+                       packages, rules_gen, package, vars.copy())
+
+
+def do_package(config, templates, modinfo, firmware_modules,
+               packages, rules_gen, package, vars):
+    config_entry = config['base', package]
+    vars.update(config_entry)
+    vars['package'] = package
+    vars['package-env-prefix'] = 'FIRMWARE_' + package.upper().replace('-', '_')
+
+    # Those might be absent, set them to empty string for replacement to work:
+    for optional in ['replaces', 'conflicts', 'breaks', 'provides', 'recommends']:
+        if optional not in vars:
+            vars[optional] = ''
+
+    package_dir = "debian/config/%s" % package
+
+    try:
+        os.unlink('debian/firmware-%s.bug-presubj' % package)
+    except OSError:
+        pass
+    os.symlink('bug-presubj', 'debian/firmware-%s.bug-presubj' % package)
+
+    files_orig = config_entry['files']
+    files_real = {}
+    files_unused = []
+    links = {}
+    links_rev = {}
+
+    # Look for additional and replacement files in binary package config
+    for root, dirs, files in os.walk(package_dir):
         try:
-            os.unlink('debian/firmware-%s.bug-presubj' % package)
-        except OSError:
+            dirs.remove('.svn')
+        except ValueError:
             pass
-        os.symlink('bug-presubj', 'debian/firmware-%s.bug-presubj' % package)
-
-        files_orig = config_entry['files']
-        files_real = {}
-        files_unused = []
-        links = {}
-        links_rev = {}
-
-        # Look for additional and replacement files in binary package config
-        for root, dirs, files in os.walk(package_dir):
-            try:
-                dirs.remove('.svn')
-            except ValueError:
-                pass
-            for f in files:
-                cur_path = root + '/' + f
-                if root != package_dir:
-                    f = root[len(package_dir) + 1 : ] + '/' + f
-                if os.path.islink(cur_path):
-                    if f in files_orig:
-                        links[f] = os.readlink(cur_path)
-                    continue
-                f1 = f.rsplit('-', 1)
+        for f in files:
+            cur_path = root + '/' + f
+            if root != package_dir:
+                f = root[len(package_dir) + 1 : ] + '/' + f
+            if os.path.islink(cur_path):
                 if f in files_orig:
-                    files_real[f] = f, cur_path, None
-                    continue
-                if len(f1) > 1:
-                    f_base, f_version = f1
-                    if f_base in files_orig:
-                        if f_base in files_real:
-                            raise RuntimeError("Multiple files for %s" % f_base)
-                        files_real[f_base] = f_base, package_dir + '/' + f, \
-                                             f_version
-                        continue
-                # Whitelist files not expected to be installed as firmware
-                if f in ['defines', 'LICENSE.install',
-                         'update.py', 'update.sh']:
+                    links[f] = os.readlink(cur_path)
+                continue
+            f1 = f.rsplit('-', 1)
+            if f in files_orig:
+                files_real[f] = f, cur_path, None
+                continue
+            if len(f1) > 1:
+                f_base, f_version = f1
+                if f_base in files_orig:
+                    if f_base in files_real:
+                        raise RuntimeError("Multiple files for %s" % f_base)
+                    files_real[f_base] = f_base, package_dir + '/' + f, \
+                                         f_version
                     continue
-                files_unused.append(f)
-
-        # Take all the other files from upstream
-        for f in files_orig:
-            if f not in files_real and f not in links:
-                f_upstream = os.path.join('debian/build/install', f)
-                if os.path.islink(f_upstream):
-                    links[f] = os.readlink(f_upstream)
-                elif os.path.isfile(f_upstream):
-                    files_real[f] = f, f_upstream, None
-
-        for f in links:
-            link_target = os.path.normpath(os.path.join(f, '..', links[f]))
-            links_rev.setdefault(link_target, []).append(f)
-
-        if files_unused:
-            print('W: %s: unused files:' % package, ' '.join(files_unused),
-                  file=sys.stderr)
-
-        makeflags['FILES'] = ' '.join(["%s:%s" % (i[1], i[0]) for i in sorted(files_real.values())])
-        vars['files_real'] = ' '.join(["/lib/firmware/%s" % i for i in config_entry['files']])
-
-        makeflags['LINKS'] = ' '.join(["%s:%s" % (link, target)
-                                       for link, target in sorted(links.items())])
-
-        files_desc = ["Contents:"]
-        firmware_meta_temp = self.templates.get("metainfo.xml.firmware")
-        firmware_meta_list = []
-        module_names = set()
-
-        wrap = TextWrapper(width = 71, fix_sentence_endings = True,
-                           initial_indent = ' * ',
-                           subsequent_indent = '   ').wrap
-        for f in config_entry['files']:
-            firmware_meta_list.append(self.substitute(firmware_meta_temp,
-                                                      {'filename': f}))
-            for module_name in self.firmware_modules.get(f, []):
-                module_names.add(module_name)
-            if f in links:
+            # Whitelist files not expected to be installed as firmware
+            if f in ['defines', 'LICENSE.install',
+                     'update.py', 'update.sh']:
                 continue
-            f, f_real, version = files_real[f]
-            c = self.config.get(('base', package, f), {})
-            desc = c.get('desc')
-            if version is None:
-                version = c.get('version')
-            try:
-                f = f + ', ' + ', '.join(sorted(links_rev[f]))
-            except KeyError:
-                pass
-            if desc and version:
-                desc = "%s, version %s (%s)" % (desc, version, f)
-            elif desc:
-                desc = "%s (%s)" % (desc, f)
-            else:
-                desc = "%s" % f
-            files_desc.extend(wrap(desc))
-
-        modaliases = set()
-        for module_name in module_names:
-            for modalias in self.modinfo[module_name]['alias']:
-                modaliases.add(modalias)
-        modalias_meta_list = [
-            self.substitute(self.templates.get("metainfo.xml.modalias"),
-                            {'alias': alias})
-            for alias in sorted(list(modaliases))
-        ]
-
-        packages_binary = self.templates.get_control("control.binary", vars)
-
-        packages_binary[0]['Description'].append_pre(files_desc)
-
-        if 'initramfs-tools' in config_entry.get('support', []):
-            postinst = self.templates.get('postinst.initramfs-tools')
-            with open(f'debian/firmware-{package}.postinst', 'w') as postint_f:
-                postint_f.write(self.substitute(postinst, vars))
-
-        if 'license-accept' in config_entry:
-            with open(f'{package_dir}/LICENSE.install', 'r') as license_f:
-                license = license_f.read()
-            preinst = self.templates.get('preinst.license')
-            preinst_filename = "debian/firmware-%s.preinst" % package
-            with open(preinst_filename, 'w') as preinst_f:
-                preinst_f.write(self.substitute(preinst, vars))
-
-            templates = self.templates.get_templates_control('templates.license', vars)
-            templates[0]['Description'].append(re.sub('\n\n', '\n.\n', license))
-            templates_filename = "debian/firmware-%s.templates" % package
-            self.write_rfc822(templates_filename, templates)
-
-            desc = packages_binary[0]['Description']
-            desc.append(
+            files_unused.append(f)
+
+    # Take all the other files from upstream
+    for f in files_orig:
+        if f not in files_real and f not in links:
+            f_upstream = os.path.join('debian/build/install', f)
+            if os.path.islink(f_upstream):
+                links[f] = os.readlink(f_upstream)
+            elif os.path.isfile(f_upstream):
+                files_real[f] = f, f_upstream, None
+
+    for f in links:
+        link_target = os.path.normpath(os.path.join(f, '..', links[f]))
+        links_rev.setdefault(link_target, []).append(f)
+
+    if files_unused:
+        print('W: %s: unused files:' % package, ' '.join(files_unused),
+              file=sys.stderr)
+
+    vars['files_real'] = ' '.join(["/lib/firmware/%s" % i for i in config_entry['files']])
+
+    append_to_rules_gen(rules_gen, package, files_real, links)
+
+    files_desc = ["Contents:"]
+    firmware_meta_temp = templates.get("metainfo.xml.firmware")
+    firmware_meta_list = []
+    module_names = set()
+
+    wrap = TextWrapper(width = 71, fix_sentence_endings = True,
+                       initial_indent = ' * ',
+                       subsequent_indent = '   ').wrap
+    for f in config_entry['files']:
+        firmware_meta_list.append(substitute(firmware_meta_temp,
+                                             {'filename': f}))
+        for module_name in firmware_modules.get(f, []):
+            module_names.add(module_name)
+        if f in links:
+            continue
+        f, f_real, version = files_real[f]
+        c = config.get(('base', package, f), {})
+        desc = c.get('desc')
+        if version is None:
+            version = c.get('version')
+        try:
+            f = f + ', ' + ', '.join(sorted(links_rev[f]))
+        except KeyError:
+            pass
+        if desc and version:
+            desc = "%s, version %s (%s)" % (desc, version, f)
+        elif desc:
+            desc = "%s (%s)" % (desc, f)
+        else:
+            desc = "%s" % f
+        files_desc.extend(wrap(desc))
+
+    modaliases = set()
+    for module_name in module_names:
+        for modalias in modinfo[module_name]['alias']:
+            modaliases.add(modalias)
+    modalias_meta_list = [
+        substitute(templates.get("metainfo.xml.modalias"),
+                   {'alias': alias})
+        for alias in sorted(list(modaliases))
+    ]
+
+    packages_binary = templates.get_control("control.binary", vars)
+
+    packages_binary[0]['Description'].append_pre(files_desc)
+
+    if 'initramfs-tools' in config_entry.get('support', []):
+        postinst = templates.get('postinst.initramfs-tools')
+        with open(f'debian/firmware-{package}.postinst', 'w') as postint_f:
+            postint_f.write(substitute(postinst, vars))
+
+    if 'license-accept' in config_entry:
+        with open(f'{package_dir}/LICENSE.install', 'r') as license_f:
+            license = license_f.read()
+        preinst = templates.get('preinst.license')
+        preinst_filename = "debian/firmware-%s.preinst" % package
+        with open(preinst_filename, 'w') as preinst_f:
+            preinst_f.write(substitute(preinst, vars))
+
+        templates_license = templates.get_templates_control('templates.license', vars)
+        templates_license[0]['Description'].append(re.sub('\n\n', '\n.\n', license))
+        templates_filename = "debian/firmware-%s.templates" % package
+        write_rfc822(templates_filename, templates_license)
+
+        desc = packages_binary[0]['Description']
+        desc.append(
 """This firmware is covered by the %s.
 You must agree to the terms of this license before it is installed."""
 % vars['license-title'])
-            packages_binary[0]['Pre-Depends'] = PackageRelation('debconf | debconf-2.0')
-
-        packages.extend(packages_binary)
-
-        makefile.add_cmds('binary-indep', ["$(MAKE) -f debian/rules.real binary-indep %s" % makeflags])
-
-        vars['firmware-list'] = ''.join(firmware_meta_list)
-        vars['modalias-list'] = ''.join(modalias_meta_list)
-        # Underscores are preferred to hyphens
-        vars['package-metainfo'] = package.replace('-', '_')
-        # Summary must not contain line breaks
-        vars['longdesc-metainfo'] = re.sub(r'\s+', ' ', vars['longdesc'])
-        package_meta_temp = self.templates.get("metainfo.xml", {})
-        # XXX Might need to escape some characters
-        with open(f'debian/firmware-{package}.metainfo.xml', 'w') as meta_f:
-            meta_f.write(self.substitute(package_meta_temp, vars))
-
-    def substitute(self, s, vars):
-        if isinstance(s, (list, tuple)):
-            return [self.substitute(i, vars) for i in s]
-        def subst(match):
-            if match.group(1):
-                return vars.get(match.group(2), '')
-            else:
-                return vars[match.group(2)]
-        return re.sub(r'@(\??)([-_a-z]+)@', subst, str(s))
-
-    def write(self, packages, makefile):
-        self.write_control(packages.values())
-        self.write_makefile(makefile)
-
-    def write_control(self, list):
-        self.write_rfc822('debian/control', list)
-
-    def write_makefile(self, makefile):
-        with open('debian/rules.gen', 'w') as f:
-            makefile.write(f)
-
-    def write_rfc822(self, path, list):
-        with open(path, 'w') as f:
-            for entry in list:
-                for key, value in entry.items():
-                    f.write("%s: %s\n" % (key, value))
-                f.write('\n')
+        packages_binary[0]['Pre-Depends'] = PackageRelation('debconf | debconf-2.0')
+
+    packages.extend(packages_binary)
+
+    vars['firmware-list'] = ''.join(firmware_meta_list)
+    vars['modalias-list'] = ''.join(modalias_meta_list)
+    # Underscores are preferred to hyphens
+    vars['package-metainfo'] = package.replace('-', '_')
+    # Summary must not contain line breaks
+    vars['longdesc-metainfo'] = re.sub(r'\s+', ' ', vars['longdesc'])
+    package_meta_temp = templates.get("metainfo.xml", {})
+    # XXX Might need to escape some characters
+    with open(f'debian/firmware-{package}.metainfo.xml', 'w') as meta_f:
+        meta_f.write(substitute(package_meta_temp, vars))
+
+
+def append_to_rules_gen(rules_gen, package, files_real, links):
+    deb_pkg = f'firmware-{package}'
+    pkg_dir = f'debian/{deb_pkg}'
+    firmware_dir = f'{pkg_dir}/lib/firmware'
+
+    for dst, src, _vsn in files_real.values():
+        rules_gen.write(f"install -m644 -D '{src}' '{firmware_dir}/{dst}'\n")
+
+    # Avoid flooding the build log with redundant 'install -d'.
+    seen_dirnames = set()
+    for link, target in links.items():
+        link_path = f'{firmware_dir}/{link}'
+        link_dirname = os.path.dirname(link_path)
+
+        if link_dirname not in seen_dirnames:
+            seen_dirnames.add(link_dirname)
+            rules_gen.write(f"install -d '{link_dirname}'\n")
+
+        rules_gen.write(f"ln -s '{target}' '{link_path}'\n")
+
+    rules_gen.write(
+        f'dh_install -p{deb_pkg} {pkg_dir}.metainfo.xml usr/share/metainfo\n')
+
+
+def substitute(s, vars):
+    if isinstance(s, (list, tuple)):
+        return [substitute(i, vars) for i in s]
+    def subst(match):
+        if match.group(1):
+            return vars.get(match.group(2), '')
+        else:
+            return vars[match.group(2)]
+    return re.sub(r'@(\??)([-_a-z]+)@', subst, str(s))
+
+
+def write_rfc822(path, list):
+    with open(path, 'w') as f:
+        for entry in list:
+            for key, value in entry.items():
+                f.write("%s: %s\n" % (key, value))
+            f.write('\n')
+
 
 if __name__ == '__main__':
-    GenControl()()
+    main()
diff --git a/debian/rules b/debian/rules
index f455e5e..503d6b6 100755
--- a/debian/rules
+++ b/debian/rules
@@ -9,21 +9,26 @@ include debian/rules.defs
 
 GENCONTROL = debian/bin/gencontrol.py
 
-# Nothing to build
-build-indep build-arch build: debian/control
-
-clean: debian/control
-	dh_testdir
-	dh_clean
-
-binary-indep: build-indep
-	dh_testdir
+binary binary-arch binary-indep build build-arch build-indep clean: \
+                                                             debian/control
+	dh $@
+
+# Tell debhelper to ignore ./configure and Makefile.
+override_dh_auto_configure:
+override_dh_auto_build:
+override_dh_auto_install:
 	./copy-firmware.sh -v debian/build/install
-	$(MAKE) -f debian/rules.gen binary-indep
+override_dh_auto_test:
+
+execute_before_dh_install: debian/rules.gen
+	cat $<
+	sh -e $<
 
-binary-arch: build-arch
+override_dh_installdocs:
+	dh_installdocs -XTODO
 
-binary:	binary-indep binary-arch
+execute_after_dh_installdeb:
+	if command -v dh_movetousr >/dev/null; then dh_movetousr; fi
 
 CONTROL_FILES = debian/build/version-info $(wildcard debian/templates/*.in)
 CONTROL_FILES += $(GENCONTROL) debian/config/defines $(wildcard debian/config/*/defines) debian/modinfo.json
diff --git a/debian/rules.real b/debian/rules.real
deleted file mode 100644
index 3fa602f..0000000
--- a/debian/rules.real
+++ /dev/null
@@ -1,45 +0,0 @@
-SHELL  := sh -e
-
-export DH_OPTIONS
-
-#
-# Targets
-#
-binary-indep: install
-
-install: PACKAGE_NAME = firmware-$(PACKAGE)
-install: DH_OPTIONS = -p$(PACKAGE_NAME)
-install:
-	dh_testdir
-	dh_testroot
-	dh_prep
-	@for i in $(FILES); do \
-	  s="$${i%:*}"; \
-	  d=/lib/firmware/"$${i#*:}"; \
-	  echo install -m644 -D "$$s" debian/$(PACKAGE_NAME)"$$d"; \
-	  install -m644 -D "$$s" debian/$(PACKAGE_NAME)"$$d"; \
-	done
-	@for i in $(LINKS); do \
-	  link=debian/$(PACKAGE_NAME)/lib/firmware/"$${i%:*}"; \
-	  target="$${i#*:}"; \
-	  install -d "$${link%/*}"; \
-	  echo ln -s "$$target" "$$link"; \
-	  ln -s "$$target" "$$link"; \
-	done
-ifneq ($(FILES),)
-	dh_installdirs /usr/share/metainfo
-	dh_install debian/$(PACKAGE_NAME).metainfo.xml /usr/share/metainfo
-endif
-	dh_bugfiles
-	dh_installchangelogs
-	dh_installdocs -XTODO
-	dh_installdebconf
-	dh_lintian
-	dh_link
-	dh_compress
-	dh_fixperms
-	dh_installdeb
-	if command -v dh_movetousr >/dev/null; then dh_movetousr; fi
-	dh_gencontrol
-	dh_md5sums
-	dh_builddeb
-- 
2.39.2


Reply to: