14/07/2023

The Debian Janitor is an automated
system that commits fixes for (minor) issues in Debian packages that can be
fixed by software. It gradually started proposing merges in early December. The
first set of changes sent out ran lintian-brush on sid packages maintained in
Git. This post is part of a series about the progress of the Janitor.Scheduling Lintian Fixes
To determine which packages to process, the Janitor looks at the import of lintian output across the archive that is available
in UDD[1]. It
will prioritize those packages with the most and more severe issues that it has
fixers for.
Once a package is selected, it will clone the packaging repository and run
lintian-brush
on it. Lintian-brush provides a framework for applying a set of fixers to a
package. It will run each of a set of fixers in a pristine version of the
repository, and handles most of the heavy lifting.
The Inner Workings of a Fixer
Each fixer is just an executable which gets run in a clean
checkout of the package, and can make changes there. Most
of the fixers are written in Python or shell, but they
can be in any language.
The contract for fixers is pretty simple:

  • If the fixer exits with non-zero, the changes are reverted and fixer is
    considered to have failed
  • If exits with zero and made changes, then it should write a summary of its
    changes to standard out

If a fixer is uncertain about the changes it has made, it should report so on
standard output using a pseudo-header. By default, lintian-brush will discard
any changes with uncertainty but if you are running it locally you can still
apply them by specifying –uncertain.
The summary message on standard out will be used for the commit message and
(possibly) the changelog message, if the package doesnt use gbp dch.
Example Fixer
Lets look at an example. The package priority extra is deprecated since
Debian Policy 4.0.1 (released August 2 017) see
Policy 2.5 “Priorities”.
Instead, most packages should use the optional priority.
Lintian will warn when a package uses the deprecated extra value for the
Priority – the associated tag is
priority-extra-is-replaced-by-priority-optional.
Lintian-brush has a fixer script that can automatically replace extra with
optional.
On systems that have lintian-brush installed, the source for the fixer lives in
/usr/share/lintian-brush/fixers/priority-extra-is-replaced-by-priority-optional.py,
but here is a copy of it for reference:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/python3fromdebmutate.controlimportControlEditorfromlintian_brush.fixerimportreport_result,fixed_lintian_tagwithControlEditor()asupdater:forparainupdater.paragraphs:ifpara.get(“Priority”)==”extra”:para[“Priority”]=”optional”fixed_lintian_tag(para,’priority-extra-is-replaced-by-priority-optional’)report_result(“Change priority extra to priority optional.”)

This fixer is written in Python and uses the debmutate library to easily modify
control files while preserving formatting or back out if it is not possible
to preserve formatting.
All the current fixers come with tests, e.g. for this particular fixer the
tests can be found here:
https://salsa.debian.org/jelmer/lintian-brush/-/tree/master/tests/priority-extra-is-replaced-by-priority-optional.
For more details on writing new fixers, see the README for
lintian-brush.
For more details on debugging them, see the manual page.