mirror of
https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
synced 2025-03-07 01:01:15 +00:00
britney.py: Add support for multiple components
Adds a --components command line argument (and corresponding config file option). If specified, package info is expected to be in the usual Debian mirror layout, ie: testing/source/Sources testing/binary-${ARCH}/Packages (nthykier: Squashed, rebased and did some porting to Python3) Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
parent
e2b98872cf
commit
496e48c9a7
139
britney.py
139
britney.py
@ -387,6 +387,8 @@ class Britney(object):
|
|||||||
help="do not build the non-installability status, use the cache from file")
|
help="do not build the non-installability status, use the cache from file")
|
||||||
parser.add_option("", "--print-uninst", action="store_true", dest="print_uninst", default=False,
|
parser.add_option("", "--print-uninst", action="store_true", dest="print_uninst", default=False,
|
||||||
help="just print a summary of uninstallable packages")
|
help="just print a summary of uninstallable packages")
|
||||||
|
parser.add_option("", "--components", action="store", dest="components",
|
||||||
|
help="Sources/Packages are laid out by components listed (, sep)")
|
||||||
(self.options, self.args) = parser.parse_args()
|
(self.options, self.args) = parser.parse_args()
|
||||||
|
|
||||||
# integrity checks
|
# integrity checks
|
||||||
@ -417,6 +419,11 @@ class Britney(object):
|
|||||||
not getattr(self.options, k.lower()):
|
not getattr(self.options, k.lower()):
|
||||||
setattr(self.options, k.lower(), v)
|
setattr(self.options, k.lower(), v)
|
||||||
|
|
||||||
|
if getattr(self.options, "components", None):
|
||||||
|
self.options.components = [s.strip() for s in self.options.components.split(",")]
|
||||||
|
else:
|
||||||
|
self.options.components = None
|
||||||
|
|
||||||
if not hasattr(self.options, "heidi_delta_output"):
|
if not hasattr(self.options, "heidi_delta_output"):
|
||||||
self.options.heidi_delta_output = self.options.heidi_output + "Delta"
|
self.options.heidi_delta_output = self.options.heidi_output + "Delta"
|
||||||
|
|
||||||
@ -543,19 +550,10 @@ class Britney(object):
|
|||||||
# Data reading/writing methods
|
# Data reading/writing methods
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
|
|
||||||
def read_sources(self, basedir, intern=sys.intern):
|
def _read_sources_file(self, filename, sources=None, intern=sys.intern):
|
||||||
"""Read the list of source packages from the specified directory
|
if sources is None:
|
||||||
|
|
||||||
The source packages are read from the `Sources' file within the
|
|
||||||
directory specified as `basedir' parameter. Considering the
|
|
||||||
large amount of memory needed, not all the fields are loaded
|
|
||||||
in memory. The available fields are Version, Maintainer and Section.
|
|
||||||
|
|
||||||
The method returns a list where every item represents a source
|
|
||||||
package as a dictionary.
|
|
||||||
"""
|
|
||||||
sources = {}
|
sources = {}
|
||||||
filename = os.path.join(basedir, "Sources")
|
|
||||||
self.__log("Loading source packages from %s" % filename)
|
self.__log("Loading source packages from %s" % filename)
|
||||||
|
|
||||||
with open(filename, encoding='utf-8') as f:
|
with open(filename, encoding='utf-8') as f:
|
||||||
@ -583,38 +581,37 @@ class Britney(object):
|
|||||||
]
|
]
|
||||||
return sources
|
return sources
|
||||||
|
|
||||||
def read_binaries(self, basedir, distribution, arch, intern=sys.intern):
|
def read_sources(self, basedir):
|
||||||
"""Read the list of binary packages from the specified directory
|
"""Read the list of source packages from the specified directory
|
||||||
|
|
||||||
The binary packages are read from the `Packages_${arch}' files
|
The source packages are read from the `Sources' file within the
|
||||||
within the directory specified as `basedir' parameter, replacing
|
directory specified as `basedir' parameter. Considering the
|
||||||
${arch} with the value of the arch parameter. Considering the
|
|
||||||
large amount of memory needed, not all the fields are loaded
|
large amount of memory needed, not all the fields are loaded
|
||||||
in memory. The available fields are Version, Source, Multi-Arch,
|
in memory. The available fields are Version, Maintainer and Section.
|
||||||
Depends, Conflicts, Provides and Architecture.
|
|
||||||
|
|
||||||
After reading the packages, reverse dependencies are computed
|
The method returns a list where every item represents a source
|
||||||
and saved in the `rdepends' keys, and the `Provides' field is
|
package as a dictionary.
|
||||||
used to populate the virtual packages list.
|
|
||||||
|
|
||||||
The dependencies are parsed with the apt_pkg.parse_depends method,
|
|
||||||
and they are stored both as the format of its return value and
|
|
||||||
text.
|
|
||||||
|
|
||||||
The method returns a tuple. The first element is a list where
|
|
||||||
every item represents a binary package as a dictionary; the second
|
|
||||||
element is a dictionary which maps virtual packages to real
|
|
||||||
packages that provide them.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
packages = {}
|
if self.options.components:
|
||||||
provides = defaultdict(set)
|
sources = {}
|
||||||
sources = self.sources
|
for component in self.options.components:
|
||||||
all_binaries = self.all_binaries
|
filename = os.path.join(basedir, component, "source", "Sources")
|
||||||
|
self._read_sources_file(filename, sources)
|
||||||
|
else:
|
||||||
|
filename = os.path.join(basedir, "Sources")
|
||||||
|
sources = self._read_sources_file(filename)
|
||||||
|
|
||||||
filename = os.path.join(basedir, "Packages_%s" % arch)
|
return sources
|
||||||
|
|
||||||
|
def _read_packages_file(self, filename, arch, srcdist, packages=None, intern=sys.intern):
|
||||||
self.__log("Loading binary packages from %s" % filename)
|
self.__log("Loading binary packages from %s" % filename)
|
||||||
|
|
||||||
|
if packages is None:
|
||||||
|
packages = {}
|
||||||
|
|
||||||
|
all_binaries = self.all_binaries
|
||||||
|
|
||||||
with open(filename, encoding='utf-8') as f:
|
with open(filename, encoding='utf-8') as f:
|
||||||
Packages = apt_pkg.TagFile(f)
|
Packages = apt_pkg.TagFile(f)
|
||||||
get_field = Packages.section.get
|
get_field = Packages.section.get
|
||||||
@ -675,20 +672,19 @@ class Britney(object):
|
|||||||
dpkg[SOURCEVER] = intern(source[source.find("(")+1:source.find(")")])
|
dpkg[SOURCEVER] = intern(source[source.find("(")+1:source.find(")")])
|
||||||
|
|
||||||
# if the source package is available in the distribution, then register this binary package
|
# if the source package is available in the distribution, then register this binary package
|
||||||
if dpkg[SOURCE] in sources[distribution]:
|
if dpkg[SOURCE] in srcdist:
|
||||||
# There may be multiple versions of any arch:all packages
|
# There may be multiple versions of any arch:all packages
|
||||||
# (in unstable) if some architectures have out-of-date
|
# (in unstable) if some architectures have out-of-date
|
||||||
# binaries. We only want to include the package in the
|
# binaries. We only want to include the package in the
|
||||||
# source -> binary mapping once. It doesn't matter which
|
# source -> binary mapping once. It doesn't matter which
|
||||||
# of the versions we include as only the package name and
|
# of the versions we include as only the package name and
|
||||||
# architecture are recorded.
|
# architecture are recorded.
|
||||||
if pkg_id not in sources[distribution][dpkg[SOURCE]][BINARIES]:
|
if pkg_id not in srcdist[dpkg[SOURCE]][BINARIES]:
|
||||||
sources[distribution][dpkg[SOURCE]][BINARIES].append(pkg_id)
|
srcdist[dpkg[SOURCE]][BINARIES].append(pkg_id)
|
||||||
# if the source package doesn't exist, create a fake one
|
# if the source package doesn't exist, create a fake one
|
||||||
else:
|
else:
|
||||||
sources[distribution][dpkg[SOURCE]] = [dpkg[SOURCEVER], 'faux', [pkg_id], None, True]
|
srcdist[dpkg[SOURCE]] = [dpkg[SOURCEVER], 'faux', [pkg_id], None, True]
|
||||||
|
|
||||||
# register virtual packages and real packages that provide them
|
|
||||||
if dpkg[PROVIDES]:
|
if dpkg[PROVIDES]:
|
||||||
parts = apt_pkg.parse_depends(dpkg[PROVIDES], False)
|
parts = apt_pkg.parse_depends(dpkg[PROVIDES], False)
|
||||||
nprov = []
|
nprov = []
|
||||||
@ -706,7 +702,6 @@ class Britney(object):
|
|||||||
provided = intern(provided)
|
provided = intern(provided)
|
||||||
provided_version = intern(provided_version)
|
provided_version = intern(provided_version)
|
||||||
part = (provided, provided_version, intern(op))
|
part = (provided, provided_version, intern(op))
|
||||||
provides[provided].add((pkg, provided_version))
|
|
||||||
nprov.append(part)
|
nprov.append(part)
|
||||||
dpkg[PROVIDES] = nprov
|
dpkg[PROVIDES] = nprov
|
||||||
else:
|
else:
|
||||||
@ -719,6 +714,66 @@ class Britney(object):
|
|||||||
else:
|
else:
|
||||||
all_binaries[pkg_id] = dpkg
|
all_binaries[pkg_id] = dpkg
|
||||||
|
|
||||||
|
# add the resulting dictionary to the package list
|
||||||
|
packages[pkg] = dpkg
|
||||||
|
|
||||||
|
return packages
|
||||||
|
|
||||||
|
def read_binaries(self, basedir, distribution, arch):
|
||||||
|
"""Read the list of binary packages from the specified directory
|
||||||
|
|
||||||
|
The binary packages are read from the `Packages' files for `arch'.
|
||||||
|
|
||||||
|
If components are specified, the files
|
||||||
|
for each component are loaded according to the usual Debian mirror
|
||||||
|
layout.
|
||||||
|
|
||||||
|
If no components are specified, a single file named
|
||||||
|
`Packages_${arch}' is expected to be within the directory
|
||||||
|
specified as `basedir' parameter, replacing ${arch} with the
|
||||||
|
value of the arch parameter.
|
||||||
|
|
||||||
|
Considering the
|
||||||
|
large amount of memory needed, not all the fields are loaded
|
||||||
|
in memory. The available fields are Version, Source, Multi-Arch,
|
||||||
|
Depends, Conflicts, Provides and Architecture.
|
||||||
|
|
||||||
|
After reading the packages, reverse dependencies are computed
|
||||||
|
and saved in the `rdepends' keys, and the `Provides' field is
|
||||||
|
used to populate the virtual packages list.
|
||||||
|
|
||||||
|
The dependencies are parsed with the apt_pkg.parse_depends method,
|
||||||
|
and they are stored both as the format of its return value and
|
||||||
|
text.
|
||||||
|
|
||||||
|
The method returns a tuple. The first element is a list where
|
||||||
|
every item represents a binary package as a dictionary; the second
|
||||||
|
element is a dictionary which maps virtual packages to real
|
||||||
|
packages that provide them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.options.components:
|
||||||
|
packages = {}
|
||||||
|
for component in self.options.components:
|
||||||
|
filename = os.path.join(basedir,
|
||||||
|
component, "binary-%s" % arch, "Packages")
|
||||||
|
self._read_packages_file(filename, arch,
|
||||||
|
self.sources[distribution], packages)
|
||||||
|
else:
|
||||||
|
filename = os.path.join(basedir, "Packages_%s" % arch)
|
||||||
|
packages = self._read_packages_file(filename, arch,
|
||||||
|
self.sources[distribution])
|
||||||
|
|
||||||
|
# create provides
|
||||||
|
provides = defaultdict(set)
|
||||||
|
|
||||||
|
for pkg, dpkg in packages.items():
|
||||||
|
# register virtual packages and real packages that provide
|
||||||
|
# them
|
||||||
|
for provided_pkg, provided_version, _ in dpkg[PROVIDES]:
|
||||||
|
provides[provided_pkg].add((pkg, provided_version))
|
||||||
|
|
||||||
|
|
||||||
# return a tuple with the list of real and virtual packages
|
# return a tuple with the list of real and virtual packages
|
||||||
return (packages, provides)
|
return (packages, provides)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user