2015-02-10 13:19:34 +00:00
|
|
|
# -*- 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
|
2016-09-21 12:49:13 +00:00
|
|
|
# along with this program; if not, see <https://gnu.org/licenses/>.
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
|
2016-03-31 08:07:09 +00:00
|
|
|
from .. import util
|
|
|
|
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
PACKAGES_RE = {
|
2015-07-10 10:43:06 +00:00
|
|
|
"rpm": re.compile(r"^RPM(\((?P<flags>[^\)]*)\))?: (?P<path>.+)$"),
|
|
|
|
"srpm": re.compile(r"^SRPM(\((?P<flags>[^\)]*)\))?: (?P<path>.+)$"),
|
|
|
|
"debuginfo": re.compile(r"^DEBUGINFO(\((?P<flags>[^\)]*)\))?: (?P<path>.+)$"),
|
2015-02-10 13:19:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UNRESOLVED_DEPENDENCY_RE = re.compile(r"^.*Unresolvable dependency (.+) in ([^ ]+).*$")
|
|
|
|
|
2020-02-03 03:50:06 +00:00
|
|
|
MISSING_COMPS_PACKAGE_RE = re.compile(
|
|
|
|
r"^.*Could not find a match for (.+) in any configured repo"
|
|
|
|
)
|
2017-08-03 11:28:34 +00:00
|
|
|
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2018-03-07 11:35:33 +00:00
|
|
|
def _write_ks_section(f, section, lines):
|
|
|
|
if lines:
|
|
|
|
f.write("\n%%%s\n" % section)
|
|
|
|
for i in sorted(lines):
|
|
|
|
f.write("%s\n" % i)
|
|
|
|
|
|
|
|
f.write("%end\n")
|
|
|
|
|
|
|
|
|
2015-02-10 13:19:34 +00:00
|
|
|
class PungiWrapper(object):
|
2020-02-03 03:50:06 +00:00
|
|
|
def write_kickstart(
|
|
|
|
self,
|
|
|
|
ks_path,
|
|
|
|
repos,
|
|
|
|
groups,
|
|
|
|
packages,
|
|
|
|
exclude_packages=None,
|
|
|
|
comps_repo=None,
|
|
|
|
lookaside_repos=None,
|
|
|
|
fulltree_excludes=None,
|
|
|
|
multilib_blacklist=None,
|
|
|
|
multilib_whitelist=None,
|
|
|
|
prepopulate=None,
|
|
|
|
):
|
2015-02-10 13:19:34 +00:00
|
|
|
groups = groups or []
|
|
|
|
exclude_packages = exclude_packages or {}
|
|
|
|
lookaside_repos = lookaside_repos or {}
|
|
|
|
# repos = {name: url}
|
|
|
|
fulltree_excludes = fulltree_excludes or set()
|
|
|
|
multilib_blacklist = multilib_blacklist or set()
|
|
|
|
multilib_whitelist = multilib_whitelist or set()
|
|
|
|
ks_path = os.path.abspath(ks_path)
|
|
|
|
|
|
|
|
ks_dir = os.path.dirname(ks_path)
|
2016-03-31 08:07:09 +00:00
|
|
|
util.makedirs(ks_dir)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
kickstart = open(ks_path, "w")
|
|
|
|
|
|
|
|
# repos
|
2017-09-05 08:01:21 +00:00
|
|
|
for repo_name, repo_url in list(repos.items()) + list(lookaside_repos.items()):
|
2015-02-10 13:19:34 +00:00
|
|
|
if "://" not in repo_url:
|
|
|
|
repo_url = "file://" + os.path.abspath(repo_url)
|
|
|
|
repo_str = "repo --name=%s --baseurl=%s" % (repo_name, repo_url)
|
|
|
|
# TODO: make sure pungi works when there are no comps in repodata
|
|
|
|
# XXX: if groups are ignored, langpacks are ignored too
|
|
|
|
if comps_repo and repo_name != comps_repo:
|
|
|
|
repo_str += " --ignoregroups=true"
|
|
|
|
kickstart.write(repo_str + "\n")
|
|
|
|
|
|
|
|
# %packages
|
|
|
|
kickstart.write("\n")
|
|
|
|
kickstart.write("%packages\n")
|
|
|
|
|
|
|
|
for group in sorted(groups):
|
|
|
|
kickstart.write("@%s --optional\n" % group)
|
|
|
|
|
|
|
|
for package in sorted(packages):
|
|
|
|
kickstart.write("%s\n" % package)
|
|
|
|
|
|
|
|
for package in sorted(exclude_packages):
|
|
|
|
kickstart.write("-%s\n" % package)
|
|
|
|
|
|
|
|
kickstart.write("%end\n")
|
|
|
|
|
2018-03-07 11:35:33 +00:00
|
|
|
_write_ks_section(kickstart, "fulltree-excludes", fulltree_excludes)
|
|
|
|
_write_ks_section(kickstart, "multilib-blacklist", multilib_blacklist)
|
|
|
|
_write_ks_section(kickstart, "multilib-whitelist", multilib_whitelist)
|
|
|
|
_write_ks_section(kickstart, "prepopulate", prepopulate)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
kickstart.close()
|
|
|
|
|
2020-02-03 03:50:06 +00:00
|
|
|
def get_pungi_cmd(
|
|
|
|
self,
|
|
|
|
config,
|
|
|
|
destdir,
|
|
|
|
name,
|
|
|
|
version=None,
|
|
|
|
flavor=None,
|
|
|
|
selfhosting=False,
|
|
|
|
fulltree=False,
|
|
|
|
greedy=None,
|
|
|
|
nodeps=False,
|
|
|
|
nodownload=True,
|
|
|
|
full_archlist=False,
|
|
|
|
arch=None,
|
|
|
|
cache_dir=None,
|
|
|
|
lookaside_repos=None,
|
|
|
|
multilib_methods=None,
|
|
|
|
profiler=False,
|
|
|
|
):
|
2015-03-12 18:15:29 +00:00
|
|
|
cmd = ["pungi"]
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
# Gather stage
|
|
|
|
cmd.append("-G")
|
|
|
|
|
|
|
|
# path to a kickstart file
|
|
|
|
cmd.append("--config=%s" % config)
|
|
|
|
|
2020-02-06 07:09:32 +00:00
|
|
|
# destdir is optional in Pungi (defaults to current dir), but
|
|
|
|
# want it mandatory here
|
2015-02-10 13:19:34 +00:00
|
|
|
cmd.append("--destdir=%s" % destdir)
|
|
|
|
|
|
|
|
# name
|
|
|
|
cmd.append("--name=%s" % name)
|
|
|
|
|
|
|
|
# version; optional, defaults to datestamp
|
|
|
|
if version:
|
|
|
|
cmd.append("--ver=%s" % version)
|
|
|
|
|
|
|
|
# rhel variant; optional
|
|
|
|
if flavor:
|
|
|
|
cmd.append("--flavor=%s" % flavor)
|
|
|
|
|
|
|
|
# turn selfhosting on
|
|
|
|
if selfhosting:
|
|
|
|
cmd.append("--selfhosting")
|
|
|
|
|
|
|
|
# NPLB
|
|
|
|
if fulltree:
|
|
|
|
cmd.append("--fulltree")
|
|
|
|
|
|
|
|
greedy = greedy or "none"
|
|
|
|
cmd.append("--greedy=%s" % greedy)
|
|
|
|
|
|
|
|
if nodeps:
|
|
|
|
cmd.append("--nodeps")
|
|
|
|
|
|
|
|
# don't download packages, just print paths
|
|
|
|
if nodownload:
|
|
|
|
cmd.append("--nodownload")
|
|
|
|
|
|
|
|
if full_archlist:
|
|
|
|
cmd.append("--full-archlist")
|
|
|
|
|
|
|
|
if arch:
|
|
|
|
cmd.append("--arch=%s" % arch)
|
|
|
|
|
|
|
|
if multilib_methods:
|
|
|
|
for i in multilib_methods:
|
|
|
|
cmd.append("--multilib=%s" % i)
|
|
|
|
|
|
|
|
if cache_dir:
|
|
|
|
cmd.append("--cachedir=%s" % cache_dir)
|
|
|
|
|
|
|
|
if lookaside_repos:
|
|
|
|
for i in lookaside_repos:
|
|
|
|
cmd.append("--lookaside-repo=%s" % i)
|
|
|
|
|
|
|
|
return cmd
|
|
|
|
|
2020-02-03 03:50:06 +00:00
|
|
|
def get_pungi_cmd_dnf(
|
|
|
|
self,
|
|
|
|
config,
|
|
|
|
destdir,
|
|
|
|
name,
|
|
|
|
version=None,
|
|
|
|
flavor=None,
|
|
|
|
selfhosting=False,
|
|
|
|
fulltree=False,
|
|
|
|
greedy=None,
|
|
|
|
nodeps=False,
|
|
|
|
nodownload=True,
|
|
|
|
full_archlist=False,
|
|
|
|
arch=None,
|
|
|
|
cache_dir=None,
|
|
|
|
lookaside_repos=None,
|
|
|
|
multilib_methods=None,
|
|
|
|
profiler=False,
|
|
|
|
):
|
2015-07-10 10:43:06 +00:00
|
|
|
cmd = ["pungi-gather"]
|
|
|
|
|
|
|
|
# path to a kickstart file
|
|
|
|
cmd.append("--config=%s" % config)
|
|
|
|
|
|
|
|
# turn selfhosting on
|
|
|
|
if selfhosting:
|
|
|
|
cmd.append("--selfhosting")
|
|
|
|
|
|
|
|
# NPLB
|
|
|
|
if fulltree:
|
|
|
|
cmd.append("--fulltree")
|
|
|
|
|
|
|
|
greedy = greedy or "none"
|
|
|
|
cmd.append("--greedy=%s" % greedy)
|
|
|
|
|
|
|
|
if nodeps:
|
|
|
|
cmd.append("--nodeps")
|
|
|
|
|
|
|
|
if arch:
|
|
|
|
cmd.append("--arch=%s" % arch)
|
|
|
|
|
2017-08-14 12:15:18 +00:00
|
|
|
if not nodownload:
|
|
|
|
cmd.append("--download-to=%s" % destdir)
|
|
|
|
|
2015-07-10 10:43:06 +00:00
|
|
|
if multilib_methods:
|
|
|
|
for i in multilib_methods:
|
|
|
|
cmd.append("--multilib=%s" % i)
|
|
|
|
|
|
|
|
if lookaside_repos:
|
|
|
|
for i in lookaside_repos:
|
|
|
|
cmd.append("--lookaside=%s" % i)
|
|
|
|
|
2017-09-02 00:04:02 +00:00
|
|
|
if profiler:
|
|
|
|
cmd.append("--profiler")
|
|
|
|
|
2015-07-10 10:43:06 +00:00
|
|
|
return cmd
|
|
|
|
|
2017-08-03 11:42:04 +00:00
|
|
|
def parse_log(self, f):
|
|
|
|
packages = dict(((i, []) for i in PACKAGES_RE))
|
|
|
|
broken_deps = {}
|
|
|
|
missing_comps = set()
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2017-06-14 13:20:20 +00:00
|
|
|
for line in f:
|
2017-09-05 08:01:21 +00:00
|
|
|
for file_type, pattern in PACKAGES_RE.items():
|
2015-02-10 13:19:34 +00:00
|
|
|
match = pattern.match(line)
|
|
|
|
if match:
|
|
|
|
item = {}
|
2015-07-10 10:43:06 +00:00
|
|
|
item["path"] = match.groupdict()["path"].strip()
|
|
|
|
if item["path"].startswith("file://"):
|
|
|
|
item["path"] = item["path"][7:]
|
2015-02-10 13:19:34 +00:00
|
|
|
flags = match.groupdict()["flags"] or ""
|
|
|
|
flags = sorted([i.strip() for i in flags.split(",") if i.strip()])
|
|
|
|
item["flags"] = flags
|
2017-08-03 11:42:04 +00:00
|
|
|
packages[file_type].append(item)
|
2015-02-10 13:19:34 +00:00
|
|
|
break
|
|
|
|
|
2017-08-03 11:28:34 +00:00
|
|
|
match = MISSING_COMPS_PACKAGE_RE.match(line)
|
|
|
|
if match:
|
2017-08-03 11:42:04 +00:00
|
|
|
missing_comps.add(match.group(1))
|
2017-08-03 11:28:34 +00:00
|
|
|
|
2015-02-10 13:19:34 +00:00
|
|
|
match = UNRESOLVED_DEPENDENCY_RE.match(line)
|
|
|
|
if match:
|
2017-08-03 11:42:04 +00:00
|
|
|
broken_deps.setdefault(match.group(2), set()).add(match.group(1))
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2017-08-03 11:42:04 +00:00
|
|
|
return packages, broken_deps, missing_comps
|
2016-11-04 08:08:11 +00:00
|
|
|
|
2020-02-03 03:50:06 +00:00
|
|
|
def run_pungi(
|
|
|
|
self,
|
|
|
|
ks_file,
|
|
|
|
destdir,
|
|
|
|
name,
|
|
|
|
selfhosting=False,
|
|
|
|
fulltree=False,
|
|
|
|
greedy="",
|
|
|
|
cache_dir=None,
|
|
|
|
arch="",
|
|
|
|
multilib_methods=[],
|
|
|
|
nodeps=False,
|
|
|
|
lookaside_repos=[],
|
|
|
|
):
|
2016-11-04 08:08:11 +00:00
|
|
|
"""
|
|
|
|
This is a replacement for get_pungi_cmd that runs it in-process. Not
|
|
|
|
all arguments are supported.
|
|
|
|
"""
|
|
|
|
from .. import ks, gather, config
|
2020-02-03 03:50:06 +00:00
|
|
|
|
2016-11-04 08:08:11 +00:00
|
|
|
ksparser = ks.get_ksparser(ks_path=ks_file)
|
|
|
|
cfg = config.Config()
|
2020-02-03 03:50:06 +00:00
|
|
|
cfg.set("pungi", "destdir", destdir)
|
|
|
|
cfg.set("pungi", "family", name)
|
|
|
|
cfg.set("pungi", "iso_basename", name)
|
|
|
|
cfg.set("pungi", "fulltree", str(fulltree))
|
|
|
|
cfg.set("pungi", "selfhosting", str(selfhosting))
|
|
|
|
cfg.set("pungi", "cachedir", cache_dir)
|
|
|
|
cfg.set("pungi", "full_archlist", "True")
|
|
|
|
cfg.set("pungi", "workdirbase", "%s/work" % destdir)
|
|
|
|
cfg.set("pungi", "greedy", greedy)
|
|
|
|
cfg.set("pungi", "nosource", "False")
|
|
|
|
cfg.set("pungi", "nodebuginfo", "False")
|
|
|
|
cfg.set("pungi", "force", "False")
|
|
|
|
cfg.set("pungi", "resolve_deps", str(not nodeps))
|
2016-11-04 08:08:11 +00:00
|
|
|
if arch:
|
2020-02-03 03:50:06 +00:00
|
|
|
cfg.set("pungi", "arch", arch)
|
2016-11-04 08:08:11 +00:00
|
|
|
if multilib_methods:
|
2020-02-03 03:50:06 +00:00
|
|
|
cfg.set("pungi", "multilib", " ".join(multilib_methods))
|
2016-11-04 08:08:11 +00:00
|
|
|
if lookaside_repos:
|
2020-02-03 03:50:06 +00:00
|
|
|
cfg.set("pungi", "lookaside_repos", " ".join(lookaside_repos))
|
2016-11-04 08:08:11 +00:00
|
|
|
|
|
|
|
mypungi = gather.Pungi(cfg, ksparser)
|
|
|
|
|
2020-02-03 03:50:06 +00:00
|
|
|
with open(os.path.join(destdir, "out"), "w") as f:
|
2016-11-04 08:08:11 +00:00
|
|
|
with mypungi.yumlock:
|
|
|
|
mypungi._inityum()
|
|
|
|
mypungi.gather()
|
|
|
|
|
|
|
|
for line in mypungi.list_packages():
|
|
|
|
flags_str = ",".join(line["flags"])
|
|
|
|
if flags_str:
|
|
|
|
flags_str = "(%s)" % flags_str
|
|
|
|
f.write("RPM%s: %s\n" % (flags_str, line["path"]))
|
|
|
|
mypungi.makeCompsFile()
|
|
|
|
mypungi.getDebuginfoList()
|
|
|
|
for line in mypungi.list_debuginfo():
|
|
|
|
flags_str = ",".join(line["flags"])
|
|
|
|
if flags_str:
|
|
|
|
flags_str = "(%s)" % flags_str
|
|
|
|
f.write("DEBUGINFO%s: %s\n" % (flags_str, line["path"]))
|
|
|
|
for line in mypungi.list_srpms():
|
|
|
|
flags_str = ",".join(line["flags"])
|
|
|
|
if flags_str:
|
|
|
|
flags_str = "(%s)" % flags_str
|
|
|
|
f.write("SRPM%s: %s\n" % (flags_str, line["path"]))
|