diff options
Diffstat (limited to 'MgaRepo/rpmutil.py')
-rw-r--r-- | MgaRepo/rpmutil.py | 314 |
1 files changed, 243 insertions, 71 deletions
diff --git a/MgaRepo/rpmutil.py b/MgaRepo/rpmutil.py index 769167c..49ef07f 100644 --- a/MgaRepo/rpmutil.py +++ b/MgaRepo/rpmutil.py @@ -1,9 +1,10 @@ #!/usr/bin/python3 from MgaRepo import Error, config from MgaRepo import mirror, layout, log, binrepo +from MgaRepo.git import GIT from MgaRepo.svn import SVN from MgaRepo.simplerpm import SRPM -from MgaRepo.util import execcmd +from MgaRepo.util import execcmd, CommandError from MgaRepo.command import default_parent import rpm import urllib.parse @@ -14,13 +15,38 @@ import glob import sys import os +def detectVCS(url): + if ':' in url: + protocol,uri = url.split(":") + if "svn" in protocol: + return SVN(url=url) + elif "git" in protocol: + return GIT(url=url) + elif "http" in protocol: + if uri.endswith(".git"): + return GIT(url=url) + elif "svn" in uri: + return SVN(url=url) + raise Error("Unknown protocol %s for %s" % (protocol, url)) + elif os.path.exists(url) and os.path.isdir(url): + while True: + url = os.path.abspath(url) + for vcs in (SVN, GIT): + vcsdir = os.path.join(url, vcs.vcs_dirname) + if os.path.exists(vcsdir) and os.path.isdir(vcsdir): + return vcs(path=url) + url = os.path.dirname(url) + if url == "/": + break + raise Error("No supported repository found at path: %s" % url) + def get_spec(pkgdirurl, targetdir=".", submit=False): - svn = SVN() + svn = detectVCS(pkgdirurl) tmpdir = tempfile.mktemp() try: geturl = layout.checkout_url(pkgdirurl, append_path="SPECS") mirror.info(geturl) - svn.export("'%s'" % geturl, tmpdir) + svn.export(geturl, tmpdir) speclist = glob.glob(os.path.join(tmpdir, "*.spec")) if not speclist: raise Error("no spec files found") @@ -33,14 +59,9 @@ def get_spec(pkgdirurl, targetdir=".", submit=False): if os.path.isdir(tmpdir): shutil.rmtree(tmpdir) -def rpm_macros_defs(macros): - defs = ("--define \"%s %s\"" % macro for macro in macros) - args = " ".join(defs) - return args - #FIXME move it to another module def rev_touched_url(url, rev): - svn = SVN() + svn = detectVCS(url) info = svn.info2(url) if info is None: raise Error("can't fetch svn info about the URL: %s" % url) @@ -95,16 +116,21 @@ def get_srpm(pkgdirurl, template = None, macros = [], verbose = 0, - strict = False): - svn = SVN() + strict = False, + fullnames = False): + svn = detectVCS(pkgdirurl) tmpdir = tempfile.mktemp() - topdir = "--define '_topdir %s'" % tmpdir - builddir = "--define '_builddir %s/%s'" % (tmpdir, "BUILD") - rpmdir = "--define '_rpmdir %s/%s'" % (tmpdir, "RPMS") - sourcedir = "--define '_sourcedir %s/%s'" % (tmpdir, "SOURCES") - specdir = "--define '_specdir %s/%s'" % (tmpdir, "SPECS") - srcrpmdir = "--define '_srcrpmdir %s/%s'" % (tmpdir, "SRPMS") - patchdir = "--define '_patchdir %s/%s'" % (tmpdir, "SOURCES") + topdir = "_topdir %s" % tmpdir + builddir = "_builddir %s/%s" % (tmpdir, "BUILD") + rpmdir = "_rpmdir %s/%s" % (tmpdir, "RPMS") + sourcedir = "_sourcedir %s/%s" % (tmpdir, "SOURCES") + specdir = "_specdir %s/%s" % (tmpdir, "SPECS") + srcrpmdir = "_srcrpmdir %s/%s" % (tmpdir, "SRPMS") + patchdir = "_patchdir %s/%s" % (tmpdir, "SOURCES") + temppath = "_tmppath %s" % (tmpdir) + + rpmdefs = [("--define", expr) for expr in (topdir, builddir, rpmdir, + sourcedir, specdir, srcrpmdir, patchdir, temppath)] try: if mode == "version": @@ -133,24 +159,29 @@ def get_srpm(pkgdirurl, if config.getbool("srpm", "run-prep", False): makefile = os.path.join(tmpdir, "Makefile") if os.path.exists(makefile): - execcmd("make", "-C", tmpdir, "srpm-prep") + execcmd(("make", "-C", tmpdir, "srpm-prep")) if not speclist: raise Error("no spec files found") spec = speclist[0] - defs = rpm_macros_defs(macros) sourcecmd = config.get("helper", "rpmbuild", "rpmbuild") if packager: packager = " --define 'packager %s'" % packager + sourcecmd = config.get("helper", "rpmbuild", "rpmbuild") + args = [sourcecmd, "-bs", "--nodeps"] + for pair in rpmdefs: + args.extend(pair) + for pair in macros: + args.extend(("--define", "%s %s" % pair)) + args.append(spec) if svnlog: submit = not not revision try: log.specfile_svn2rpm(pkgdirurl, spec, revision, submit=submit, - template=template, macros=macros, exported=tmpdir) + template=template, macros=macros, exported=tmpdir, fullnames=fullnames) except: - execcmd("%s -bs --nodeps %s %s %s %s %s %s %s %s %s %s" % - (sourcecmd, topdir, builddir, rpmdir, sourcedir, specdir, - srcrpmdir, patchdir, packager, spec, defs)) + #cmd = [sourcecmd, topdir, builddir, rpmdir, sourcedir, specdir + execcmd(args) cp_srpms(revision, revname, geturl, targetdirs, srpmsdir, verbose) log.specfile_svn2rpm(pkgdirurl, spec, revision, submit=submit, template=template, macros=macros, exported=tmpdir, create=True) @@ -162,9 +193,15 @@ def get_srpm(pkgdirurl, if status != 0: raise Error("script %s failed" % script) - execcmd("%s -bs --nodeps %s %s %s %s %s %s %s %s %s %s" % - (sourcecmd, topdir, builddir, rpmdir, sourcedir, specdir, - srcrpmdir, patchdir, packager, spec, defs)) + try: + execcmd(args) + except CommandError as e: + if config.getbool("global", "verbose"): + cmdline = e.cmdline + "\n" + else: + cmdline = "" + raise Error("error while creating the source RPM " + "(with %s):\n%s%s" % (sourcecmd, cmdline, e.output)) # copy the generated SRPMs to their target locations targetsrpms = cp_srpms(revision, revname, geturl, targetdirs, srpmsdir, verbose) @@ -175,7 +212,7 @@ def get_srpm(pkgdirurl, def patch_spec(pkgdirurl, patchfile, log=""): #FIXME use get_spec - svn = SVN() + svn = detectVCS(pkgdirurl) tmpdir = tempfile.mktemp() try: geturl = layout.checkout_url(pkgdirurl, append_path="SPECS") @@ -184,7 +221,7 @@ def patch_spec(pkgdirurl, patchfile, log=""): if not speclist: raise Error("no spec files found") spec = speclist[0] - status, output = execcmd("patch", spec, patchfile) + status, output = execcmd(["patch", spec, patchfile]) if status != 0: raise Error("can't apply patch:\n%s\n" % output) else: @@ -195,7 +232,6 @@ def patch_spec(pkgdirurl, patchfile, log=""): def put_srpm(srpmfile, markrelease=False, striplog=True, branch=None, baseurl=None, baseold=None, logmsg=None, rename=True): - svn = SVN() srpm = SRPM(srpmfile) tmpdir = tempfile.mktemp() if baseurl: @@ -203,6 +239,7 @@ def put_srpm(srpmfile, markrelease=False, striplog=True, branch=None, else: pkgurl = layout.package_url(srpm.name, distro=branch, mirrored=False) + svn = detectVCS(pkgdirurl) print("Importing package to %s" % pkgurl) try: if srpm.epoch: @@ -264,9 +301,9 @@ def put_srpm(srpmfile, markrelease=False, striplog=True, branch=None, svn.remove(entrypath) # Copy all files - execcmd("cp -rlf", uspecsdir, currentdir) + execcmd(["cp", "-rf", uspecsdir, currentdir]) if os.path.isdir(usourcesdir): - execcmd("cp -rlf", usourcesdir, currentdir) + execcmd(["cp", "-rlf", usourcesdir, currentdir]) # Add new entries for entry in [x for x in uspecsentries @@ -355,8 +392,106 @@ def put_srpm(srpmfile, markrelease=False, striplog=True, branch=None, log="Copying release %s-%s to releases/ directory." % (version, srpm.release)) +def build_rpm(build_cmd="b", + verbose=True, + rpmlint=True, + short_circuit=False, + packager = None, + installdeps = True, + use_dnf = False, + svnlog = False, + fullnames = True, + macros = [], + **rpmargs): + top = os.getcwd() + topdir = "_topdir %s" % top + builddir = "_builddir %s/%s" % (top, "BUILD") + rpmdir = "_rpmdir %s/%s" % (top, "RPMS") + sourcedir = "_sourcedir %s/%s" % (top, "SOURCES") + specdir = "_specdir %s/%s" % (top, "SPECS") + srcrpmdir = "_srcrpmdir %s/%s" % (top, "SRPMS") + patchdir = "_patchdir %s/%s" % (top, "SOURCES") + + build = os.path.join(top, "BUILD") + if not os.path.exists(build): + os.mkdir(build) + specsdir = os.path.join(top, "SPECS") + speclist = glob.glob(os.path.join(specsdir, "*.spec")) + if not speclist: + raise Error("no spec files found") + spec = speclist[0] + + # If we're building package with %changelog, we'll make a temporary + # copy of the spec file with %changelog applied that we'll use for + # building. This way we avoid modifying files in repository. + # TODO: implement support for external changelog in rpm + if svnlog: + vcs = detectVCS(top) + specsdir = tempfile.mkdtemp() + shutil.copy(spec, specsdir) + specdir = "_specdir "+specsdir + spec = os.path.join(specsdir,os.path.basename(spec)) + info = vcs.info2(top) + pkgdirurl = layout.remove_current(info["URL"]) + log.specfile_svn2rpm(pkgdirurl, spec, rev=None, submit=False, + template=None, macros=macros, exported=top, fullnames=fullnames) + + rpmdefs = [("--define", expr) for expr in (topdir, builddir, rpmdir, + sourcedir, specdir, srcrpmdir, patchdir)] + + if packager: + rpmdefs.append(("--define", "packager %s" % packager)) + + if rpmlint: + rpmdefs.append(("--define", "_build_pkgcheck_set %{_bindir}/rpmlint")) + + rpmbuild = config.get("helper", "rpmbuild", "rpmbuild") + args = [rpmbuild, spec] + if short_circuit: + args.append("--short-circuit") + for pair in rpmdefs: + args.extend(pair) + for pair in macros: + args.extend(("--define", "%s %s" % pair)) + args.extend(("--define", "_disable_source_fetch 0")) + args.extend(*rpmargs.values()) + os.environ["LC_ALL"] = "C" + # First check whether dependencies are satisfied + status, output = execcmd(*args + ["--nobuild"], show=verbose, collecterr=True, noerror=True) + if status: + if "error: Failed build dependencies:" in output: + if not installdeps: + raise Error("Automatic installation of dependencies disabled," + "aborting...") + else: + if verbose: + print("Installing missing build dependencies") + if use_dnf: + pkg_mgr_base = ["dnf"] + pkg_mgr_builddep = pkg_mgr_base + ["--assume-yes", "--setopt=install_weak_deps=False", "builddep"] + else: + pkg_mgr_base = ["urpmi"] + pkg_mgr_builddep = pkg_mgr_base + ["--auto", "--buildrequires", "--no-recommends"] + if os.getuid() != 0: + print("Trying to obtain privileges for installing build dependencies:") + sudocheck = ["sudo", "-l"] + pkg_mgr_base + status, output = execcmd(*sudocheck, collecter=True, noerror=True) + if status: + raise Error("%s\nFailed! Cannot proceed without, aborting..." + % output.splitlines()[-1]) + cmd_base = ["sudo"] + pkg_mgr_builddep + else: + cmd_base = pkg_mgr_builddep + cmd = cmd_base + [spec] + status, output = execcmd(*cmd, show=verbose, collecter=True, noerror=True) + + status, output = execcmd(*args + ["-b"+build_cmd], show=verbose) + if svnlog: + if os.path.isdir(specsdir): + shutil.rmtree(specsdir) + def create_package(pkgdirurl, log="", verbose=0): - svn = SVN() + svn = detectVCS(pkgdirurl) tmpdir = tempfile.mktemp() try: basename = layout.package_name(pkgdirurl) @@ -397,7 +532,7 @@ revision: %s return log def mark_release(pkgdirurl, version, release, revision): - svn = SVN() + svn = detectVCS(pkgdirurl) releasesurl = layout.checkout_url(pkgdirurl, releases=True) versionurl = "/".join([releasesurl, version]) releaseurl = "/".join([versionurl, release]) @@ -419,7 +554,7 @@ def mark_release(pkgdirurl, version, release, revision): log=markreleaselog) def check_changed(pkgdirurl, all=0, show=0, verbose=0): - svn = SVN() + svn = detectVCS(pkgdirurl) if all: baseurl = pkgdirurl packages = [] @@ -490,33 +625,48 @@ def checkout(pkgdirurl, path=None, revision=None, branch=None, distro=None, back if path is None: path = layout.package_name(pkgdirurl) mirror.info(current, write=True) - svn = SVN() + svn = detectVCS(pkgdirurl) svn.checkout(current, path, rev=revision, show=1) if not spec: binrepo.download_binaries(path) -def getpkgtopdir(basedir=None): - #FIXME this implementation doesn't work well with relative path names, - # which is something we need in order to have a friendlier output - if basedir is None: - basedir = os.path.curdir - while not ispkgtopdir(basedir): - if os.path.abspath(basedir) == "/": - raise Error("can't find top package directories SOURCES and SPECS") - basedir = os.path.join(basedir, os.path.pardir) - if basedir.startswith("./"): - basedir = basedir[2:] - return basedir - -def ispkgtopdir(path=None): +def clone(pkgdirurl, path=None, revision=None, branch=None, distro=None, backports=None, + spec=False, fullnames = True, bindownload = True): + o_pkgdirurl = pkgdirurl + pkgdirurl = layout.package_url(o_pkgdirurl, distro=distro, backports=backports) + append = None + if spec: + append = "SPECS" + current = layout.checkout_url(pkgdirurl, branch=branch, backports=backports, + append_path=append) + if path is None: + path = layout.package_name(pkgdirurl) + mirror.info(current, write=True) + git = GIT() + git.clone(current, path, fullnames=fullnames, show=1) + if not spec and bindownload: + binrepo.download_binaries(path) + +def getpkgtopdir(basedir=os.path.curdir): + vcs = detectVCS(basedir) + if vcs: + basedir = os.path.relpath(vcs.get_topdir()) + if ispkgtopdir(basedir, vcs_dirname=vcs.vcs_dirname): + return basedir + raise Error("can't find top package directories SOURCES and SPECS") + +def ispkgtopdir(path=None, vcs_dirname=None): if path is None: path = os.getcwd() names = os.listdir(path) - return (".svn" in names and "SPECS" in names and "SOURCES" in names) + if not vcs_dirname: + vcs = detectVCS(path) + vcs_dirname = vcs.vcs_dirname + return (vcs_dirname in names and "SPECS" in names and "SOURCES" in names) def sync(dryrun=False, commit=False, download=False): - svn = SVN() topdir = getpkgtopdir() + svn = detectVCS(topdir) spath = binrepo.sources_path(topdir) binrepoentries = binrepo.parse_sources(spath) # run svn info because svn st does not complain when topdir is not an @@ -598,7 +748,7 @@ def sync(dryrun=False, commit=False, download=False): upload([path], commit=commit) def commit(target=".", message=None, logfile=None): - svn = SVN() + svn = detectVCS(target) status = svn.status(target, quiet=True) if not status: print("nothing to commit") @@ -633,39 +783,41 @@ def spec_sources(topdir): return sources def update(target=None): - svn = SVN() + vcs = None info = None - svn_target = None + vcs_target = None br_target = None if target: - svn_target = target + vcs_target = target else: top = getpkgtopdir() - svn_target = top + vcs_target = top br_target = top - if svn_target: - svn.update(svn_target, show=True) + if vcs_target: + vcs = detectVCS(vcs_target) + vcs.update(vcs_target, show=True) if br_target: - info = svn.info2(svn_target) - if not br_target and not svn_target: - raise Error("target not in SVN nor in binaries "\ - "repository: %s" % target) + if not vcs: + vcs = detectVCS(br_target) + info = vcs.info2(vcs_target) + if not br_target and not vcs_target: + raise Error("target not in %s nor in binaries "\ + "repository: %s" % (type(vcs).__name__,target)) url = info["URL"] binrepo.download_binaries(br_target) def upload(paths, commit=False): + topdir = getpkgtopdir() + svn = detectVCS(topdir) for path in paths: if os.path.isdir(path) or binrepo.is_binary(path): - topdir = getpkgtopdir() binrepo.upload_binary(topdir, os.path.basename(path)) binrepo.update_sources(topdir, added=[path]) if commit: - svn = SVN() silent = config.get("log", "ignore-string", "SILENT") message = "%s: new file %s" % (silent, path) svn.commit(binrepo.sources_path(topdir), log=message) else: - svn = SVN() svn.add(path, local=True) if commit: silent = config.get("log", "ignore-string", "SILENT") @@ -674,16 +826,15 @@ def upload(paths, commit=False): def delete(paths, commit=False): silent = config.get("log", "ignore-string", "SILENT") + topdir = getpkgtopdir() + svn = detectVCS(topdir) for path in paths: message = "%s: delete file %s" % (silent, path) if binrepo.is_binary(path): - topdir = getpkgtopdir() binrepo.update_sources(topdir, removed=[os.path.basename(path)]) if commit: - svn = SVN() svn.commit(binrepo.sources_path(topdir), log=message) else: - svn = SVN() svn.remove(path, local=True) if commit: svn.commit(path, log=message) @@ -692,7 +843,7 @@ def obsolete(pkgdirurl, branch=None, distro=None, backports=None, commit=False, o_pkgdirurl = pkgdirurl pkgdirurl = layout.package_url(o_pkgdirurl, distro=distro, backports=backports) pkgdest = layout.package_url(o_pkgdirurl, obsolete=True, backports=backports) - svn = SVN() + svn = detectVCS(pkgdirurl) svn.mv(pkgdirurl, pkgdest, message=log) if commit: svn.commit(path, log=log) @@ -727,7 +878,7 @@ def get_submit_info(path): if not os.path.isdir(os.path.join(path, ".svn")): raise Error("subversion directory not found") - svn = SVN() + svn = detectVCS(path) # Now, extract the package name. info = svn.info2(path) @@ -766,4 +917,25 @@ def get_submit_info(path): return name, url, max +def get_pkg_tag(tag, path=os.path.curdir, subpkg=None): + topdir = getpkgtopdir(path) + speclist = glob.glob(os.path.join(topdir, "SPECS", "*.spec")) + if not speclist: + raise Error("no spec files found") + specfile = speclist[0] + + pkg = rpm.spec(specfile) + if subpkg is None: + header = pkg.sourceHeader + elif isinstance(subpkg,int): + header = pkg.packages(subpkg) + else: + raise Error("Subpkg must be the index number of a package,"\ + "or None for source package") + + if isinstance(header[tag],bytes): + return header[tag].decode("utf8") + else: + return header[tag] + # vim:et:ts=4:sw=4 |