packaging
This commit is contained in:
parent
a9108584b7
commit
18f5a29ead
4 changed files with 32 additions and 208 deletions
219
builder/kojid
219
builder/kojid
|
|
@ -26,6 +26,7 @@ from __future__ import absolute_import, division
|
||||||
import copy
|
import copy
|
||||||
import glob
|
import glob
|
||||||
import grp
|
import grp
|
||||||
|
import io
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
|
|
@ -48,6 +49,8 @@ from gzip import GzipFile
|
||||||
from optparse import SUPPRESS_HELP, OptionParser
|
from optparse import SUPPRESS_HELP, OptionParser
|
||||||
|
|
||||||
import Cheetah.Template
|
import Cheetah.Template
|
||||||
|
import dnf
|
||||||
|
import librepo
|
||||||
import requests
|
import requests
|
||||||
import rpm
|
import rpm
|
||||||
import six
|
import six
|
||||||
|
|
@ -79,26 +82,6 @@ except ImportError: # pragma: no cover
|
||||||
except ImportError: # pragma: no cover
|
except ImportError: # pragma: no cover
|
||||||
reqgssapi = None
|
reqgssapi = None
|
||||||
|
|
||||||
try:
|
|
||||||
import librepo
|
|
||||||
import io
|
|
||||||
except ImportError:
|
|
||||||
librepo = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
import dnf
|
|
||||||
except ImportError:
|
|
||||||
dnf = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
# yum
|
|
||||||
from yum import repoMDObject
|
|
||||||
import yum.packages
|
|
||||||
import yum.Errors
|
|
||||||
yum_available = True
|
|
||||||
except ImportError:
|
|
||||||
yum_available = False
|
|
||||||
|
|
||||||
# imports for LiveCD, LiveMedia, and Appliance handler
|
# imports for LiveCD, LiveMedia, and Appliance handler
|
||||||
try:
|
try:
|
||||||
import pykickstart.parser as ksparser
|
import pykickstart.parser as ksparser
|
||||||
|
|
@ -803,42 +786,26 @@ class BuildRoot(object):
|
||||||
opts = dict([(k, getattr(self.options, k)) for k in ('topurl', 'topdir')])
|
opts = dict([(k, getattr(self.options, k)) for k in ('topurl', 'topdir')])
|
||||||
opts['tempdir'] = self.options.workdir
|
opts['tempdir'] = self.options.workdir
|
||||||
|
|
||||||
# prefer librepo
|
repo_url = os.path.join(repodir, self.br_arch)
|
||||||
if librepo is not None:
|
# repo_url can start with '/', don't use os.path.join
|
||||||
repo_url = os.path.join(repodir, self.br_arch)
|
if self.options.topurl:
|
||||||
# repo_url can start with '/', don't use os.path.join
|
repo_url = '%s/%s' % (self.options.topurl, repo_url)
|
||||||
if self.options.topurl:
|
elif self.options.topdir:
|
||||||
repo_url = '%s/%s' % (self.options.topurl, repo_url)
|
repo_url = '%s/%s' % (self.options.topdir, repo_url)
|
||||||
elif self.options.topdir:
|
logging.error(repo_url)
|
||||||
repo_url = '%s/%s' % (self.options.topdir, repo_url)
|
tmpdir = os.path.join(self.tmpdir(), 'librepo-markExternalRPMs')
|
||||||
logging.error(repo_url)
|
koji.ensuredir(tmpdir)
|
||||||
tmpdir = os.path.join(self.tmpdir(), 'librepo-markExternalRPMs')
|
h = librepo.Handle()
|
||||||
koji.ensuredir(tmpdir)
|
r = librepo.Result()
|
||||||
h = librepo.Handle()
|
h.setopt(librepo.LRO_REPOTYPE, librepo.LR_YUMREPO)
|
||||||
r = librepo.Result()
|
h.setopt(librepo.LRO_URLS, [repo_url])
|
||||||
h.setopt(librepo.LRO_REPOTYPE, librepo.LR_YUMREPO)
|
h.setopt(librepo.LRO_DESTDIR, tmpdir)
|
||||||
h.setopt(librepo.LRO_URLS, [repo_url])
|
# We are using this just to find out location of 'origin',
|
||||||
h.setopt(librepo.LRO_DESTDIR, tmpdir)
|
# we don't even need to download it since we use openRemoteFile
|
||||||
# We are using this just to find out location of 'origin',
|
h.setopt(librepo.LRO_YUMDLIST, [])
|
||||||
# we don't even need to download it since we use openRemoteFile
|
h.perform(r)
|
||||||
h.setopt(librepo.LRO_YUMDLIST, [])
|
pkgorigins = r.getinfo(librepo.LRR_YUM_REPOMD)['origin']['location_href']
|
||||||
h.perform(r)
|
koji.util.rmtree(tmpdir)
|
||||||
pkgorigins = r.getinfo(librepo.LRR_YUM_REPOMD)['origin']['location_href']
|
|
||||||
koji.util.rmtree(tmpdir)
|
|
||||||
elif yum_available:
|
|
||||||
# XXX - cheap hack to get relative paths
|
|
||||||
repomdpath = os.path.join(repodir, self.br_arch, 'repodata', 'repomd.xml')
|
|
||||||
with koji.openRemoteFile(repomdpath, **opts) as fo:
|
|
||||||
try:
|
|
||||||
repodata = repoMDObject.RepoMD('ourrepo', fo)
|
|
||||||
except Exception:
|
|
||||||
raise koji.BuildError("Unable to parse repomd.xml file for %s" %
|
|
||||||
os.path.join(repodir, self.br_arch))
|
|
||||||
data = repodata.getData('origin')
|
|
||||||
pkgorigins = data.location[1]
|
|
||||||
else:
|
|
||||||
# shouldn't occur
|
|
||||||
raise koji.GenericError("install librepo or yum")
|
|
||||||
|
|
||||||
relpath = os.path.join(repodir, self.br_arch, pkgorigins)
|
relpath = os.path.join(repodir, self.br_arch, pkgorigins)
|
||||||
with koji.openRemoteFile(relpath, **opts) as fo:
|
with koji.openRemoteFile(relpath, **opts) as fo:
|
||||||
|
|
@ -5754,10 +5721,7 @@ class createDistRepoTask(BaseTaskHandler):
|
||||||
self.uploadpath = self.getUploadDir()
|
self.uploadpath = self.getUploadDir()
|
||||||
self.get_rpms(tag, arch, keys, opts)
|
self.get_rpms(tag, arch, keys, opts)
|
||||||
if opts['multilib'] and koji.arch.isMultiLibArch(arch):
|
if opts['multilib'] and koji.arch.isMultiLibArch(arch):
|
||||||
if dnf is not None:
|
self.do_multilib(arch, self.archmap[arch], opts['multilib'])
|
||||||
self.do_multilib_dnf(arch, self.archmap[arch], opts['multilib'])
|
|
||||||
else:
|
|
||||||
self.do_multilib_yum(arch, self.archmap[arch], opts['multilib'])
|
|
||||||
self.split_pkgs(opts)
|
self.split_pkgs(opts)
|
||||||
self.write_kojipkgs()
|
self.write_kojipkgs()
|
||||||
self.write_pkglist()
|
self.write_pkglist()
|
||||||
|
|
@ -5884,7 +5848,7 @@ class createDistRepoTask(BaseTaskHandler):
|
||||||
raise koji.GenericError('failed to create repo: %s'
|
raise koji.GenericError('failed to create repo: %s'
|
||||||
% parseStatus(status, ' '.join(cmd)))
|
% parseStatus(status, ' '.join(cmd)))
|
||||||
|
|
||||||
def do_multilib_dnf(self, arch, ml_arch, conf):
|
def do_multilib(self, arch, ml_arch, conf):
|
||||||
repodir = koji.pathinfo.distrepo(self.rinfo['id'], self.rinfo['tag_name'])
|
repodir = koji.pathinfo.distrepo(self.rinfo['id'], self.rinfo['tag_name'])
|
||||||
mldir = os.path.join(repodir, koji.canonArch(ml_arch))
|
mldir = os.path.join(repodir, koji.canonArch(ml_arch))
|
||||||
ml_true = set() # multilib packages we need to include before depsolve
|
ml_true = set() # multilib packages we need to include before depsolve
|
||||||
|
|
@ -6010,139 +5974,6 @@ enabled=1
|
||||||
rpminfo['_multilib'] = True
|
rpminfo['_multilib'] = True
|
||||||
self.kojipkgs[bnp] = rpminfo
|
self.kojipkgs[bnp] = rpminfo
|
||||||
|
|
||||||
def do_multilib_yum(self, arch, ml_arch, conf):
|
|
||||||
repodir = koji.pathinfo.distrepo(self.rinfo['id'], self.rinfo['tag_name'])
|
|
||||||
mldir = os.path.join(repodir, koji.canonArch(ml_arch))
|
|
||||||
ml_true = set() # multilib packages we need to include before depsolve
|
|
||||||
ml_conf = os.path.join(koji.pathinfo.work(), conf)
|
|
||||||
|
|
||||||
# read pkgs data from multilib repo
|
|
||||||
ml_pkgfile = os.path.join(mldir, 'kojipkgs')
|
|
||||||
ml_pkgs = json.load(open(ml_pkgfile, 'r'))
|
|
||||||
|
|
||||||
# step 1: figure out which packages are multilib (should already exist)
|
|
||||||
mlm = multilib.DevelMultilibMethod(ml_conf)
|
|
||||||
fs_missing = set()
|
|
||||||
for bnp in self.kojipkgs:
|
|
||||||
rpminfo = self.kojipkgs[bnp]
|
|
||||||
ppath = rpminfo['_pkgpath']
|
|
||||||
po = yum.packages.YumLocalPackage(filename=ppath)
|
|
||||||
if mlm.select(po):
|
|
||||||
# we need a multilib package to be included
|
|
||||||
ml_bnp = bnp.replace(arch, self.archmap[arch])
|
|
||||||
ml_path = os.path.join(mldir, ml_bnp[0].lower(), ml_bnp)
|
|
||||||
# ^ XXX - should actually generate this
|
|
||||||
if ml_bnp not in ml_pkgs:
|
|
||||||
# not in our multilib repo
|
|
||||||
self.logger.error('%s (multilib) is not on the filesystem' % ml_path)
|
|
||||||
fs_missing.add(ml_path)
|
|
||||||
# we defer failure so can report all the missing deps
|
|
||||||
continue
|
|
||||||
ml_true.add(ml_path)
|
|
||||||
|
|
||||||
# step 2: set up architectures for yum configuration
|
|
||||||
self.logger.info("Resolving multilib for %s using method devel" % arch)
|
|
||||||
yumbase = yum.YumBase()
|
|
||||||
yumbase.verbose_logger.setLevel(logging.ERROR)
|
|
||||||
yumdir = os.path.join(self.workdir, 'yum')
|
|
||||||
# TODO: unwind this arch mess
|
|
||||||
archlist = (arch, 'noarch')
|
|
||||||
transaction_arch = arch
|
|
||||||
archlist = archlist + self.compat[self.biarch[arch]]
|
|
||||||
best_compat = self.compat[self.biarch[arch]][0]
|
|
||||||
if koji.arch.archDifference(best_compat, arch) > 0:
|
|
||||||
transaction_arch = best_compat
|
|
||||||
if hasattr(koji.arch, 'ArchStorage'):
|
|
||||||
yumbase.preconf.arch = transaction_arch
|
|
||||||
else:
|
|
||||||
koji.arch.canonArch = transaction_arch
|
|
||||||
|
|
||||||
yconfig = """
|
|
||||||
[main]
|
|
||||||
debuglevel=2
|
|
||||||
pkgpolicy=newest
|
|
||||||
exactarch=1
|
|
||||||
gpgcheck=0
|
|
||||||
reposdir=/dev/null
|
|
||||||
cachedir=/yumcache
|
|
||||||
installroot=%s
|
|
||||||
logfile=/yum.log
|
|
||||||
|
|
||||||
[koji-%s]
|
|
||||||
name=koji multilib task
|
|
||||||
baseurl=file://%s
|
|
||||||
enabled=1
|
|
||||||
|
|
||||||
""" % (yumdir, self.id, mldir)
|
|
||||||
os.makedirs(os.path.join(yumdir, "yumcache"))
|
|
||||||
os.makedirs(os.path.join(yumdir, 'var/lib/rpm'))
|
|
||||||
|
|
||||||
# step 3: proceed with yum config and set up
|
|
||||||
yconfig_path = os.path.join(yumdir, 'yum.conf-koji-%s' % arch)
|
|
||||||
with open(yconfig_path, 'w') as f:
|
|
||||||
f.write(yconfig)
|
|
||||||
self.session.uploadWrapper(yconfig_path, self.uploadpath,
|
|
||||||
os.path.basename(yconfig_path))
|
|
||||||
yumbase.doConfigSetup(fn=yconfig_path)
|
|
||||||
yumbase.conf.cache = 0
|
|
||||||
yumbase.doRepoSetup()
|
|
||||||
yumbase.doTsSetup()
|
|
||||||
yumbase.doRpmDBSetup()
|
|
||||||
# we trust Koji's files, so skip verifying sigs and digests
|
|
||||||
yumbase.ts.pushVSFlags(
|
|
||||||
(rpm._RPMVSF_NOSIGNATURES | rpm._RPMVSF_NODIGESTS))
|
|
||||||
yumbase.doSackSetup(archlist=archlist, thisrepo='koji-%s' % arch)
|
|
||||||
yumbase.doSackFilelistPopulate()
|
|
||||||
for pkg in ml_true:
|
|
||||||
# TODO: store packages by first letter
|
|
||||||
# ppath = os.path.join(pkgdir, pkg.name[0].lower(), pname)
|
|
||||||
po = yum.packages.YumLocalPackage(filename=pkg)
|
|
||||||
yumbase.tsInfo.addInstall(po)
|
|
||||||
|
|
||||||
# step 4: execute yum transaction to get dependencies
|
|
||||||
self.logger.info("Resolving depenencies for arch %s" % arch)
|
|
||||||
rc, errors = yumbase.resolveDeps()
|
|
||||||
ml_needed = {}
|
|
||||||
for tspkg in yumbase.tsInfo.getMembers():
|
|
||||||
bnp = os.path.basename(tspkg.po.localPkg())
|
|
||||||
dep_path = os.path.join(mldir, bnp[0].lower(), bnp)
|
|
||||||
ml_needed[dep_path] = tspkg
|
|
||||||
self.logger.debug("added %s" % dep_path)
|
|
||||||
if not os.path.exists(dep_path):
|
|
||||||
self.logger.error('%s (multilib dep) not on filesystem' % dep_path)
|
|
||||||
fs_missing.add(dep_path)
|
|
||||||
self.logger.info('yum return code: %s' % rc)
|
|
||||||
if not rc:
|
|
||||||
self.logger.error('yum depsolve was unsuccessful')
|
|
||||||
raise koji.GenericError(errors)
|
|
||||||
if len(fs_missing) > 0:
|
|
||||||
missing_log = os.path.join(self.workdir, 'missing_multilib.log')
|
|
||||||
with open(missing_log, 'w') as outfile:
|
|
||||||
outfile.write('The following multilib files were missing:\n')
|
|
||||||
for ml_path in fs_missing:
|
|
||||||
outfile.write(ml_path)
|
|
||||||
outfile.write('\n')
|
|
||||||
self.session.uploadWrapper(missing_log, self.uploadpath)
|
|
||||||
raise koji.GenericError('multilib packages missing. '
|
|
||||||
'See missing_multilib.log')
|
|
||||||
|
|
||||||
# step 5: update kojipkgs
|
|
||||||
for dep_path in ml_needed:
|
|
||||||
tspkg = ml_needed[dep_path]
|
|
||||||
bnp = os.path.basename(dep_path)
|
|
||||||
if bnp in self.kojipkgs:
|
|
||||||
# we expect duplication with noarch, but not other arches
|
|
||||||
if tspkg.arch != 'noarch':
|
|
||||||
self.logger.warning("Multilib duplicate: %s", bnp)
|
|
||||||
continue
|
|
||||||
rpminfo = ml_pkgs[bnp].copy()
|
|
||||||
# fix _pkgpath, which comes from another task and could be wrong
|
|
||||||
# for us
|
|
||||||
# TODO: would be better if we could use the proper path here
|
|
||||||
rpminfo['_pkgpath'] = dep_path
|
|
||||||
rpminfo['_multilib'] = True
|
|
||||||
self.kojipkgs[bnp] = rpminfo
|
|
||||||
|
|
||||||
def pick_key(self, keys, avail_keys):
|
def pick_key(self, keys, avail_keys):
|
||||||
best = None
|
best = None
|
||||||
best_idx = None
|
best_idx = None
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,13 @@
|
||||||
# and no python2 on rhel8+
|
# and no python2 on rhel8+
|
||||||
%define py2_support 0
|
%define py2_support 0
|
||||||
%else
|
%else
|
||||||
%if 0%{?rhel}
|
%if 0%{?rhel} >= 7
|
||||||
# No python3 for older rhel
|
# No python3 for older rhel
|
||||||
%define py3_support 0
|
%define py3_support 0
|
||||||
|
%else
|
||||||
|
# don't build anything for rhel6
|
||||||
|
%define py2_support 0
|
||||||
|
%define py3_support 0
|
||||||
%endif
|
%endif
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
|
|
||||||
11
setup.py
11
setup.py
|
|
@ -13,6 +13,7 @@ def get_install_requires():
|
||||||
|
|
||||||
requires = [
|
requires = [
|
||||||
'python-dateutil',
|
'python-dateutil',
|
||||||
|
'pyOpenSSL',
|
||||||
'requests',
|
'requests',
|
||||||
'requests-gssapi',
|
'requests-gssapi',
|
||||||
'six',
|
'six',
|
||||||
|
|
@ -20,13 +21,6 @@ def get_install_requires():
|
||||||
# 'rpm-py-installer', # it is optional feature
|
# 'rpm-py-installer', # it is optional feature
|
||||||
# 'rpm',
|
# 'rpm',
|
||||||
]
|
]
|
||||||
# since pyOpenSSL-18.0.0, py26 support is dropped
|
|
||||||
# see https://pagure.io/koji/issue/1060
|
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] < 7:
|
|
||||||
requires.append('pyOpenSSL<18.0.0')
|
|
||||||
else:
|
|
||||||
requires.append('pyOpenSSL')
|
|
||||||
|
|
||||||
return requires
|
return requires
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -51,7 +45,6 @@ setup(
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)",
|
"License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)",
|
||||||
"Natural Language :: English",
|
"Natural Language :: English",
|
||||||
"Programming Language :: Python :: 2.6",
|
|
||||||
"Programming Language :: Python :: 2.7",
|
"Programming Language :: Python :: 2.7",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Operating System :: POSIX :: Linux",
|
"Operating System :: POSIX :: Linux",
|
||||||
|
|
@ -74,6 +67,6 @@ setup(
|
||||||
'util/koji-sweep-db',
|
'util/koji-sweep-db',
|
||||||
'util/kojira',
|
'util/kojira',
|
||||||
],
|
],
|
||||||
python_requires='>=2.6',
|
python_requires='>=2.7',
|
||||||
install_requires=get_install_requires(),
|
install_requires=get_install_requires(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
4
tox.ini
4
tox.ini
|
|
@ -4,10 +4,6 @@ envlist = flake8,py2,py3
|
||||||
[testenv:flake8]
|
[testenv:flake8]
|
||||||
deps =
|
deps =
|
||||||
flake8
|
flake8
|
||||||
# On EL6, pip would get us a flake8 that doesn't work with python2.6. The next
|
|
||||||
# two lines let us use an RPM-based version from EPEL if it is installed
|
|
||||||
sitepackages = true
|
|
||||||
whitelist_externals = flake8
|
|
||||||
# These two lines just speed things up by avoiding unnecessary setup
|
# These two lines just speed things up by avoiding unnecessary setup
|
||||||
skip_install=true
|
skip_install=true
|
||||||
usedevelop=true
|
usedevelop=true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue