summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHarmen Stoppels <harmenstoppels@gmail.com>2022-10-26 09:19:24 +0200
committerGitHub <noreply@github.com>2022-10-26 09:19:24 +0200
commita2520e80c0b2bee62cc4d57090ded2422b96263a (patch)
treeeaf59321da878652af2c63c139b8fddd318ef39f /lib
parentd039744a5be714d476e8c41e38ec6a789dfe6de7 (diff)
downloadspack-a2520e80c0b2bee62cc4d57090ded2422b96263a.tar.gz
spack-a2520e80c0b2bee62cc4d57090ded2422b96263a.tar.bz2
spack-a2520e80c0b2bee62cc4d57090ded2422b96263a.tar.xz
spack-a2520e80c0b2bee62cc4d57090ded2422b96263a.zip
gitlab ci: install binary deps faster (#33248)
* Fast Gitlab CI job setup, and better legibility * Use a non-broken, recent GNU Make
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/ci.py33
-rw-r--r--lib/spack/spack/cmd/ci.py92
-rw-r--r--lib/spack/spack/test/cmd/ci.py10
3 files changed, 95 insertions, 40 deletions
diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py
index 1a63949efb..bec7a2f38b 100644
--- a/lib/spack/spack/ci.py
+++ b/lib/spack/spack/ci.py
@@ -17,7 +17,7 @@ import tempfile
import time
import zipfile
-from six import iteritems
+from six import iteritems, string_types
from six.moves.urllib.error import HTTPError, URLError
from six.moves.urllib.parse import urlencode
from six.moves.urllib.request import HTTPHandler, Request, build_opener
@@ -1936,26 +1936,35 @@ def reproduce_ci_job(url, work_dir):
print("".join(inst_list))
-def process_command(cmd, cmd_args, repro_dir):
+def process_command(name, commands, repro_dir):
"""
Create a script for and run the command. Copy the script to the
reproducibility directory.
Arguments:
- cmd (str): name of the command being processed
- cmd_args (list): string arguments to pass to the command
+ name (str): name of the command being processed
+ commands (list): list of arguments for single command or list of lists of
+ arguments for multiple commands. No shell escape is performed.
repro_dir (str): Job reproducibility directory
Returns: the exit code from processing the command
"""
- tty.debug("spack {0} arguments: {1}".format(cmd, cmd_args))
+ tty.debug("spack {0} arguments: {1}".format(name, commands))
+
+ if len(commands) == 0 or isinstance(commands[0], string_types):
+ commands = [commands]
+
+ # Create a string [command 1] && [command 2] && ... && [command n] with commands
+ # quoted using double quotes.
+ args_to_string = lambda args: " ".join('"{}"'.format(arg) for arg in args)
+ full_command = " && ".join(map(args_to_string, commands))
# Write the command to a shell script
- script = "{0}.sh".format(cmd)
+ script = "{0}.sh".format(name)
with open(script, "w") as fd:
- fd.write("#!/bin/bash\n\n")
- fd.write("\n# spack {0} command\n".format(cmd))
- fd.write(" ".join(['"{0}"'.format(i) for i in cmd_args]))
+ fd.write("#!/bin/sh\n\n")
+ fd.write("\n# spack {0} command\n".format(name))
+ fd.write(full_command)
fd.write("\n")
st = os.stat(script)
@@ -1967,15 +1976,15 @@ def process_command(cmd, cmd_args, repro_dir):
# Run the generated install.sh shell script as if it were being run in
# a login shell.
try:
- cmd_process = subprocess.Popen(["bash", "./{0}".format(script)])
+ cmd_process = subprocess.Popen(["/bin/sh", "./{0}".format(script)])
cmd_process.wait()
exit_code = cmd_process.returncode
except (ValueError, subprocess.CalledProcessError, OSError) as err:
- tty.error("Encountered error running {0} script".format(cmd))
+ tty.error("Encountered error running {0} script".format(name))
tty.error(err)
exit_code = 1
- tty.debug("spack {0} exited {1}".format(cmd, exit_code))
+ tty.debug("spack {0} exited {1}".format(name, exit_code))
return exit_code
diff --git a/lib/spack/spack/cmd/ci.py b/lib/spack/spack/cmd/ci.py
index e49bf9a2a6..11a47d5016 100644
--- a/lib/spack/spack/cmd/ci.py
+++ b/lib/spack/spack/cmd/ci.py
@@ -25,7 +25,8 @@ description = "manage continuous integration pipelines"
section = "build"
level = "long"
-CI_REBUILD_INSTALL_BASE_ARGS = ["spack", "--color=always", "--backtrace", "--verbose"]
+SPACK_COMMAND = "spack"
+MAKE_COMMAND = "make"
INSTALL_FAIL_CODE = 1
@@ -509,41 +510,88 @@ def ci_rebuild(args):
# No hash match anywhere means we need to rebuild spec
# Start with spack arguments
- install_args = [base_arg for base_arg in CI_REBUILD_INSTALL_BASE_ARGS]
+ spack_cmd = [SPACK_COMMAND, "--color=always", "--backtrace", "--verbose"]
config = cfg.get("config")
if not config["verify_ssl"]:
- install_args.append("-k")
+ spack_cmd.append("-k")
- install_args.extend(
- [
- "install",
- "--keep-stage",
- "--use-buildcache",
- "dependencies:only,package:never",
- ]
- )
+ install_args = []
can_verify = spack_ci.can_verify_binaries()
verify_binaries = can_verify and spack_is_pr_pipeline is False
if not verify_binaries:
install_args.append("--no-check-signature")
+ cdash_args = []
if cdash_handler:
# Add additional arguments to `spack install` for CDash reporting.
- install_args.extend(cdash_handler.args())
-
- # A compiler action of 'FIND_ANY' means we are building a bootstrap
- # compiler or one of its deps.
- # TODO: when compilers are dependencies, we should include --no-add
- if compiler_action != "FIND_ANY":
- install_args.append("--no-add")
-
- # Identify spec to install by hash
- install_args.append("/{0}".format(job_spec.dag_hash()))
+ cdash_args.extend(cdash_handler.args())
+
+ slash_hash = "/{}".format(job_spec.dag_hash())
+ deps_install_args = install_args
+ root_install_args = install_args + [
+ "--no-add",
+ "--keep-stage",
+ "--only=package",
+ "--use-buildcache=package:never,dependencies:only",
+ slash_hash,
+ ]
+
+ # ["x", "y"] -> "'x' 'y'"
+ args_to_string = lambda args: " ".join("'{}'".format(arg) for arg in args)
+
+ commands = [
+ # apparently there's a race when spack bootstraps? do it up front once
+ [
+ SPACK_COMMAND,
+ "-e",
+ env.path,
+ "bootstrap",
+ "now",
+ ],
+ [
+ SPACK_COMMAND,
+ "-e",
+ env.path,
+ "config",
+ "add",
+ "config:db_lock_timeout:120", # 2 minutes for processes to fight for a db lock
+ ],
+ [
+ SPACK_COMMAND,
+ "-e",
+ env.path,
+ "env",
+ "depfile",
+ "-o",
+ "Makefile",
+ "--use-buildcache=package:never,dependencies:only",
+ "--make-target-prefix",
+ "ci",
+ slash_hash, # limit to spec we're building
+ ],
+ [
+ # --output-sync requires GNU make 4.x.
+ # Old make errors when you pass it a flag it doesn't recognize,
+ # but it doesn't error or warn when you set unrecognized flags in
+ # this variable.
+ "export",
+ "GNUMAKEFLAGS=--output-sync=recurse",
+ ],
+ [
+ MAKE_COMMAND,
+ "SPACK={}".format(args_to_string(spack_cmd)),
+ "SPACK_COLOR=always",
+ "SPACK_INSTALL_FLAGS={}".format(args_to_string(deps_install_args)),
+ "-j$(nproc)",
+ "ci/.install-deps/{}".format(job_spec.dag_hash()),
+ ],
+ spack_cmd + ["install"] + root_install_args,
+ ]
tty.debug("Installing {0} from source".format(job_spec.name))
- install_exit_code = spack_ci.process_command("install", install_args, repro_dir)
+ install_exit_code = spack_ci.process_command("install", commands, repro_dir)
# Now do the post-install tasks
tty.debug("spack install exited {0}".format(install_exit_code))
diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py
index 2edf8788d5..117dec0ed4 100644
--- a/lib/spack/spack/test/cmd/ci.py
+++ b/lib/spack/spack/test/cmd/ci.py
@@ -916,11 +916,8 @@ def test_ci_rebuild_mock_success(
pkg_name = "archive-files"
rebuild_env = create_rebuild_env(tmpdir, pkg_name, broken_tests)
- monkeypatch.setattr(
- spack.cmd.ci,
- "CI_REBUILD_INSTALL_BASE_ARGS",
- ["echo"],
- )
+ monkeypatch.setattr(spack.cmd.ci, "SPACK_COMMAND", "echo")
+ monkeypatch.setattr(spack.cmd.ci, "MAKE_COMMAND", "echo")
with rebuild_env.env_dir.as_cwd():
activate_rebuild_env(tmpdir, pkg_name, rebuild_env)
@@ -965,7 +962,8 @@ def test_ci_rebuild(
ci_cmd("rebuild", "--tests", fail_on_error=False)
- monkeypatch.setattr(spack.cmd.ci, "CI_REBUILD_INSTALL_BASE_ARGS", ["notcommand"])
+ monkeypatch.setattr(spack.cmd.ci, "SPACK_COMMAND", "notcommand")
+ monkeypatch.setattr(spack.cmd.ci, "MAKE_COMMAND", "notcommand")
monkeypatch.setattr(spack.cmd.ci, "INSTALL_FAIL_CODE", 127)
with rebuild_env.env_dir.as_cwd():