ci: copy logs from failed job stage dir (#49884)
This commit is contained in:
parent
c62cc6a45d
commit
3fd6066e54
@ -764,7 +764,7 @@ def copy_tree(
|
|||||||
|
|
||||||
files = glob.glob(src)
|
files = glob.glob(src)
|
||||||
if not files:
|
if not files:
|
||||||
raise OSError("No such file or directory: '{0}'".format(src))
|
raise OSError("No such file or directory: '{0}'".format(src), errno.ENOENT)
|
||||||
|
|
||||||
# For Windows hard-links and junctions, the source path must exist to make a symlink. Add
|
# For Windows hard-links and junctions, the source path must exist to make a symlink. Add
|
||||||
# all symlinks to this list while traversing the tree, then when finished, make all
|
# all symlinks to this list while traversing the tree, then when finished, make all
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.binary_distribution as bindist
|
import spack.binary_distribution as bindist
|
||||||
|
import spack.builder
|
||||||
import spack.config as cfg
|
import spack.config as cfg
|
||||||
import spack.environment as ev
|
import spack.environment as ev
|
||||||
import spack.error
|
import spack.error
|
||||||
@ -613,32 +614,40 @@ def copy_stage_logs_to_artifacts(job_spec: spack.spec.Spec, job_log_dir: str) ->
|
|||||||
job_spec, and attempts to copy the files into the directory given
|
job_spec, and attempts to copy the files into the directory given
|
||||||
by job_log_dir.
|
by job_log_dir.
|
||||||
|
|
||||||
Args:
|
Parameters:
|
||||||
job_spec: spec associated with spack install log
|
job_spec: spec associated with spack install log
|
||||||
job_log_dir: path into which build log should be copied
|
job_log_dir: path into which build log should be copied
|
||||||
"""
|
"""
|
||||||
tty.debug(f"job spec: {job_spec}")
|
tty.debug(f"job spec: {job_spec}")
|
||||||
|
if not job_spec.concrete:
|
||||||
try:
|
tty.warn("Cannot copy artifacts for non-concrete specs")
|
||||||
package_metadata_root = pathlib.Path(spack.store.STORE.layout.metadata_path(job_spec))
|
|
||||||
except spack.error.SpackError as e:
|
|
||||||
tty.error(f"Cannot copy logs: {str(e)}")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get the package's archived files
|
package_metadata_root = pathlib.Path(spack.store.STORE.layout.metadata_path(job_spec))
|
||||||
archive_files = []
|
if not os.path.isdir(package_metadata_root):
|
||||||
archive_root = package_metadata_root / "archived-files"
|
# Fallback to using the stage directory
|
||||||
if archive_root.is_dir():
|
job_pkg = job_spec.package
|
||||||
archive_files = [f for f in archive_root.rglob("*") if f.is_file()]
|
|
||||||
else:
|
|
||||||
msg = "Cannot copy package archived files: archived-files must be a directory"
|
|
||||||
tty.warn(msg)
|
|
||||||
|
|
||||||
|
package_metadata_root = pathlib.Path(job_pkg.stage.path)
|
||||||
|
archive_files = spack.builder.create(job_pkg).archive_files
|
||||||
|
tty.warn("Package not installed, falling back to use stage dir")
|
||||||
|
tty.debug(f"stage dir: {package_metadata_root}")
|
||||||
|
else:
|
||||||
|
# Get the package's archived files
|
||||||
|
archive_files = []
|
||||||
|
archive_root = package_metadata_root / "archived-files"
|
||||||
|
if os.path.isdir(archive_root):
|
||||||
|
archive_files = [str(f) for f in archive_root.rglob("*") if os.path.isfile(f)]
|
||||||
|
else:
|
||||||
|
tty.debug(f"No archived files detected at {archive_root}")
|
||||||
|
|
||||||
|
# Try zipped and unzipped versions of the build log
|
||||||
build_log_zipped = package_metadata_root / "spack-build-out.txt.gz"
|
build_log_zipped = package_metadata_root / "spack-build-out.txt.gz"
|
||||||
|
build_log = package_metadata_root / "spack-build-out.txt"
|
||||||
build_env_mods = package_metadata_root / "spack-build-env.txt"
|
build_env_mods = package_metadata_root / "spack-build-env.txt"
|
||||||
|
|
||||||
for f in [build_log_zipped, build_env_mods, *archive_files]:
|
for f in [build_log_zipped, build_log, build_env_mods, *archive_files]:
|
||||||
copy_files_to_artifacts(str(f), job_log_dir)
|
copy_files_to_artifacts(str(f), job_log_dir, compress_artifacts=True)
|
||||||
|
|
||||||
|
|
||||||
def copy_test_logs_to_artifacts(test_stage, job_test_dir):
|
def copy_test_logs_to_artifacts(test_stage, job_test_dir):
|
||||||
@ -651,11 +660,12 @@ def copy_test_logs_to_artifacts(test_stage, job_test_dir):
|
|||||||
"""
|
"""
|
||||||
tty.debug(f"test stage: {test_stage}")
|
tty.debug(f"test stage: {test_stage}")
|
||||||
if not os.path.exists(test_stage):
|
if not os.path.exists(test_stage):
|
||||||
msg = f"Cannot copy test logs: job test stage ({test_stage}) does not exist"
|
tty.error(f"Cannot copy test logs: job test stage ({test_stage}) does not exist")
|
||||||
tty.error(msg)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
copy_files_to_artifacts(os.path.join(test_stage, "*", "*.txt"), job_test_dir)
|
copy_files_to_artifacts(
|
||||||
|
os.path.join(test_stage, "*", "*.txt"), job_test_dir, compress_artifacts=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def download_and_extract_artifacts(url, work_dir) -> str:
|
def download_and_extract_artifacts(url, work_dir) -> str:
|
||||||
|
@ -2,9 +2,13 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
import copy
|
import copy
|
||||||
|
import errno
|
||||||
|
import glob
|
||||||
|
import gzip
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from collections import deque
|
from collections import deque
|
||||||
@ -25,6 +29,7 @@
|
|||||||
import spack.mirrors.mirror
|
import spack.mirrors.mirror
|
||||||
import spack.schema
|
import spack.schema
|
||||||
import spack.spec
|
import spack.spec
|
||||||
|
import spack.util.compression as compression
|
||||||
import spack.util.spack_yaml as syaml
|
import spack.util.spack_yaml as syaml
|
||||||
import spack.util.url as url_util
|
import spack.util.url as url_util
|
||||||
import spack.util.web as web_util
|
import spack.util.web as web_util
|
||||||
@ -40,22 +45,67 @@
|
|||||||
_urlopen = web_util.urlopen
|
_urlopen = web_util.urlopen
|
||||||
|
|
||||||
|
|
||||||
def copy_files_to_artifacts(src, artifacts_dir):
|
def copy_gzipped(glob_or_path: str, dest: str) -> None:
|
||||||
|
"""Copy all of the files in the source glob/path to the destination.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
glob_or_path: path to file to test
|
||||||
|
dest: destination path to copy to
|
||||||
|
"""
|
||||||
|
|
||||||
|
files = glob.glob(glob_or_path)
|
||||||
|
if not files:
|
||||||
|
raise OSError("No such file or directory: '{0}'".format(glob_or_path), errno.ENOENT)
|
||||||
|
if len(files) > 1 and not os.path.isdir(dest):
|
||||||
|
raise ValueError(
|
||||||
|
"'{0}' matches multiple files but '{1}' is not a directory".format(glob_or_path, dest)
|
||||||
|
)
|
||||||
|
|
||||||
|
def is_gzipped(path):
|
||||||
|
with open(path, "rb") as fd:
|
||||||
|
return compression.GZipFileType().matches_magic(fd)
|
||||||
|
|
||||||
|
for src in files:
|
||||||
|
if is_gzipped(src):
|
||||||
|
fs.copy(src, dest)
|
||||||
|
else:
|
||||||
|
# Compress and copy in one step
|
||||||
|
src_name = os.path.basename(src)
|
||||||
|
if os.path.isdir(dest):
|
||||||
|
zipped = os.path.join(dest, f"{src_name}.gz")
|
||||||
|
elif not dest.endswith(".gz"):
|
||||||
|
zipped = f"{dest}.gz"
|
||||||
|
else:
|
||||||
|
zipped = dest
|
||||||
|
|
||||||
|
with open(src, "rb") as fin, gzip.open(zipped, "wb") as fout:
|
||||||
|
shutil.copyfileobj(fin, fout)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_files_to_artifacts(
|
||||||
|
src: str, artifacts_dir: str, *, compress_artifacts: bool = False
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Copy file(s) to the given artifacts directory
|
Copy file(s) to the given artifacts directory
|
||||||
|
|
||||||
Parameters:
|
Args:
|
||||||
src (str): the glob-friendly path expression for the file(s) to copy
|
src (str): the glob-friendly path expression for the file(s) to copy
|
||||||
artifacts_dir (str): the destination directory
|
artifacts_dir (str): the destination directory
|
||||||
|
compress_artifacts (bool): option to compress copied artifacts using Gzip
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
fs.copy(src, artifacts_dir)
|
|
||||||
|
if compress_artifacts:
|
||||||
|
copy_gzipped(src, artifacts_dir)
|
||||||
|
else:
|
||||||
|
fs.copy(src, artifacts_dir)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
msg = (
|
tty.warn(
|
||||||
f"Unable to copy files ({src}) to artifacts {artifacts_dir} due to "
|
(
|
||||||
f"exception: {str(err)}"
|
f"Unable to copy files ({src}) to artifacts {artifacts_dir} due to "
|
||||||
|
f"exception: {str(err)}"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
tty.warn(msg)
|
|
||||||
|
|
||||||
|
|
||||||
def win_quote(quote_str: str) -> str:
|
def win_quote(quote_str: str) -> str:
|
||||||
|
@ -453,7 +453,7 @@ def ci_rebuild(args):
|
|||||||
|
|
||||||
# Arguments when installing the root from sources
|
# Arguments when installing the root from sources
|
||||||
deps_install_args = install_args + ["--only=dependencies"]
|
deps_install_args = install_args + ["--only=dependencies"]
|
||||||
root_install_args = install_args + ["--only=package"]
|
root_install_args = install_args + ["--keep-stage", "--only=package"]
|
||||||
|
|
||||||
if cdash_handler:
|
if cdash_handler:
|
||||||
# Add additional arguments to `spack install` for CDash reporting.
|
# Add additional arguments to `spack install` for CDash reporting.
|
||||||
@ -493,6 +493,9 @@ def ci_rebuild(args):
|
|||||||
# Copy logs and archived files from the install metadata (.spack) directory to artifacts now
|
# Copy logs and archived files from the install metadata (.spack) directory to artifacts now
|
||||||
spack_ci.copy_stage_logs_to_artifacts(job_spec, job_log_dir)
|
spack_ci.copy_stage_logs_to_artifacts(job_spec, job_log_dir)
|
||||||
|
|
||||||
|
# Clear the stage directory
|
||||||
|
spack.stage.purge()
|
||||||
|
|
||||||
# If the installation succeeded and we're running stand-alone tests for
|
# If the installation succeeded and we're running stand-alone tests for
|
||||||
# the package, run them and copy the output. Failures of any kind should
|
# the package, run them and copy the output. Failures of any kind should
|
||||||
# *not* terminate the build process or preclude creating the build cache.
|
# *not* terminate the build process or preclude creating the build cache.
|
||||||
|
Loading…
Reference in New Issue
Block a user