Resolve multilib packages. Controlled by the --multilib option.
This commit is contained in:
parent
91f70cbb43
commit
30c0f358d9
8
setup.py
8
setup.py
@ -11,6 +11,10 @@ setup(name='pungi',
|
|||||||
package_dir = {'': 'src'},
|
package_dir = {'': 'src'},
|
||||||
packages = ['pypungi'],
|
packages = ['pypungi'],
|
||||||
scripts = ['src/bin/pungi.py'],
|
scripts = ['src/bin/pungi.py'],
|
||||||
data_files=[('/usr/share/pungi', glob.glob('share/*'))]
|
data_files=[
|
||||||
)
|
('/usr/share/pungi', glob.glob('share/*.xsl')),
|
||||||
|
('/usr/share/pungi', glob.glob('share/*.ks')),
|
||||||
|
('/usr/share/pungi/multilib', glob.glob('share/multilib/*')),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
9
share/multilib/devel-blacklist.conf
Normal file
9
share/multilib/devel-blacklist.conf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
dmraid-devel
|
||||||
|
kdeutils-devel
|
||||||
|
kernel-devel
|
||||||
|
mkinitrd-devel
|
||||||
|
java-1.5.0-gcj-devel
|
||||||
|
java-1.6.0-openjdk-devel
|
||||||
|
java-1.7.0-icedtea-devel
|
||||||
|
java-1.7.0-openjdk-devel
|
||||||
|
php-devel
|
2
share/multilib/devel-whitelist.conf
Normal file
2
share/multilib/devel-whitelist.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
glibc-static
|
||||||
|
libstdc++-static
|
2
share/multilib/runtime-blacklist.conf
Normal file
2
share/multilib/runtime-blacklist.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
kernel
|
||||||
|
tomcat-native
|
78
share/multilib/runtime-patterns.conf
Normal file
78
share/multilib/runtime-patterns.conf
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# format: <path> <filename_wildcard>
|
||||||
|
# * if filename_wildcard is set to -, then only a directory is matched
|
||||||
|
# $LIBDIR gets expanded to /lib*, /usr/lib*
|
||||||
|
|
||||||
|
# libraries in standard dirs
|
||||||
|
$LIBDIR *.so.*
|
||||||
|
$LIBDIR/* *.so.*
|
||||||
|
|
||||||
|
# dri
|
||||||
|
$LIBDIR/dri -
|
||||||
|
|
||||||
|
# krb5
|
||||||
|
$LIBDIR/krb5/plugins -
|
||||||
|
|
||||||
|
# pam
|
||||||
|
$LIBDIR/security -
|
||||||
|
|
||||||
|
# sasl
|
||||||
|
$LIBDIR/sasl2 -
|
||||||
|
|
||||||
|
# nss - include nss plugins incl. libnss_*.so
|
||||||
|
$LIBDIR libnss_*.so
|
||||||
|
|
||||||
|
# alsa plugins
|
||||||
|
$LIBDIR/alsa-lib -
|
||||||
|
|
||||||
|
# lsb
|
||||||
|
/etc/lsb-release.d -
|
||||||
|
|
||||||
|
# mysql, qt, etc.
|
||||||
|
/etc/ld.so.conf.d *.conf
|
||||||
|
|
||||||
|
# gtk2-engines
|
||||||
|
$LIBDIR/gtk-2.0/*/engines -
|
||||||
|
|
||||||
|
# accessibility
|
||||||
|
$LIBDIR/gtk-2.0/modules -
|
||||||
|
$LIBDIR/gtk-2.0/*/modules -
|
||||||
|
|
||||||
|
# scim-bridge-gtk
|
||||||
|
$LIBDIR/gtk-2.0/immodules -
|
||||||
|
$LIBDIR/gtk-2.0/*/immodules -
|
||||||
|
|
||||||
|
# images
|
||||||
|
$LIBDIR/gtk-2.0/*/loaders -
|
||||||
|
$LIBDIR/gdk-pixbuf-2.0/*/loaders -
|
||||||
|
$LIBDIR/gtk-2.0/*/printbackends -
|
||||||
|
$LIBDIR/gtk-2.0/*/filesystems -
|
||||||
|
|
||||||
|
# qt plugins
|
||||||
|
$LIBDIR/qt*/plugins/* -
|
||||||
|
|
||||||
|
# KDE plugins
|
||||||
|
$LIBDIR/kde*/plugins/* -
|
||||||
|
|
||||||
|
# gstreamer
|
||||||
|
$LIBDIR/gstreamer-* -
|
||||||
|
|
||||||
|
# xine-lib
|
||||||
|
$LIBDIR/xine/plugins/* -
|
||||||
|
|
||||||
|
# oprofile
|
||||||
|
$LIBDIR/oprofile *.so.*
|
||||||
|
|
||||||
|
# wine
|
||||||
|
$LIBDIR/wine *.so'
|
||||||
|
|
||||||
|
# db
|
||||||
|
$LIBDIR libdb-*
|
||||||
|
|
||||||
|
# sane drivers
|
||||||
|
$LIBDIR/sane libsane-*
|
||||||
|
|
||||||
|
# opencryptoki
|
||||||
|
$LIBDIR/opencryptoki -
|
||||||
|
|
||||||
|
# openssl engines
|
||||||
|
$LIBDIR/openssl/engines *.so
|
12
share/multilib/runtime-whitelist.conf
Normal file
12
share/multilib/runtime-whitelist.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
glibc-static
|
||||||
|
libflashsupport
|
||||||
|
libgnat
|
||||||
|
lmms-vst
|
||||||
|
nspluginwrapper
|
||||||
|
perl-libs
|
||||||
|
pulseaudio-utils
|
||||||
|
redhat-lsb
|
||||||
|
valgrind
|
||||||
|
wine
|
||||||
|
wine-arts
|
||||||
|
yaboot
|
@ -87,6 +87,8 @@ def main():
|
|||||||
config.set('pungi', 'full_archlist', "True")
|
config.set('pungi', 'full_archlist', "True")
|
||||||
if opts.arch:
|
if opts.arch:
|
||||||
config.set('pungi', 'arch', opts.arch)
|
config.set('pungi', 'arch', opts.arch)
|
||||||
|
if opts.multilib:
|
||||||
|
config.set('pungi', 'multilib', " ".join(opts.multilib))
|
||||||
if opts.lookaside_repos:
|
if opts.lookaside_repos:
|
||||||
config.set('pungi', 'lookaside_repos', " ".join(opts.lookaside_repos))
|
config.set('pungi', 'lookaside_repos', " ".join(opts.lookaside_repos))
|
||||||
|
|
||||||
@ -224,6 +226,8 @@ if __name__ == '__main__':
|
|||||||
help='Use the full arch list for x86_64 (include i686, i386, etc.)')
|
help='Use the full arch list for x86_64 (include i686, i386, etc.)')
|
||||||
parser.add_option("--arch",
|
parser.add_option("--arch",
|
||||||
help='Override default (uname based) arch')
|
help='Override default (uname based) arch')
|
||||||
|
parser.add_option("--multilib", action="append", metavar="METHOD",
|
||||||
|
help='Multilib method; can be specified multiple times; recommended: devel, runtime')
|
||||||
parser.add_option("--lookaside-repo", action="append", dest="lookaside_repos", metavar="NAME",
|
parser.add_option("--lookaside-repo", action="append", dest="lookaside_repos", metavar="NAME",
|
||||||
help='Specify lookaside repo name(s) (packages will used for depsolving but not be included in the output)')
|
help='Specify lookaside repo name(s) (packages will used for depsolving but not be included in the output)')
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import pylorax
|
|||||||
from fnmatch import fnmatch
|
from fnmatch import fnmatch
|
||||||
|
|
||||||
import arch as arch_module
|
import arch as arch_module
|
||||||
|
import multilib
|
||||||
|
|
||||||
|
|
||||||
def is_debug(po):
|
def is_debug(po):
|
||||||
@ -45,6 +46,12 @@ def is_source(po):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_noarch(po):
|
||||||
|
if po.arch == "noarch":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def is_package(po):
|
def is_package(po):
|
||||||
if is_debug(po):
|
if is_debug(po):
|
||||||
return False
|
return False
|
||||||
@ -184,6 +191,7 @@ class Pungi(pypungi.PungiBase):
|
|||||||
self.resolved_deps = {} # list the deps we've already resolved, short circuit.
|
self.resolved_deps = {} # list the deps we've already resolved, short circuit.
|
||||||
self.excluded_pkgs = {} # list the packages we've already excluded.
|
self.excluded_pkgs = {} # list the packages we've already excluded.
|
||||||
self.seen_pkgs = {} # list the packages we've already seen so we can check all deps only once
|
self.seen_pkgs = {} # list the packages we've already seen so we can check all deps only once
|
||||||
|
self.multilib_methods = self.config.get('pungi', 'multilib').split(" ")
|
||||||
self.lookaside_repos = self.config.get('pungi', 'lookaside_repos').split(" ")
|
self.lookaside_repos = self.config.get('pungi', 'lookaside_repos').split(" ")
|
||||||
self.sourcerpm_arch_map = {} # {sourcerpm: set[arches]} - used for gathering debuginfo
|
self.sourcerpm_arch_map = {} # {sourcerpm: set[arches]} - used for gathering debuginfo
|
||||||
|
|
||||||
@ -394,10 +402,10 @@ class Pungi(pypungi.PungiBase):
|
|||||||
|
|
||||||
reqs = po.requires
|
reqs = po.requires
|
||||||
provs = po.provides
|
provs = po.provides
|
||||||
added = []
|
added = set()
|
||||||
|
|
||||||
# get langpacks for each processed package
|
added.update(self.getLangpacks([po]))
|
||||||
added.extend(self.getLangpacks(po))
|
added.update(self.getMultilib([po]))
|
||||||
|
|
||||||
for req in reqs:
|
for req in reqs:
|
||||||
if req in self.resolved_deps:
|
if req in self.resolved_deps:
|
||||||
@ -424,7 +432,7 @@ class Pungi(pypungi.PungiBase):
|
|||||||
if dep not in added:
|
if dep not in added:
|
||||||
msg = 'Added %s.%s for %s.%s' % (dep.name, dep.arch, po.name, po.arch)
|
msg = 'Added %s.%s for %s.%s' % (dep.name, dep.arch, po.name, po.arch)
|
||||||
self.add_package(dep, msg)
|
self.add_package(dep, msg)
|
||||||
added.append(dep)
|
added.add(dep)
|
||||||
|
|
||||||
except (yum.Errors.InstallError, yum.Errors.YumBaseError), ex:
|
except (yum.Errors.InstallError, yum.Errors.YumBaseError), ex:
|
||||||
self.logger.warn("Unresolvable dependency %s in %s.%s" % (r, po.name, po.arch))
|
self.logger.warn("Unresolvable dependency %s in %s.%s" % (r, po.name, po.arch))
|
||||||
@ -434,13 +442,14 @@ class Pungi(pypungi.PungiBase):
|
|||||||
for add in added:
|
for add in added:
|
||||||
self.getPackageDeps(add)
|
self.getPackageDeps(add)
|
||||||
|
|
||||||
def getLangpacks(self, po):
|
def getLangpacks(self, po_list):
|
||||||
added = []
|
added = []
|
||||||
|
|
||||||
|
for po in po_list:
|
||||||
# get all langpacks matching the package name
|
# get all langpacks matching the package name
|
||||||
langpacks = [ i for i in self.langpacks if i["name"] == po.name ]
|
langpacks = [ i for i in self.langpacks if i["name"] == po.name ]
|
||||||
if not langpacks:
|
if not langpacks:
|
||||||
return []
|
continue
|
||||||
|
|
||||||
for langpack in langpacks:
|
for langpack in langpacks:
|
||||||
pattern = langpack["install"] % "*" # replace '%s' with '*'
|
pattern = langpack["install"] % "*" # replace '%s' with '*'
|
||||||
@ -462,6 +471,35 @@ class Pungi(pypungi.PungiBase):
|
|||||||
|
|
||||||
return added
|
return added
|
||||||
|
|
||||||
|
def getMultilib(self, po_list):
|
||||||
|
added = []
|
||||||
|
|
||||||
|
if not self.multilib_methods:
|
||||||
|
return added
|
||||||
|
|
||||||
|
for po in po_list:
|
||||||
|
if po.arch in ("noarch", "src", "nosrc"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if po.arch in self.valid_multilib_arches:
|
||||||
|
continue
|
||||||
|
|
||||||
|
matches = self.ayum.pkgSack.searchNevra(name=po.name, ver=po.version, rel=po.release)
|
||||||
|
matches = [i for i in matches if i.arch in self.valid_multilib_arches]
|
||||||
|
if not matches:
|
||||||
|
continue
|
||||||
|
matches = self.excludePackages(matches)
|
||||||
|
match = self.ayum._bestPackageFromList(matches)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
method = multilib.po_is_multilib(po, self.multilib_methods)
|
||||||
|
if not method:
|
||||||
|
continue
|
||||||
|
msg = "Added multilib package %s.%s for package %s.%s (method: %s)" % (match.name, match.arch, po.name, po.arch, method)
|
||||||
|
self.add_package(match, msg)
|
||||||
|
added.append(match)
|
||||||
|
return added
|
||||||
|
|
||||||
def getPackagesFromGroup(self, group):
|
def getPackagesFromGroup(self, group):
|
||||||
"""Get a list of package names from a ksparser group object
|
"""Get a list of package names from a ksparser group object
|
||||||
|
|
||||||
|
@ -46,5 +46,6 @@ class Config(SafeConfigParser):
|
|||||||
self.set('pungi', 'isfinal', "False")
|
self.set('pungi', 'isfinal', "False")
|
||||||
self.set('pungi', 'nohash', "False")
|
self.set('pungi', 'nohash', "False")
|
||||||
self.set('pungi', 'full_archlist', "False")
|
self.set('pungi', 'full_archlist', "False")
|
||||||
|
self.set('pungi', 'multilib', '')
|
||||||
self.set('pungi', 'lookaside_repos', '')
|
self.set('pungi', 'lookaside_repos', '')
|
||||||
|
|
||||||
|
371
src/pypungi/multilib.py
Executable file
371
src/pypungi/multilib.py
Executable file
@ -0,0 +1,371 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; version 2 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Library General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
|
||||||
|
import re
|
||||||
|
import fnmatch
|
||||||
|
import pathmatch
|
||||||
|
|
||||||
|
#from pypungi import is_package, is_source, is_debug, is_noarch
|
||||||
|
import pypungi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LINE_PATTERN_RE = re.compile(r"^\s*(?P<line>[^#]+)(:?\s+(?P<comment>#.*))?$")
|
||||||
|
RUNTIME_PATTERN_SPLIT_RE = re.compile(r"^\s*(?P<path>[^\s]+)\s+(?P<pattern>[^\s]+)(:?\s+(?P<comment>#.*))?$")
|
||||||
|
|
||||||
|
|
||||||
|
def read_lines(lines):
|
||||||
|
result = []
|
||||||
|
for i in lines:
|
||||||
|
i = i.strip()
|
||||||
|
|
||||||
|
if not i:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# skip comments
|
||||||
|
if i.startswith("#"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
match = LINE_PATTERN_RE.match(i)
|
||||||
|
if match is None:
|
||||||
|
raise ValueError("Couldn't parse line: %s" % i)
|
||||||
|
gd = match.groupdict()
|
||||||
|
result.append(gd["line"])
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def read_lines_from_file(path):
|
||||||
|
lines = open(path, "r").readlines()
|
||||||
|
lines = read_lines(lines)
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def read_runtime_patterns(lines):
|
||||||
|
result = []
|
||||||
|
for i in read_lines(lines):
|
||||||
|
match = RUNTIME_PATTERN_SPLIT_RE.match(i)
|
||||||
|
if match is None:
|
||||||
|
raise ValueError("Couldn't parse pattern: %s" % i)
|
||||||
|
gd = match.groupdict()
|
||||||
|
result.append((gd["path"], gd["pattern"]))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def read_runtime_patterns_from_file(path):
|
||||||
|
lines = open(path, "r").readlines()
|
||||||
|
return read_runtime_patterns(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def expand_runtime_patterns(patterns):
|
||||||
|
pm = pathmatch.PathMatch()
|
||||||
|
result = []
|
||||||
|
for path, pattern in patterns:
|
||||||
|
for root in ("", "/opt/*/*/root"):
|
||||||
|
# include Software Collections: /opt/<vendor>/<scl_name>/root/...
|
||||||
|
if "$LIBDIR" in path:
|
||||||
|
for lib_dir in ("/lib", "/lib64", "/usr/lib", "/usr/lib64"):
|
||||||
|
path_pattern = path.replace("$LIBDIR", lib_dir)
|
||||||
|
path_pattern = "%s/%s" % (root, path_pattern.lstrip("/"))
|
||||||
|
pm[path_pattern] = (path_pattern, pattern)
|
||||||
|
else:
|
||||||
|
path_pattern = "%s/%s" % (root, path.lstrip("/"))
|
||||||
|
pm[path_pattern] = (path_pattern, pattern)
|
||||||
|
return pm
|
||||||
|
|
||||||
|
|
||||||
|
class MultilibMethodBase(object):
|
||||||
|
"""a base class for multilib methods"""
|
||||||
|
name = "base"
|
||||||
|
|
||||||
|
def select(self, po):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def skip(self, po):
|
||||||
|
if pypungi.is_noarch(po) or pypungi.is_source(po) or pypungi.is_debug(po):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_kernel(self, po):
|
||||||
|
for p_name, p_flag, (p_e, p_v, p_r) in po.provides:
|
||||||
|
if p_name == "kernel":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_kernel_devel(self, po):
|
||||||
|
for p_name, p_flag, (p_e, p_v, p_r) in po.provides:
|
||||||
|
if p_name == "kernel-devel":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_kernel_or_kernel_devel(self, po):
|
||||||
|
for p_name, p_flag, (p_e, p_v, p_r) in po.provides:
|
||||||
|
if p_name in ("kernel", "kernel-devel"):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class NoneMultilibMethod(MultilibMethodBase):
|
||||||
|
"""multilib disabled"""
|
||||||
|
name = "none"
|
||||||
|
|
||||||
|
def select(self, po):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class AllMultilibMethod(MultilibMethodBase):
|
||||||
|
"""all packages are multilib"""
|
||||||
|
name = "all"
|
||||||
|
|
||||||
|
def select(self, po):
|
||||||
|
if self.skip(po):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class RuntimeMultilibMethod(MultilibMethodBase):
|
||||||
|
"""pre-defined paths to libs"""
|
||||||
|
name = "runtime"
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.blacklist = read_lines_from_file("/usr/share/pungi/multilib/runtime-blacklist.conf")
|
||||||
|
self.whitelist = read_lines_from_file("/usr/share/pungi/multilib/runtime-whitelist.conf")
|
||||||
|
self.patterns = expand_runtime_patterns(read_runtime_patterns_from_file("/usr/share/pungi/multilib/runtime-patterns.conf"))
|
||||||
|
|
||||||
|
def select(self, po):
|
||||||
|
if self.skip(po):
|
||||||
|
return False
|
||||||
|
if po.name in self.blacklist:
|
||||||
|
return False
|
||||||
|
if po.name in self.whitelist:
|
||||||
|
return True
|
||||||
|
if self.is_kernel(po):
|
||||||
|
return False
|
||||||
|
|
||||||
|
for path in po.returnFileEntries() + po.returnFileEntries("ghost"):
|
||||||
|
dirname, filename = path.rsplit("/", 1)
|
||||||
|
dirname = dirname.rstrip("/")
|
||||||
|
|
||||||
|
patterns = self.patterns[dirname]
|
||||||
|
if not patterns:
|
||||||
|
continue
|
||||||
|
for dir_pattern, file_pattern in patterns:
|
||||||
|
if file_pattern == "-":
|
||||||
|
return True
|
||||||
|
if fnmatch.fnmatch(filename, file_pattern):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class FileMultilibMethod(MultilibMethodBase):
|
||||||
|
"""explicitely defined whitelist and blacklist"""
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.name = "file"
|
||||||
|
whitelist = kwargs.pop("whitelist", None)
|
||||||
|
blacklist = kwargs.pop("blacklist", None)
|
||||||
|
self.whitelist = self.read_file(whitelist)
|
||||||
|
self.blacklist = self.read_file(blacklist)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def read_file(path):
|
||||||
|
if not path:
|
||||||
|
return []
|
||||||
|
result = [ i.strip() for i in open(path, "r") if not i.strip().startswith("#") ]
|
||||||
|
return result
|
||||||
|
|
||||||
|
def select(self, po):
|
||||||
|
for pattern in self.blacklist:
|
||||||
|
if fnmatch.fnmatch(po.name, pattern):
|
||||||
|
return False
|
||||||
|
for pattern in self.whitelist:
|
||||||
|
if fnmatch.fnmatch(po.name, pattern):
|
||||||
|
return False
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class KernelMultilibMethod(MultilibMethodBase):
|
||||||
|
"""kernel and kernel-devel"""
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.name = "kernel"
|
||||||
|
|
||||||
|
def select(self, po):
|
||||||
|
if self.is_kernel_or_kernel_devel(po):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class DevelMultilibMethod(MultilibMethodBase):
|
||||||
|
"""all -devel and -static packages"""
|
||||||
|
name = "devel"
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.blacklist = read_lines_from_file("/usr/share/pungi/multilib/devel-blacklist.conf")
|
||||||
|
self.whitelist = read_lines_from_file("/usr/share/pungi/multilib/devel-whitelist.conf")
|
||||||
|
|
||||||
|
def select(self, po):
|
||||||
|
if self.skip(po):
|
||||||
|
return False
|
||||||
|
if po.name in self.blacklist:
|
||||||
|
return False
|
||||||
|
if po.name in self.whitelist:
|
||||||
|
return True
|
||||||
|
if self.is_kernel_devel(po):
|
||||||
|
return False
|
||||||
|
# HACK: exclude ghc*
|
||||||
|
if po.name.startswith("ghc-"):
|
||||||
|
return False
|
||||||
|
if po.name.endswith("-devel"):
|
||||||
|
return True
|
||||||
|
if po.name.endswith("-static"):
|
||||||
|
return True
|
||||||
|
for p_name, p_flag, (p_e, p_v, p_r) in po.provides:
|
||||||
|
if p_name.endswith("-devel"):
|
||||||
|
return True
|
||||||
|
if p_name.endswith("-static"):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_METHODS = ["devel", "runtime"]
|
||||||
|
METHOD_MAP = {}
|
||||||
|
for cls in (AllMultilibMethod, DevelMultilibMethod, FileMultilibMethod, KernelMultilibMethod, NoneMultilibMethod, RuntimeMultilibMethod):
|
||||||
|
method = cls()
|
||||||
|
METHOD_MAP[method.name] = method
|
||||||
|
|
||||||
|
|
||||||
|
def po_is_multilib(po, methods):
|
||||||
|
for method_name in methods:
|
||||||
|
if not method_name:
|
||||||
|
continue
|
||||||
|
method = METHOD_MAP[method_name]
|
||||||
|
if method.select(po):
|
||||||
|
return method_name
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def do_multilib(yum_arch, methods, repos, tmpdir, logfile):
|
||||||
|
import os
|
||||||
|
import yum
|
||||||
|
import rpm
|
||||||
|
import logging
|
||||||
|
|
||||||
|
archlist = yum.rpmUtils.arch.getArchList(yum_arch)
|
||||||
|
|
||||||
|
yumbase = yum.YumBase()
|
||||||
|
yumbase.preconf.init_plugins = False
|
||||||
|
yumbase.preconf.root = tmpdir
|
||||||
|
# order matters!
|
||||||
|
# must run doConfigSetup() before touching yumbase.conf
|
||||||
|
yumbase.doConfigSetup(fn="/dev/null")
|
||||||
|
yumbase.conf.cache = False
|
||||||
|
yumbase.conf.cachedir = tmpdir
|
||||||
|
yumbase.conf.exactarch = True
|
||||||
|
yumbase.conf.gpgcheck = False
|
||||||
|
yumbase.conf.logfile = logfile
|
||||||
|
yumbase.conf.plugins = False
|
||||||
|
yumbase.conf.reposdir = []
|
||||||
|
yumbase.verbose_logger.setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
yumbase.doRepoSetup()
|
||||||
|
yumbase.doTsSetup()
|
||||||
|
yumbase.doRpmDBSetup()
|
||||||
|
yumbase.ts.pushVSFlags((rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS))
|
||||||
|
|
||||||
|
for repo in yumbase.repos.findRepos("*"):
|
||||||
|
repo.disable()
|
||||||
|
|
||||||
|
for i, baseurl in enumerate(repos):
|
||||||
|
repo_id = "multilib-%s" % i
|
||||||
|
if "://" not in baseurl:
|
||||||
|
baseurl = "file://" + os.path.abspath(baseurl)
|
||||||
|
yumbase.add_enable_repo(repo_id, baseurls=[baseurl])
|
||||||
|
|
||||||
|
yumbase.doSackSetup(archlist=archlist)
|
||||||
|
yumbase.doSackFilelistPopulate()
|
||||||
|
|
||||||
|
method_kwargs = {}
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for po in sorted(yumbase.pkgSack):
|
||||||
|
method = po_is_multilib(po, methods)
|
||||||
|
if method:
|
||||||
|
nvra = "%s-%s-%s.%s.rpm" % (po.name, po.version, po.release, po.arch)
|
||||||
|
result.append((nvra, method))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import optparse
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
class MyOptionParser(optparse.OptionParser):
|
||||||
|
def print_help(self, *args, **kwargs):
|
||||||
|
optparse.OptionParser.print_help(self, *args, **kwargs)
|
||||||
|
print
|
||||||
|
print "Available multilib methods:"
|
||||||
|
for key, value in sorted(METHOD_MAP.items()):
|
||||||
|
default = (key in DEFAULT_METHODS) and " (default)" or ""
|
||||||
|
print " %-10s %s%s" % (key, value.__doc__ or "", default)
|
||||||
|
|
||||||
|
parser = MyOptionParser("usage: %prog [options]")
|
||||||
|
|
||||||
|
parser.add_option(
|
||||||
|
"--arch",
|
||||||
|
)
|
||||||
|
parser.add_option(
|
||||||
|
"--method",
|
||||||
|
action="append",
|
||||||
|
default=DEFAULT_METHODS,
|
||||||
|
help="multilib method",
|
||||||
|
)
|
||||||
|
parser.add_option(
|
||||||
|
"--repo",
|
||||||
|
dest="repos",
|
||||||
|
action="append",
|
||||||
|
help="path or url to yum repo; can be specified multiple times",
|
||||||
|
)
|
||||||
|
parser.add_option("--tmpdir")
|
||||||
|
parser.add_option("--logfile", action="store")
|
||||||
|
|
||||||
|
opts, args = parser.parse_args()
|
||||||
|
|
||||||
|
if args:
|
||||||
|
parser.error("no arguments expected")
|
||||||
|
|
||||||
|
if not opts.repos:
|
||||||
|
parser.error("provide at least one repo")
|
||||||
|
|
||||||
|
for method_name in opts.method:
|
||||||
|
if method_name not in METHOD_MAP:
|
||||||
|
parser.error("unknown method: %s" % method_name)
|
||||||
|
print opts.method
|
||||||
|
|
||||||
|
tmpdir = opts.tmpdir
|
||||||
|
if not opts.tmpdir:
|
||||||
|
tmpdir = tempfile.mkdtemp(prefix="multilib_")
|
||||||
|
|
||||||
|
nvra_list = do_multilib(opts.arch, opts.method, opts.repos, tmpdir, opts.logfile)
|
||||||
|
for nvra, method in nvra_list:
|
||||||
|
print "MULTILIB(%s): %s" % (method, nvra)
|
||||||
|
|
||||||
|
if not opts.tmpdir:
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
60
src/pypungi/pathmatch.py
Normal file
60
src/pypungi/pathmatch.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
|
||||||
|
|
||||||
|
def head_tail_split(name):
|
||||||
|
name_split = name.strip("/").split("/", 1)
|
||||||
|
if len(name_split) == 2:
|
||||||
|
head = name_split[0]
|
||||||
|
tail = name_split[1].strip("/")
|
||||||
|
else:
|
||||||
|
head, tail = name_split[0], None
|
||||||
|
return head, tail
|
||||||
|
|
||||||
|
|
||||||
|
class PathMatch(object):
|
||||||
|
def __init__(self, parent=None, desc=None):
|
||||||
|
self._patterns = {}
|
||||||
|
self._final_patterns = {}
|
||||||
|
self._values = []
|
||||||
|
|
||||||
|
def __setitem__(self, name, value):
|
||||||
|
head, tail = head_tail_split(name)
|
||||||
|
|
||||||
|
if tail is not None:
|
||||||
|
# recursion
|
||||||
|
if head not in self._patterns:
|
||||||
|
self._patterns[head] = PathMatch(parent=self, desc=head)
|
||||||
|
self._patterns[head][tail] = value
|
||||||
|
else:
|
||||||
|
if head not in self._final_patterns:
|
||||||
|
self._final_patterns[head] = PathMatch(parent=self, desc=head)
|
||||||
|
if value not in self._final_patterns[head]._values:
|
||||||
|
self._final_patterns[head]._values.append(value)
|
||||||
|
|
||||||
|
def __getitem__(self, name):
|
||||||
|
result = []
|
||||||
|
head, tail = head_tail_split(name)
|
||||||
|
for pattern in self._patterns:
|
||||||
|
if fnmatch.fnmatch(head, pattern):
|
||||||
|
if tail is None:
|
||||||
|
values = self._patterns[pattern]._values
|
||||||
|
else:
|
||||||
|
values = self._patterns[pattern][tail]
|
||||||
|
for value in values:
|
||||||
|
if value not in result:
|
||||||
|
result.append(value)
|
||||||
|
|
||||||
|
for pattern in self._final_patterns:
|
||||||
|
if tail is None:
|
||||||
|
x = head
|
||||||
|
else:
|
||||||
|
x = "%s/%s" % (head, tail)
|
||||||
|
if fnmatch.fnmatch(x, pattern):
|
||||||
|
values = self._final_patterns[pattern]._values
|
||||||
|
for value in values:
|
||||||
|
if value not in result:
|
||||||
|
result.append(value)
|
||||||
|
return result
|
71
tests/test_pathmatch.py
Executable file
71
tests/test_pathmatch.py
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src", "pypungi")))
|
||||||
|
|
||||||
|
from pathmatch import PathMatch, head_tail_split
|
||||||
|
|
||||||
|
|
||||||
|
class TestHeadTailSplit(unittest.TestCase):
|
||||||
|
def test_1(self):
|
||||||
|
head, tail = head_tail_split("a")
|
||||||
|
self.assertEqual(head, "a")
|
||||||
|
self.assertEqual(tail, None)
|
||||||
|
|
||||||
|
head, tail = head_tail_split("/*")
|
||||||
|
self.assertEqual(head, "*")
|
||||||
|
self.assertEqual(tail, None)
|
||||||
|
|
||||||
|
head, tail = head_tail_split("///*")
|
||||||
|
self.assertEqual(head, "*")
|
||||||
|
self.assertEqual(tail, None)
|
||||||
|
|
||||||
|
head, tail = head_tail_split("///*//")
|
||||||
|
self.assertEqual(head, "*")
|
||||||
|
self.assertEqual(tail, None)
|
||||||
|
|
||||||
|
head, tail = head_tail_split("///*//-")
|
||||||
|
self.assertEqual(head, "*")
|
||||||
|
self.assertEqual(tail, "-")
|
||||||
|
|
||||||
|
|
||||||
|
class TestPathMatch(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.pm = PathMatch()
|
||||||
|
|
||||||
|
def test_1(self):
|
||||||
|
self.pm["/*"] = "/star1"
|
||||||
|
self.assertEqual(self.pm._final_patterns.keys(), ["*"])
|
||||||
|
self.assertEqual(self.pm._values, [])
|
||||||
|
self.assertEqual(self.pm._final_patterns["*"]._values, ["/star1"])
|
||||||
|
self.assertEqual(sorted(self.pm["/lib"]), ["/star1"])
|
||||||
|
|
||||||
|
self.pm["/*"] = "/star2"
|
||||||
|
self.assertEqual(sorted(self.pm["/lib"]), ["/star1", "/star2"])
|
||||||
|
|
||||||
|
self.pm["/lib"] = "/lib"
|
||||||
|
self.assertEqual(sorted(self.pm["/lib"]), ["/lib", "/star1", "/star2"])
|
||||||
|
|
||||||
|
self.pm["/lib64"] = "/lib64"
|
||||||
|
self.assertEqual(sorted(self.pm["/lib64"]), ["/lib64", "/star1", "/star2"])
|
||||||
|
|
||||||
|
def test_2(self):
|
||||||
|
self.pm["/*/*"] = "/star/star1"
|
||||||
|
self.assertEqual(self.pm._patterns.keys(), ["*"])
|
||||||
|
self.assertEqual(self.pm._patterns["*"]._final_patterns.keys(), ["*"])
|
||||||
|
self.assertEqual(self.pm._patterns["*"]._final_patterns["*"]._values, ["/star/star1"])
|
||||||
|
self.assertEqual(sorted(self.pm["/lib/asd"]), ["/star/star1"])
|
||||||
|
|
||||||
|
self.pm["/*"] = "/star2"
|
||||||
|
self.assertEqual(sorted(self.pm["/lib"]), ["/star2"])
|
||||||
|
|
||||||
|
self.assertEqual(sorted(self.pm["/lib/foo"]), ["/star/star1", "/star2"])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue
Block a user