summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Server/Plugins/Packages/Pyapt.py
diff options
context:
space:
mode:
authorAlexander Sulfrian <asulfrian@zedat.fu-berlin.de>2022-01-16 08:40:09 +0100
committerAlexander Sulfrian <asulfrian@zedat.fu-berlin.de>2022-01-17 16:41:32 +0100
commit3842939e7d94373a8a4d4214072c9b24b1e32b6d (patch)
treebb5f8844df88d5eac3dda931004cafb1b3622846 /src/lib/Bcfg2/Server/Plugins/Packages/Pyapt.py
parent000a832751563cfe571363a27e293fd3d9db31a4 (diff)
downloadbcfg2-3842939e7d94373a8a4d4214072c9b24b1e32b6d.tar.gz
bcfg2-3842939e7d94373a8a4d4214072c9b24b1e32b6d.tar.bz2
bcfg2-3842939e7d94373a8a4d4214072c9b24b1e32b6d.zip
Packages: Add "pyapt" source type
Pyapt is a new source that is using the apt python bindings to parse the Packages files from debian repositories. Compared to the python implementation it is faster and more robust. It will use the dependencies of the newest version of a package from a specific source (because it can use the python bindings to compare the version numbers).
Diffstat (limited to 'src/lib/Bcfg2/Server/Plugins/Packages/Pyapt.py')
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Pyapt.py93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Pyapt.py b/src/lib/Bcfg2/Server/Plugins/Packages/Pyapt.py
new file mode 100644
index 000000000..5e0eb55be
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Pyapt.py
@@ -0,0 +1,93 @@
+"""
+APT backend for :mod:`Bcfg2.Server.Plugins.Packages` using
+apt_pkg python bindings.
+"""
+
+import apt_pkg
+from Bcfg2.Server.Plugins.Packages.Apt import AptCollection, AptSource
+
+
+class PyaptCollection(AptCollection):
+ """ Handle collections of PyAPT sources. This is a no-op object
+ that simply inherits from
+ :class:`Bcfg2.Server.Plugins.Packages.Apt.AptCollection` and
+ overrides nothing.
+ """
+ pass
+
+
+class PyaptSource(AptSource):
+ """ Handle PyAPT sources """
+
+ def read_files(self): # pylint: disable=R0912
+ bdeps = dict()
+ brecs = dict()
+ bprov = dict()
+ bvers = dict()
+ self.pkgnames = set()
+ self.essentialpkgs = set()
+ for fname in self.files:
+ barch = self._get_arch(fname)
+ if barch not in bdeps:
+ bdeps[barch] = dict()
+ brecs[barch] = dict()
+ bprov[barch] = dict()
+
+ apt_pkg.init_system()
+ with apt_pkg.TagFile(fname) as tagfile:
+ for section in tagfile:
+ pkgname = section['Package']
+
+ if pkgname in bvers:
+ new = section['Version']
+ old = bvers[pkgname]
+ if apt_pkg.version_compare(new, old) <= 0:
+ continue
+
+ self.pkgnames.add(pkgname)
+ bvers[pkgname] = section['Version']
+ bdeps[barch][pkgname] = []
+ brecs[barch][pkgname] = []
+
+ if section.find_flag('Essential'):
+ self.essentialpkgs.add(pkgname)
+
+ for dep_type in ['Depends', 'Pre-Depends', 'Recommends']:
+ dep_str = section.find(dep_type)
+ if dep_str is None:
+ continue
+
+ vindex = 0
+ for dep in apt_pkg.parse_depends(dep_str):
+ if len(dep) > 1:
+ cdeps = [cdep for (cdep, _, _) in dep]
+ dyn_dname = "choice-%s-%s-%s" % (pkgname,
+ barch,
+ vindex)
+ vindex += 1
+
+ if dep_type == 'Recommends':
+ brecs[barch][pkgname].append(dyn_dname)
+ else:
+ bdeps[barch][pkgname].append(dyn_dname)
+ bprov[barch][dyn_dname] = set(cdeps)
+ else:
+ (raw_dep, _, _) = dep[0]
+ if dep_type == 'Recommends':
+ brecs[barch][pkgname].append(raw_dep)
+ else:
+ bdeps[barch][pkgname].append(raw_dep)
+
+ provides = section.find('Provides')
+ if provides is not None:
+ provided_packages = [
+ pkg
+ for group in apt_pkg.parse_depends(provides)
+ for (pkg, _, _) in group]
+ for dname in provided_packages:
+ if dname not in bprov[barch]:
+ bprov[barch][dname] = set()
+ bprov[barch][dname].add(pkgname)
+
+ self.process_files(bdeps, bprov, brecs)
+ read_files.__doc__ = AptSource.read_files.__doc__