Blame scripts/build-many-glibcs.py

Packit Service 82fcde
#!/usr/bin/python3
Packit Service 82fcde
# Build many configurations of glibc.
Packit Service 82fcde
# Copyright (C) 2016-2018 Free Software Foundation, Inc.
Packit Service 82fcde
# This file is part of the GNU C Library.
Packit Service 82fcde
#
Packit Service 82fcde
# The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
# modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
# License as published by the Free Software Foundation; either
Packit Service 82fcde
# version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
#
Packit Service 82fcde
# The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
# Lesser General Public License for more details.
Packit Service 82fcde
#
Packit Service 82fcde
# You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
# License along with the GNU C Library; if not, see
Packit Service 82fcde
# <http://www.gnu.org/licenses/>.
Packit Service 82fcde
Packit Service 82fcde
"""Build many configurations of glibc.
Packit Service 82fcde
Packit Service 82fcde
This script takes as arguments a directory name (containing a src
Packit Service 82fcde
subdirectory with sources of the relevant toolchain components) and a
Packit Service 82fcde
description of what to do: 'checkout', to check out sources into that
Packit Service 82fcde
directory, 'bot-cycle', to run a series of checkout and build steps,
Packit Service 82fcde
'bot', to run 'bot-cycle' repeatedly, 'host-libraries', to build
Packit Service 82fcde
libraries required by the toolchain, 'compilers', to build
Packit Service 82fcde
cross-compilers for various configurations, or 'glibcs', to build
Packit Service 82fcde
glibc for various configurations and run the compilation parts of the
Packit Service 82fcde
testsuite.  Subsequent arguments name the versions of components to
Packit Service 82fcde
check out (<component>-
Packit Service 82fcde
other than 'checkout' and 'bot-cycle', name configurations for which
Packit Service 82fcde
compilers or glibc are to be built.
Packit Service 82fcde
Packit Service 82fcde
"""
Packit Service 82fcde
Packit Service 82fcde
import argparse
Packit Service 82fcde
import datetime
Packit Service 82fcde
import email.mime.text
Packit Service 82fcde
import email.utils
Packit Service 82fcde
import json
Packit Service 82fcde
import os
Packit Service 82fcde
import re
Packit Service 82fcde
import shutil
Packit Service 82fcde
import smtplib
Packit Service 82fcde
import stat
Packit Service 82fcde
import subprocess
Packit Service 82fcde
import sys
Packit Service 82fcde
import time
Packit Service 82fcde
import urllib.request
Packit Service 82fcde
Packit Service 82fcde
try:
Packit Service 82fcde
    os.cpu_count
Packit Service 82fcde
except:
Packit Service 82fcde
    import multiprocessing
Packit Service 82fcde
    os.cpu_count = lambda: multiprocessing.cpu_count()
Packit Service 82fcde
Packit Service 82fcde
try:
Packit Service 82fcde
    re.fullmatch
Packit Service 82fcde
except:
Packit Service 82fcde
    re.fullmatch = lambda p,s,f=0: re.match(p+"\\Z",s,f)
Packit Service 82fcde
Packit Service 82fcde
try:
Packit Service 82fcde
    subprocess.run
Packit Service 82fcde
except:
Packit Service 82fcde
    class _CompletedProcess:
Packit Service 82fcde
        def __init__(self, args, returncode, stdout=None, stderr=None):
Packit Service 82fcde
            self.args = args
Packit Service 82fcde
            self.returncode = returncode
Packit Service 82fcde
            self.stdout = stdout
Packit Service 82fcde
            self.stderr = stderr
Packit Service 82fcde
Packit Service 82fcde
    def _run(*popenargs, input=None, timeout=None, check=False, **kwargs):
Packit Service 82fcde
        assert(timeout is None)
Packit Service 82fcde
        with subprocess.Popen(*popenargs, **kwargs) as process:
Packit Service 82fcde
            try:
Packit Service 82fcde
                stdout, stderr = process.communicate(input)
Packit Service 82fcde
            except:
Packit Service 82fcde
                process.kill()
Packit Service 82fcde
                process.wait()
Packit Service 82fcde
                raise
Packit Service 82fcde
            returncode = process.poll()
Packit Service 82fcde
            if check and returncode:
Packit Service 82fcde
                raise subprocess.CalledProcessError(returncode, popenargs)
Packit Service 82fcde
        return _CompletedProcess(popenargs, returncode, stdout, stderr)
Packit Service 82fcde
Packit Service 82fcde
    subprocess.run = _run
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
class Context(object):
Packit Service 82fcde
    """The global state associated with builds in a given directory."""
Packit Service 82fcde
Packit Service 82fcde
    def __init__(self, topdir, parallelism, keep, replace_sources, strip,
Packit Service 82fcde
                 action):
Packit Service 82fcde
        """Initialize the context."""
Packit Service 82fcde
        self.topdir = topdir
Packit Service 82fcde
        self.parallelism = parallelism
Packit Service 82fcde
        self.keep = keep
Packit Service 82fcde
        self.replace_sources = replace_sources
Packit Service 82fcde
        self.strip = strip
Packit Service 82fcde
        self.srcdir = os.path.join(topdir, 'src')
Packit Service 82fcde
        self.versions_json = os.path.join(self.srcdir, 'versions.json')
Packit Service 82fcde
        self.build_state_json = os.path.join(topdir, 'build-state.json')
Packit Service 82fcde
        self.bot_config_json = os.path.join(topdir, 'bot-config.json')
Packit Service 82fcde
        self.installdir = os.path.join(topdir, 'install')
Packit Service 82fcde
        self.host_libraries_installdir = os.path.join(self.installdir,
Packit Service 82fcde
                                                      'host-libraries')
Packit Service 82fcde
        self.builddir = os.path.join(topdir, 'build')
Packit Service 82fcde
        self.logsdir = os.path.join(topdir, 'logs')
Packit Service 82fcde
        self.logsdir_old = os.path.join(topdir, 'logs-old')
Packit Service 82fcde
        self.makefile = os.path.join(self.builddir, 'Makefile')
Packit Service 82fcde
        self.wrapper = os.path.join(self.builddir, 'wrapper')
Packit Service 82fcde
        self.save_logs = os.path.join(self.builddir, 'save-logs')
Packit Service 82fcde
        self.script_text = self.get_script_text()
Packit Service 82fcde
        if action != 'checkout':
Packit Service 82fcde
            self.build_triplet = self.get_build_triplet()
Packit Service 82fcde
            self.glibc_version = self.get_glibc_version()
Packit Service 82fcde
        self.configs = {}
Packit Service 82fcde
        self.glibc_configs = {}
Packit Service 82fcde
        self.makefile_pieces = ['.PHONY: all\n']
Packit Service 82fcde
        self.add_all_configs()
Packit Service 82fcde
        self.load_versions_json()
Packit Service 82fcde
        self.load_build_state_json()
Packit Service 82fcde
        self.status_log_list = []
Packit Service 82fcde
        self.email_warning = False
Packit Service 82fcde
Packit Service 82fcde
    def get_script_text(self):
Packit Service 82fcde
        """Return the text of this script."""
Packit Service 82fcde
        with open(sys.argv[0], 'r') as f:
Packit Service 82fcde
            return f.read()
Packit Service 82fcde
Packit Service 82fcde
    def exec_self(self):
Packit Service 82fcde
        """Re-execute this script with the same arguments."""
Packit Service 82fcde
        sys.stdout.flush()
Packit Service 82fcde
        os.execv(sys.executable, [sys.executable] + sys.argv)
Packit Service 82fcde
Packit Service 82fcde
    def get_build_triplet(self):
Packit Service 82fcde
        """Determine the build triplet with config.guess."""
Packit Service 82fcde
        config_guess = os.path.join(self.component_srcdir('gcc'),
Packit Service 82fcde
                                    'config.guess')
Packit Service 82fcde
        cg_out = subprocess.run([config_guess], stdout=subprocess.PIPE,
Packit Service 82fcde
                                check=True, universal_newlines=True).stdout
Packit Service 82fcde
        return cg_out.rstrip()
Packit Service 82fcde
Packit Service 82fcde
    def get_glibc_version(self):
Packit Service 82fcde
        """Determine the glibc version number (major.minor)."""
Packit Service 82fcde
        version_h = os.path.join(self.component_srcdir('glibc'), 'version.h')
Packit Service 82fcde
        with open(version_h, 'r') as f:
Packit Service 82fcde
            lines = f.readlines()
Packit Service 82fcde
        starttext = '#define VERSION "'
Packit Service 82fcde
        for l in lines:
Packit Service 82fcde
            if l.startswith(starttext):
Packit Service 82fcde
                l = l[len(starttext):]
Packit Service 82fcde
                l = l.rstrip('"\n')
Packit Service 82fcde
                m = re.fullmatch('([0-9]+)\.([0-9]+)[.0-9]*', l)
Packit Service 82fcde
                return '%s.%s' % m.group(1, 2)
Packit Service 82fcde
        print('error: could not determine glibc version')
Packit Service 82fcde
        exit(1)
Packit Service 82fcde
Packit Service 82fcde
    def add_all_configs(self):
Packit Service 82fcde
        """Add all known glibc build configurations."""
Packit Service 82fcde
        self.add_config(arch='aarch64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        extra_glibcs=[{'variant': 'disable-multi-arch',
Packit Service 82fcde
                                       'cfg': ['--disable-multi-arch']}])
Packit Service 82fcde
        self.add_config(arch='aarch64_be',
Packit Service 82fcde
                        os_name='linux-gnu')
Packit Service 82fcde
        self.add_config(arch='alpha',
Packit Service 82fcde
                        os_name='linux-gnu')
Packit Service 82fcde
        self.add_config(arch='arm',
Packit Service 82fcde
                        os_name='linux-gnueabi')
Packit Service 82fcde
        self.add_config(arch='armeb',
Packit Service 82fcde
                        os_name='linux-gnueabi')
Packit Service 82fcde
        self.add_config(arch='armeb',
Packit Service 82fcde
                        os_name='linux-gnueabi',
Packit Service 82fcde
                        variant='be8',
Packit Service 82fcde
                        gcc_cfg=['--with-arch=armv7-a'])
Packit Service 82fcde
        self.add_config(arch='arm',
Packit Service 82fcde
                        os_name='linux-gnueabihf',
Packit Service 82fcde
                        gcc_cfg=['--with-float=hard', '--with-cpu=arm926ej-s'],
Packit Service 82fcde
                        extra_glibcs=[{'variant': 'v7a',
Packit Service 82fcde
                                       'ccopts': '-march=armv7-a -mfpu=vfpv3'},
Packit Service 82fcde
                                      {'variant': 'v7a-disable-multi-arch',
Packit Service 82fcde
                                       'ccopts': '-march=armv7-a -mfpu=vfpv3',
Packit Service 82fcde
                                       'cfg': ['--disable-multi-arch']}])
Packit Service 82fcde
        self.add_config(arch='armeb',
Packit Service 82fcde
                        os_name='linux-gnueabihf',
Packit Service 82fcde
                        gcc_cfg=['--with-float=hard', '--with-cpu=arm926ej-s'])
Packit Service 82fcde
        self.add_config(arch='armeb',
Packit Service 82fcde
                        os_name='linux-gnueabihf',
Packit Service 82fcde
                        variant='be8',
Packit Service 82fcde
                        gcc_cfg=['--with-float=hard', '--with-arch=armv7-a',
Packit Service 82fcde
                                 '--with-fpu=vfpv3'])
Packit Service 82fcde
        self.add_config(arch='hppa',
Packit Service 82fcde
                        os_name='linux-gnu')
Packit Service 82fcde
        self.add_config(arch='i686',
Packit Service 82fcde
                        os_name='gnu')
Packit Service 82fcde
        self.add_config(arch='ia64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        first_gcc_cfg=['--with-system-libunwind'])
Packit Service 82fcde
        self.add_config(arch='m68k',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib'])
Packit Service 82fcde
        self.add_config(arch='m68k',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='coldfire',
Packit Service 82fcde
                        gcc_cfg=['--with-arch=cf', '--disable-multilib'])
Packit Service 82fcde
        self.add_config(arch='m68k',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='coldfire-soft',
Packit Service 82fcde
                        gcc_cfg=['--with-arch=cf', '--with-cpu=54455',
Packit Service 82fcde
                                 '--disable-multilib'])
Packit Service 82fcde
        self.add_config(arch='microblaze',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib'])
Packit Service 82fcde
        self.add_config(arch='microblazeel',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib'])
Packit Service 82fcde
        self.add_config(arch='mips64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--with-mips-plt'],
Packit Service 82fcde
                        glibcs=[{'variant': 'n32'},
Packit Service 82fcde
                                {'arch': 'mips',
Packit Service 82fcde
                                 'ccopts': '-mabi=32'},
Packit Service 82fcde
                                {'variant': 'n64',
Packit Service 82fcde
                                 'ccopts': '-mabi=64'}])
Packit Service 82fcde
        self.add_config(arch='mips64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='soft',
Packit Service 82fcde
                        gcc_cfg=['--with-mips-plt', '--with-float=soft'],
Packit Service 82fcde
                        glibcs=[{'variant': 'n32-soft'},
Packit Service 82fcde
                                {'variant': 'soft',
Packit Service 82fcde
                                 'arch': 'mips',
Packit Service 82fcde
                                 'ccopts': '-mabi=32'},
Packit Service 82fcde
                                {'variant': 'n64-soft',
Packit Service 82fcde
                                 'ccopts': '-mabi=64'}])
Packit Service 82fcde
        self.add_config(arch='mips64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='nan2008',
Packit Service 82fcde
                        gcc_cfg=['--with-mips-plt', '--with-nan=2008',
Packit Service 82fcde
                                 '--with-arch-64=mips64r2',
Packit Service 82fcde
                                 '--with-arch-32=mips32r2'],
Packit Service 82fcde
                        glibcs=[{'variant': 'n32-nan2008'},
Packit Service 82fcde
                                {'variant': 'nan2008',
Packit Service 82fcde
                                 'arch': 'mips',
Packit Service 82fcde
                                 'ccopts': '-mabi=32'},
Packit Service 82fcde
                                {'variant': 'n64-nan2008',
Packit Service 82fcde
                                 'ccopts': '-mabi=64'}])
Packit Service 82fcde
        self.add_config(arch='mips64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='nan2008-soft',
Packit Service 82fcde
                        gcc_cfg=['--with-mips-plt', '--with-nan=2008',
Packit Service 82fcde
                                 '--with-arch-64=mips64r2',
Packit Service 82fcde
                                 '--with-arch-32=mips32r2',
Packit Service 82fcde
                                 '--with-float=soft'],
Packit Service 82fcde
                        glibcs=[{'variant': 'n32-nan2008-soft'},
Packit Service 82fcde
                                {'variant': 'nan2008-soft',
Packit Service 82fcde
                                 'arch': 'mips',
Packit Service 82fcde
                                 'ccopts': '-mabi=32'},
Packit Service 82fcde
                                {'variant': 'n64-nan2008-soft',
Packit Service 82fcde
                                 'ccopts': '-mabi=64'}])
Packit Service 82fcde
        self.add_config(arch='mips64el',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--with-mips-plt'],
Packit Service 82fcde
                        glibcs=[{'variant': 'n32'},
Packit Service 82fcde
                                {'arch': 'mipsel',
Packit Service 82fcde
                                 'ccopts': '-mabi=32'},
Packit Service 82fcde
                                {'variant': 'n64',
Packit Service 82fcde
                                 'ccopts': '-mabi=64'}])
Packit Service 82fcde
        self.add_config(arch='mips64el',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='soft',
Packit Service 82fcde
                        gcc_cfg=['--with-mips-plt', '--with-float=soft'],
Packit Service 82fcde
                        glibcs=[{'variant': 'n32-soft'},
Packit Service 82fcde
                                {'variant': 'soft',
Packit Service 82fcde
                                 'arch': 'mipsel',
Packit Service 82fcde
                                 'ccopts': '-mabi=32'},
Packit Service 82fcde
                                {'variant': 'n64-soft',
Packit Service 82fcde
                                 'ccopts': '-mabi=64'}])
Packit Service 82fcde
        self.add_config(arch='mips64el',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='nan2008',
Packit Service 82fcde
                        gcc_cfg=['--with-mips-plt', '--with-nan=2008',
Packit Service 82fcde
                                 '--with-arch-64=mips64r2',
Packit Service 82fcde
                                 '--with-arch-32=mips32r2'],
Packit Service 82fcde
                        glibcs=[{'variant': 'n32-nan2008'},
Packit Service 82fcde
                                {'variant': 'nan2008',
Packit Service 82fcde
                                 'arch': 'mipsel',
Packit Service 82fcde
                                 'ccopts': '-mabi=32'},
Packit Service 82fcde
                                {'variant': 'n64-nan2008',
Packit Service 82fcde
                                 'ccopts': '-mabi=64'}])
Packit Service 82fcde
        self.add_config(arch='mips64el',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='nan2008-soft',
Packit Service 82fcde
                        gcc_cfg=['--with-mips-plt', '--with-nan=2008',
Packit Service 82fcde
                                 '--with-arch-64=mips64r2',
Packit Service 82fcde
                                 '--with-arch-32=mips32r2',
Packit Service 82fcde
                                 '--with-float=soft'],
Packit Service 82fcde
                        glibcs=[{'variant': 'n32-nan2008-soft'},
Packit Service 82fcde
                                {'variant': 'nan2008-soft',
Packit Service 82fcde
                                 'arch': 'mipsel',
Packit Service 82fcde
                                 'ccopts': '-mabi=32'},
Packit Service 82fcde
                                {'variant': 'n64-nan2008-soft',
Packit Service 82fcde
                                 'ccopts': '-mabi=64'}])
Packit Service 82fcde
        self.add_config(arch='nios2',
Packit Service 82fcde
                        os_name='linux-gnu')
Packit Service 82fcde
        self.add_config(arch='powerpc',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib', '--enable-secureplt'],
Packit Service 82fcde
                        extra_glibcs=[{'variant': 'power4',
Packit Service 82fcde
                                       'ccopts': '-mcpu=power4',
Packit Service 82fcde
                                       'cfg': ['--with-cpu=power4']}])
Packit Service 82fcde
        self.add_config(arch='powerpc',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='soft',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib', '--with-float=soft',
Packit Service 82fcde
                                 '--enable-secureplt'])
Packit Service 82fcde
        self.add_config(arch='powerpc64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib', '--enable-secureplt'])
Packit Service 82fcde
        self.add_config(arch='powerpc64le',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib', '--enable-secureplt'])
Packit Service 82fcde
        self.add_config(arch='powerpc',
Packit Service 82fcde
                        os_name='linux-gnuspe',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib', '--enable-secureplt',
Packit Service 82fcde
                                 '--enable-e500-double', '--enable-obsolete'])
Packit Service 82fcde
        self.add_config(arch='powerpc',
Packit Service 82fcde
                        os_name='linux-gnuspe',
Packit Service 82fcde
                        variant='e500v1',
Packit Service 82fcde
                        gcc_cfg=['--disable-multilib', '--enable-secureplt',
Packit Service 82fcde
                                 '--enable-obsolete'])
Packit Service 82fcde
        self.add_config(arch='riscv64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='rv64imac-lp64',
Packit Service 82fcde
                        gcc_cfg=['--with-arch=rv64imac', '--with-abi=lp64',
Packit Service 82fcde
                                 '--disable-multilib'])
Packit Service 82fcde
        self.add_config(arch='riscv64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='rv64imafdc-lp64',
Packit Service 82fcde
                        gcc_cfg=['--with-arch=rv64imafdc', '--with-abi=lp64',
Packit Service 82fcde
                                 '--disable-multilib'])
Packit Service 82fcde
        self.add_config(arch='riscv64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='rv64imafdc-lp64d',
Packit Service 82fcde
                        gcc_cfg=['--with-arch=rv64imafdc', '--with-abi=lp64d',
Packit Service 82fcde
                                 '--disable-multilib'])
Packit Service 82fcde
        self.add_config(arch='s390x',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        glibcs=[{},
Packit Service 82fcde
                                {'arch': 's390', 'ccopts': '-m31'}])
Packit Service 82fcde
        self.add_config(arch='sh3',
Packit Service 82fcde
                        os_name='linux-gnu')
Packit Service 82fcde
        self.add_config(arch='sh3eb',
Packit Service 82fcde
                        os_name='linux-gnu')
Packit Service 82fcde
        self.add_config(arch='sh4',
Packit Service 82fcde
                        os_name='linux-gnu')
Packit Service 82fcde
        self.add_config(arch='sh4eb',
Packit Service 82fcde
                        os_name='linux-gnu')
Packit Service 82fcde
        self.add_config(arch='sh4',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='soft',
Packit Service 82fcde
                        gcc_cfg=['--without-fp'])
Packit Service 82fcde
        self.add_config(arch='sh4eb',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        variant='soft',
Packit Service 82fcde
                        gcc_cfg=['--without-fp'])
Packit Service 82fcde
        self.add_config(arch='sparc64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        glibcs=[{},
Packit Service 82fcde
                                {'arch': 'sparcv9',
Packit Service 82fcde
                                 'ccopts': '-m32 -mlong-double-128'}],
Packit Service 82fcde
                        extra_glibcs=[{'variant': 'disable-multi-arch',
Packit Service 82fcde
                                       'cfg': ['--disable-multi-arch']},
Packit Service 82fcde
                                      {'variant': 'disable-multi-arch',
Packit Service 82fcde
                                       'arch': 'sparcv9',
Packit Service 82fcde
                                       'ccopts': '-m32 -mlong-double-128',
Packit Service 82fcde
                                       'cfg': ['--disable-multi-arch']}])
Packit Service 82fcde
        self.add_config(arch='x86_64',
Packit Service 82fcde
                        os_name='linux-gnu',
Packit Service 82fcde
                        gcc_cfg=['--with-multilib-list=m64,m32,mx32'],
Packit Service 82fcde
                        glibcs=[{},
Packit Service 82fcde
                                {'variant': 'x32', 'ccopts': '-mx32'},
Packit Service 82fcde
                                {'arch': 'i686', 'ccopts': '-m32 -march=i686'}],
Packit Service 82fcde
                        extra_glibcs=[{'variant': 'disable-multi-arch',
Packit Service 82fcde
                                       'cfg': ['--disable-multi-arch']},
Packit Service 82fcde
                                      {'variant': 'static-pie',
Packit Service 82fcde
                                       'cfg': ['--enable-static-pie']},
Packit Service 82fcde
                                      {'variant': 'x32-static-pie',
Packit Service 82fcde
                                       'ccopts': '-mx32',
Packit Service 82fcde
                                       'cfg': ['--enable-static-pie']},
Packit Service 82fcde
                                      {'variant': 'static-pie',
Packit Service 82fcde
                                       'arch': 'i686',
Packit Service 82fcde
                                       'ccopts': '-m32 -march=i686',
Packit Service 82fcde
                                       'cfg': ['--enable-static-pie']},
Packit Service 82fcde
                                      {'variant': 'disable-multi-arch',
Packit Service 82fcde
                                       'arch': 'i686',
Packit Service 82fcde
                                       'ccopts': '-m32 -march=i686',
Packit Service 82fcde
                                       'cfg': ['--disable-multi-arch']},
Packit Service 82fcde
                                      {'arch': 'i486',
Packit Service 82fcde
                                       'ccopts': '-m32 -march=i486'},
Packit Service 82fcde
                                      {'arch': 'i586',
Packit Service 82fcde
                                       'ccopts': '-m32 -march=i586'}])
Packit Service 82fcde
Packit Service 82fcde
    def add_config(self, **args):
Packit Service 82fcde
        """Add an individual build configuration."""
Packit Service 82fcde
        cfg = Config(self, **args)
Packit Service 82fcde
        if cfg.name in self.configs:
Packit Service 82fcde
            print('error: duplicate config %s' % cfg.name)
Packit Service 82fcde
            exit(1)
Packit Service 82fcde
        self.configs[cfg.name] = cfg
Packit Service 82fcde
        for c in cfg.all_glibcs:
Packit Service 82fcde
            if c.name in self.glibc_configs:
Packit Service 82fcde
                print('error: duplicate glibc config %s' % c.name)
Packit Service 82fcde
                exit(1)
Packit Service 82fcde
            self.glibc_configs[c.name] = c
Packit Service 82fcde
Packit Service 82fcde
    def component_srcdir(self, component):
Packit Service 82fcde
        """Return the source directory for a given component, e.g. gcc."""
Packit Service 82fcde
        return os.path.join(self.srcdir, component)
Packit Service 82fcde
Packit Service 82fcde
    def component_builddir(self, action, config, component, subconfig=None):
Packit Service 82fcde
        """Return the directory to use for a build."""
Packit Service 82fcde
        if config is None:
Packit Service 82fcde
            # Host libraries.
Packit Service 82fcde
            assert subconfig is None
Packit Service 82fcde
            return os.path.join(self.builddir, action, component)
Packit Service 82fcde
        if subconfig is None:
Packit Service 82fcde
            return os.path.join(self.builddir, action, config, component)
Packit Service 82fcde
        else:
Packit Service 82fcde
            # glibc build as part of compiler build.
Packit Service 82fcde
            return os.path.join(self.builddir, action, config, component,
Packit Service 82fcde
                                subconfig)
Packit Service 82fcde
Packit Service 82fcde
    def compiler_installdir(self, config):
Packit Service 82fcde
        """Return the directory in which to install a compiler."""
Packit Service 82fcde
        return os.path.join(self.installdir, 'compilers', config)
Packit Service 82fcde
Packit Service 82fcde
    def compiler_bindir(self, config):
Packit Service 82fcde
        """Return the directory in which to find compiler binaries."""
Packit Service 82fcde
        return os.path.join(self.compiler_installdir(config), 'bin')
Packit Service 82fcde
Packit Service 82fcde
    def compiler_sysroot(self, config):
Packit Service 82fcde
        """Return the sysroot directory for a compiler."""
Packit Service 82fcde
        return os.path.join(self.compiler_installdir(config), 'sysroot')
Packit Service 82fcde
Packit Service 82fcde
    def glibc_installdir(self, config):
Packit Service 82fcde
        """Return the directory in which to install glibc."""
Packit Service 82fcde
        return os.path.join(self.installdir, 'glibcs', config)
Packit Service 82fcde
Packit Service 82fcde
    def run_builds(self, action, configs):
Packit Service 82fcde
        """Run the requested builds."""
Packit Service 82fcde
        if action == 'checkout':
Packit Service 82fcde
            self.checkout(configs)
Packit Service 82fcde
            return
Packit Service 82fcde
        if action == 'bot-cycle':
Packit Service 82fcde
            if configs:
Packit Service 82fcde
                print('error: configurations specified for bot-cycle')
Packit Service 82fcde
                exit(1)
Packit Service 82fcde
            self.bot_cycle()
Packit Service 82fcde
            return
Packit Service 82fcde
        if action == 'bot':
Packit Service 82fcde
            if configs:
Packit Service 82fcde
                print('error: configurations specified for bot')
Packit Service 82fcde
                exit(1)
Packit Service 82fcde
            self.bot()
Packit Service 82fcde
            return
Packit Service 82fcde
        if action == 'host-libraries' and configs:
Packit Service 82fcde
            print('error: configurations specified for host-libraries')
Packit Service 82fcde
            exit(1)
Packit Service 82fcde
        self.clear_last_build_state(action)
Packit Service 82fcde
        build_time = datetime.datetime.utcnow()
Packit Service 82fcde
        if action == 'host-libraries':
Packit Service 82fcde
            build_components = ('gmp', 'mpfr', 'mpc')
Packit Service 82fcde
            old_components = ()
Packit Service 82fcde
            old_versions = {}
Packit Service 82fcde
            self.build_host_libraries()
Packit Service 82fcde
        elif action == 'compilers':
Packit Service 82fcde
            build_components = ('binutils', 'gcc', 'glibc', 'linux', 'mig',
Packit Service 82fcde
                                'gnumach', 'hurd')
Packit Service 82fcde
            old_components = ('gmp', 'mpfr', 'mpc')
Packit Service 82fcde
            old_versions = self.build_state['host-libraries']['build-versions']
Packit Service 82fcde
            self.build_compilers(configs)
Packit Service 82fcde
        else:
Packit Service 82fcde
            build_components = ('glibc',)
Packit Service 82fcde
            old_components = ('gmp', 'mpfr', 'mpc', 'binutils', 'gcc', 'linux',
Packit Service 82fcde
                              'mig', 'gnumach', 'hurd')
Packit Service 82fcde
            old_versions = self.build_state['compilers']['build-versions']
Packit Service 82fcde
            self.build_glibcs(configs)
Packit Service 82fcde
        self.write_files()
Packit Service 82fcde
        self.do_build()
Packit Service 82fcde
        if configs:
Packit Service 82fcde
            # Partial build, do not update stored state.
Packit Service 82fcde
            return
Packit Service 82fcde
        build_versions = {}
Packit Service 82fcde
        for k in build_components:
Packit Service 82fcde
            if k in self.versions:
Packit Service 82fcde
                build_versions[k] = {'version': self.versions[k]['version'],
Packit Service 82fcde
                                     'revision': self.versions[k]['revision']}
Packit Service 82fcde
        for k in old_components:
Packit Service 82fcde
            if k in old_versions:
Packit Service 82fcde
                build_versions[k] = {'version': old_versions[k]['version'],
Packit Service 82fcde
                                     'revision': old_versions[k]['revision']}
Packit Service 82fcde
        self.update_build_state(action, build_time, build_versions)
Packit Service 82fcde
Packit Service 82fcde
    @staticmethod
Packit Service 82fcde
    def remove_dirs(*args):
Packit Service 82fcde
        """Remove directories and their contents if they exist."""
Packit Service 82fcde
        for dir in args:
Packit Service 82fcde
            shutil.rmtree(dir, ignore_errors=True)
Packit Service 82fcde
Packit Service 82fcde
    @staticmethod
Packit Service 82fcde
    def remove_recreate_dirs(*args):
Packit Service 82fcde
        """Remove directories if they exist, and create them as empty."""
Packit Service 82fcde
        Context.remove_dirs(*args)
Packit Service 82fcde
        for dir in args:
Packit Service 82fcde
            os.makedirs(dir, exist_ok=True)
Packit Service 82fcde
Packit Service 82fcde
    def add_makefile_cmdlist(self, target, cmdlist, logsdir):
Packit Service 82fcde
        """Add makefile text for a list of commands."""
Packit Service 82fcde
        commands = cmdlist.makefile_commands(self.wrapper, logsdir)
Packit Service 82fcde
        self.makefile_pieces.append('all: %s\n.PHONY: %s\n%s:\n%s\n' %
Packit Service 82fcde
                                    (target, target, target, commands))
Packit Service 82fcde
        self.status_log_list.extend(cmdlist.status_logs(logsdir))
Packit Service 82fcde
Packit Service 82fcde
    def write_files(self):
Packit Service 82fcde
        """Write out the Makefile and wrapper script."""
Packit Service 82fcde
        mftext = ''.join(self.makefile_pieces)
Packit Service 82fcde
        with open(self.makefile, 'w') as f:
Packit Service 82fcde
            f.write(mftext)
Packit Service 82fcde
        wrapper_text = (
Packit Service 82fcde
            '#!/bin/sh\n'
Packit Service 82fcde
            'prev_base=$1\n'
Packit Service 82fcde
            'this_base=$2\n'
Packit Service 82fcde
            'desc=$3\n'
Packit Service 82fcde
            'dir=$4\n'
Packit Service 82fcde
            'path=$5\n'
Packit Service 82fcde
            'shift 5\n'
Packit Service 82fcde
            'prev_status=$prev_base-status.txt\n'
Packit Service 82fcde
            'this_status=$this_base-status.txt\n'
Packit Service 82fcde
            'this_log=$this_base-log.txt\n'
Packit Service 82fcde
            'date > "$this_log"\n'
Packit Service 82fcde
            'echo >> "$this_log"\n'
Packit Service 82fcde
            'echo "Description: $desc" >> "$this_log"\n'
Packit Service 82fcde
            'printf "%s" "Command:" >> "$this_log"\n'
Packit Service 82fcde
            'for word in "$@"; do\n'
Packit Service 82fcde
            '  if expr "$word" : "[]+,./0-9@A-Z_a-z-]\\\\{1,\\\\}\\$" > /dev/null; then\n'
Packit Service 82fcde
            '    printf " %s" "$word"\n'
Packit Service 82fcde
            '  else\n'
Packit Service 82fcde
            '    printf " \'"\n'
Packit Service 82fcde
            '    printf "%s" "$word" | sed -e "s/\'/\'\\\\\\\\\'\'/"\n'
Packit Service 82fcde
            '    printf "\'"\n'
Packit Service 82fcde
            '  fi\n'
Packit Service 82fcde
            'done >> "$this_log"\n'
Packit Service 82fcde
            'echo >> "$this_log"\n'
Packit Service 82fcde
            'echo "Directory: $dir" >> "$this_log"\n'
Packit Service 82fcde
            'echo "Path addition: $path" >> "$this_log"\n'
Packit Service 82fcde
            'echo >> "$this_log"\n'
Packit Service 82fcde
            'record_status ()\n'
Packit Service 82fcde
            '{\n'
Packit Service 82fcde
            '  echo >> "$this_log"\n'
Packit Service 82fcde
            '  echo "$1: $desc" > "$this_status"\n'
Packit Service 82fcde
            '  echo "$1: $desc" >> "$this_log"\n'
Packit Service 82fcde
            '  echo >> "$this_log"\n'
Packit Service 82fcde
            '  date >> "$this_log"\n'
Packit Service 82fcde
            '  echo "$1: $desc"\n'
Packit Service 82fcde
            '  exit 0\n'
Packit Service 82fcde
            '}\n'
Packit Service 82fcde
            'check_error ()\n'
Packit Service 82fcde
            '{\n'
Packit Service 82fcde
            '  if [ "$1" != "0" ]; then\n'
Packit Service 82fcde
            '    record_status FAIL\n'
Packit Service 82fcde
            '  fi\n'
Packit Service 82fcde
            '}\n'
Packit Service 82fcde
            'if [ "$prev_base" ] && ! grep -q "^PASS" "$prev_status"; then\n'
Packit Service 82fcde
            '    record_status UNRESOLVED\n'
Packit Service 82fcde
            'fi\n'
Packit Service 82fcde
            'if [ "$dir" ]; then\n'
Packit Service 82fcde
            '  cd "$dir"\n'
Packit Service 82fcde
            '  check_error "$?"\n'
Packit Service 82fcde
            'fi\n'
Packit Service 82fcde
            'if [ "$path" ]; then\n'
Packit Service 82fcde
            '  PATH=$path:$PATH\n'
Packit Service 82fcde
            'fi\n'
Packit Service 82fcde
            '"$@" < /dev/null >> "$this_log" 2>&1\n'
Packit Service 82fcde
            'check_error "$?"\n'
Packit Service 82fcde
            'record_status PASS\n')
Packit Service 82fcde
        with open(self.wrapper, 'w') as f:
Packit Service 82fcde
            f.write(wrapper_text)
Packit Service 82fcde
        # Mode 0o755.
Packit Service 82fcde
        mode_exec = (stat.S_IRWXU|stat.S_IRGRP|stat.S_IXGRP|
Packit Service 82fcde
                     stat.S_IROTH|stat.S_IXOTH)
Packit Service 82fcde
        os.chmod(self.wrapper, mode_exec)
Packit Service 82fcde
        save_logs_text = (
Packit Service 82fcde
            '#!/bin/sh\n'
Packit Service 82fcde
            'if ! [ -f tests.sum ]; then\n'
Packit Service 82fcde
            '  echo "No test summary available."\n'
Packit Service 82fcde
            '  exit 0\n'
Packit Service 82fcde
            'fi\n'
Packit Service 82fcde
            'save_file ()\n'
Packit Service 82fcde
            '{\n'
Packit Service 82fcde
            '  echo "Contents of $1:"\n'
Packit Service 82fcde
            '  echo\n'
Packit Service 82fcde
            '  cat "$1"\n'
Packit Service 82fcde
            '  echo\n'
Packit Service 82fcde
            '  echo "End of contents of $1."\n'
Packit Service 82fcde
            '  echo\n'
Packit Service 82fcde
            '}\n'
Packit Service 82fcde
            'save_file tests.sum\n'
Packit Service 82fcde
            'non_pass_tests=$(grep -v "^PASS: " tests.sum | sed -e "s/^PASS: //")\n'
Packit Service 82fcde
            'for t in $non_pass_tests; do\n'
Packit Service 82fcde
            '  if [ -f "$t.out" ]; then\n'
Packit Service 82fcde
            '    save_file "$t.out"\n'
Packit Service 82fcde
            '  fi\n'
Packit Service 82fcde
            'done\n')
Packit Service 82fcde
        with open(self.save_logs, 'w') as f:
Packit Service 82fcde
            f.write(save_logs_text)
Packit Service 82fcde
        os.chmod(self.save_logs, mode_exec)
Packit Service 82fcde
Packit Service 82fcde
    def do_build(self):
Packit Service 82fcde
        """Do the actual build."""
Packit Service 82fcde
        cmd = ['make', '-j%d' % self.parallelism]
Packit Service 82fcde
        subprocess.run(cmd, cwd=self.builddir, check=True)
Packit Service 82fcde
Packit Service 82fcde
    def build_host_libraries(self):
Packit Service 82fcde
        """Build the host libraries."""
Packit Service 82fcde
        installdir = self.host_libraries_installdir
Packit Service 82fcde
        builddir = os.path.join(self.builddir, 'host-libraries')
Packit Service 82fcde
        logsdir = os.path.join(self.logsdir, 'host-libraries')
Packit Service 82fcde
        self.remove_recreate_dirs(installdir, builddir, logsdir)
Packit Service 82fcde
        cmdlist = CommandList('host-libraries', self.keep)
Packit Service 82fcde
        self.build_host_library(cmdlist, 'gmp')
Packit Service 82fcde
        self.build_host_library(cmdlist, 'mpfr',
Packit Service 82fcde
                                ['--with-gmp=%s' % installdir])
Packit Service 82fcde
        self.build_host_library(cmdlist, 'mpc',
Packit Service 82fcde
                                ['--with-gmp=%s' % installdir,
Packit Service 82fcde
                                '--with-mpfr=%s' % installdir])
Packit Service 82fcde
        cmdlist.add_command('done', ['touch', os.path.join(installdir, 'ok')])
Packit Service 82fcde
        self.add_makefile_cmdlist('host-libraries', cmdlist, logsdir)
Packit Service 82fcde
Packit Service 82fcde
    def build_host_library(self, cmdlist, lib, extra_opts=None):
Packit Service 82fcde
        """Build one host library."""
Packit Service 82fcde
        srcdir = self.component_srcdir(lib)
Packit Service 82fcde
        builddir = self.component_builddir('host-libraries', None, lib)
Packit Service 82fcde
        installdir = self.host_libraries_installdir
Packit Service 82fcde
        cmdlist.push_subdesc(lib)
Packit Service 82fcde
        cmdlist.create_use_dir(builddir)
Packit Service 82fcde
        cfg_cmd = [os.path.join(srcdir, 'configure'),
Packit Service 82fcde
                   '--prefix=%s' % installdir,
Packit Service 82fcde
                   '--disable-shared']
Packit Service 82fcde
        if extra_opts:
Packit Service 82fcde
            cfg_cmd.extend (extra_opts)
Packit Service 82fcde
        cmdlist.add_command('configure', cfg_cmd)
Packit Service 82fcde
        cmdlist.add_command('build', ['make'])
Packit Service 82fcde
        cmdlist.add_command('check', ['make', 'check'])
Packit Service 82fcde
        cmdlist.add_command('install', ['make', 'install'])
Packit Service 82fcde
        cmdlist.cleanup_dir()
Packit Service 82fcde
        cmdlist.pop_subdesc()
Packit Service 82fcde
Packit Service 82fcde
    def build_compilers(self, configs):
Packit Service 82fcde
        """Build the compilers."""
Packit Service 82fcde
        if not configs:
Packit Service 82fcde
            self.remove_dirs(os.path.join(self.builddir, 'compilers'))
Packit Service 82fcde
            self.remove_dirs(os.path.join(self.installdir, 'compilers'))
Packit Service 82fcde
            self.remove_dirs(os.path.join(self.logsdir, 'compilers'))
Packit Service 82fcde
            configs = sorted(self.configs.keys())
Packit Service 82fcde
        for c in configs:
Packit Service 82fcde
            self.configs[c].build()
Packit Service 82fcde
Packit Service 82fcde
    def build_glibcs(self, configs):
Packit Service 82fcde
        """Build the glibcs."""
Packit Service 82fcde
        if not configs:
Packit Service 82fcde
            self.remove_dirs(os.path.join(self.builddir, 'glibcs'))
Packit Service 82fcde
            self.remove_dirs(os.path.join(self.installdir, 'glibcs'))
Packit Service 82fcde
            self.remove_dirs(os.path.join(self.logsdir, 'glibcs'))
Packit Service 82fcde
            configs = sorted(self.glibc_configs.keys())
Packit Service 82fcde
        for c in configs:
Packit Service 82fcde
            self.glibc_configs[c].build()
Packit Service 82fcde
Packit Service 82fcde
    def load_versions_json(self):
Packit Service 82fcde
        """Load information about source directory versions."""
Packit Service 82fcde
        if not os.access(self.versions_json, os.F_OK):
Packit Service 82fcde
            self.versions = {}
Packit Service 82fcde
            return
Packit Service 82fcde
        with open(self.versions_json, 'r') as f:
Packit Service 82fcde
            self.versions = json.load(f)
Packit Service 82fcde
Packit Service 82fcde
    def store_json(self, data, filename):
Packit Service 82fcde
        """Store information in a JSON file."""
Packit Service 82fcde
        filename_tmp = filename + '.tmp'
Packit Service 82fcde
        with open(filename_tmp, 'w') as f:
Packit Service 82fcde
            json.dump(data, f, indent=2, sort_keys=True)
Packit Service 82fcde
        os.rename(filename_tmp, filename)
Packit Service 82fcde
Packit Service 82fcde
    def store_versions_json(self):
Packit Service 82fcde
        """Store information about source directory versions."""
Packit Service 82fcde
        self.store_json(self.versions, self.versions_json)
Packit Service 82fcde
Packit Service 82fcde
    def set_component_version(self, component, version, explicit, revision):
Packit Service 82fcde
        """Set the version information for a component."""
Packit Service 82fcde
        self.versions[component] = {'version': version,
Packit Service 82fcde
                                    'explicit': explicit,
Packit Service 82fcde
                                    'revision': revision}
Packit Service 82fcde
        self.store_versions_json()
Packit Service 82fcde
Packit Service 82fcde
    def checkout(self, versions):
Packit Service 82fcde
        """Check out the desired component versions."""
Packit Service 82fcde
        default_versions = {'binutils': 'vcs-2.31',
Packit Service 82fcde
                            'gcc': 'vcs-8',
Packit Service 82fcde
                            'glibc': 'vcs-mainline',
Packit Service 82fcde
                            'gmp': '6.1.2',
Packit Service 82fcde
                            'linux': '4.17',
Packit Service 82fcde
                            'mpc': '1.1.0',
Packit Service 82fcde
                            'mpfr': '4.0.1',
Packit Service 82fcde
                            'mig': 'vcs-mainline',
Packit Service 82fcde
                            'gnumach': 'vcs-mainline',
Packit Service 82fcde
                            'hurd': 'vcs-mainline'}
Packit Service 82fcde
        use_versions = {}
Packit Service 82fcde
        explicit_versions = {}
Packit Service 82fcde
        for v in versions:
Packit Service 82fcde
            found_v = False
Packit Service 82fcde
            for k in default_versions.keys():
Packit Service 82fcde
                kx = k + '-'
Packit Service 82fcde
                if v.startswith(kx):
Packit Service 82fcde
                    vx = v[len(kx):]
Packit Service 82fcde
                    if k in use_versions:
Packit Service 82fcde
                        print('error: multiple versions for %s' % k)
Packit Service 82fcde
                        exit(1)
Packit Service 82fcde
                    use_versions[k] = vx
Packit Service 82fcde
                    explicit_versions[k] = True
Packit Service 82fcde
                    found_v = True
Packit Service 82fcde
                    break
Packit Service 82fcde
            if not found_v:
Packit Service 82fcde
                print('error: unknown component in %s' % v)
Packit Service 82fcde
                exit(1)
Packit Service 82fcde
        for k in default_versions.keys():
Packit Service 82fcde
            if k not in use_versions:
Packit Service 82fcde
                if k in self.versions and self.versions[k]['explicit']:
Packit Service 82fcde
                    use_versions[k] = self.versions[k]['version']
Packit Service 82fcde
                    explicit_versions[k] = True
Packit Service 82fcde
                else:
Packit Service 82fcde
                    use_versions[k] = default_versions[k]
Packit Service 82fcde
                    explicit_versions[k] = False
Packit Service 82fcde
        os.makedirs(self.srcdir, exist_ok=True)
Packit Service 82fcde
        for k in sorted(default_versions.keys()):
Packit Service 82fcde
            update = os.access(self.component_srcdir(k), os.F_OK)
Packit Service 82fcde
            v = use_versions[k]
Packit Service 82fcde
            if (update and
Packit Service 82fcde
                k in self.versions and
Packit Service 82fcde
                v != self.versions[k]['version']):
Packit Service 82fcde
                if not self.replace_sources:
Packit Service 82fcde
                    print('error: version of %s has changed from %s to %s, '
Packit Service 82fcde
                          'use --replace-sources to check out again' %
Packit Service 82fcde
                          (k, self.versions[k]['version'], v))
Packit Service 82fcde
                    exit(1)
Packit Service 82fcde
                shutil.rmtree(self.component_srcdir(k))
Packit Service 82fcde
                update = False
Packit Service 82fcde
            if v.startswith('vcs-'):
Packit Service 82fcde
                revision = self.checkout_vcs(k, v[4:], update)
Packit Service 82fcde
            else:
Packit Service 82fcde
                self.checkout_tar(k, v, update)
Packit Service 82fcde
                revision = v
Packit Service 82fcde
            self.set_component_version(k, v, explicit_versions[k], revision)
Packit Service 82fcde
        if self.get_script_text() != self.script_text:
Packit Service 82fcde
            # Rerun the checkout process in case the updated script
Packit Service 82fcde
            # uses different default versions or new components.
Packit Service 82fcde
            self.exec_self()
Packit Service 82fcde
Packit Service 82fcde
    def checkout_vcs(self, component, version, update):
Packit Service 82fcde
        """Check out the given version of the given component from version
Packit Service 82fcde
        control.  Return a revision identifier."""
Packit Service 82fcde
        if component == 'binutils':
Packit Service 82fcde
            git_url = 'git://sourceware.org/git/binutils-gdb.git'
Packit Service 82fcde
            if version == 'mainline':
Packit Service 82fcde
                git_branch = 'master'
Packit Service 82fcde
            else:
Packit Service 82fcde
                trans = str.maketrans({'.': '_'})
Packit Service 82fcde
                git_branch = 'binutils-%s-branch' % version.translate(trans)
Packit Service 82fcde
            return self.git_checkout(component, git_url, git_branch, update)
Packit Service 82fcde
        elif component == 'gcc':
Packit Service 82fcde
            if version == 'mainline':
Packit Service 82fcde
                branch = 'trunk'
Packit Service 82fcde
            else:
Packit Service 82fcde
                trans = str.maketrans({'.': '_'})
Packit Service 82fcde
                branch = 'branches/gcc-%s-branch' % version.translate(trans)
Packit Service 82fcde
            svn_url = 'svn://gcc.gnu.org/svn/gcc/%s' % branch
Packit Service 82fcde
            return self.gcc_checkout(svn_url, update)
Packit Service 82fcde
        elif component == 'glibc':
Packit Service 82fcde
            git_url = 'git://sourceware.org/git/glibc.git'
Packit Service 82fcde
            if version == 'mainline':
Packit Service 82fcde
                git_branch = 'master'
Packit Service 82fcde
            else:
Packit Service 82fcde
                git_branch = 'release/%s/master' % version
Packit Service 82fcde
            r = self.git_checkout(component, git_url, git_branch, update)
Packit Service 82fcde
            self.fix_glibc_timestamps()
Packit Service 82fcde
            return r
Packit Service 82fcde
        elif component == 'gnumach':
Packit Service 82fcde
            git_url = 'git://git.savannah.gnu.org/hurd/gnumach.git'
Packit Service 82fcde
            git_branch = 'master'
Packit Service 82fcde
            r = self.git_checkout(component, git_url, git_branch, update)
Packit Service 82fcde
            subprocess.run(['autoreconf', '-i'],
Packit Service 82fcde
                           cwd=self.component_srcdir(component), check=True)
Packit Service 82fcde
            return r
Packit Service 82fcde
        elif component == 'mig':
Packit Service 82fcde
            git_url = 'git://git.savannah.gnu.org/hurd/mig.git'
Packit Service 82fcde
            git_branch = 'master'
Packit Service 82fcde
            r = self.git_checkout(component, git_url, git_branch, update)
Packit Service 82fcde
            subprocess.run(['autoreconf', '-i'],
Packit Service 82fcde
                           cwd=self.component_srcdir(component), check=True)
Packit Service 82fcde
            return r
Packit Service 82fcde
        elif component == 'hurd':
Packit Service 82fcde
            git_url = 'git://git.savannah.gnu.org/hurd/hurd.git'
Packit Service 82fcde
            git_branch = 'master'
Packit Service 82fcde
            r = self.git_checkout(component, git_url, git_branch, update)
Packit Service 82fcde
            subprocess.run(['autoconf'],
Packit Service 82fcde
                           cwd=self.component_srcdir(component), check=True)
Packit Service 82fcde
            return r
Packit Service 82fcde
        else:
Packit Service 82fcde
            print('error: component %s coming from VCS' % component)
Packit Service 82fcde
            exit(1)
Packit Service 82fcde
Packit Service 82fcde
    def git_checkout(self, component, git_url, git_branch, update):
Packit Service 82fcde
        """Check out a component from git.  Return a commit identifier."""
Packit Service 82fcde
        if update:
Packit Service 82fcde
            subprocess.run(['git', 'remote', 'prune', 'origin'],
Packit Service 82fcde
                           cwd=self.component_srcdir(component), check=True)
Packit Service 82fcde
            if self.replace_sources:
Packit Service 82fcde
                subprocess.run(['git', 'clean', '-dxfq'],
Packit Service 82fcde
                               cwd=self.component_srcdir(component), check=True)
Packit Service 82fcde
            subprocess.run(['git', 'pull', '-q'],
Packit Service 82fcde
                           cwd=self.component_srcdir(component), check=True)
Packit Service 82fcde
        else:
Packit Service 82fcde
            subprocess.run(['git', 'clone', '-q', '-b', git_branch, git_url,
Packit Service 82fcde
                            self.component_srcdir(component)], check=True)
Packit Service 82fcde
        r = subprocess.run(['git', 'rev-parse', 'HEAD'],
Packit Service 82fcde
                           cwd=self.component_srcdir(component),
Packit Service 82fcde
                           stdout=subprocess.PIPE,
Packit Service 82fcde
                           check=True, universal_newlines=True).stdout
Packit Service 82fcde
        return r.rstrip()
Packit Service 82fcde
Packit Service 82fcde
    def fix_glibc_timestamps(self):
Packit Service 82fcde
        """Fix timestamps in a glibc checkout."""
Packit Service 82fcde
        # Ensure that builds do not try to regenerate generated files
Packit Service 82fcde
        # in the source tree.
Packit Service 82fcde
        srcdir = self.component_srcdir('glibc')
Packit Service 82fcde
        for dirpath, dirnames, filenames in os.walk(srcdir):
Packit Service 82fcde
            for f in filenames:
Packit Service 82fcde
                if (f == 'configure' or
Packit Service 82fcde
                    f == 'preconfigure' or
Packit Service 82fcde
                    f.endswith('-kw.h')):
Packit Service 82fcde
                    to_touch = os.path.join(dirpath, f)
Packit Service 82fcde
                    subprocess.run(['touch', to_touch], check=True)
Packit Service 82fcde
Packit Service 82fcde
    def gcc_checkout(self, svn_url, update):
Packit Service 82fcde
        """Check out GCC from SVN.  Return the revision number."""
Packit Service 82fcde
        if not update:
Packit Service 82fcde
            subprocess.run(['svn', 'co', '-q', svn_url,
Packit Service 82fcde
                            self.component_srcdir('gcc')], check=True)
Packit Service 82fcde
        subprocess.run(['contrib/gcc_update', '--silent'],
Packit Service 82fcde
                       cwd=self.component_srcdir('gcc'), check=True)
Packit Service 82fcde
        r = subprocess.run(['svnversion', self.component_srcdir('gcc')],
Packit Service 82fcde
                           stdout=subprocess.PIPE,
Packit Service 82fcde
                           check=True, universal_newlines=True).stdout
Packit Service 82fcde
        return r.rstrip()
Packit Service 82fcde
Packit Service 82fcde
    def checkout_tar(self, component, version, update):
Packit Service 82fcde
        """Check out the given version of the given component from a
Packit Service 82fcde
        tarball."""
Packit Service 82fcde
        if update:
Packit Service 82fcde
            return
Packit Service 82fcde
        url_map = {'binutils': 'https://ftp.gnu.org/gnu/binutils/binutils-%(version)s.tar.bz2',
Packit Service 82fcde
                   'gcc': 'https://ftp.gnu.org/gnu/gcc/gcc-%(version)s/gcc-%(version)s.tar.gz',
Packit Service 82fcde
                   'gmp': 'https://ftp.gnu.org/gnu/gmp/gmp-%(version)s.tar.xz',
Packit Service 82fcde
                   'linux': 'https://www.kernel.org/pub/linux/kernel/v4.x/linux-%(version)s.tar.xz',
Packit Service 82fcde
                   'mpc': 'https://ftp.gnu.org/gnu/mpc/mpc-%(version)s.tar.gz',
Packit Service 82fcde
                   'mpfr': 'https://ftp.gnu.org/gnu/mpfr/mpfr-%(version)s.tar.xz',
Packit Service 82fcde
                   'mig': 'https://ftp.gnu.org/gnu/mig/mig-%(version)s.tar.bz2',
Packit Service 82fcde
                   'gnumach': 'https://ftp.gnu.org/gnu/gnumach/gnumach-%(version)s.tar.bz2',
Packit Service 82fcde
                   'hurd': 'https://ftp.gnu.org/gnu/hurd/hurd-%(version)s.tar.bz2'}
Packit Service 82fcde
        if component not in url_map:
Packit Service 82fcde
            print('error: component %s coming from tarball' % component)
Packit Service 82fcde
            exit(1)
Packit Service 82fcde
        url = url_map[component] % {'version': version}
Packit Service 82fcde
        filename = os.path.join(self.srcdir, url.split('/')[-1])
Packit Service 82fcde
        response = urllib.request.urlopen(url)
Packit Service 82fcde
        data = response.read()
Packit Service 82fcde
        with open(filename, 'wb') as f:
Packit Service 82fcde
            f.write(data)
Packit Service 82fcde
        subprocess.run(['tar', '-C', self.srcdir, '-x', '-f', filename],
Packit Service 82fcde
                       check=True)
Packit Service 82fcde
        os.rename(os.path.join(self.srcdir, '%s-%s' % (component, version)),
Packit Service 82fcde
                  self.component_srcdir(component))
Packit Service 82fcde
        os.remove(filename)
Packit Service 82fcde
Packit Service 82fcde
    def load_build_state_json(self):
Packit Service 82fcde
        """Load information about the state of previous builds."""
Packit Service 82fcde
        if os.access(self.build_state_json, os.F_OK):
Packit Service 82fcde
            with open(self.build_state_json, 'r') as f:
Packit Service 82fcde
                self.build_state = json.load(f)
Packit Service 82fcde
        else:
Packit Service 82fcde
            self.build_state = {}
Packit Service 82fcde
        for k in ('host-libraries', 'compilers', 'glibcs'):
Packit Service 82fcde
            if k not in self.build_state:
Packit Service 82fcde
                self.build_state[k] = {}
Packit Service 82fcde
            if 'build-time' not in self.build_state[k]:
Packit Service 82fcde
                self.build_state[k]['build-time'] = ''
Packit Service 82fcde
            if 'build-versions' not in self.build_state[k]:
Packit Service 82fcde
                self.build_state[k]['build-versions'] = {}
Packit Service 82fcde
            if 'build-results' not in self.build_state[k]:
Packit Service 82fcde
                self.build_state[k]['build-results'] = {}
Packit Service 82fcde
            if 'result-changes' not in self.build_state[k]:
Packit Service 82fcde
                self.build_state[k]['result-changes'] = {}
Packit Service 82fcde
            if 'ever-passed' not in self.build_state[k]:
Packit Service 82fcde
                self.build_state[k]['ever-passed'] = []
Packit Service 82fcde
Packit Service 82fcde
    def store_build_state_json(self):
Packit Service 82fcde
        """Store information about the state of previous builds."""
Packit Service 82fcde
        self.store_json(self.build_state, self.build_state_json)
Packit Service 82fcde
Packit Service 82fcde
    def clear_last_build_state(self, action):
Packit Service 82fcde
        """Clear information about the state of part of the build."""
Packit Service 82fcde
        # We clear the last build time and versions when starting a
Packit Service 82fcde
        # new build.  The results of the last build are kept around,
Packit Service 82fcde
        # as comparison is still meaningful if this build is aborted
Packit Service 82fcde
        # and a new one started.
Packit Service 82fcde
        self.build_state[action]['build-time'] = ''
Packit Service 82fcde
        self.build_state[action]['build-versions'] = {}
Packit Service 82fcde
        self.store_build_state_json()
Packit Service 82fcde
Packit Service 82fcde
    def update_build_state(self, action, build_time, build_versions):
Packit Service 82fcde
        """Update the build state after a build."""
Packit Service 82fcde
        build_time = build_time.replace(microsecond=0)
Packit Service 82fcde
        self.build_state[action]['build-time'] = str(build_time)
Packit Service 82fcde
        self.build_state[action]['build-versions'] = build_versions
Packit Service 82fcde
        build_results = {}
Packit Service 82fcde
        for log in self.status_log_list:
Packit Service 82fcde
            with open(log, 'r') as f:
Packit Service 82fcde
                log_text = f.read()
Packit Service 82fcde
            log_text = log_text.rstrip()
Packit Service 82fcde
            m = re.fullmatch('([A-Z]+): (.*)', log_text)
Packit Service 82fcde
            result = m.group(1)
Packit Service 82fcde
            test_name = m.group(2)
Packit Service 82fcde
            assert test_name not in build_results
Packit Service 82fcde
            build_results[test_name] = result
Packit Service 82fcde
        old_build_results = self.build_state[action]['build-results']
Packit Service 82fcde
        self.build_state[action]['build-results'] = build_results
Packit Service 82fcde
        result_changes = {}
Packit Service 82fcde
        all_tests = set(old_build_results.keys()) | set(build_results.keys())
Packit Service 82fcde
        for t in all_tests:
Packit Service 82fcde
            if t in old_build_results:
Packit Service 82fcde
                old_res = old_build_results[t]
Packit Service 82fcde
            else:
Packit Service 82fcde
                old_res = '(New test)'
Packit Service 82fcde
            if t in build_results:
Packit Service 82fcde
                new_res = build_results[t]
Packit Service 82fcde
            else:
Packit Service 82fcde
                new_res = '(Test removed)'
Packit Service 82fcde
            if old_res != new_res:
Packit Service 82fcde
                result_changes[t] = '%s -> %s' % (old_res, new_res)
Packit Service 82fcde
        self.build_state[action]['result-changes'] = result_changes
Packit Service 82fcde
        old_ever_passed = {t for t in self.build_state[action]['ever-passed']
Packit Service 82fcde
                           if t in build_results}
Packit Service 82fcde
        new_passes = {t for t in build_results if build_results[t] == 'PASS'}
Packit Service 82fcde
        self.build_state[action]['ever-passed'] = sorted(old_ever_passed |
Packit Service 82fcde
                                                         new_passes)
Packit Service 82fcde
        self.store_build_state_json()
Packit Service 82fcde
Packit Service 82fcde
    def load_bot_config_json(self):
Packit Service 82fcde
        """Load bot configuration."""
Packit Service 82fcde
        with open(self.bot_config_json, 'r') as f:
Packit Service 82fcde
            self.bot_config = json.load(f)
Packit Service 82fcde
Packit Service 82fcde
    def part_build_old(self, action, delay):
Packit Service 82fcde
        """Return whether the last build for a given action was at least a
Packit Service 82fcde
        given number of seconds ago, or does not have a time recorded."""
Packit Service 82fcde
        old_time_str = self.build_state[action]['build-time']
Packit Service 82fcde
        if not old_time_str:
Packit Service 82fcde
            return True
Packit Service 82fcde
        old_time = datetime.datetime.strptime(old_time_str,
Packit Service 82fcde
                                              '%Y-%m-%d %H:%M:%S')
Packit Service 82fcde
        new_time = datetime.datetime.utcnow()
Packit Service 82fcde
        delta = new_time - old_time
Packit Service 82fcde
        return delta.total_seconds() >= delay
Packit Service 82fcde
Packit Service 82fcde
    def bot_cycle(self):
Packit Service 82fcde
        """Run a single round of checkout and builds."""
Packit Service 82fcde
        print('Bot cycle starting %s.' % str(datetime.datetime.utcnow()))
Packit Service 82fcde
        self.load_bot_config_json()
Packit Service 82fcde
        actions = ('host-libraries', 'compilers', 'glibcs')
Packit Service 82fcde
        self.bot_run_self(['--replace-sources'], 'checkout')
Packit Service 82fcde
        self.load_versions_json()
Packit Service 82fcde
        if self.get_script_text() != self.script_text:
Packit Service 82fcde
            print('Script changed, re-execing.')
Packit Service 82fcde
            # On script change, all parts of the build should be rerun.
Packit Service 82fcde
            for a in actions:
Packit Service 82fcde
                self.clear_last_build_state(a)
Packit Service 82fcde
            self.exec_self()
Packit Service 82fcde
        check_components = {'host-libraries': ('gmp', 'mpfr', 'mpc'),
Packit Service 82fcde
                            'compilers': ('binutils', 'gcc', 'glibc', 'linux',
Packit Service 82fcde
                                          'mig', 'gnumach', 'hurd'),
Packit Service 82fcde
                            'glibcs': ('glibc',)}
Packit Service 82fcde
        must_build = {}
Packit Service 82fcde
        for a in actions:
Packit Service 82fcde
            build_vers = self.build_state[a]['build-versions']
Packit Service 82fcde
            must_build[a] = False
Packit Service 82fcde
            if not self.build_state[a]['build-time']:
Packit Service 82fcde
                must_build[a] = True
Packit Service 82fcde
            old_vers = {}
Packit Service 82fcde
            new_vers = {}
Packit Service 82fcde
            for c in check_components[a]:
Packit Service 82fcde
                if c in build_vers:
Packit Service 82fcde
                    old_vers[c] = build_vers[c]
Packit Service 82fcde
                new_vers[c] = {'version': self.versions[c]['version'],
Packit Service 82fcde
                               'revision': self.versions[c]['revision']}
Packit Service 82fcde
            if new_vers == old_vers:
Packit Service 82fcde
                print('Versions for %s unchanged.' % a)
Packit Service 82fcde
            else:
Packit Service 82fcde
                print('Versions changed or rebuild forced for %s.' % a)
Packit Service 82fcde
                if a == 'compilers' and not self.part_build_old(
Packit Service 82fcde
                        a, self.bot_config['compilers-rebuild-delay']):
Packit Service 82fcde
                    print('Not requiring rebuild of compilers this soon.')
Packit Service 82fcde
                else:
Packit Service 82fcde
                    must_build[a] = True
Packit Service 82fcde
        if must_build['host-libraries']:
Packit Service 82fcde
            must_build['compilers'] = True
Packit Service 82fcde
        if must_build['compilers']:
Packit Service 82fcde
            must_build['glibcs'] = True
Packit Service 82fcde
        for a in actions:
Packit Service 82fcde
            if must_build[a]:
Packit Service 82fcde
                print('Must rebuild %s.' % a)
Packit Service 82fcde
                self.clear_last_build_state(a)
Packit Service 82fcde
            else:
Packit Service 82fcde
                print('No need to rebuild %s.' % a)
Packit Service 82fcde
        if os.access(self.logsdir, os.F_OK):
Packit Service 82fcde
            shutil.rmtree(self.logsdir_old, ignore_errors=True)
Packit Service 82fcde
            shutil.copytree(self.logsdir, self.logsdir_old)
Packit Service 82fcde
        for a in actions:
Packit Service 82fcde
            if must_build[a]:
Packit Service 82fcde
                build_time = datetime.datetime.utcnow()
Packit Service 82fcde
                print('Rebuilding %s at %s.' % (a, str(build_time)))
Packit Service 82fcde
                self.bot_run_self([], a)
Packit Service 82fcde
                self.load_build_state_json()
Packit Service 82fcde
                self.bot_build_mail(a, build_time)
Packit Service 82fcde
        print('Bot cycle done at %s.' % str(datetime.datetime.utcnow()))
Packit Service 82fcde
Packit Service 82fcde
    def bot_build_mail(self, action, build_time):
Packit Service 82fcde
        """Send email with the results of a build."""
Packit Service 82fcde
        if not ('email-from' in self.bot_config and
Packit Service 82fcde
                'email-server' in self.bot_config and
Packit Service 82fcde
                'email-subject' in self.bot_config and
Packit Service 82fcde
                'email-to' in self.bot_config):
Packit Service 82fcde
            if not self.email_warning:
Packit Service 82fcde
                print("Email not configured, not sending.")
Packit Service 82fcde
                self.email_warning = True
Packit Service 82fcde
            return
Packit Service 82fcde
Packit Service 82fcde
        build_time = build_time.replace(microsecond=0)
Packit Service 82fcde
        subject = (self.bot_config['email-subject'] %
Packit Service 82fcde
                   {'action': action,
Packit Service 82fcde
                    'build-time': str(build_time)})
Packit Service 82fcde
        results = self.build_state[action]['build-results']
Packit Service 82fcde
        changes = self.build_state[action]['result-changes']
Packit Service 82fcde
        ever_passed = set(self.build_state[action]['ever-passed'])
Packit Service 82fcde
        versions = self.build_state[action]['build-versions']
Packit Service 82fcde
        new_regressions = {k for k in changes if changes[k] == 'PASS -> FAIL'}
Packit Service 82fcde
        all_regressions = {k for k in ever_passed if results[k] == 'FAIL'}
Packit Service 82fcde
        all_fails = {k for k in results if results[k] == 'FAIL'}
Packit Service 82fcde
        if new_regressions:
Packit Service 82fcde
            new_reg_list = sorted(['FAIL: %s' % k for k in new_regressions])
Packit Service 82fcde
            new_reg_text = ('New regressions:\n\n%s\n\n' %
Packit Service 82fcde
                            '\n'.join(new_reg_list))
Packit Service 82fcde
        else:
Packit Service 82fcde
            new_reg_text = ''
Packit Service 82fcde
        if all_regressions:
Packit Service 82fcde
            all_reg_list = sorted(['FAIL: %s' % k for k in all_regressions])
Packit Service 82fcde
            all_reg_text = ('All regressions:\n\n%s\n\n' %
Packit Service 82fcde
                            '\n'.join(all_reg_list))
Packit Service 82fcde
        else:
Packit Service 82fcde
            all_reg_text = ''
Packit Service 82fcde
        if all_fails:
Packit Service 82fcde
            all_fail_list = sorted(['FAIL: %s' % k for k in all_fails])
Packit Service 82fcde
            all_fail_text = ('All failures:\n\n%s\n\n' %
Packit Service 82fcde
                             '\n'.join(all_fail_list))
Packit Service 82fcde
        else:
Packit Service 82fcde
            all_fail_text = ''
Packit Service 82fcde
        if changes:
Packit Service 82fcde
            changes_list = sorted(changes.keys())
Packit Service 82fcde
            changes_list = ['%s: %s' % (changes[k], k) for k in changes_list]
Packit Service 82fcde
            changes_text = ('All changed results:\n\n%s\n\n' %
Packit Service 82fcde
                            '\n'.join(changes_list))
Packit Service 82fcde
        else:
Packit Service 82fcde
            changes_text = ''
Packit Service 82fcde
        results_text = (new_reg_text + all_reg_text + all_fail_text +
Packit Service 82fcde
                        changes_text)
Packit Service 82fcde
        if not results_text:
Packit Service 82fcde
            results_text = 'Clean build with unchanged results.\n\n'
Packit Service 82fcde
        versions_list = sorted(versions.keys())
Packit Service 82fcde
        versions_list = ['%s: %s (%s)' % (k, versions[k]['version'],
Packit Service 82fcde
                                          versions[k]['revision'])
Packit Service 82fcde
                         for k in versions_list]
Packit Service 82fcde
        versions_text = ('Component versions for this build:\n\n%s\n' %
Packit Service 82fcde
                         '\n'.join(versions_list))
Packit Service 82fcde
        body_text = results_text + versions_text
Packit Service 82fcde
        msg = email.mime.text.MIMEText(body_text)
Packit Service 82fcde
        msg['Subject'] = subject
Packit Service 82fcde
        msg['From'] = self.bot_config['email-from']
Packit Service 82fcde
        msg['To'] = self.bot_config['email-to']
Packit Service 82fcde
        msg['Message-ID'] = email.utils.make_msgid()
Packit Service 82fcde
        msg['Date'] = email.utils.format_datetime(datetime.datetime.utcnow())
Packit Service 82fcde
        with smtplib.SMTP(self.bot_config['email-server']) as s:
Packit Service 82fcde
            s.send_message(msg)
Packit Service 82fcde
Packit Service 82fcde
    def bot_run_self(self, opts, action, check=True):
Packit Service 82fcde
        """Run a copy of this script with given options."""
Packit Service 82fcde
        cmd = [sys.executable, sys.argv[0], '--keep=none',
Packit Service 82fcde
               '-j%d' % self.parallelism]
Packit Service 82fcde
        cmd.extend(opts)
Packit Service 82fcde
        cmd.extend([self.topdir, action])
Packit Service 82fcde
        sys.stdout.flush()
Packit Service 82fcde
        subprocess.run(cmd, check=check)
Packit Service 82fcde
Packit Service 82fcde
    def bot(self):
Packit Service 82fcde
        """Run repeated rounds of checkout and builds."""
Packit Service 82fcde
        while True:
Packit Service 82fcde
            self.load_bot_config_json()
Packit Service 82fcde
            if not self.bot_config['run']:
Packit Service 82fcde
                print('Bot exiting by request.')
Packit Service 82fcde
                exit(0)
Packit Service 82fcde
            self.bot_run_self([], 'bot-cycle', check=False)
Packit Service 82fcde
            self.load_bot_config_json()
Packit Service 82fcde
            if not self.bot_config['run']:
Packit Service 82fcde
                print('Bot exiting by request.')
Packit Service 82fcde
                exit(0)
Packit Service 82fcde
            time.sleep(self.bot_config['delay'])
Packit Service 82fcde
            if self.get_script_text() != self.script_text:
Packit Service 82fcde
                print('Script changed, bot re-execing.')
Packit Service 82fcde
                self.exec_self()
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
class Config(object):
Packit Service 82fcde
    """A configuration for building a compiler and associated libraries."""
Packit Service 82fcde
Packit Service 82fcde
    def __init__(self, ctx, arch, os_name, variant=None, gcc_cfg=None,
Packit Service 82fcde
                 first_gcc_cfg=None, glibcs=None, extra_glibcs=None):
Packit Service 82fcde
        """Initialize a Config object."""
Packit Service 82fcde
        self.ctx = ctx
Packit Service 82fcde
        self.arch = arch
Packit Service 82fcde
        self.os = os_name
Packit Service 82fcde
        self.variant = variant
Packit Service 82fcde
        if variant is None:
Packit Service 82fcde
            self.name = '%s-%s' % (arch, os_name)
Packit Service 82fcde
        else:
Packit Service 82fcde
            self.name = '%s-%s-%s' % (arch, os_name, variant)
Packit Service 82fcde
        self.triplet = '%s-glibc-%s' % (arch, os_name)
Packit Service 82fcde
        if gcc_cfg is None:
Packit Service 82fcde
            self.gcc_cfg = []
Packit Service 82fcde
        else:
Packit Service 82fcde
            self.gcc_cfg = gcc_cfg
Packit Service 82fcde
        if first_gcc_cfg is None:
Packit Service 82fcde
            self.first_gcc_cfg = []
Packit Service 82fcde
        else:
Packit Service 82fcde
            self.first_gcc_cfg = first_gcc_cfg
Packit Service 82fcde
        if glibcs is None:
Packit Service 82fcde
            glibcs = [{'variant': variant}]
Packit Service 82fcde
        if extra_glibcs is None:
Packit Service 82fcde
            extra_glibcs = []
Packit Service 82fcde
        glibcs = [Glibc(self, **g) for g in glibcs]
Packit Service 82fcde
        extra_glibcs = [Glibc(self, **g) for g in extra_glibcs]
Packit Service 82fcde
        self.all_glibcs = glibcs + extra_glibcs
Packit Service 82fcde
        self.compiler_glibcs = glibcs
Packit Service 82fcde
        self.installdir = ctx.compiler_installdir(self.name)
Packit Service 82fcde
        self.bindir = ctx.compiler_bindir(self.name)
Packit Service 82fcde
        self.sysroot = ctx.compiler_sysroot(self.name)
Packit Service 82fcde
        self.builddir = os.path.join(ctx.builddir, 'compilers', self.name)
Packit Service 82fcde
        self.logsdir = os.path.join(ctx.logsdir, 'compilers', self.name)
Packit Service 82fcde
Packit Service 82fcde
    def component_builddir(self, component):
Packit Service 82fcde
        """Return the directory to use for a (non-glibc) build."""
Packit Service 82fcde
        return self.ctx.component_builddir('compilers', self.name, component)
Packit Service 82fcde
Packit Service 82fcde
    def build(self):
Packit Service 82fcde
        """Generate commands to build this compiler."""
Packit Service 82fcde
        self.ctx.remove_recreate_dirs(self.installdir, self.builddir,
Packit Service 82fcde
                                      self.logsdir)
Packit Service 82fcde
        cmdlist = CommandList('compilers-%s' % self.name, self.ctx.keep)
Packit Service 82fcde
        cmdlist.add_command('check-host-libraries',
Packit Service 82fcde
                            ['test', '-f',
Packit Service 82fcde
                             os.path.join(self.ctx.host_libraries_installdir,
Packit Service 82fcde
                                          'ok')])
Packit Service 82fcde
        cmdlist.use_path(self.bindir)
Packit Service 82fcde
        self.build_cross_tool(cmdlist, 'binutils', 'binutils',
Packit Service 82fcde
                              ['--disable-gdb',
Packit Service 82fcde
                               '--disable-libdecnumber',
Packit Service 82fcde
                               '--disable-readline',
Packit Service 82fcde
                               '--disable-sim'])
Packit Service 82fcde
        if self.os.startswith('linux'):
Packit Service 82fcde
            self.install_linux_headers(cmdlist)
Packit Service 82fcde
        self.build_gcc(cmdlist, True)
Packit Service 82fcde
        if self.os == 'gnu':
Packit Service 82fcde
            self.install_gnumach_headers(cmdlist)
Packit Service 82fcde
            self.build_cross_tool(cmdlist, 'mig', 'mig')
Packit Service 82fcde
            self.install_hurd_headers(cmdlist)
Packit Service 82fcde
        for g in self.compiler_glibcs:
Packit Service 82fcde
            cmdlist.push_subdesc('glibc')
Packit Service 82fcde
            cmdlist.push_subdesc(g.name)
Packit Service 82fcde
            g.build_glibc(cmdlist, True)
Packit Service 82fcde
            cmdlist.pop_subdesc()
Packit Service 82fcde
            cmdlist.pop_subdesc()
Packit Service 82fcde
        self.build_gcc(cmdlist, False)
Packit Service 82fcde
        cmdlist.add_command('done', ['touch',
Packit Service 82fcde
                                     os.path.join(self.installdir, 'ok')])
Packit Service 82fcde
        self.ctx.add_makefile_cmdlist('compilers-%s' % self.name, cmdlist,
Packit Service 82fcde
                                      self.logsdir)
Packit Service 82fcde
Packit Service 82fcde
    def build_cross_tool(self, cmdlist, tool_src, tool_build, extra_opts=None):
Packit Service 82fcde
        """Build one cross tool."""
Packit Service 82fcde
        srcdir = self.ctx.component_srcdir(tool_src)
Packit Service 82fcde
        builddir = self.component_builddir(tool_build)
Packit Service 82fcde
        cmdlist.push_subdesc(tool_build)
Packit Service 82fcde
        cmdlist.create_use_dir(builddir)
Packit Service 82fcde
        cfg_cmd = [os.path.join(srcdir, 'configure'),
Packit Service 82fcde
                   '--prefix=%s' % self.installdir,
Packit Service 82fcde
                   '--build=%s' % self.ctx.build_triplet,
Packit Service 82fcde
                   '--host=%s' % self.ctx.build_triplet,
Packit Service 82fcde
                   '--target=%s' % self.triplet,
Packit Service 82fcde
                   '--with-sysroot=%s' % self.sysroot]
Packit Service 82fcde
        if extra_opts:
Packit Service 82fcde
            cfg_cmd.extend(extra_opts)
Packit Service 82fcde
        cmdlist.add_command('configure', cfg_cmd)
Packit Service 82fcde
        cmdlist.add_command('build', ['make'])
Packit Service 82fcde
        # Parallel "make install" for GCC has race conditions that can
Packit Service 82fcde
        # cause it to fail; see
Packit Service 82fcde
        # <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42980>.  Such
Packit Service 82fcde
        # problems are not known for binutils, but doing the
Packit Service 82fcde
        # installation in parallel within a particular toolchain build
Packit Service 82fcde
        # (as opposed to installation of one toolchain from
Packit Service 82fcde
        # build-many-glibcs.py running in parallel to the installation
Packit Service 82fcde
        # of other toolchains being built) is not known to be
Packit Service 82fcde
        # significantly beneficial, so it is simplest just to disable
Packit Service 82fcde
        # parallel install for cross tools here.
Packit Service 82fcde
        cmdlist.add_command('install', ['make', '-j1', 'install'])
Packit Service 82fcde
        cmdlist.cleanup_dir()
Packit Service 82fcde
        cmdlist.pop_subdesc()
Packit Service 82fcde
Packit Service 82fcde
    def install_linux_headers(self, cmdlist):
Packit Service 82fcde
        """Install Linux kernel headers."""
Packit Service 82fcde
        arch_map = {'aarch64': 'arm64',
Packit Service 82fcde
                    'alpha': 'alpha',
Packit Service 82fcde
                    'arm': 'arm',
Packit Service 82fcde
                    'hppa': 'parisc',
Packit Service 82fcde
                    'i486': 'x86',
Packit Service 82fcde
                    'i586': 'x86',
Packit Service 82fcde
                    'i686': 'x86',
Packit Service 82fcde
                    'i786': 'x86',
Packit Service 82fcde
                    'ia64': 'ia64',
Packit Service 82fcde
                    'm68k': 'm68k',
Packit Service 82fcde
                    'microblaze': 'microblaze',
Packit Service 82fcde
                    'mips': 'mips',
Packit Service 82fcde
                    'nios2': 'nios2',
Packit Service 82fcde
                    'powerpc': 'powerpc',
Packit Service 82fcde
                    's390': 's390',
Packit Service 82fcde
                    'riscv32': 'riscv',
Packit Service 82fcde
                    'riscv64': 'riscv',
Packit Service 82fcde
                    'sh': 'sh',
Packit Service 82fcde
                    'sparc': 'sparc',
Packit Service 82fcde
                    'x86_64': 'x86'}
Packit Service 82fcde
        linux_arch = None
Packit Service 82fcde
        for k in arch_map:
Packit Service 82fcde
            if self.arch.startswith(k):
Packit Service 82fcde
                linux_arch = arch_map[k]
Packit Service 82fcde
                break
Packit Service 82fcde
        assert linux_arch is not None
Packit Service 82fcde
        srcdir = self.ctx.component_srcdir('linux')
Packit Service 82fcde
        builddir = self.component_builddir('linux')
Packit Service 82fcde
        headers_dir = os.path.join(self.sysroot, 'usr')
Packit Service 82fcde
        cmdlist.push_subdesc('linux')
Packit Service 82fcde
        cmdlist.create_use_dir(builddir)
Packit Service 82fcde
        cmdlist.add_command('install-headers',
Packit Service 82fcde
                            ['make', '-C', srcdir, 'O=%s' % builddir,
Packit Service 82fcde
                             'ARCH=%s' % linux_arch,
Packit Service 82fcde
                             'INSTALL_HDR_PATH=%s' % headers_dir,
Packit Service 82fcde
                             'headers_install'])
Packit Service 82fcde
        cmdlist.cleanup_dir()
Packit Service 82fcde
        cmdlist.pop_subdesc()
Packit Service 82fcde
Packit Service 82fcde
    def install_gnumach_headers(self, cmdlist):
Packit Service 82fcde
        """Install GNU Mach headers."""
Packit Service 82fcde
        srcdir = self.ctx.component_srcdir('gnumach')
Packit Service 82fcde
        builddir = self.component_builddir('gnumach')
Packit Service 82fcde
        cmdlist.push_subdesc('gnumach')
Packit Service 82fcde
        cmdlist.create_use_dir(builddir)
Packit Service 82fcde
        cmdlist.add_command('configure',
Packit Service 82fcde
                            [os.path.join(srcdir, 'configure'),
Packit Service 82fcde
                             '--build=%s' % self.ctx.build_triplet,
Packit Service 82fcde
                             '--host=%s' % self.triplet,
Packit Service 82fcde
                             '--prefix=',
Packit Service 82fcde
                             'CC=%s-gcc -nostdlib' % self.triplet])
Packit Service 82fcde
        cmdlist.add_command('install', ['make', 'DESTDIR=%s' % self.sysroot,
Packit Service 82fcde
                                        'install-data'])
Packit Service 82fcde
        cmdlist.cleanup_dir()
Packit Service 82fcde
        cmdlist.pop_subdesc()
Packit Service 82fcde
Packit Service 82fcde
    def install_hurd_headers(self, cmdlist):
Packit Service 82fcde
        """Install Hurd headers."""
Packit Service 82fcde
        srcdir = self.ctx.component_srcdir('hurd')
Packit Service 82fcde
        builddir = self.component_builddir('hurd')
Packit Service 82fcde
        cmdlist.push_subdesc('hurd')
Packit Service 82fcde
        cmdlist.create_use_dir(builddir)
Packit Service 82fcde
        cmdlist.add_command('configure',
Packit Service 82fcde
                            [os.path.join(srcdir, 'configure'),
Packit Service 82fcde
                             '--build=%s' % self.ctx.build_triplet,
Packit Service 82fcde
                             '--host=%s' % self.triplet,
Packit Service 82fcde
                             '--prefix=',
Packit Service 82fcde
                             '--disable-profile', '--without-parted',
Packit Service 82fcde
                             'CC=%s-gcc -nostdlib' % self.triplet])
Packit Service 82fcde
        cmdlist.add_command('install', ['make', 'prefix=%s' % self.sysroot,
Packit Service 82fcde
                                        'no_deps=t', 'install-headers'])
Packit Service 82fcde
        cmdlist.cleanup_dir()
Packit Service 82fcde
        cmdlist.pop_subdesc()
Packit Service 82fcde
Packit Service 82fcde
    def build_gcc(self, cmdlist, bootstrap):
Packit Service 82fcde
        """Build GCC."""
Packit Service 82fcde
        # libsanitizer commonly breaks because of glibc header
Packit Service 82fcde
        # changes, or on unusual targets.  libssp is of little
Packit Service 82fcde
        # relevance with glibc's own stack checking support.
Packit Service 82fcde
        # libcilkrts does not support GNU/Hurd (and has been removed
Packit Service 82fcde
        # in GCC 8, so --disable-libcilkrts can be removed once glibc
Packit Service 82fcde
        # no longer supports building with older GCC versions).
Packit Service 82fcde
        cfg_opts = list(self.gcc_cfg)
Packit Service 82fcde
        cfg_opts += ['--disable-libsanitizer', '--disable-libssp',
Packit Service 82fcde
                     '--disable-libcilkrts']
Packit Service 82fcde
        host_libs = self.ctx.host_libraries_installdir
Packit Service 82fcde
        cfg_opts += ['--with-gmp=%s' % host_libs,
Packit Service 82fcde
                     '--with-mpfr=%s' % host_libs,
Packit Service 82fcde
                     '--with-mpc=%s' % host_libs]
Packit Service 82fcde
        if bootstrap:
Packit Service 82fcde
            tool_build = 'gcc-first'
Packit Service 82fcde
            # Building a static-only, C-only compiler that is
Packit Service 82fcde
            # sufficient to build glibc.  Various libraries and
Packit Service 82fcde
            # features that may require libc headers must be disabled.
Packit Service 82fcde
            # When configuring with a sysroot, --with-newlib is
Packit Service 82fcde
            # required to define inhibit_libc (to stop some parts of
Packit Service 82fcde
            # libgcc including libc headers); --without-headers is not
Packit Service 82fcde
            # sufficient.
Packit Service 82fcde
            cfg_opts += ['--enable-languages=c', '--disable-shared',
Packit Service 82fcde
                         '--disable-threads',
Packit Service 82fcde
                         '--disable-libatomic',
Packit Service 82fcde
                         '--disable-decimal-float',
Packit Service 82fcde
                         '--disable-libffi',
Packit Service 82fcde
                         '--disable-libgomp',
Packit Service 82fcde
                         '--disable-libitm',
Packit Service 82fcde
                         '--disable-libmpx',
Packit Service 82fcde
                         '--disable-libquadmath',
Packit Service 82fcde
                         '--without-headers', '--with-newlib',
Packit Service 82fcde
                         '--with-glibc-version=%s' % self.ctx.glibc_version
Packit Service 82fcde
                         ]
Packit Service 82fcde
            cfg_opts += self.first_gcc_cfg
Packit Service 82fcde
        else:
Packit Service 82fcde
            tool_build = 'gcc'
Packit Service 82fcde
            cfg_opts += ['--enable-languages=c,c++', '--enable-shared',
Packit Service 82fcde
                         '--enable-threads']
Packit Service 82fcde
        self.build_cross_tool(cmdlist, 'gcc', tool_build, cfg_opts)
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
class Glibc(object):
Packit Service 82fcde
    """A configuration for building glibc."""
Packit Service 82fcde
Packit Service 82fcde
    def __init__(self, compiler, arch=None, os_name=None, variant=None,
Packit Service 82fcde
                 cfg=None, ccopts=None):
Packit Service 82fcde
        """Initialize a Glibc object."""
Packit Service 82fcde
        self.ctx = compiler.ctx
Packit Service 82fcde
        self.compiler = compiler
Packit Service 82fcde
        if arch is None:
Packit Service 82fcde
            self.arch = compiler.arch
Packit Service 82fcde
        else:
Packit Service 82fcde
            self.arch = arch
Packit Service 82fcde
        if os_name is None:
Packit Service 82fcde
            self.os = compiler.os
Packit Service 82fcde
        else:
Packit Service 82fcde
            self.os = os_name
Packit Service 82fcde
        self.variant = variant
Packit Service 82fcde
        if variant is None:
Packit Service 82fcde
            self.name = '%s-%s' % (self.arch, self.os)
Packit Service 82fcde
        else:
Packit Service 82fcde
            self.name = '%s-%s-%s' % (self.arch, self.os, variant)
Packit Service 82fcde
        self.triplet = '%s-glibc-%s' % (self.arch, self.os)
Packit Service 82fcde
        if cfg is None:
Packit Service 82fcde
            self.cfg = []
Packit Service 82fcde
        else:
Packit Service 82fcde
            self.cfg = cfg
Packit Service 82fcde
        self.ccopts = ccopts
Packit Service 82fcde
Packit Service 82fcde
    def tool_name(self, tool):
Packit Service 82fcde
        """Return the name of a cross-compilation tool."""
Packit Service 82fcde
        ctool = '%s-%s' % (self.compiler.triplet, tool)
Packit Service 82fcde
        if self.ccopts and (tool == 'gcc' or tool == 'g++'):
Packit Service 82fcde
            ctool = '%s %s' % (ctool, self.ccopts)
Packit Service 82fcde
        return ctool
Packit Service 82fcde
Packit Service 82fcde
    def build(self):
Packit Service 82fcde
        """Generate commands to build this glibc."""
Packit Service 82fcde
        builddir = self.ctx.component_builddir('glibcs', self.name, 'glibc')
Packit Service 82fcde
        installdir = self.ctx.glibc_installdir(self.name)
Packit Service 82fcde
        logsdir = os.path.join(self.ctx.logsdir, 'glibcs', self.name)
Packit Service 82fcde
        self.ctx.remove_recreate_dirs(installdir, builddir, logsdir)
Packit Service 82fcde
        cmdlist = CommandList('glibcs-%s' % self.name, self.ctx.keep)
Packit Service 82fcde
        cmdlist.add_command('check-compilers',
Packit Service 82fcde
                            ['test', '-f',
Packit Service 82fcde
                             os.path.join(self.compiler.installdir, 'ok')])
Packit Service 82fcde
        cmdlist.use_path(self.compiler.bindir)
Packit Service 82fcde
        self.build_glibc(cmdlist, False)
Packit Service 82fcde
        self.ctx.add_makefile_cmdlist('glibcs-%s' % self.name, cmdlist,
Packit Service 82fcde
                                      logsdir)
Packit Service 82fcde
Packit Service 82fcde
    def build_glibc(self, cmdlist, for_compiler):
Packit Service 82fcde
        """Generate commands to build this glibc, either as part of a compiler
Packit Service 82fcde
        build or with the bootstrapped compiler (and in the latter case, run
Packit Service 82fcde
        tests as well)."""
Packit Service 82fcde
        srcdir = self.ctx.component_srcdir('glibc')
Packit Service 82fcde
        if for_compiler:
Packit Service 82fcde
            builddir = self.ctx.component_builddir('compilers',
Packit Service 82fcde
                                                   self.compiler.name, 'glibc',
Packit Service 82fcde
                                                   self.name)
Packit Service 82fcde
            installdir = self.compiler.sysroot
Packit Service 82fcde
            srcdir_copy = self.ctx.component_builddir('compilers',
Packit Service 82fcde
                                                      self.compiler.name,
Packit Service 82fcde
                                                      'glibc-src',
Packit Service 82fcde
                                                      self.name)
Packit Service 82fcde
        else:
Packit Service 82fcde
            builddir = self.ctx.component_builddir('glibcs', self.name,
Packit Service 82fcde
                                                   'glibc')
Packit Service 82fcde
            installdir = self.ctx.glibc_installdir(self.name)
Packit Service 82fcde
            srcdir_copy = self.ctx.component_builddir('glibcs', self.name,
Packit Service 82fcde
                                                      'glibc-src')
Packit Service 82fcde
        cmdlist.create_use_dir(builddir)
Packit Service 82fcde
        # glibc builds write into the source directory, and even if
Packit Service 82fcde
        # not intentionally there is a risk of bugs that involve
Packit Service 82fcde
        # writing into the working directory.  To avoid possible
Packit Service 82fcde
        # concurrency issues, copy the source directory.
Packit Service 82fcde
        cmdlist.create_copy_dir(srcdir, srcdir_copy)
Packit Service 82fcde
        use_usr = self.os != 'gnu'
Packit Service 82fcde
        prefix = '/usr' if use_usr else ''
Packit Service 82fcde
        cfg_cmd = [os.path.join(srcdir_copy, 'configure'),
Packit Service 82fcde
                   '--prefix=%s' % prefix,
Packit Service 82fcde
                   '--enable-profile',
Packit Service 82fcde
                   '--build=%s' % self.ctx.build_triplet,
Packit Service 82fcde
                   '--host=%s' % self.triplet,
Packit Service 82fcde
                   'CC=%s' % self.tool_name('gcc'),
Packit Service 82fcde
                   'CXX=%s' % self.tool_name('g++'),
Packit Service 82fcde
                   'AR=%s' % self.tool_name('ar'),
Packit Service 82fcde
                   'AS=%s' % self.tool_name('as'),
Packit Service 82fcde
                   'LD=%s' % self.tool_name('ld'),
Packit Service 82fcde
                   'NM=%s' % self.tool_name('nm'),
Packit Service 82fcde
                   'OBJCOPY=%s' % self.tool_name('objcopy'),
Packit Service 82fcde
                   'OBJDUMP=%s' % self.tool_name('objdump'),
Packit Service 82fcde
                   'RANLIB=%s' % self.tool_name('ranlib'),
Packit Service 82fcde
                   'READELF=%s' % self.tool_name('readelf'),
Packit Service 82fcde
                   'STRIP=%s' % self.tool_name('strip')]
Packit Service 82fcde
        if self.os == 'gnu':
Packit Service 82fcde
            cfg_cmd += ['MIG=%s' % self.tool_name('mig')]
Packit Service 82fcde
        cfg_cmd += self.cfg
Packit Service 82fcde
        cmdlist.add_command('configure', cfg_cmd)
Packit Service 82fcde
        cmdlist.add_command('build', ['make'])
Packit Service 82fcde
        cmdlist.add_command('install', ['make', 'install',
Packit Service 82fcde
                                        'install_root=%s' % installdir])
Packit Service 82fcde
        # GCC uses paths such as lib/../lib64, so make sure lib
Packit Service 82fcde
        # directories always exist.
Packit Service 82fcde
        mkdir_cmd = ['mkdir', '-p',
Packit Service 82fcde
                     os.path.join(installdir, 'lib')]
Packit Service 82fcde
        if use_usr:
Packit Service 82fcde
            mkdir_cmd += [os.path.join(installdir, 'usr', 'lib')]
Packit Service 82fcde
        cmdlist.add_command('mkdir-lib', mkdir_cmd)
Packit Service 82fcde
        if not for_compiler:
Packit Service 82fcde
            if self.ctx.strip:
Packit Service 82fcde
                cmdlist.add_command('strip',
Packit Service 82fcde
                                    ['sh', '-c',
Packit Service 82fcde
                                     ('%s $(find %s/lib* -name "*.so")' %
Packit Service 82fcde
                                      (self.tool_name('strip'), installdir))])
Packit Service 82fcde
            cmdlist.add_command('check', ['make', 'check'])
Packit Service 82fcde
            cmdlist.add_command('save-logs', [self.ctx.save_logs],
Packit Service 82fcde
                                always_run=True)
Packit Service 82fcde
        cmdlist.cleanup_dir('cleanup-src', srcdir_copy)
Packit Service 82fcde
        cmdlist.cleanup_dir()
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
class Command(object):
Packit Service 82fcde
    """A command run in the build process."""
Packit Service 82fcde
Packit Service 82fcde
    def __init__(self, desc, num, dir, path, command, always_run=False):
Packit Service 82fcde
        """Initialize a Command object."""
Packit Service 82fcde
        self.dir = dir
Packit Service 82fcde
        self.path = path
Packit Service 82fcde
        self.desc = desc
Packit Service 82fcde
        trans = str.maketrans({' ': '-'})
Packit Service 82fcde
        self.logbase = '%03d-%s' % (num, desc.translate(trans))
Packit Service 82fcde
        self.command = command
Packit Service 82fcde
        self.always_run = always_run
Packit Service 82fcde
Packit Service 82fcde
    @staticmethod
Packit Service 82fcde
    def shell_make_quote_string(s):
Packit Service 82fcde
        """Given a string not containing a newline, quote it for use by the
Packit Service 82fcde
        shell and make."""
Packit Service 82fcde
        assert '\n' not in s
Packit Service 82fcde
        if re.fullmatch('[]+,./0-9@A-Z_a-z-]+', s):
Packit Service 82fcde
            return s
Packit Service 82fcde
        strans = str.maketrans({"'": "'\\''"})
Packit Service 82fcde
        s = "'%s'" % s.translate(strans)
Packit Service 82fcde
        mtrans = str.maketrans({'$': '$$'})
Packit Service 82fcde
        return s.translate(mtrans)
Packit Service 82fcde
Packit Service 82fcde
    @staticmethod
Packit Service 82fcde
    def shell_make_quote_list(l, translate_make):
Packit Service 82fcde
        """Given a list of strings not containing newlines, quote them for use
Packit Service 82fcde
        by the shell and make, returning a single string.  If translate_make
Packit Service 82fcde
        is true and the first string is 'make', change it to $(MAKE)."""
Packit Service 82fcde
        l = [Command.shell_make_quote_string(s) for s in l]
Packit Service 82fcde
        if translate_make and l[0] == 'make':
Packit Service 82fcde
            l[0] = '$(MAKE)'
Packit Service 82fcde
        return ' '.join(l)
Packit Service 82fcde
Packit Service 82fcde
    def shell_make_quote(self):
Packit Service 82fcde
        """Return this command quoted for the shell and make."""
Packit Service 82fcde
        return self.shell_make_quote_list(self.command, True)
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
class CommandList(object):
Packit Service 82fcde
    """A list of commands run in the build process."""
Packit Service 82fcde
Packit Service 82fcde
    def __init__(self, desc, keep):
Packit Service 82fcde
        """Initialize a CommandList object."""
Packit Service 82fcde
        self.cmdlist = []
Packit Service 82fcde
        self.dir = None
Packit Service 82fcde
        self.path = None
Packit Service 82fcde
        self.desc = [desc]
Packit Service 82fcde
        self.keep = keep
Packit Service 82fcde
Packit Service 82fcde
    def desc_txt(self, desc):
Packit Service 82fcde
        """Return the description to use for a command."""
Packit Service 82fcde
        return '%s %s' % (' '.join(self.desc), desc)
Packit Service 82fcde
Packit Service 82fcde
    def use_dir(self, dir):
Packit Service 82fcde
        """Set the default directory for subsequent commands."""
Packit Service 82fcde
        self.dir = dir
Packit Service 82fcde
Packit Service 82fcde
    def use_path(self, path):
Packit Service 82fcde
        """Set a directory to be prepended to the PATH for subsequent
Packit Service 82fcde
        commands."""
Packit Service 82fcde
        self.path = path
Packit Service 82fcde
Packit Service 82fcde
    def push_subdesc(self, subdesc):
Packit Service 82fcde
        """Set the default subdescription for subsequent commands (e.g., the
Packit Service 82fcde
        name of a component being built, within the series of commands
Packit Service 82fcde
        building it)."""
Packit Service 82fcde
        self.desc.append(subdesc)
Packit Service 82fcde
Packit Service 82fcde
    def pop_subdesc(self):
Packit Service 82fcde
        """Pop a subdescription from the list of descriptions."""
Packit Service 82fcde
        self.desc.pop()
Packit Service 82fcde
Packit Service 82fcde
    def create_use_dir(self, dir):
Packit Service 82fcde
        """Remove and recreate a directory and use it for subsequent
Packit Service 82fcde
        commands."""
Packit Service 82fcde
        self.add_command_dir('rm', None, ['rm', '-rf', dir])
Packit Service 82fcde
        self.add_command_dir('mkdir', None, ['mkdir', '-p', dir])
Packit Service 82fcde
        self.use_dir(dir)
Packit Service 82fcde
Packit Service 82fcde
    def create_copy_dir(self, src, dest):
Packit Service 82fcde
        """Remove a directory and recreate it as a copy from the given
Packit Service 82fcde
        source."""
Packit Service 82fcde
        self.add_command_dir('copy-rm', None, ['rm', '-rf', dest])
Packit Service 82fcde
        parent = os.path.dirname(dest)
Packit Service 82fcde
        self.add_command_dir('copy-mkdir', None, ['mkdir', '-p', parent])
Packit Service 82fcde
        self.add_command_dir('copy', None, ['cp', '-a', src, dest])
Packit Service 82fcde
Packit Service 82fcde
    def add_command_dir(self, desc, dir, command, always_run=False):
Packit Service 82fcde
        """Add a command to run in a given directory."""
Packit Service 82fcde
        cmd = Command(self.desc_txt(desc), len(self.cmdlist), dir, self.path,
Packit Service 82fcde
                      command, always_run)
Packit Service 82fcde
        self.cmdlist.append(cmd)
Packit Service 82fcde
Packit Service 82fcde
    def add_command(self, desc, command, always_run=False):
Packit Service 82fcde
        """Add a command to run in the default directory."""
Packit Service 82fcde
        cmd = Command(self.desc_txt(desc), len(self.cmdlist), self.dir,
Packit Service 82fcde
                      self.path, command, always_run)
Packit Service 82fcde
        self.cmdlist.append(cmd)
Packit Service 82fcde
Packit Service 82fcde
    def cleanup_dir(self, desc='cleanup', dir=None):
Packit Service 82fcde
        """Clean up a build directory.  If no directory is specified, the
Packit Service 82fcde
        default directory is cleaned up and ceases to be the default
Packit Service 82fcde
        directory."""
Packit Service 82fcde
        if dir is None:
Packit Service 82fcde
            dir = self.dir
Packit Service 82fcde
            self.use_dir(None)
Packit Service 82fcde
        if self.keep != 'all':
Packit Service 82fcde
            self.add_command_dir(desc, None, ['rm', '-rf', dir],
Packit Service 82fcde
                                 always_run=(self.keep == 'none'))
Packit Service 82fcde
Packit Service 82fcde
    def makefile_commands(self, wrapper, logsdir):
Packit Service 82fcde
        """Return the sequence of commands in the form of text for a Makefile.
Packit Service 82fcde
        The given wrapper script takes arguments: base of logs for
Packit Service 82fcde
        previous command, or empty; base of logs for this command;
Packit Service 82fcde
        description; directory; PATH addition; the command itself."""
Packit Service 82fcde
        # prev_base is the base of the name for logs of the previous
Packit Service 82fcde
        # command that is not always-run (that is, a build command,
Packit Service 82fcde
        # whose failure should stop subsequent build commands from
Packit Service 82fcde
        # being run, as opposed to a cleanup command, which is run
Packit Service 82fcde
        # even if previous commands failed).
Packit Service 82fcde
        prev_base = ''
Packit Service 82fcde
        cmds = []
Packit Service 82fcde
        for c in self.cmdlist:
Packit Service 82fcde
            ctxt = c.shell_make_quote()
Packit Service 82fcde
            if prev_base and not c.always_run:
Packit Service 82fcde
                prev_log = os.path.join(logsdir, prev_base)
Packit Service 82fcde
            else:
Packit Service 82fcde
                prev_log = ''
Packit Service 82fcde
            this_log = os.path.join(logsdir, c.logbase)
Packit Service 82fcde
            if not c.always_run:
Packit Service 82fcde
                prev_base = c.logbase
Packit Service 82fcde
            if c.dir is None:
Packit Service 82fcde
                dir = ''
Packit Service 82fcde
            else:
Packit Service 82fcde
                dir = c.dir
Packit Service 82fcde
            if c.path is None:
Packit Service 82fcde
                path = ''
Packit Service 82fcde
            else:
Packit Service 82fcde
                path = c.path
Packit Service 82fcde
            prelims = [wrapper, prev_log, this_log, c.desc, dir, path]
Packit Service 82fcde
            prelim_txt = Command.shell_make_quote_list(prelims, False)
Packit Service 82fcde
            cmds.append('\t@%s %s' % (prelim_txt, ctxt))
Packit Service 82fcde
        return '\n'.join(cmds)
Packit Service 82fcde
Packit Service 82fcde
    def status_logs(self, logsdir):
Packit Service 82fcde
        """Return the list of log files with command status."""
Packit Service 82fcde
        return [os.path.join(logsdir, '%s-status.txt' % c.logbase)
Packit Service 82fcde
                for c in self.cmdlist]
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
def get_parser():
Packit Service 82fcde
    """Return an argument parser for this module."""
Packit Service 82fcde
    parser = argparse.ArgumentParser(description=__doc__)
Packit Service 82fcde
    parser.add_argument('-j', dest='parallelism',
Packit Service 82fcde
                        help='Run this number of jobs in parallel',
Packit Service 82fcde
                        type=int, default=os.cpu_count())
Packit Service 82fcde
    parser.add_argument('--keep', dest='keep',
Packit Service 82fcde
                        help='Whether to keep all build directories, '
Packit Service 82fcde
                        'none or only those from failed builds',
Packit Service 82fcde
                        default='none', choices=('none', 'all', 'failed'))
Packit Service 82fcde
    parser.add_argument('--replace-sources', action='store_true',
Packit Service 82fcde
                        help='Remove and replace source directories '
Packit Service 82fcde
                        'with the wrong version of a component')
Packit Service 82fcde
    parser.add_argument('--strip', action='store_true',
Packit Service 82fcde
                        help='Strip installed glibc libraries')
Packit Service 82fcde
    parser.add_argument('topdir',
Packit Service 82fcde
                        help='Toplevel working directory')
Packit Service 82fcde
    parser.add_argument('action',
Packit Service 82fcde
                        help='What to do',
Packit Service 82fcde
                        choices=('checkout', 'bot-cycle', 'bot',
Packit Service 82fcde
                                 'host-libraries', 'compilers', 'glibcs'))
Packit Service 82fcde
    parser.add_argument('configs',
Packit Service 82fcde
                        help='Versions to check out or configurations to build',
Packit Service 82fcde
                        nargs='*')
Packit Service 82fcde
    return parser
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
def main(argv):
Packit Service 82fcde
    """The main entry point."""
Packit Service 82fcde
    parser = get_parser()
Packit Service 82fcde
    opts = parser.parse_args(argv)
Packit Service 82fcde
    topdir = os.path.abspath(opts.topdir)
Packit Service 82fcde
    ctx = Context(topdir, opts.parallelism, opts.keep, opts.replace_sources,
Packit Service 82fcde
                  opts.strip, opts.action)
Packit Service 82fcde
    ctx.run_builds(opts.action, opts.configs)
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
if __name__ == '__main__':
Packit Service 82fcde
    main(sys.argv[1:])