Blame utils/scap-as-rpm

Packit Service deda86
#!/usr/bin/env python3
Packit 517ee8
Packit 517ee8
# Copyright 2013 Red Hat Inc., Durham, North Carolina.
Packit 517ee8
# All Rights Reserved.
Packit 517ee8
#
Packit 517ee8
# This library is free software; you can redistribute it and/or
Packit 517ee8
# modify it under the terms of the GNU Lesser General Public
Packit 517ee8
# License as published by the Free Software Foundation; either
Packit 517ee8
# version 2.1 of the License, or (at your option) any later version.
Packit 517ee8
#
Packit 517ee8
# This library is distributed in the hope that it will be useful,
Packit 517ee8
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 517ee8
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 517ee8
# Lesser General Public License for more details.
Packit 517ee8
#
Packit 517ee8
# You should have received a copy of the GNU Lesser General Public
Packit 517ee8
# License along with this library; if not, write to the Free Software
Packit 517ee8
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Packit 517ee8
#
Packit 517ee8
# Authors:
Packit 517ee8
#      Martin Preisler <mpreisle@redhat.com>
Packit 517ee8
#      Vratislav Podzimek <vpodzime@redhat.com>
Packit 517ee8
Packit 517ee8
import locale
Packit 517ee8
# We shall always behave the same, regardless of locale
Packit 517ee8
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
Packit 517ee8
Packit 517ee8
Packit 517ee8
import argparse
Packit 517ee8
import string
Packit 517ee8
import os.path
Packit 517ee8
import shutil
Packit 517ee8
import datetime
Packit 517ee8
import tempfile
Packit 517ee8
import subprocess
Packit 517ee8
import sys
Packit 517ee8
Packit 517ee8
class CannotContinueError(Exception):
Packit 517ee8
    """Exception class for cases where processing cannot continue."""
Packit 517ee8
Packit 517ee8
    pass
Packit 517ee8
Packit 517ee8
if subprocess.call(["rpmbuild", "--version"], stdout = sys.stdout, stderr = sys.stderr) != 0:
Packit 517ee8
    sys.stderr.write("Could not execute `rpmbuild --version`. "
Packit 517ee8
        "Please make sure it's installed (often packaged as 'rpm-build').\n")
Packit 517ee8
    sys.exit(1)
Packit 517ee8
Packit 517ee8
def get_rpmbuild_paths():
Packit 517ee8
    sources = subprocess.check_output(["rpm", "--eval", "%{_sourcedir}"]).strip().decode('utf-8')
Packit 517ee8
Packit 517ee8
    if not os.path.exists(sources):
Packit 517ee8
        if subprocess.call(["rpmdev-setuptree"], stdout = sys.stdout, stderr = sys.stderr) != 0:
Packit 517ee8
            raise CannotContinueError("Failed to setup rpmbuild tree. Please make sure you have rpmdev-setuptree "
Packit 517ee8
                "installed, or set it up manually. The SOURCES directory (%%{_sourcedir}) was expected at "
Packit 517ee8
                "'%s'" % (sources))
Packit 517ee8
Packit 517ee8
    rpm = subprocess.check_output(["rpm", "--eval", "%{_rpmdir}"]).strip().decode('utf-8')
Packit 517ee8
    srpm = subprocess.check_output(["rpm", "--eval", "%{_srcrpmdir}"]).strip().decode('utf-8')
Packit 517ee8
Packit 517ee8
    if not os.path.exists(rpm) or not os.path.exists(srpm):
Packit 517ee8
        sys.stderr.write("The SOURCES rpmbuild directory exists but RPM or SRPM do not. Please make "
Packit 517ee8
            "sure your rpmbuild tree is setup correctly. Delete it and it will be created automatically.\n")
Packit 517ee8
Packit 517ee8
    return sources, rpm, srpm
Packit 517ee8
Packit 517ee8
def copy_sources_to_rpmbuild(rpmbuild_sources_path, files):
Packit 517ee8
    for f in files:
Packit 517ee8
        shutil.copyfile(f.name, "%s/%s" % (rpmbuild_sources_path, os.path.basename(f.name)))
Packit 517ee8
Packit 517ee8
def make_sources_list(files):
Packit 517ee8
    ret = ""
Packit 517ee8
Packit 517ee8
    for (i, f) in enumerate(files):
Packit 517ee8
        ret += "Source%i: %s\n" % (i, os.path.basename(f.name))
Packit 517ee8
Packit 517ee8
    return ret
Packit 517ee8
Packit 517ee8
def make_installer(scap_location, files):
Packit 517ee8
    prepper = ""
Packit 517ee8
    installer = ""
Packit 517ee8
    installed_files = ""
Packit 517ee8
Packit 517ee8
    for (i, f) in enumerate(files):
Packit 517ee8
        prepper += "cp %%SOURCE%i .\n" % (i)
Packit 517ee8
Packit 517ee8
        installer += "cp %s $RPM_BUILD_ROOT/%s/%%{name}/\n" % (os.path.basename(f.name), scap_location)
Packit 517ee8
        installed_files += "%s/%%{name}/%s\n" % (scap_location, os.path.basename(f.name))
Packit 517ee8
Packit 517ee8
    return prepper, installer, installed_files
Packit 517ee8
Packit 517ee8
def create_spec(template_path, name,
Packit 517ee8
        version, release, summary, license,
Packit 517ee8
        scap_location, files,
Packit 517ee8
        target_file):
Packit 517ee8
Packit 517ee8
    spec_template = """
Packit 517ee8
# __ prefixed varibles in the form of ${__*} will get replaced by Python's string.Template
Packit 517ee8
Packit 517ee8
Name:           ${__package_name}
Packit 517ee8
Version:        ${__package_version}
Packit 517ee8
Release:        ${__package_release}
Packit 517ee8
Summary:        ${__package_summary}
Packit 517ee8
License:        ${__package_license}
Packit 517ee8
Packit 517ee8
${__package_sources}
Packit 517ee8
Packit 517ee8
BuildArch:      noarch
Packit 517ee8
Packit 517ee8
#BuildRequires:  openscap-utils >= ${__package_openscap_version}
Packit 517ee8
#Requires:       openscap-utils >= ${__package_openscap_version}
Packit 517ee8
Packit 517ee8
%description
Packit 517ee8
This package was generated by scap-as-rpm.
Packit 517ee8
Packit 517ee8
%prep
Packit 517ee8
${__package_prepper}
Packit 517ee8
Packit 517ee8
%build
Packit 517ee8
Packit 517ee8
%install
Packit 517ee8
mkdir -p $RPM_BUILD_ROOT/${__package_scap_location}/%{name}
Packit 517ee8
${__package_installer}
Packit 517ee8
Packit 517ee8
%files
Packit 517ee8
${__package_installed_files}
Packit 517ee8
Packit 517ee8
%changelog
Packit 517ee8
* ${__changelog_date} save-as-rpm - ${__package_version}-${__package_release}
Packit 517ee8
- Autogenerated
Packit 517ee8
"""
Packit 517ee8
Packit 517ee8
    template = string.Template(spec_template)
Packit 517ee8
Packit 517ee8
    sources_list = make_sources_list(files)
Packit 517ee8
    prepper, installer, installed_files = make_installer(scap_location, files)
Packit 517ee8
Packit 517ee8
    spec_source = template.safe_substitute(
Packit 517ee8
        __package_name = name,
Packit 517ee8
Packit 517ee8
        __package_version = version,
Packit 517ee8
        __package_release = release,
Packit 517ee8
        __package_summary = summary,
Packit 517ee8
        __package_license = license,
Packit 517ee8
Packit 517ee8
        __package_scap_location = scap_location,
Packit 517ee8
Packit 517ee8
        __package_sources = sources_list,
Packit 517ee8
        __package_openscap_version = "0.9.12", # FIXME
Packit 517ee8
        __package_prepper = prepper,
Packit 517ee8
        __package_installer = installer,
Packit 517ee8
        __package_installed_files = installed_files,
Packit 517ee8
        __changelog_date = datetime.date.today().strftime("%a %b %d %Y")
Packit 517ee8
    )
Packit 517ee8
Packit 517ee8
    target_file.write(spec_source)
Packit 517ee8
Packit 517ee8
def main():
Packit 517ee8
    parser = argparse.ArgumentParser(
Packit 517ee8
        description = "Takes given SCAP input(s) and makes an RPM package that contains them. "
Packit 517ee8
                      "The result RPM can be installed using # yum install ./package-name-1-1.rpm "
Packit 517ee8
                      "which will put the contents into /usr/share/xml/scap. No dependency on openscap "
Packit 517ee8
                      "or scap-workbench is enforced in the output package so you can use any "
Packit 517ee8
                      "SCAP-capable scanner to evaluate the content.")
Packit 517ee8
Packit 517ee8
    # we choose name automatically if its missing
Packit 517ee8
    parser.add_argument("--pkg-name", dest = "pkg_name", default = None,
Packit 517ee8
            help = "Name of the RPM package, if none is provided the basename of the first SCAP input is used. Ex.: xyz-security-guide")
Packit 517ee8
    parser.add_argument("--pkg-version", dest = "pkg_version", default = "1")
Packit 517ee8
    parser.add_argument("--pkg-release", dest = "pkg_release", default = "1")
Packit 517ee8
    parser.add_argument("--pkg-summary", dest = "pkg_summary", default = "stub",
Packit 517ee8
        help = "Optional short description of the package.")
Packit 517ee8
    parser.add_argument("--pkg-license", dest = "pkg_license", default = "Unknown",
Packit 517ee8
        help = "Short name of the license that you want to publish the package under. Ex.: GPLv2+, BSD, ...")
Packit 517ee8
Packit 517ee8
    parser.add_argument("--pkg-scap-location", dest = "pkg_scap_location", default = "%{_datadir}/xml/scap",
Packit 517ee8
        help = "Folder where SCAP files are supposed to be installed. Each package will have its own folder "
Packit 517ee8
               "inside this folder. RPM variables can be used and will be expanded as usual. It is "
Packit 517ee8
               "recommended to keep the default settings.")
Packit 517ee8
Packit 517ee8
    parser.add_argument("--rpm-destination", dest = "rpm_destination", default = ".",
Packit 517ee8
        help = "The folder (absolute or relative to CWD) where the result RPM shall be saved.")
Packit 517ee8
    parser.add_argument("--srpm-destination", dest = "srpm_destination", default = None,
Packit 517ee8
        help = "The folder (absolute or relative to CWD) where the result SRPM shall be saved.")
Packit 517ee8
    parser.add_argument("files", metavar = "FILE", nargs = "+",
Packit 517ee8
        help = "List of files that should be put into the result package. "
Packit 517ee8
               "These should be SCAP XML files but such requirement is not enforced.")
Packit 517ee8
Packit 517ee8
    args = parser.parse_args()
Packit 517ee8
Packit 517ee8
    if not args.rpm_destination:
Packit 517ee8
        print("--rpm-destination has to be specified")
Packit 517ee8
        parser.print_help()
Packit 517ee8
        return 1
Packit 517ee8
Packit 517ee8
    if not os.path.isdir(args.rpm_destination):
Packit 517ee8
        print("'%s' does not seem like a directory or isn't accessible!" % args.rpm_destination)
Packit 517ee8
        parser.print_help()
Packit 517ee8
        return 1
Packit 517ee8
Packit 517ee8
    if args.srpm_destination is not None and not os.path.isdir(args.srpm_destination):
Packit 517ee8
        print("'%s' does not seem like a directory or isn't accessible!" % args.srpm_destination)
Packit 517ee8
        parser.print_help()
Packit 517ee8
        return 1
Packit 517ee8
Packit 517ee8
    for fpath in args.files:
Packit 517ee8
        if not os.path.exists(fpath):
Packit 517ee8
            print("File '%s' does not exist or isn't accessible!" % fpath)
Packit 517ee8
            parser.print_help()
Packit 517ee8
            return 1
Packit 517ee8
Packit 517ee8
    args.files = [open(fpath, "r") for fpath in args.files]
Packit 517ee8
Packit 517ee8
    rpmbuild_sources_path, rpmbuild_rpm_path, rpmbuild_srpm_path = get_rpmbuild_paths()
Packit 517ee8
Packit 517ee8
    copy_sources_to_rpmbuild(rpmbuild_sources_path, args.files)
Packit 517ee8
Packit 517ee8
    name = args.pkg_name
Packit 517ee8
    if name is None:
Packit 517ee8
        name, _ = os.path.splitext(os.path.basename(args.files[0].name))
Packit 517ee8
Packit 517ee8
    temp_dir = tempfile.mkdtemp()
Packit 517ee8
    spec_file = open("%s/%s.spec" % (temp_dir, name), "w")
Packit 517ee8
    try:
Packit 517ee8
        create_spec("templates/package.spec",
Packit 517ee8
            name,
Packit 517ee8
            args.pkg_version, args.pkg_release, args.pkg_summary, args.pkg_license,
Packit 517ee8
            args.pkg_scap_location, args.files,
Packit 517ee8
            spec_file)
Packit 517ee8
        spec_file_path = spec_file.name
Packit 517ee8
        spec_file.close()
Packit 517ee8
Packit 517ee8
        ret = subprocess.call(["rpmbuild", "-ba", spec_file_path], stdout = sys.stdout)
Packit 517ee8
        if ret != 0:
Packit 517ee8
            raise CannotContinueError("Failed to build RPM and SRPM for %s" % spec_file_path)
Packit 517ee8
Packit 517ee8
    finally:
Packit 517ee8
        shutil.rmtree(temp_dir)
Packit 517ee8
Packit 517ee8
    rpm_basename = "%s-%s-%s.noarch.rpm" % (name, args.pkg_version, args.pkg_release)
Packit 517ee8
    srpm_basename = "%s-%s-%s.src.rpm" % (name, args.pkg_version, args.pkg_release)
Packit 517ee8
Packit 517ee8
    shutil.copy(os.path.join(rpmbuild_rpm_path, "noarch", rpm_basename), os.path.join(args.rpm_destination, rpm_basename))
Packit 517ee8
    if args.srpm_destination is not None:
Packit 517ee8
        shutil.copy(os.path.join(rpmbuild_srpm_path, srpm_basename), os.path.join(args.srpm_destination, srpm_basename))
Packit 517ee8
Packit 517ee8
    print("")
Packit 517ee8
    print("Resulting RPM:\t'%s'" % (os.path.join(args.rpm_destination, rpm_basename)))
Packit 517ee8
    if args.srpm_destination is not None:
Packit 517ee8
        print("Resulting SRPM:\t'%s'" % (os.path.join(args.srpm_destination, srpm_basename)))
Packit 517ee8
    print("")
Packit 517ee8
    print("Finished!")
Packit 517ee8
Packit 517ee8
    return 0
Packit 517ee8
Packit 517ee8
if __name__ == "__main__":
Packit 517ee8
    try:
Packit 517ee8
        ret = main()
Packit 517ee8
        sys.exit(ret)
Packit 517ee8
    except CannotContinueError as e:
Packit 517ee8
        sys.stderr.write("%s\n" % e.message)
Packit 517ee8
        sys.exit(1)