upgrades: Add augeas lens for Deb822 apt sources

Helps #214.

Tests:

- Augeas lens tests passed using augparse.

Signed-off-by: James Valleroy <jvalleroy@mailbox.org>
[sunil: Fix issue with not being able write back with lens]
[sunil: Parse single/multi field values based on man page]
[sunil: Allow creating multi field values by adding \n at the end of the value]
[sunil: Add documentation and make ready for upstream submission]
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
James Valleroy 2022-11-19 07:08:12 -05:00 committed by Sunil Mohan Adapa
parent 3fac4f55fe
commit cd21c7f247
No known key found for this signature in database
GPG Key ID: 43EA1CFF0AA7C5F2
2 changed files with 224 additions and 0 deletions

View File

@ -0,0 +1,104 @@
(*
Module: Aptsources822
Augeas module for souces list (Deb822 style) for Apt package manager
Authors:
James Valleroy <jvalleroy@mailbox.org>
Sunil Mohan Adapa <sunil@medhas.org>
About: Reference
1. Deb822(5):
https://manpages.debian.org/bullseye/dpkg-dev/deb822.5.en.html
2. sources.list(5):
https://manpages.debian.org/bullseye/apt/sources.list.5.en.html
About: License
This file is licensed under the LGPLv2+, like the rest of Augeas.
About: Configuration files
This lens applies to files in /etc/apt/sources.list.d/ ending with the
extension .sources. See <filter>.
*)
module Aptsources822 =
autoload xfm
(* Variable: single_value_field_name
Names of known fields for which only a single value is allowed. *)
let single_value_field_name = /(Enabled|PDiffs|By-Hash|Allow-Insecure|Allow-Weak|Allow-Downgrade-To-Insecure|Trusted|Check-Valid-Until|Valid-Until-Min|Valid-Until-Max|Check-Date|Date-Max-Future|InRelease-Path)/
(* Variable: multi_value_field_name
Names of known fields for which multiple values are allowed and names of
unknown fields. Unknown fields are assumed to contain multiple values as
that is the safest assumption.
According to deb822(5) man page, "The field name is composed of US-ASCII
characters excluding control characters, space, and colon (i.e., characters
in the ranges U+0021 ! through U+0039 9, and U+003B ; through U+007E
~, inclusive). Field names must not begin with the comment character
(U+0023 #), nor with the hyphen character (U+002D -)." *)
let multi_value_field_name = /[!"$-,.-9;-~][!-9;-~]*/ - single_value_field_name
(* Variable: field_value
Value that a field can contain. Deb822 styles sources list files defines some
fields to have multiple values separated by space, tab or a newline. *)
let field_value = /[!-Z\\^-~][!-Z\\^-~]*/
(* Variable: empty_line
Lens for an empty line separating two stanzas. It can't be a comment. Only
tabs and spaces are allowed. *)
let empty_line = Util.empty_generic /[ \t]*/
(* Variable: name_value_separator
Lens for separating a name and value. Field name is followed by a ':' and
then optionally space. The file format also allow for a value to be on a
new line when the new line starts with space or a tab. *)
let name_value_separator = Sep.colon . del (Rx.opt_space . /(\n[ \t])?/) " "
(* Variable: field_value_with_newline
Lens for value that followed by a new line and a space. This indicates that
another value follows it. *)
let field_value_with_newline = [seq "item" . store (field_value . /\n/) .
del /[\t ]/ " "]
(* Variable: field_value_with_separator
Lens for value that followed by a space or a tab. This indicates that another
value follows it. *)
let field_value_with_separator = [seq "item" . store field_value . del Rx.space " "]
(* Variable: field_value_with_eol
Lens for value that followed by an end-of-line. This indicates that this is
the last value for this field. *)
let field_value_with_eol = [seq "item" . store field_value . Util.eol]
(* Variable: single_value_field
Lens for a field (field name, separator and field value) with only a single
value. *)
let single_value_field = [ key single_value_field_name . name_value_separator .
store field_value . Util.eol ]
(* Variable: multi_value_field
Lens for a field (field name, separator and field value) with multiple values
*)
let multi_value_field = [ key multi_value_field_name . name_value_separator .
counter "item" . (field_value_with_newline | field_value_with_separator)* .
field_value_with_eol ]
(* Variable: stanza
Lens for a stanza that describes one or more sources for apt. *)
let stanza = [ seq "source" . (single_value_field | multi_value_field |
Util.comment_noindent)+ ]
(* Variable: lns
Lens for parsing the entire apt sources file in Deb822 format. *)
let lns = stanza . (empty_line . stanza)*
(* Variable: filter
All files in the sources.list.d directory are files describing sources.
However, only those ending with .sources extension are in Deb822 format. *)
let filter = incl "/etc/apt/sources.list.d/*.sources"
let xfm = transform lns filter

View File

@ -0,0 +1,120 @@
module Test_Aptsources822 =
(* Test multiple values, multi-line values and multiple source stanzas *)
let sources1 = "Enabled: yes
Types: deb deb-src
URIs: http://deb.debian.org/debian
Suites: bullseye
bullseye-backports
Components: main non-free-firmware
Allow-Insecure: no
Signed-By:
-----BEGIN PGP PUBLIC KEY BLOCK-----
.
mDMEYCQjIxYJKwYBBAHaRw8BAQdAD/P5Nvvnvk66SxBBHDbhRml9ORg1WV5CvzKY
CuMfoIS0BmFiY2RlZoiQBBMWCgA4FiEErCIG1VhKWMWo2yfAREZd5NfO31cFAmAk
IyMCGyMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQREZd5NfO31fbOwD6ArzS
dM0Dkd5h2Ujy1b6KcAaVW9FOa5UNfJ9FFBtjLQEBAJ7UyWD3dZzhvlaAwunsk7DG
3bHcln8DMpIJVXht78sL
=IE0r
-----END PGP PUBLIC KEY BLOCK-----
Enabled: no
URIs: http://dl.google.com/linux/chrome/deb
Suites: stable
Components: main
Architectures: amd64
"
test Aptsources822.lns get sources1 =
{ "1"
{ "Enabled" = "yes" }
{ "Types"
{ "1" = "deb" }
{ "2" = "deb-src" }
}
{ "URIs" { "1" = "http://deb.debian.org/debian" } }
{ "Suites"
{ "1" = "bullseye\n" }
{ "2" = "bullseye-backports" }
}
{ "Components"
{ "1" = "main" }
{ "2" = "non-free-firmware" }
}
{ "Allow-Insecure" = "no" }
{ "Signed-By"
{ "1" = "-----BEGIN" }
{ "2" = "PGP" }
{ "3" = "PUBLIC" }
{ "4" = "KEY" }
{ "5" = "BLOCK-----\n" }
{ "6" = ".\n" }
{ "7" = "mDMEYCQjIxYJKwYBBAHaRw8BAQdAD/P5Nvvnvk66SxBBHDbhRml9ORg1WV5CvzKY\n" }
{ "8" = "CuMfoIS0BmFiY2RlZoiQBBMWCgA4FiEErCIG1VhKWMWo2yfAREZd5NfO31cFAmAk\n" }
{ "9" = "IyMCGyMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQREZd5NfO31fbOwD6ArzS\n" }
{ "10" = "dM0Dkd5h2Ujy1b6KcAaVW9FOa5UNfJ9FFBtjLQEBAJ7UyWD3dZzhvlaAwunsk7DG\n" }
{ "11" = "3bHcln8DMpIJVXht78sL\n" }
{ "12" = "=IE0r\n" }
{ "13" = "-----END" }
{ "14" = "PGP" }
{ "15" = "PUBLIC" }
{ "16" = "KEY" }
{ "17" = "BLOCK-----" }
}
}
{ }
{ "2"
{ "Enabled" = "no" }
{ "URIs" { "1" = "http://dl.google.com/linux/chrome/deb" } }
{ "Suites" { "1" = "stable" } }
{ "Components" { "1" = "main" } }
{ "Architectures" { "1" = "amd64" } }
}
let sources2 = "Enabled: yes
Types: deb deb-src
URIs: http://archive.ubuntu.com/ubuntu
Suites: disco disco-updates disco-security disco-backports
Components: main universe multiverse restricted
Enabled: yes
Types: deb
URIs: http://ppa.launchpad.net/system76/pop/ubuntu
Suites: disco
Components: main
"
test Aptsources822.lns get sources2 =
{ "1"
{ "Enabled" = "yes" }
{ "Types"
{ "1" = "deb" }
{ "2" = "deb-src" }
}
{ "URIs" { "1" = "http://archive.ubuntu.com/ubuntu" } }
{ "Suites"
{ "1" = "disco" }
{ "2" = "disco-updates" }
{ "3" = "disco-security" }
{ "4" = "disco-backports" }
}
{ "Components"
{ "1" = "main" }
{ "2" = "universe" }
{ "3" = "multiverse" }
{ "4" = "restricted" }
}
}
{ }
{ "2"
{ "Enabled" = "yes" }
{ "Types" { "1" = "deb" } }
{ "URIs" { "1" = "http://ppa.launchpad.net/system76/pop/ubuntu" } }
{ "Suites" { "1" = "disco" } }
{ "Components" { "1" = "main" } }
}
(* Test adding nodes to tree *)
test Aptsources822.lns put "Types: deb\n" after set "/1/Enabled" "yes" = "Types: deb\nEnabled: yes\n"
test Aptsources822.lns put "Types: deb\n" after
set "/1/URIs/1" "uri1\n";
set "/1/URIs/2" "uri2" = "Types: deb\nURIs: uri1\n uri2\n"