#!/usr/bin/python3
#
# specfile.py - part of autospec
# Copyright (C) 2016 Intel Corporation
#
# 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, either version 3 of the License, or
# (at your option) any later version.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Write spec file
#

import os
import re
import time
import types
from collections import OrderedDict

import buildreq
import config
import tarball
from util import _file_write
from util import open_auto


class Specfile(object):
    """Holds data and methods needed to write the spec file."""

    def __init__(self, url, version, name, release):
        """Add default information for specfile template."""
        self.url = url
        self.version = version
        self.name = name
        self.release = release
        self.keepstatic = False
        self.urlban = ""
        self.no_autostart = False
        self.specfile = None
        self.sources = {"unit": [], "gcov": [], "tmpfile": [], "archive": [], "destination": [], "godep": []}
        self.source_index = {}
        self.default_sum = ""
        self.hashes = dict()
        self.licenses = []
        self.license_files = []
        self.packages = OrderedDict()
        self.requires = set()
        self.buildreqs = []
        self.patches = []
        self.verpatches = OrderedDict()
        self.default_desc = ""
        self.locales = []
        self.default_pattern = ""
        self.autoreconf = False
        self.set_gopath = True
        self.extra_make = ""
        self.extra32_make = ""
        self.extra_make_install = ""
        self.extra_make32_install = ""
        self.tarball_prefix = ""
        self.prefixes = dict()    # Detected prefixes, indexed by source URL
        self.build_dirs = dict()  # Build directories, indexed by source URL
        self.gcov_file = ""
        self.rawname = ""
        self.golibpath = ""
        self.archive_details = {}
        self.need_avx2_flags = False
        self.need_avx512_flags = False
        self.tests_config = ""
        self.subdir = ""
        self.install_macro = "%make_install"
        self.disable_static = "--disable-static"
        self.extra_cmake = ""
        self.cmake_srcdir = ".."
        self.prep_prepend = []
        self.build_prepend = []
        self.build_append = []
        self.make_prepend = []
        self.install_prepend = []
        self.install_append = []
        self.service_restart = []
        self.excludes = []
        self.custom_extras = {}
        self.keyid = ""
        self.email = ""
        self.cargo_bin = False

    def write_spec(self, path):
        """Write spec file."""
        self.specfile = open_auto("{}/{}.spec".format(path, self.name), "w")
        self.specfile.write_strip = types.MethodType(_file_write, self.specfile)

        # spec file comment header
        self.write_comment_header()

        if self.keepstatic:
            self._write("%define keepstatic 1\n")

        # general package header
        self.write_nvr()
        self.write_sources()
        self.write_summary()
        self.write_license()

        self.write_main_subpackage_requires()
        self.write_buildreq()
        self.write_strip_command()
        self.write_debug_command()
        self.write_patch_header()

        # main package extra content
        self.write_description()
        self.write_files_header()

        # build instructions
        self.write_buildpattern()

        # scriplets
        self.write_scriplets()

        # %files
        self.write_files()
        self.write_lang_files()

        self.specfile.close()

    def write_comment_header(self):
        """Write comment header to spec file."""
        self._write("#\n")
        self._write("# This file is auto-generated. DO NOT EDIT\n")
        self._write("# Generated by: autospec.py\n")
        self._write("#\n")

        # if package was verified, write public key information
        if self.keyid:
            sig_msg = "# Source0 file verified with key 0x{}".format(self.keyid)
            if self.email:
                sig_msg += " ({})".format(self.email)

            self._write_strip(sig_msg)
            self._write_strip("#")

    def write_nvr(self):
        """Write name, version, and release information."""
        if self.urlban:
            clean_url = re.sub(self.urlban, "localhost", self.url)
            # Duplicate prefixes entry before we change the url
            self.prefixes[clean_url] = self.prefixes.get(self.url)
            self.url = clean_url
        self._write("Name     : {}\n".format(self.name))
        self._write("Version  : {}\n".format(self.version))
        self._write("Release  : {}\n".format(str(self.release)))
        self._write("URL      : {}\n".format(self.url))
        if not self.default_pattern == "godep":
            self._write("Source0  : {}\n".format(self.url))

    def write_sources(self):
        """Append additional source files.

        Append systemd unit files, gcov, and additional source tarballs are the currently supported file types.
        """
        count = 0
        for source in sorted(self.sources["version"] + self.sources["unit"] + self.sources["archive"] + self.sources["tmpfile"] + self.sources["gcov"] + self.sources["godep"]):
            count += 1
            self.source_index[source] = count
            if self.urlban:
                source = re.sub(self.urlban, "localhost", source)
            self._write("Source{0}  : {1}\n".format(count, source))

        # if package is verified, include the signature in the source tarball
        if self.keyid and config.signature:
            self._write_strip(f"Source{count+1} : {config.signature}")

    def write_summary(self):
        """Write package summary to spec file."""
        if len(self.default_sum.strip()) < 1:
            self.default_sum = "No summary provided"
        self._write("Summary  : {}\n".format(self.default_sum.strip()))
        self._write("Group    : Development/Tools\n")

    def write_license(self):
        """Write license information to spec file."""
        self._write("License  : {}\n".format(" ".join(sorted(self.licenses))))

    def write_main_subpackage_requires(self):
        """Write subpackage build requirements."""
        for pkg in sorted(self.packages):
            if pkg == "autostart" and self.no_autostart:
                continue
            if pkg.startswith("extras-"):
                continue
            if pkg in ["ignore", "main", "dev", "active-units", "extras",
                       "lib32", "dev32", "doc", "abi", "staticdev",
                       "staticdev32"]:
                continue
            # honor requires_ban for manual overrides
            if "{}-{}".format(self.name, pkg) in buildreq.banned_requires:
                continue
            self._write("Requires: {}-{} = %{{version}}-%{{release}}\n".format(self.name, pkg))

        for pkg in sorted(self.requires):
            self._write("Requires: {}\n".format(pkg))

    def write_buildreq(self):
        """Write build requirements."""
        for req in sorted(self.buildreqs):
            self._write("BuildRequires : {}\n".format(req))

    def write_strip_command(self):
        """Write commands to prevent stripping binary if requested."""
        if config.config_opts['nostrip']:
            self._write("# Suppress stripping binaries\n")
            self._write("%define __strip /bin/true\n%define debug_package %{nil}\n")

    def write_debug_command(self):
        """Write commands to prevent debug info generation if requested."""
        if config.config_opts['nodebug']:
            self._write("# Suppress generation of debuginfo\n")
            self._write("%global debug_package %{nil}\n")

    def write_patch_header(self):
        """Write patch list header."""
        # First loop will set this to 0 when we start. Second loop adds one
        # and picks up from where first loop left off.
        count = -1
        # Write the patches for the primary version as given in Makefile
        for count, patch in enumerate(self.patches):
            self._write("Patch{0}: {1}\n".format(count + 1, patch.split()[0]))
        # Write the version-specific patches
        for version in config.verpatches:
            for count, patch in enumerate(config.verpatches[version], start=count + 1):
                self._write("Patch{0}: {1}\n".format(count + 1, patch.split()[0]))

    def write_description(self):
        """Write package description."""
        self._write("\n%description\n{}\n".format(self.default_desc.strip()))

    def write_files_header(self):
        """Write file headers to spec file."""
        groups = {}
        groups["dev"] = "Development"
        groups["bin"] = "Binaries"
        groups["lib"] = "Libraries"
        groups["doc"] = "Documentation"
        groups["data"] = "Data"
        groups["services"] = "Systemd services"

        deps = {}
        deps["dev"] = ["lib", "bin", "data"]
        deps["doc"] = ["man", "info"]
        deps["dev32"] = ["lib32", "bin", "data", "dev"]
        deps["bin"] = ["data", "libexec", "config", "setuid", "attr", "license", "services"]
        deps["lib"] = ["data", "libexec", "license"]
        deps["libexec"] = ["config", "license"]
        deps["lib32"] = ["data", "license"]
        deps["python"] = ["python3"]
        if config.config_opts['dev_requires_extras']:
            deps["dev"].append("extras")
        for k, v in self.custom_extras.items():
            if "requires" in v:
                deps[k] = v['requires']

        # migration workaround; if we have a python3 package
        # we add an artificial python package

        if ("python3" in self.packages) and ("python" not in self.packages):
            self.packages["python"] = set()

        provides = {}
        provides["dev"] = ["devel"]

        for pkg in sorted(self.packages):
            if pkg in ["ignore", "main"]:
                continue

            self._write("\n%package {}\n".format(pkg))
            self._write("Summary: {} components for the {} package.\n"
                        .format(pkg, self.name))
            if pkg in groups:
                self._write("Group: {}\n".format(groups[pkg]))
            else:
                self._write("Group: Default\n")

            for dep in deps.get(pkg, []):
                if dep in self.packages:
                    self._write("Requires: {}-{} = %{{version}}-%{{release}}\n".format(self.name, dep))

            for prov in provides.get(pkg, []):
                self._write("Provides: {}-{} = %{{version}}-%{{release}}\n".format(self.name, prov))

            if pkg == "python":
                if self.name != self.name.lower():
                    self._write("Provides: {}-python\n".format(self.name.lower()))

            if pkg == "dev":
                self._write("Requires: {} = %{{version}}-%{{release}}\n".format(self.name))

            if pkg == "staticdev":
                self._write("Requires: {}-dev = %{{version}}-%{{release}}\n".format(self.name))

            if pkg == "staticdev32":
                self._write("Requires: {}-dev = %{{version}}-%{{release}}\n".format(self.name))

            if pkg == "python3":
                self._write("Requires: python3-core\n")

            if pkg == "perl":
                self._write("Requires: {} = %{{version}}-%{{release}}\n".format(self.name))

            self._write("\n%description {}\n".format(pkg))
            self._write("{} components for the {} package.\n".format(pkg, self.name))
            self._write("\n")

    def write_buildpattern(self):
        """Write build pattern to spec file.

        Currently depends on buildpattern.py due to pattern-matched methods.
        """
        self._write_strip("\n")
        pattern_method = getattr(self, 'write_{}_pattern'.format(self.default_pattern))
        if pattern_method:
            pattern_method()

        self.write_source_installs()
        self.write_service_restart()
        self.write_exclude_deletes()
        self.write_install_append()
        # self.write_systemd_units()

    def write_scriplets(self):
        """Write post and pre scripts to spec file."""
        for pkg in sorted(self.packages):
            if pkg in ["ignore", "main", "locales"]:
                continue
            for script in ["post", "pre"]:
                content = config.read_conf_file("{}.{}".format(script, pkg))
                if content:
                    self._write("\n%{0} {1}\n".format(script, pkg))
                    content = ['{}\n'.format(l) for l in content]
                    self.specfile.writelines(content)

    def write_files(self):
        """Write %files section to spec file."""
        self._write("\n%files\n")
        self._write("%defattr(-,root,root,-)\n")
        if "main" in self.packages:
            for filename in sorted(self.packages["main"]):
                self._write("{}\n".format(self.quote_filename(filename)))

        for pkg in sorted(self.packages):
            if pkg in ["ignore", "main", "locales"]:
                continue

            self._write("\n%files {}\n".format(pkg))
            if pkg in ["doc", "license", "man", "info"]:
                self._write("%defattr(0644,root,root,0755)\n")
            else:
                self._write("%defattr(-,root,root,-)\n")
            for filename in sorted(self.packages[pkg]):
                self._write("{}\n".format(self.quote_filename(filename)))

    def write_lang_files(self):
        """Write lang files to spec."""
        if not self.locales:
            return

        self._write("\n%files locales")
        for lang in self.locales:
            self._write(" -f {}.lang".format(lang))

        self._write("\n%defattr(-,root,root,-)\n\n")

    def write_lang_c(self, export_epoch=False):
        """Write C language pattern."""
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("export LANG=C.UTF-8")
        if export_epoch:
            # time.time() returns a float, but we only need second-precision
            self._write_strip("export SOURCE_DATE_EPOCH={}".format(int(time.time())))
        if config.config_opts['asneeded']:
            self._write_strip("unset LD_AS_NEEDED\n")

    def write_proxy_exports(self):
        """Write proxy exports to localhost to block build/check calls to internet."""
        self._write_strip("export http_proxy=http://127.0.0.1:9/")
        self._write_strip("export https_proxy=http://127.0.0.1:9/")
        self._write_strip("export no_proxy=localhost,127.0.0.1,0.0.0.0")

    def write_make_line(self, build32=False):
        """Write make line to spec file."""
        if self.make_prepend:
            self._write_strip("## make_prepend content")
            for line in self.make_prepend:
                self._write_strip("{}\n".format(line))
            self._write_strip("## make_prepend end")
        if build32:
            self._write_strip("make {} {} {}".format(config.parallel_build, self.extra_make, self.extra32_make))
        else:
            self._write_strip("make {} {}".format(config.parallel_build, self.extra_make))

    def write_prep(self, ruby_pattern=False):
        """Write prep section to spec file."""
        self._write_strip("%prep")
        self.write_prep_prepend()
        if ruby_pattern:
            self._write_strip("gem unpack %{SOURCE0}")
            self._write_strip("%setup -q -D -T -n " + self.tarball_prefix)
            self._write_strip("gem spec %{{SOURCE0}} -l --ruby > {}.gemspec".format(self.name))
        else:
            if self.default_pattern == 'R':
                self._write_strip("%setup -q -c -n " + self.tarball_prefix)
            elif self.default_pattern == "godep":
                # No setup needed each source is installed as is
                pass
            else:
                prefix = self.prefixes[self.url]
                if prefix:
                    self._write_strip("%setup -q -n " + prefix)
                else:
                    # Have to make up a path and create it
                    prefix = os.path.splitext(os.path.basename(self.url))[0]
                    self._write_strip("%setup -q -c -n " + prefix)

                # Keep track of this build dir
                self.build_dirs[self.url] = prefix

                for archive in self.sources["archive"]:
                    # Skip POM files - they don't need to be extracted
                    if archive.endswith('.pom'):
                        continue
                    # Also JAR files
                    if archive.endswith('.jar'):
                        continue
                    # Patch files
                    if archive.endswith('.patch'):
                        continue
                    # Handle various archive types
                    extract_cmd = 'tar xf {}'
                    if archive.endswith('.zip'):
                        extract_cmd = 'unzip -q {}'
                    self._write_strip('cd %{_builddir}')
                    archive_file = os.path.basename(archive)
                    if self.archive_details[archive + "prefix"]:
                        self._write_strip(extract_cmd.format('%{_sourcedir}/' + archive_file))
                    else:
                        # The archive doesn't have a prefix inside, so we have
                        # to create it, then extract the archive under the
                        # created directory, itself beneath BUILD
                        fake_prefix = os.path.splitext(os.path.basename(archive))[0]
                        self._write_strip("mkdir -p {}".format(fake_prefix))
                        self._write_strip("cd {}".format(fake_prefix))
                        self._write_strip(extract_cmd.format('%{_sourcedir}/' + archive_file))

                self._write_strip('cd %{_builddir}/' + prefix)

                # Now handle extra versions, indexed by SOURCE
                for url in self.sources["version"]:
                    prefix = self.prefixes[url]
                    if prefix:
                        self._write_strip("cd ..")
                        self._write_strip("%setup -q -T -n {0} -b {1}"
                                          .format(prefix,
                                                  self.source_index[url]))
                    else:
                        # Have to make up a path and create it
                        prefix = os.path.splitext(os.path.basename(url))[0]
                        self._write_strip("cd ..")
                        self._write_strip("%setup -q -T -c -n {0} -b {1}"
                                          .format(prefix,
                                                  self.source_index[url]))
                    # Keep track of this build dir
                    self.build_dirs[url] = prefix

        for archive, destination in zip(self.sources["archive"], self.sources["destination"]):
            if destination.startswith(':'):
                continue
            if self.archive_details[archive + "prefix"] == self.tarball_prefix:
                print("Archive {} already unpacked in {}; ignoring destination"
                      .format(archive, self.tarball_prefix))
            else:
                self._write_strip("mkdir -p {}"
                                  .format(destination))

                # Here again, if the archive file has a top-level prefix
                # directory, we simply use it. If not, we have to figure
                # out where we extracted the files instead.
                archive_prefix = self.archive_details[archive + "prefix"]
                if not archive_prefix:
                    # Make it up
                    archive_prefix = os.path.splitext(os.path.basename(archive))[0]
                self._write_strip("cp -r %{{_builddir}}/{0}/* %{{_builddir}}/{1}/{2}"
                                  .format(archive_prefix,
                                          self.tarball_prefix,
                                          destination))
        self.apply_patches()
        if self.default_pattern != 'cmake':
            if config.config_opts['32bit']:
                self._write_strip("pushd ..")
                self._write_strip("cp -a {} build32".format(self.tarball_prefix))
                self._write_strip("popd")
            if config.config_opts['use_avx2']:
                self._write_strip("pushd ..")
                self._write_strip("cp -a {} buildavx2".format(self.tarball_prefix))
                self._write_strip("popd")
            if config.config_opts['use_avx512']:
                self._write_strip("pushd ..")
                self._write_strip("cp -a {} buildavx512".format(self.tarball_prefix))
                self._write_strip("popd")
        self._write_strip("\n")

    def write_32bit_exports(self):
        """Write 32bit only env exports."""
        self._write_strip('export PKG_CONFIG_PATH="/usr/lib32/pkgconfig"')
        self._write_strip('export ASFLAGS="${ASFLAGS}${ASFLAGS:+ }--32"')
        self._write_strip('export CFLAGS="${CFLAGS}${CFLAGS:+ }-m32 -mstackrealign"')
        self._write_strip('export CXXFLAGS="${CXXFLAGS}${CXXFLAGS:+ }-m32 -mstackrealign"')
        self._write_strip('export LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-m32 -mstackrealign"')

    def write_variables(self):
        """Write variable exports to spec file."""
        flags = []
        arch = os.uname()[4]

        # Clear ships with a patch in GCC that allows ignoring the -Werror
        # compilation flag if this environment variable is set.  -Werror
        # is a useful flag for the upstream package maintainers, but is
        # a source of headaches for downstream users.
        self._write_strip("export GCC_IGNORE_WERROR=1\n")

        if config.config_opts['use_clang']:
            self._write_strip("export CC=clang\n")
            self._write_strip("export CXX=clang++\n")
            self._write_strip("export LD=ld.gold\n")
            lto = "-flto"
        else:
            lto = "-flto=4"

        if not self.set_gopath:
            self._write_strip("export GOPROXY=file:///usr/share/goproxy")

        if config.config_opts['optimize_size']:
            if config.config_opts['use_clang']:
                flags.extend(["-Os", "-ffunction-sections", "-fdata-sections"])
            else:
                flags.extend(["-Os", "-ffunction-sections", "-fdata-sections", "-fno-semantic-interposition"])
        if config.config_opts['security_sensitive']:
            flags.append("-fstack-protector-strong")
            if arch == 'x86_64':
                flags.append("-mzero-caller-saved-regs=used")
        if self.need_avx2_flags:
            flags.extend(["-O3", "-march=haswell"])
        if self.need_avx512_flags:
            flags.extend(["-O3", "-march=skylake-avx512"])
        if config.config_opts['insecure_build']:
            self._write_strip('export CFLAGS="-O3 -g -fopt-info-vec "\n')
            self._write_strip("unset LDFLAGS\n")
        if config.config_opts['conservative_flags']:
            self._write_strip('export CFLAGS="-O2 -g -Wp,-D_FORTIFY_SOURCE=2 '
                              "-fexceptions -fstack-protector "
                              "--param=ssp-buffer-size=32 -Wformat "
                              "-Wformat-security -Wno-error "
                              "-Wl,-z,max-page-size=0x1000 "
                              '-march=westmere -mtune=haswell"\n')
            self._write_strip("export CXXFLAGS=$CFLAGS\n")
            self._write_strip("unset LDFLAGS\n")
        if config.config_opts['use_clang']:
            self._write_strip("unset LDFLAGS\n")
        if config.config_opts['funroll-loops']:
            if config.config_opts['use_clang']:
                flags.extend(["-O3"])
            else:
                flags.extend(["-O3", "-fno-semantic-interposition", "-falign-functions=32", "-fno-math-errno", "-fno-trapping-math"])
        if self.default_pattern != 'qmake':
            if config.config_opts['use_lto']:
                flags.extend(["-O3", lto, "-ffat-lto-objects"])
                if config.config_opts['use_clang']:
                    self._write_strip("export AR=llvm-ar\n")
                    self._write_strip("export RANLIB=llvm-ranlib\n")
                    self._write_strip("export NM=llvm-nm\n")
                else:
                    self._write_strip("export AR=gcc-ar\n")
                    self._write_strip("export RANLIB=gcc-ranlib\n")
                    self._write_strip("export NM=gcc-nm\n")
            else:
                flags.extend(["-fno-lto"])
        if config.config_opts['fast-math']:
            flags.extend(["-ffast-math", "-ftree-loop-vectorize"])
        if config.config_opts['pgo']:
            flags.extend(["-O3"])
        if self.gcov_file:
            flags = list(filter((lto).__ne__, flags))
            flags.extend(["-O3", "-fauto-profile=%{{SOURCE{0}}}".format(self.source_index[self.sources["gcov"][0]])])
        if flags or config.config_opts['broken_c++']:
            flags = sorted(list(set(flags)))
            self._write_strip('export CFLAGS="$CFLAGS {0} "\n'.format(" ".join(flags)))
            self._write_strip('export FCFLAGS="$CFLAGS {0} "\n'.format(" ".join(flags)))
            self._write_strip('export FFLAGS="$CFLAGS {0} "\n'.format(" ".join(flags)))
            # leave the export CXXFLAGS line open in case
            self._write('export CXXFLAGS="$CXXFLAGS {0} '.format(" ".join(flags)))
            if config.config_opts['broken_c++']:
                self._write('-std=gnu++98')
            # close the open quote from CXXFLAGS export and add newline
            self._write('"\n')

        if config.profile_payload and config.profile_payload[0] and not self.need_avx2_flags:
            genflags = []
            useflags = []
            genflags.extend(["-fprofile-generate", "-fprofile-dir=/var/tmp/pgo", "-fprofile-update=atomic"])
            useflags.extend(["-fprofile-use", "-fprofile-dir=/var/tmp/pgo", "-fprofile-correction"])

            self._write_strip('export CFLAGS_GENERATE="$CFLAGS {0} "\n'.format(" ".join(genflags)))
            self._write_strip('export FCFLAGS_GENERATE="$FCFLAGS {0} "\n'.format(" ".join(genflags)))
            self._write_strip('export FFLAGS_GENERATE="$FFLAGS {0} "\n'.format(" ".join(genflags)))
            self._write_strip('export CXXFLAGS_GENERATE="$CXXFLAGS {0} "\n'.format(" ".join(genflags)))
            self._write_strip('export LDFLAGS_GENERATE="$LDFLAGS {0} "\n'.format(" ".join(genflags)))

            self._write_strip('export CFLAGS_USE="$CFLAGS {0} "\n'.format(" ".join(useflags)))
            self._write_strip('export FCFLAGS_USE="$FCFLAGS {0} "\n'.format(" ".join(useflags)))
            self._write_strip('export FFLAGS_USE="$FFLAGS {0} "\n'.format(" ".join(useflags)))
            self._write_strip('export CXXFLAGS_USE="$CXXFLAGS {0} "\n'.format(" ".join(useflags)))
            self._write_strip('export LDFLAGS_USE="$LDFLAGS {0} "\n'.format(" ".join(useflags)))

    def write_check(self):
        """Write check section to spec file."""
        if self.tests_config and not config.config_opts['skip_tests']:
            self._write_strip("%check")
            self._write_strip("export LANG=C.UTF-8")
            self.write_proxy_exports()
            self._write_strip(self.tests_config)
            self._write_strip("\n")

    def write_license_files(self):
        """Install all license files for this package."""
        if len(self.license_files) > 0:
            self._write_strip("mkdir -p %{buildroot}/usr/share/package-licenses/" + self.name)
            for file in self.license_files:
                file2 = self.hashes[file]
                # Use the absolute path to the source license file b/c we don't know for sure where we are
                self._write_strip("cp " + "%{_builddir}/" + file + " %{buildroot}/usr/share/package-licenses/" + self.name + "/" + file2 + "\n")

    def write_profile_payload(self, pattern=None):
        """Write the profile_payload specified for this package."""
        if not config.profile_payload:
            return
        use_subdir = True
        init = ""
        post = ""
        if pattern == "configure":
            init = f"{self.get_profile_generate_flags()}" \
                   f"%configure " \
                   f"{self.disable_static} " \
                   f"{config.extra_configure} " \
                   f"{config.extra_configure64}"
        elif pattern == "configure_ac":
            init = f"{self.get_profile_generate_flags()}" \
                   f"%reconfigure " \
                   f"{self.disable_static} " \
                   f"{config.extra_configure} " \
                   f"{config.extra_configure64}"
        elif pattern == "autogen":
            init = f"{self.get_profile_generate_flags()}" \
                   f"%autogen " \
                   f"{self.disable_static} " \
                   f"{config.extra_configure} " \
                   f"{config.extra_configure64}"
        elif pattern == "cmake":
            use_subdir = False
            init = f"{self.get_profile_generate_flags()}"
            post = f"{self.get_profile_use_flags()}"
        elif pattern == "make":
            init = f"{self.get_profile_generate_flags()}"
            post = f"{self.get_profile_use_flags()}"
        if use_subdir and self.subdir:
            self._write_strip("pushd " + self.subdir)
        if init:
            self._write_strip(init)
        self.write_make_line()
        if use_subdir and self.subdir:
            self._write_strip("popd")
        self._write_strip("\n")
        self._write_strip("\n".join(config.profile_payload))
        self._write_strip("\nmake clean\n")
        if post:
            self._write_strip(post)

    def write_make_install(self):
        """Write install section to spec file for make builds."""
        self._write_strip("%install")
        # time.time() returns a float, but we only need second-precision
        self._write_strip("export SOURCE_DATE_EPOCH={}".format(int(time.time())))
        self._write_strip("rm -rf %{buildroot}")
        self.write_install_prepend()

        self.write_license_files()

        if config.config_opts['32bit']:
            self._write_strip("pushd ../build32/" + self.subdir)
            self._write_strip("%make_install32 {} {}".format(self.extra_make_install,
                                                             self.extra_make32_install))
            self._write_strip("if [ -d  %{buildroot}/usr/lib32/pkgconfig ]")
            self._write_strip("then")
            self._write_strip("    pushd %{buildroot}/usr/lib32/pkgconfig")
            self._write_strip("    for i in *.pc ; do ln -s $i 32$i ; done")
            self._write_strip("    popd")
            self._write_strip("fi")
            self._write_strip("popd")

        if self.subdir:
            self._write_strip("pushd " + self.subdir)

        if config.config_opts['use_avx512']:
            self._write_strip("pushd ../buildavx512/")
            self._write_strip("%s_avx512 %s\n" % (self.install_macro, self.extra_make_install))
            self._write_strip("popd")

        if config.config_opts['use_avx2']:
            self._write_strip("pushd ../buildavx2/")
            self._write_strip("%s_avx2 %s\n" % (self.install_macro, self.extra_make_install))
            self._write_strip("popd")

        self._write_strip("%s %s\n" % (self.install_macro, self.extra_make_install))

        if self.subdir:
            self._write_strip("popd")

        self.write_find_lang()

    def write_mvnbin_install(self):
        """Write out installation for mvnbin content."""
        self.write_license_files()

        patterns = [
            re.compile(r"maven.*org/maven2/([a-zA-Z\-\_]+)/([a-zA-Z\-\_]+)/([a-zA-Z-\_\d.]+)/[a-zA-Z-\_\d.]*\.(?:pom|jar|xml|signature)"),
            re.compile(r"maven.apache.org/maven2/([a-zA-Z\-\_]+)/([a-zA-Z\-\_]+)/([\d.]+)/[a-z-\_.\d]*\.(?:pom|jar|xml|signature)"),
            re.compile(r"maven.*org/maven2/([a-zA-Z-\_.\d/]+)/([a-zA-Z-\_.\d]*)/([a-zA-Z\d\.\_\-]+)/(?:[a-zA-Z-\_.\d]*)\.(?:pom|jar|xml|signature)"),
            re.compile(r"repository.mapr.com/maven/([a-zA-Z\-\_/]+)/([a-zA-Z\-\_]+)/([a-zA-Z-\_\d.]+)/[a-zA-Z-\_\d.]*\.(?:pom|jar|xml|signature)"),
            re.compile(r"packages.confluent.io/maven/([a-zA-Z\-\_/]+)/([a-zA-Z\-\_]+)/([a-zA-Z-\_\d.]+)/[a-zA-Z-\_\d.]*\.(?:pom|jar|xml|signature)"),
            re.compile(r"gradle.org/gradle/libs-releases/([a-zA-Z-\_.\d/]+)/([a-zA-Z-\_.\d]*)/([a-zA-Z\d\.\_\-]+)/(?:[a-zA-Z-\_.\d]*)\.(?:pom|jar)"),
            re.compile(r"gradle.org/m2/([a-zA-Z-\_.\d/]+)/([a-zA-Z-\_.\d]*)/([a-zA-Z\d\.\_\-]+)/(?:[a-zA-Z-\_.\d]*)\.(?:pom|jar)")]
        mvn_sources = [self.url] + sorted(self.sources["archive"])
        src_num = 0

        for src in mvn_sources:
            for pat in patterns:
                m = pat.search(src)
                if m:
                    groupid = m.group(1)
                    artifactid = m.group(2)
                    version = m.group(3)
                    src_dir = "{}/{}/{}".format(groupid, artifactid, version)
                    src_file = os.path.basename(src)
                    if src_file.endswith(".xml"):
                        src_file = "maven-metadata-central.xml"

                    self._write_strip("mkdir -p %{{buildroot}}/usr/share/java/.m2/repository/{}".format(src_dir))
                    self._write_strip("cp %{{SOURCE{}}} %{{buildroot}}/usr/share/java/.m2/repository/{}/{}".format(src_num, src_dir, src_file))
                    self._write_strip("\n")
                    break
            src_num += 1

    def write_maven_install(self):
        """Write installation steps to specfile for maven source packages."""
        self.write_license_files()

        # Iterate over all built versions
        for prefix in self.build_dirs.values():
            self._write_strip("cd ../{}\n".format(prefix))

            # Iterate over all target subdirs
            self._write_strip("for targetdir in $(find . -type d -name target); do")
            self._write_strip("pushd $targetdir")

            # Figure out the artifact details and path components
            # Find group ID; inherit from parent if necessary
            self._write_strip("export GROUP_PATH=$(xml sel -T -t -m '//_:project' --if 'boolean(_:groupId)' -v '_:groupId' --else -v '_:parent/_:groupId' ../pom.xml | sed 's#\\.#/#g')")
            # Find artifact name -- this should not be inherited
            self._write_strip("export ARTIFACT_ID=$(xml sel -T -t -m '//_:project' -v '_:artifactId' ../pom.xml)")
            # Find version -- this *might* be inherited from parent
            self._write_strip("export VERSION=$(xml sel -T -t -m '//_:project' --if 'boolean(_:version)' -v '_:version' --else -v '_:parent/_:version' ../pom.xml)")

            # Create the installation path
            self._write_strip("export DEPLOY_PATH=%{buildroot}/usr/share/java/.m2/repository/${GROUP_PATH}/${ARTIFACT_ID}/${VERSION}")
            self._write_strip("mkdir -p ${DEPLOY_PATH}")

            # We're going to be globbing for things that may not exist
            self._write_strip("shopt -s nullglob")

            # Copy all the jar files
            self._write_strip("for jarfile in ${ARTIFACT_ID}*.jar; do")
            self._write_strip('cp -p "${jarfile}" ${DEPLOY_PATH}/')
            self._write_strip('done')
            # Except this one -- it's redundant with the source tarball
            self._write_strip("rm -f ${DEPLOY_PATH}/${ARTIFACT_ID}-${VERSION}-sources.jar")

            # Install the POM file
            self._write_strip("cp -p ../pom.xml ${DEPLOY_PATH}/${ARTIFACT_ID}-${VERSION}.pom")

            # Next
            self._write_strip("popd")

            # All done
            self._write_strip("done")

    def write_gradle_install(self):
        """Write installation steps to specfile for gradle source packages."""
        self.write_license_files()

        # Iterate over all built versions
        for prefix in self.build_dirs.values():
            self._write_strip("cd ../{}\n".format(prefix))

            if self.subdir:
                self._write_strip("pushd " + self.subdir)

            # User must provide the install goal in make_install_args
            self._write_strip("gradle --offline " + self.extra_make_install)

            # Install from a build/install directory, if it was created
            self._write_strip("if [[ -d build/install ]]; then")

            # Enter the installation subdir, so we can touch up what gets installed
            self._write_strip("pushd build/install")

            # Handle jarfiles in lib dir
            # The install goal results in packaging not only the jars that were
            # built, but also runtime deps that came from other packages. For every
            # jar we find in the installed directory, we'll check whether there's a
            # matching jar in the M2 repository provided by installed build deps.
            # If so, we'll replace this copy with a symlink.
            # TODO: call add_requires() with an appropriately-derived value so the
            # symlink will be resolved at chroot creation.
            self._write_strip("shopt -s nullglob")
            self._write_strip("for lib_dir in */lib; do")
            self._write_strip("pushd ${lib_dir}")
            self._write_strip("for jarfile in *.jar; do")
            self._write_strip("JARNAME=$(basename ${jarfile})")
            self._write_strip('REALJAR=$(find /usr/share/java/.m2/repository -type f -name "${JARNAME}")')
            self._write_strip("if ! [[ -z ${REALJAR} ]]; then")
            self._write_strip(r'ln -sf ${REALJAR/#\/usr\/share\/java/..\/..}')
            self._write_strip("fi")
            self._write_strip("done")
            self._write_strip("popd")
            self._write_strip("done")

            # Install the contents under main java path
            self._write_strip("mkdir -p %{buildroot}/usr/share/java/" + self.name)
            self._write_strip("cp -r lib %{buildroot}/usr/share/java/" + self.name)

            # Leave the build subdir
            self._write_strip("popd")

            # Done processing build/install directory
            self._write_strip("fi")

            if self.subdir:
                self._write_strip("popd")

    def write_prep_prepend(self):
        """Write out any custom supplied commands at the start of the %prep section."""
        if self.prep_prepend:
            self._write_strip("## prep_prepend content")
            for line in self.prep_prepend:
                self._write_strip("{}\n".format(line))
            self._write_strip("## prep_prepend end")

    def write_build_prepend(self):
        """Write out any custom supplied commands at the start of the %build section."""
        if self.build_prepend:
            self._write_strip("## build_prepend content")
            for line in self.build_prepend:
                self._write_strip("{}\n".format(line))
            self._write_strip("## build_prepend end")

    def write_build_append(self):
        """Write out any custom supplied commands at the end of the %build section."""
        if self.build_append:
            self._write_strip("## build_append content")
            for line in self.build_append:
                self._write_strip("{}\n".format(line))
            self._write_strip("## build_append end")

    def write_install_prepend(self):
        """Write out any custom supplied commands at the start of the %install section."""
        if self.install_prepend:
            self._write_strip("## install_prepend content")
            for line in self.install_prepend:
                self._write_strip("{}\n".format(line))
            self._write_strip("## install_prepend end")

    def write_install_append(self):
        """Write out any custom supplied commands at the very end of the %install section."""
        if self.install_append:
            self._write_strip("## install_append content")
            for line in self.install_append:
                self._write_strip("{}\n".format(line))
            self._write_strip("## install_append end")

    def write_exclude_deletes(self):
        """Write out deletes for excluded files."""
        if self.excludes:
            self._write_strip("## Remove excluded files")
        for exclude in self.excludes:
            self._write_strip(f"rm -f %{{buildroot}}{exclude}")

    def write_service_restart(self):
        """Enable configured units to be restarted with clr-service-restart."""
        if self.service_restart:
            self._write_strip("## service_restart content")
            installdir = "%{buildroot}/usr/share/clr-service-restart"
            self._write_strip("mkdir -p {}".format(installdir))
            for unit in self.service_restart:
                basename = os.path.basename(unit)
                self._write_strip("ln -s {} {}".format(unit, os.path.join(installdir, basename)))
            self._write_strip("## service_restart end")

    def write_source_installs(self):
        """Write out installs from SourceX lines."""
        if len(self.sources["unit"]) != 0:
            self._write_strip("mkdir -p %{buildroot}/usr/lib/systemd/system")
            for unit in self.sources["unit"]:
                self._write_strip("install -m 0644 %{{SOURCE{0}}} %{{buildroot}}/usr/lib/systemd/system/{1}"
                                  .format(self.source_index[unit], unit))
        if len(self.sources["tmpfile"]) != 0:
            self._write_strip("mkdir -p %{buildroot}/usr/lib/tmpfiles.d")
            self._write_strip("install -m 0644 %{{SOURCE{0}}} %{{buildroot}}/usr/lib/tmpfiles.d/{1}.conf"
                              .format(self.source_index[self.sources["tmpfile"][0]], self.name))

    def write_cmake_install(self):
        """Write install section to spec file for cmake builds."""
        self.write_build_append()
        self._write_strip("%install")
        self._write_strip("export SOURCE_DATE_EPOCH={}".format(int(time.time())))
        self._write_strip("rm -rf %{buildroot}")
        self.write_install_prepend()

        self.write_license_files()

        if self.subdir:
            self._write_strip("pushd " + self.subdir)

        if config.config_opts['32bit']:
            self._write_strip("pushd clr-build32")
            self._write_strip("%make_install32 {} {}".format(self.extra_make_install,
                                                             self.extra_make32_install))
            self._write_strip("if [ -d  %{buildroot}/usr/lib32/pkgconfig ]")
            self._write_strip("then")
            self._write_strip("    pushd %{buildroot}/usr/lib32/pkgconfig")
            self._write_strip("    for i in *.pc ; do ln -s $i 32$i ; done")
            self._write_strip("    popd")
            self._write_strip("fi")
            self._write_strip("popd")

        if config.config_opts['use_avx512']:
            self._write_strip("pushd clr-build-avx512")
            self._write_strip("%s_avx512 %s || :\n" % (self.install_macro, self.extra_make_install))
            self._write_strip("popd")

        if config.config_opts['use_avx2']:
            self._write_strip("pushd clr-build-avx2")
            self._write_strip("%s_avx2 %s || :\n" % (self.install_macro, self.extra_make_install))
            self._write_strip("popd")

        self._write_strip("pushd clr-build")
        self._write_strip("%s %s\n" % (self.install_macro, self.extra_make_install))
        self._write_strip("popd")

        if self.subdir:
            self._write_strip("popd")

        self.write_find_lang()

    @staticmethod
    def get_profile_generate_flags():
        """Return profile generate flags if proper configuration is set.

        If config.profile_payload is non-empty, returns
                'CFLAGS="${CFLAGS_GENERATE}" '
                'CXXFLAGS="${CXXFLAGS_GENERATE}" '
                'FFLAGS="${FFLAGS_GENERATE}" '
                'FCFLAGS="${FCFLAGS_GENERATE}" '
                'LDFLAGS="${LDFLAGS_GENERATE}" '

        otherwise an empty string is returned.
        """
        if config.profile_payload and config.profile_payload[0]:
            return 'CFLAGS="${CFLAGS_GENERATE}" '     \
                   'CXXFLAGS="${CXXFLAGS_GENERATE}" ' \
                   'FFLAGS="${FFLAGS_GENERATE}" '     \
                   'FCFLAGS="${FCFLAGS_GENERATE}" '   \
                   'LDFLAGS="${LDFLAGS_GENERATE}" '
        return ""

    @staticmethod
    def get_profile_use_flags():
        """Return profile generate flags if proper configuration is set.

        If config.profile_payload is non-empty, returns
                'CFLAGS="${CFLAGS_USE}" '
                'CXXFLAGS="${CXXFLAGS_USE}" '
                'FFLAGS="${FFLAGS_USE}" '
                'FCFLAGS="${FCFLAGS_USE}" '
                'LDFLAGS="${LDFLAGS_USE}" '

        otherwise an empty string is returned.
        """
        if config.profile_payload and config.profile_payload[0]:
            return 'CFLAGS="${CFLAGS_USE}" '     \
                   'CXXFLAGS="${CXXFLAGS_USE}" ' \
                   'FFLAGS="${FFLAGS_USE}" '     \
                   'FCFLAGS="${FCFLAGS_USE}" '   \
                   'LDFLAGS="${LDFLAGS_USE}" '
        return ""

    def get_systemd_units(self):
        """Get systemd unit files from the files module."""
        service_file_section = "config"
        systemd_service_pattern = r"^/usr/lib/systemd/system/[^/]*\.(mount|service|socket|target)$"
        systemd_units = []

        if service_file_section not in self.packages:
            return systemd_units

        for serv_f in self.packages[service_file_section]:
            if re.search(systemd_service_pattern, serv_f) and serv_f not in self.excludes:
                systemd_units.append(serv_f)

        return systemd_units

    def write_systemd_units(self):
        """Write out installs for systemd unit files."""
        units = self.get_systemd_units()
        for unit in units:
            self._write("systemctl --root=%{{buildroot}} enable {0}\n".format(os.path.basename(unit)))

    def write_configure_pattern(self):
        """Write configure build pattern to spec file."""
        if self.autoreconf:
            # Patches affecting configure.* or Makefile.*, reconf instead
            self.write_configure_ac_pattern()
            return
        self.write_prep()
        self.write_lang_c(export_epoch=True)
        self.write_variables()
        self.write_profile_payload("configure")
        if self.subdir:
            self._write_strip("pushd {}".format(self.subdir))
        self._write_strip("{0}%configure {1} {2} {3}"
                          .format(self.get_profile_use_flags(),
                                  self.disable_static,
                                  config.extra_configure,
                                  config.extra_configure64))
        self.write_make_line()
        if self.subdir:
            self._write_strip("popd")
        self._write_strip("\n")
        if config.config_opts['32bit']:
            self._write_strip("pushd ../build32/" + self.subdir)
            self.write_build_prepend()
            self.write_32bit_exports()
            self._write_strip("%configure {0} {1} {2} "
                              " --libdir=/usr/lib32 "
                              "--build=i686-generic-linux-gnu "
                              "--host=i686-generic-linux-gnu "
                              "--target=i686-clr-linux-gnu"
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure32))
            self.write_make_line(True)
            self._write_strip("popd")

        if config.config_opts['use_avx2']:
            self._write_strip("unset PKG_CONFIG_PATH")
            self._write_strip("pushd ../buildavx2/" + self.subdir)
            self.write_build_prepend()
            self._write_strip("export CFLAGS=\"$CFLAGS -m64 -march=haswell\"")
            self._write_strip("export CXXFLAGS=\"$CXXFLAGS -m64 -march=haswell\"")
            self._write_strip("export LDFLAGS=\"$LDFLAGS -m64 -march=haswell\"")
            self._write_strip("%configure {0} {1} {2} "
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure_avx2))
            self.write_make_line()
            self._write_strip("popd")

        if config.config_opts['use_avx512']:
            self._write_strip("unset PKG_CONFIG_PATH")
            self.write_build_prepend()
            self._write_strip("pushd ../buildavx512/" + self.subdir)
            self._write_strip("export CFLAGS=\"$CFLAGS -m64 -march=skylake-avx512 -mprefer-vector-width=512\"")
            self._write_strip("export CXXFLAGS=\"$CXXFLAGS -m64 -march=skylake-avx512 -mprefer-vector-width=512\"")
            self._write_strip("export LDFLAGS=\"$LDFLAGS -m64 -march=skylake-avx512\"")
            self._write_strip("%configure {0} {1} {2} "
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure_avx512))
            self.write_make_line()
            self._write_strip("popd")

        self.write_check()
        self.write_make_install()

    def write_configure_ac_pattern(self):
        """Write build pattern for configure.ac style build."""
        self.write_prep()
        self.write_lang_c(export_epoch=True)
        self.write_variables()
        self.write_profile_payload("configure_ac")
        if self.subdir:
            self._write_strip("pushd " + self.subdir)
        self._write_strip("{0}%reconfigure {1} {2} {3}"
                          .format(self.get_profile_use_flags(),
                                  self.disable_static,
                                  config.extra_configure,
                                  config.extra_configure64))
        self.write_make_line()
        if self.subdir:
            self._write_strip("popd")
        if config.config_opts['32bit']:
            self._write_strip("pushd ../build32/" + self.subdir)
            self.write_build_prepend()
            self.write_32bit_exports()
            self._write_strip("%reconfigure {0} {1} {2} "
                              "--libdir=/usr/lib32 "
                              "--build=i686-generic-linux-gnu "
                              "--host=i686-generic-linux-gnu "
                              "--target=i686-clr-linux-gnu"
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure32))
            self.write_make_line(True)
            self._write_strip("popd")

        if config.config_opts['use_avx2']:
            self._write_strip("unset PKG_CONFIG_PATH")
            self._write_strip("pushd ../buildavx2/" + self.subdir)
            self.write_build_prepend()
            self._write_strip("export CFLAGS=\"$CFLAGS -m64 -march=haswell\"")
            self._write_strip("export CXXFLAGS=\"$CXXFLAGS -m64 -march=haswell\"")
            self._write_strip("export LDFLAGS=\"$LDFLAGS -m64 -march=haswell\"")
            self._write_strip("%reconfigure {0} {1} {2} "
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure_avx2))
            self.write_make_line()
            self._write_strip("popd")

        if config.config_opts['use_avx512']:
            self._write_strip("unset PKG_CONFIG_PATH")
            self._write_strip("pushd ../buildavx512/" + self.subdir)
            self.write_build_prepend()
            self._write_strip("export CFLAGS=\"$CFLAGS -m64 -march=skylake-avx512 -mprefer-vector-width=512\"")
            self._write_strip("export CXXFLAGS=\"$CXXFLAGS -m64 -march=skylake-avx512 -mprefer-vector-width=512\"")
            self._write_strip("export LDFLAGS=\"$LDFLAGS -m64 -march=skylake-avx512\"")
            self._write_strip("%reconfigure {0} {1} {2} "
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure_avx512))
            self.write_make_line()
            self._write_strip("popd")

        self._write_strip("\n")
        self.write_check()
        self.write_make_install()

    def write_make_pattern(self):
        """Write build pattern for make."""
        self.write_prep()
        self.write_lang_c(export_epoch=True)
        self.write_variables()
        self.write_profile_payload("make")
        if self.subdir:
            self._write_strip("pushd " + self.subdir)
        self.write_make_line()
        if self.subdir:
            self._write_strip("popd")
        self._write_strip("\n")
        if config.config_opts['32bit']:
            self._write_strip("pushd ../build32/" + self.subdir)
            self.write_32bit_exports()
            self.write_make_line(True)
            self._write_strip("popd")
        if config.config_opts['use_avx2']:
            self._write_strip("pushd ../buildavx2" + self.subdir)
            self.write_build_prepend()
            self._write_strip("export CFLAGS=\"$CFLAGS -m64 -march=haswell\"")
            self._write_strip("export CXXFLAGS=\"$CXXFLAGS -m64 -march=haswell\"")
            self._write_strip("export LDFLAGS=\"$LDFLAGS -m64 -march=haswell\"")
            self.write_make_line()
            self._write_strip("popd")
        if config.config_opts['use_avx512']:
            self._write_strip("pushd ../buildavx512" + self.subdir)
            self.write_build_prepend()
            self._write_strip("export CFLAGS=\"$CFLAGS -m64 -march=skylake-avx512 -mprefer-vector-width=512\"")
            self._write_strip("export CXXFLAGS=\"$CXXFLAGS -m64 -march=skylake-avx512 -mprefer-vector-width=512\"")
            self._write_strip("export LDFLAGS=\"$LDFLAGS -m64 -march=skylake-avx512\"")
            self.write_make_line()
            self._write_strip("popd")

        self._write_strip("\n")
        self.write_check()
        self.write_make_install()

    def write_autogen_pattern(self):
        """Write build pattern for autogen packages."""
        self.write_prep()
        self.write_lang_c(export_epoch=True)
        self.write_variables()
        self.write_profile_payload("autogen")
        self._write_strip("{0}%autogen {1} {2} {3}"
                          .format(self.get_profile_use_flags(),
                                  self.disable_static,
                                  config.extra_configure,
                                  config.extra_configure64))
        self.write_make_line()
        self._write_strip("\n")
        if config.config_opts['32bit']:
            self._write_strip("pushd ../build32/" + self.subdir)
            self.write_build_prepend()
            self.write_32bit_exports()
            self._write_strip("%autogen {0} {1} {2} "
                              "--libdir=/usr/lib32 "
                              "--build=i686-generic-linux-gnu "
                              "--host=i686-generic-linux-gnu "
                              "--target=i686-clr-linux-gnu"
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure32))
            self.write_make_line(True)
            self._write_strip("popd")

        if config.config_opts['use_avx2']:
            self._write_strip("pushd ../buildavx2/" + self.subdir)
            self.write_build_prepend()
            self._write_strip('export CFLAGS="$CFLAGS -m64 -march=haswell "')
            self._write_strip('export CXXFLAGS="$CXXFLAGS -m64 -march=haswell "')
            self._write_strip('export LDFLAGS="$LDFLAGS -m64 -march=haswell "')
            self._write_strip("%autogen {0} {1} {2} "
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure_avx2))
            self.write_make_line()
            self._write_strip("popd")

        if config.config_opts['use_avx512']:
            self._write_strip("pushd ../buildavx512/" + self.subdir)
            self.write_build_prepend()
            self._write_strip('export CFLAGS="$CFLAGS -m64 -march=skylake-avx512 "')
            self._write_strip('export CXXFLAGS="$CXXFLAGS -m64 -march=skylake-avx512 "')
            self._write_strip('export LDFLAGS="$LDFLAGS -m64 -march=skylake-avx512 "')
            self._write_strip("%autogen {0} {1} {2} "
                              .format(self.disable_static,
                                      config.extra_configure,
                                      config.extra_configure_avx512))
            self.write_make_line()
            self._write_strip("popd")

        self.write_check()
        self.write_make_install()

    def write_distutils3_pattern(self):
        """Write build pattern for python packages using distutils3."""
        self.write_prep()
        self.write_lang_c(export_epoch=True)
        self.write_variables()
        self._write_strip("export MAKEFLAGS=%{?_smp_mflags}")
        if self.subdir:
            self._write_strip("pushd " + self.subdir)
        self._write_strip("python3 setup.py build  " + config.extra_configure)
        self._write_strip("\n")
        if self.tests_config and not config.config_opts['skip_tests']:
            self._write_strip("%check")
            # Prevent setuptools from hitting the internet
            self.write_proxy_exports()
            self._write_strip(self.tests_config)
        if self.subdir:
            self._write_strip("popd")
        self.write_build_append()
        self._write_strip("%install")
        self._write_strip("export MAKEFLAGS=%{?_smp_mflags}")
        self._write_strip("rm -rf %{buildroot}")
        self.write_install_prepend()

        self.write_license_files()

        if self.subdir:
            self._write_strip("pushd " + self.subdir)
        self._write_strip("python3 -tt setup.py build  install --root=%{buildroot}")
        if self.subdir:
            self._write_strip("popd")
        self._write_strip("echo ----[ mark ]----")
        self._write_strip("cat %{buildroot}/usr/lib/python3*/site-packages/*/requires.txt || :")
        self._write_strip("echo ----[ mark ]----")
        self.write_find_lang()

    def write_distutils36_pattern(self):
        """Write build pattern for python packages using distutils36."""
        self.write_prep()
        self.write_lang_c(export_epoch=True)
        self.write_variables()
        if self.subdir:
            self._write_strip("pushd " + self.subdir)
        self._write_strip("python3.6 setup.py build -b py3 " + config.extra_configure)
        self._write_strip("\n")
        if self.tests_config and not config.config_opts['skip_tests']:
            self._write_strip("%check")
            # Prevent setuptools from hitting the internet
            self.write_proxy_exports()
            self._write_strip(self.tests_config)
        if self.subdir:
            self._write_strip("popd")
        self.write_build_append()
        self._write_strip("%install")
        self._write_strip("export SOURCE_DATE_EPOCH={}".format(int(time.time())))
        self._write_strip("rm -rf %{buildroot}")
        self.write_install_prepend()

        self.write_license_files()

        if self.subdir:
            self._write_strip("pushd " + self.subdir)
        self._write_strip("python3.6 -tt setup.py build -b py3 install --root=%{buildroot} --force")
        if self.subdir:
            self._write_strip("popd")
        self._write_strip("echo ----[ mark ]----")
        self._write_strip("cat %{buildroot}/usr/lib/python3*/site-packages/*/requires.txt || :")
        self._write_strip("echo ----[ mark ]----")
        self.write_find_lang()

    def write_R_pattern(self):
        """Write build pattern for R packages."""
        self.write_prep()
        self.write_lang_c(export_epoch=True)
        self._write_strip("\n")

        self._write_strip("%install")
        self._write_strip("export SOURCE_DATE_EPOCH={}".format(int(time.time())))
        self._write_strip("rm -rf %{buildroot}")
        self.write_install_prepend()
        self._write_strip("export LANG=C.UTF-8")
        self._write_strip('export CFLAGS="$CFLAGS -O3 -flto -fno-semantic-interposition "\n')
        self._write_strip('export FCFLAGS="$CFLAGS -O3 -flto -fno-semantic-interposition "\n')
        self._write_strip('export FFLAGS="$CFLAGS -O3 -flto -fno-semantic-interposition "\n')
        self._write_strip('export CXXFLAGS="$CXXFLAGS -O3 -flto -fno-semantic-interposition "\n')
        self._write_strip("export AR=gcc-ar\n")
        self._write_strip("export RANLIB=gcc-ranlib\n")
        self._write_strip('export LDFLAGS="$LDFLAGS  -Wl,-z -Wl,relro"\n')

        self._write_strip("mkdir -p %{buildroot}/usr/lib64/R/library")
        self._write_strip("\n")
        self._write_strip("mkdir -p ~/.R")
        self._write_strip("mkdir -p ~/.stash")

        self._write_strip("echo \"CFLAGS = $CFLAGS -march=haswell -ftree-vectorize \" > ~/.R/Makevars")
        self._write_strip("echo \"FFLAGS = $FFLAGS -march=haswell -ftree-vectorize \" >> ~/.R/Makevars")
        self._write_strip("echo \"CXXFLAGS = $CXXFLAGS -march=haswell -ftree-vectorize \" >> ~/.R/Makevars")

        self._write_strip("R CMD INSTALL "
                          "--install-tests "
                          "--built-timestamp=${SOURCE_DATE_EPOCH} "
                          "--build  -l "
                          "%{buildroot}/usr/lib64/R/library " + self.rawname)
        self._write_strip("for i in `find %{buildroot}/usr/lib64/R/ -name \"*.so\"`; do mv $i $i.avx2 ; mv $i.avx2 ~/.stash/; done\n")

        self._write_strip("echo \"CFLAGS = $CFLAGS -march=skylake-avx512 -ftree-vectorize \" > ~/.R/Makevars")
        self._write_strip("echo \"FFLAGS = $FFLAGS -march=skylake-avx512 -ftree-vectorize \" >> ~/.R/Makevars")
        self._write_strip("echo \"CXXFLAGS = $CXXFLAGS -march=skylake-avx512 -ftree-vectorize \" >> ~/.R/Makevars")

        self._write_strip("R CMD INSTALL "
                          "--preclean "
                          "--install-tests "
                          "--no-test-load "
                          "--built-timestamp=${SOURCE_DATE_EPOCH} "
                          "--build  -l "
                          "%{buildroot}/usr/lib64/R/library " + self.rawname)
        self._write_strip("for i in `find %{buildroot}/usr/lib64/R/ -name \"*.so\"`; do mv $i $i.avx512 ; mv $i.avx512 ~/.stash/; done\n")

        self._write_strip("echo \"CFLAGS = $CFLAGS -ftree-vectorize \" > ~/.R/Makevars")
        self._write_strip("echo \"FFLAGS = $FFLAGS -ftree-vectorize \" >> ~/.R/Makevars")
        self._write_strip("echo \"CXXFLAGS = $CXXFLAGS -ftree-vectorize \" >> ~/.R/Makevars")

        self._write_strip("R CMD INSTALL "
                          "--preclean "
                          "--install-tests "
                          "--built-timestamp=${SOURCE_DATE_EPOCH} "
                          "--build  -l "
                          "%{buildroot}/usr/lib64/R/library " + self.rawname)
        self._write_strip("cp ~/.stash/* %{buildroot}/usr/lib64/R/library/*/libs/ || :")

        self._write_strip("%{__rm} -rf %{buildroot}%{_datadir}/R/library/R.css")
        self.write_find_lang()
        self.write_check()

    def write_ruby_pattern(self):
        """Write build pattern for ruby packages."""
        self.write_prep(ruby_pattern=True)
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("export LANG=C.UTF-8")
        self._write_strip("gem build {}.gemspec".format(self.name))
        self.write_build_append()
        self._write_strip("\n")

        self._write_strip("%install")
        self.write_install_prepend()
        self._write_strip("%global gem_dir $(ruby -e'puts Gem.default_dir')")
        self._write_strip("gem install -V \\")
        self._write_strip("  --local \\")
        self._write_strip("  --force \\")
        self._write_strip("  --install-dir .%{gem_dir} \\")
        self._write_strip("  --bindir .%{_bindir} \\")
        self._write_strip(" {}.gem".format(self.tarball_prefix))
        self._write_strip("\n")

        self._write_strip("mkdir -p %{buildroot}%{gem_dir}")
        self._write_strip("cp -pa .%{gem_dir}/* \\")
        self._write_strip("        %{buildroot}%{gem_dir}")
        self._write_strip("\n")

        self._write_strip("if [ -d .%{_bindir} ]; then")
        self._write_strip("    mkdir -p %{buildroot}%{_bindir}")
        self._write_strip("    cp -pa .%{_bindir}/* \\")
        self._write_strip("        %{buildroot}%{_bindir}/")
        self._write_strip("fi")
        self._write_strip("\n")
        self.write_find_lang()
        self.write_check()

    def write_cmake_pattern(self):
        """Write cmake pattern to spec file."""
        if self.extra_make == "" or self.extra_cmake == " ":
            self.extra_make = "VERBOSE=1"
        self.write_prep()
        self.write_lang_c(export_epoch=True)

        if self.subdir:
            self._write_strip("pushd " + self.subdir)

        self._write_strip("mkdir -p clr-build")
        self._write_strip("pushd clr-build")
        self.write_variables()
        self._write_strip("%cmake {} {}".format(self.cmake_srcdir, self.extra_cmake))

        self.write_profile_payload("cmake")

        self.write_make_line()
        self._write_strip("popd")

        if config.config_opts['use_avx2']:
            self._write_strip("mkdir -p clr-build-avx2")
            self._write_strip("pushd clr-build-avx2")
            saved_avx2flags = self.need_avx2_flags
            self.need_avx2_flags = True
            self.write_build_prepend()
            self.write_variables()
            self.need_avx2_flags = saved_avx2flags
            self._write_strip('export CFLAGS="$CFLAGS -march=haswell -m64"')
            self._write_strip('export CXXFLAGS="$CXXFLAGS -march=haswell -m64"')
            self._write_strip("%cmake {} {}".format(self.cmake_srcdir, self.extra_cmake))
            self.write_make_line()
            self._write_strip("popd")

        if config.config_opts['use_avx512']:
            self._write_strip("mkdir -p clr-build-avx512")
            self._write_strip("pushd clr-build-avx512")
            saved_avx512flags = self.need_avx512_flags
            self.need_avx512_flags = True
            self.write_build_prepend()
            self.write_variables()
            self.need_avx512_flags = saved_avx512flags
            self._write_strip('export CFLAGS="$CFLAGS -march=skylake-avx512 -m64 "')
            self._write_strip('export CXXFLAGS="$CXXFLAGS -march=skylake-avx512 -m64 "')
            self._write_strip("%cmake {} {}".format(self.cmake_srcdir, self.extra_cmake))
            self.write_make_line()
            self._write_strip("popd")

        if config.config_opts['32bit']:
            self._write_strip("mkdir -p clr-build32")
            self._write_strip("pushd clr-build32")
            self.write_build_prepend()
            self.write_variables()
            self.write_32bit_exports()
            self._write_strip("%cmake -DLIB_INSTALL_DIR:PATH=/usr/lib32 "
                              "-DCMAKE_INSTALL_LIBDIR=/usr/lib32 "
                              "-DLIB_SUFFIX=32 "
                              "{} {} ".format(self.cmake_srcdir, self.extra_cmake))
            self.write_make_line()
            self._write_strip("unset PKG_CONFIG_PATH")
            self._write_strip("popd")

        if self.subdir:
            self._write_strip("popd")

        self._write_strip("\n")
        self.write_check()

        self.write_cmake_install()

    def write_qmake_pattern(self):
        """Write qmake build pattern to spec file."""
        extra_qmake_args = ""
        if config.config_opts['use_clang']:
            extra_qmake_args = "-spec linux-clang "
        if config.config_opts['use_lto']:
            extra_qmake_args += "-config ltcg -config fat-static-lto "
        else:
            extra_qmake_args += "QMAKE_CFLAGS+=-fno-lto QMAKE_CXXFLAGS+=-fno-lto "

        self.write_prep()
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("export LANG=C.UTF-8")
        self.write_variables()

        if self.subdir:
            self._write_strip("pushd " + self.subdir)

        self._write_strip("%qmake {} {}".format(extra_qmake_args, config.extra_configure))
        self._write_strip("test -r config.log && cat config.log")
        self.write_make_line()

        if self.subdir:
            self._write_strip("popd")

        if config.config_opts['use_avx2']:
            self._write_strip("pushd ../buildavx2/" + self.subdir)
            self._write("%qmake 'QT_CPU_FEATURES.x86_64 += avx avx2 bmi bmi2 f16c fma lzcnt popcnt'\\\n")
            self._write("    QMAKE_CFLAGS+=-march=haswell QMAKE_CXXFLAGS+=-march=haswell \\\n")
            self._write("    QMAKE_LFLAGS+=-march=haswell {} {}\n".format(extra_qmake_args, config.extra_configure))
            self.write_make_line()
            self._write_strip("popd")

        self.write_build_append()
        self._write_strip("\n")
        self.write_make_install()

    def write_cargo_pattern(self):
        """Write cargo build pattern to spec file."""
        self.write_prep()
        src_dir = "/usr/share/rust/src/{0}".format(self.name)
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("mkdir .cargo")
        self._write("echo \"[source.crates-io]\nreplace-with = 'vendored-sources'\n[source.vendored-sources]\ndirectory = '{}'\" > .cargo/config\n".format(os.path.dirname(src_dir)))
        self._write_strip('echo \'{"files":{},"package":""}\' > .cargo-checksum.json')
        # Don't let cargo get outside
        self._write_strip("export http_proxy=http://127.0.0.1:9/")
        self._write_strip("export https_proxy=http://127.0.0.1:9/")
        self._write_strip("export no_proxy=localhost,127.0.0.1,0.0.0.0")
        self._write_strip("cargo build --release")
        self.write_build_append()
        self._write_strip("\n")
        self._write_strip("%install")
        self.write_install_prepend()
        if self.cargo_bin:
            self._write_strip("cargo install --frozen --root /")
        self._write_strip("cargo clean")
        self._write_strip("install -d -p %{buildroot}" + src_dir)
        self._write_strip("cp -a . %{buildroot}" + src_dir)

    def write_cpan_pattern(self):
        """Write cpan build pattern to spec file."""
        self.write_prep()
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("export LANG=C.UTF-8")
        self._write_strip("if test -f Makefile.PL; then")
        self._write_strip("%{__perl} Makefile.PL")
        self.write_make_line()
        self._write_strip("else")
        self._write_strip("%{__perl} Build.PL")
        self._write_strip("./Build")
        self._write_strip("fi")
        self.write_build_append()
        self._write_strip("\n")
        self.write_check()
        self._write_strip("%install")
        self._write_strip("rm -rf %{buildroot}")
        self.write_install_prepend()
        self.write_license_files()
        self._write_strip("if test -f Makefile.PL; then")
        self._write_strip("make pure_install PERL_INSTALL_ROOT=%{buildroot} INSTALLDIRS=vendor " + self.extra_make_install)
        self._write_strip("else")
        self._write_strip("./Build install --installdirs=vendor --destdir=%{buildroot} " + self.extra_make_install)
        self._write_strip("fi")
        self._write_strip("find %{buildroot} -type f -name .packlist -exec rm -f {} ';'")
        self._write_strip("find %{buildroot} -depth -type d -exec rmdir {} 2>/dev/null ';'")
        self._write_strip("find %{buildroot} -type f -name '*.bs' -empty -exec rm -f {} ';'")
        self._write_strip("%{_fixperms} %{buildroot}/*")
        self.write_find_lang()

    def write_scons_pattern(self):
        """Write scons build pattern to spec file."""
        self.write_prep()
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("export LANG=C.UTF-8")
        self.write_variables()
        self._write_strip("scons{} {}".format(config.parallel_build, config.extra_configure))
        self.write_build_append()
        self._write_strip("\n")
        self._write_strip("%install")
        self.write_install_prepend()
        self._write_strip("scons install " + self.extra_make_install)
        self.write_license_files()

    def write_golang_pattern(self):
        """Write build pattern for go packages."""
        self.write_prep()
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("export LANG=C.UTF-8")
        if self.set_gopath:
            self._write_strip("export GOPATH=\"$PWD\"")
            self._write_strip("go build {}".format(self.extra_make))
        else:
            self._write_strip("export GOPROXY=file:///usr/share/goproxy")
            self._write_strip("go mod vendor")
            self._write_strip("go build -mod=vendor {}".format(self.extra_make))
        self.write_build_append()
        self._write_strip("\n")
        self._write_strip("%install")
        self._write_strip("rm -rf %{buildroot}")
        self.write_install_prepend()
        self.write_license_files()
        self._write_strip("\n")

    def write_godep_pattern(self):
        """Write godep build pattern to spec file."""
        self.write_prep()
        self._write_strip("%install")
        self.write_install_prepend()
        self._write_strip("rm -fr %{buildroot}")
        # Remove golang default proxy prefix and filename to get proxy path for the install
        proxy_path = os.path.join("%{buildroot}/usr/share/goproxy",
                                  os.path.dirname(self.url[len("https://proxy.golang.org/"):]))
        self._write_strip(f"mkdir -p {proxy_path}")
        list_file = os.path.join(proxy_path, "list")
        self._write_strip("# Create list file using packaged versions")
        for ver in list(tarball.multi_version.keys()):
            self._write_strip(f"echo {ver} >> {list_file}")
        for idx, source in enumerate(sorted(self.sources["godep"])):
            file_path = os.path.join(proxy_path, os.path.basename(source))
            self._write_strip(f"install -m 0644 %{{SOURCE{idx+1}}} {file_path}")
        self._write_strip("\n")

    def write_ant_pattern(self):
        """Write ant build pattern to spec file."""
        self.write_prep()
        self._write_strip("%build")
        self.write_proxy_exports()
        self._write_strip("export ANT_HOME=/usr/share/ant")
        for prefix in self.build_dirs.values():
            self._write_strip("cd ../{}\n".format(prefix))
            self.write_build_prepend()
            self._write_strip("ant -d -v " + self.extra_make)
            self.write_build_append()
        self._write_strip("\n")
        self._write_strip("%install")
        self.write_install_prepend()
        self._write_strip("")

    def write_gradle_pattern(self):
        """Write gradle build pattern to spec file."""
        self.write_prep()
        self._write_strip("%build")
        self.write_proxy_exports()
        self._write_strip("mkdir -p %{buildroot}")

        # Copy M2 repo contents from buildreqs to Maven's default location.
        # It's ok if this doesn't exist.
        self._write_strip("mkdir -p ~/.m2")
        self._write_strip("cp -r /usr/share/java/.m2/* ~/.m2/ || :")

        for prefix in self.build_dirs.values():
            self._write_strip("cd ../{}\n".format(prefix))

            if self.subdir:
                self._write_strip("pushd " + self.subdir)

            self.write_build_prepend()

            # Point to our local maven repo, first
            # style check does not like the escapes here
            self._write_strip(r"find . -type f '(' -name '*.gradle' -o -name '*.gradle.kts' ')' -exec sed -i 's|\(repositories\s*{\)|\1\n    mavenLocal()|' {} +")

            # Opportunistically report detected dependencies
            self._write_strip("gradle --offline dependencies || :")

            # Execute the build goal -- but user must provide it in make_args
            self._write_strip("gradle --offline " + self.extra_make)

            self.write_build_append()

            if self.subdir:
                self._write_strip("popd")

        self._write_strip("\n")
        self._write_strip("%install")
        self.write_install_prepend()
        self._write_strip("")
        self.write_gradle_install()

    def write_maven_pattern(self):
        """Write maven build pattern to spec file."""
        self.write_prep()
        self._write_strip("%build")
        self.write_proxy_exports()
        self._write_strip("mkdir -p %{buildroot}")
        # It's ok if this doesn't exist
        self._write_strip("mkdir -p ~/.m2")
        self._write_strip("cp -r /usr/share/java/.m2/* ~/.m2/ || :")
        for prefix in self.build_dirs.values():
            self._write_strip("cd ../{}\n".format(prefix))
            self.write_build_prepend()
            self._write_strip("mvn --offline package " + self.extra_make)
            self.write_build_append()
        self._write_strip("\n")
        self._write_strip("%install")
        self.write_install_prepend()
        self._write_strip("")
        self.write_maven_install()

    def write_mvnbin_pattern(self):
        """Write maven build pattern to spec file."""
        self.write_prep()
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_build_append()
        self._write_strip("\n")
        self._write_strip("%install")
        self.write_install_prepend()
        self.write_mvnbin_install()

    def write_meson_pattern(self):
        """Write meson build pattern to spec file."""
        self.write_prep()
        self.write_lang_c(export_epoch=True)
        self.write_variables()
        self._write_strip('CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" meson --libdir=lib64 --prefix=/usr --buildtype=plain {0} {1} builddir'
                          .format(config.extra_configure,
                                  config.extra_configure64))
        self._write_strip("ninja -v -C builddir")

        if config.config_opts['use_avx2']:
            self._write_strip('CFLAGS="$CFLAGS -m64 -march=haswell" CXXFLAGS="$CXXFLAGS -m64 -march=haswell " LDFLAGS="$LDFLAGS -m64 -march=haswell" '
                              'meson --libdir=lib64/haswell --prefix=/usr --buildtype=plain {0} '
                              '{1} builddiravx2'.format(config.extra_configure, config.extra_configure64))
            self._write_strip('ninja -v -C builddiravx2')

        if config.config_opts['32bit']:
            self._write_strip("pushd ../build32")
            self.write_32bit_exports()
            self._write_strip('meson '
                              '--libdir=lib32 --prefix=/usr --buildtype=plain {0} {1} builddir'
                              .format(config.extra_configure,
                                      config.extra_configure32))
            self._write_strip('ninja -v -C builddir')
            self._write_strip('popd')

        self.write_build_append()
        self._write_strip("\n")
        self.write_check()
        self._write_strip("%install")
        self.write_install_prepend()
        self.write_license_files()
        if config.config_opts['32bit']:
            self._write_strip('pushd ../build32')
            self._write_strip('DESTDIR=%{buildroot} ninja -C builddir install')
            self._write_strip("if [ -d  %{buildroot}/usr/lib32/pkgconfig ]")
            self._write_strip("then")
            self._write_strip("    pushd %{buildroot}/usr/lib32/pkgconfig")
            self._write_strip("    for i in *.pc ; do ln -s $i 32$i ; done")
            self._write_strip("    popd")
            self._write_strip("fi")
            self._write_strip("popd")

        if config.config_opts['use_avx2']:
            self._write_strip('DESTDIR=%{buildroot} ninja -C builddiravx2 install')

        self._write_strip("DESTDIR=%{buildroot} ninja -C builddir install")
        self.write_find_lang()

    def write_phpize_pattern(self):
        """Write phpize build pattern to spec file."""
        self.write_prep()
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("phpize")
        self._write_strip("%configure")
        self.write_make_line()
        self.write_build_append()
        self._write_strip("\n")
        self._write_strip("%install")
        self.write_install_prepend()
        self._write_strip("%make_install")
        self._write_strip("\n")

    def write_nginx_pattern(self):
        """Write nginx build pattern to spec file."""
        self.write_prep()
        self._write_strip("%build")
        self.write_build_prepend()
        self.write_proxy_exports()
        self._write_strip("nginx-module configure")
        self._write_strip("nginx-module build")
        self.write_build_append()
        self._write_strip("\n")
        self._write_strip("%install")
        self.write_install_prepend()
        self._write_strip("nginx-module install %{buildroot}")
        self._write_strip("\n")

    def write_find_lang(self):
        """Write %find_lang macro to spec file."""
        for lang in self.locales:
            self._write("%find_lang {}\n".format(lang))

    def apply_patches(self):
        """Write patch list to spec file."""
        counter = 1
        for p in self.patches:
            name = p.split(None, 1)[0]
            if name == p:
                options = "-p1"
            else:
                options = p.split(None, 1)[1]
            if not p.split()[0].endswith(".nopatch"):
                self._write("%patch{} {}\n".format(counter, options))
            counter = counter + 1

        # Write version-specific patch commands
        for version in self.verpatches:
            if self.verpatches[version]:
                self._write("cd ../{}\n".format(self.build_dirs[config.versions[version]]))
            for p in self.verpatches[version]:
                name = p.split(None, 1)[0]
                if name == p:
                    options = "-p1"
                else:
                    options = p.split(None, 1)[1]
                if not p.split()[0].endswith(".nopatch"):
                    self._write("%patch{} {}\n".format(counter, options))
                counter = counter + 1

    def _write(self, string):
        self.specfile.write(string)

    def _write_strip(self, string):
        self.specfile.write_strip(string)

    def quote_filename(self, filename):
        """Quotes the filename, if necessary. Identifies and skips any RPM directive prefix."""
        # Characters that require quoting -- only those with special
        # meaning in specfiles
        special_chars = set(" \t")
        # Build up the output as a string
        quoted = ''
        # Capture any directive prefix separately from actual filename
        #                          (1                   )(3 )
        directive_re = re.compile(r"(%\w+(\([^\)]*\))?\s+)(.*)")
        parts = directive_re.match(filename)
        if parts:
            # Add prefix to the output
            quoted += parts.group(1)
            # Set the filename to the remaining portion
            filename = parts.group(3)

        # Now check for special characters
        if any(c in filename for c in special_chars):
            # Quote the filename
            quoted += '"{}"'.format(filename)
        else:
            # Add the filename as-is
            quoted += filename
        return quoted
