diff --git a/.gitignore b/.gitignore
index 5f2b6788f8..97cb8f6825 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,5 +8,5 @@ env/
spack-build_stage/
spack-test_stage/
spack-misc_cache/
-user-config/
+user-config/linux/
user-cache/
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile
index 17ce8f8e2c..1bcb58d363 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -12,13 +12,10 @@ pipeline {
}
post {
always {
- archiveArtifacts artifacts: 'log/**/*.log', allowEmptyArchive: true
- withCredentials([string(credentialsId: 'd976fe24-cabf-479e-854f-587c152644bc', variable: 'GITHUB_AUTH_TOKEN')]) {
- sh """
- source env/bin/activate
- python3 src/report_tests.py --auth_token ${GITHUB_AUTH_TOKEN} --build_id ${BUILD_ID} --issue_id ${ghprbPullId}
- """
- }
+ sh """
+ python3 tools/summarize_logs.py || true
+ """
+ archiveArtifacts artifacts: 'log/*', allowEmptyArchive: true
deleteDir()
}
}
@@ -32,21 +29,20 @@ pipeline {
"""
}
}
- stage('Unit Tests') {
+ stage('Bootstrap spack') {
steps {
sh """
- mkdir -p log/${NODENAME}/unit_test
source env/bin/activate
- python3 test/unit_test.py ${NODENAME} > log/${NODENAME}/unit_test/summary.log 2>&1
+ source ./setup-env.sh
+ spack spec gnuconfig
"""
}
}
- stage('Bootstrap spack') {
+ stage('Unit Tests') {
steps {
sh """
source env/bin/activate
- . ./setup-env.sh
- spack spec gnuconfig
+ python3 test/unit_test.py
"""
}
}
@@ -54,14 +50,18 @@ pipeline {
steps {
sh """
source env/bin/activate
- pytest -v -n auto --scope \"""" + env.ghprbCommentBody + " \" test/integration_test.py"
+ source ./setup-env.sh $USER_ENV_ROOT
+ pytest -v -n auto test/integration_test.py
+ """
}
}
stage('System Tests') {
steps {
sh """
source env/bin/activate
- pytest -v -n auto --maxprocesses=24 --scope \"""" + env.ghprbCommentBody + " \" test/system_test.py"
+ source ./setup-env.sh $USER_ENV_ROOT
+ pytest -v -n auto test/system_test.py
+ """
}
}
}
diff --git a/setup-env.sh b/setup-env.sh
index da1c8239a5..b939ea95c0 100644
--- a/setup-env.sh
+++ b/setup-env.sh
@@ -3,24 +3,21 @@
parent_dir=$( cd "$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}")" ; pwd -P )
if [[ "$#" == 1 ]]; then
- machine="$1"
-else
- machine="$( "$parent_dir"/src/machine.sh )"
- if [[ "$machine" == "balfrin" || "$machine" == "tasna" ]]; then
- machine="/mch-environment/v6"
- fi
-fi
+ uenv="$1"
+ export SPACK_UENV_PATH="$uenv"
+ export SPACK_SYSTEM_CONFIG_PATH="$uenv"/config
-if [[ ${machine:0:1} == "/" ]]; then
- export SPACK_SYSTEM_CONFIG_PATH="$machine"/config
- export SPACK_USER_CONFIG_PATH="$parent_dir"/sysconfigs/uenv
-else
- export SPACK_SYSTEM_CONFIG_PATH="$parent_dir"/sysconfigs/"$machine"
- export SPACK_USER_CONFIG_PATH="$parent_dir"/user-config
+ if [[ $uenv == "euler" ]]; then
+ export SPACK_SYSTEM_CONFIG_PATH="$parent_dir"/sysconfigs/euler
+ fi
fi
+export SPACK_USER_CONFIG_PATH="$parent_dir"/user-config
export SPACK_USER_CACHE_PATH="$parent_dir"/user-cache
-
. "$parent_dir"/spack/share/spack/setup-env.sh
-echo Spack configured for "$machine".
+if [[ -n "$uenv" ]]; then
+ echo Spack configured with upstream "$uenv".
+else
+ echo Spack configured with no upstream.
+fi
diff --git a/src/format.py b/src/format.py
deleted file mode 100644
index c39e71fcfc..0000000000
--- a/src/format.py
+++ /dev/null
@@ -1,34 +0,0 @@
-def time_format(seconds) -> str:
- "Returns a string formatted as 'XXh YYm ZZ.ZZs'."
-
- m, s = divmod(seconds, 60)
- h, m = divmod(m, 60)
-
- parts = []
- if h:
- parts.append(f'{h:.0f}h')
- if m:
- parts.append(f'{m:.0f}m')
- if s:
- parts.append(f'{s:.2f}s')
- return ' '.join(parts)
-
-
-def sanitized_filename(filename: str) -> str:
- "Removes irrelevant information and replaces problematic chars."
-
- replacements = [
- (' --show-log-on-error', ''), # irrelevant in filename
- (' --test=root', ''), # irrelevant in filename
- (' --until build', ''), # irrelevant in filename
- (' --dont-restage', ''), # irrelevant in filename
- (' -n', ''), # irrelevant in filename
- (' -v', ''), # irrelevant in filename
- ('%', ''), # causes problems in web browsers
- (' ', '_'), # causes problems in bash
- ('"', ''), # causes problems with parameter expansion in bash
- ("'", ""), # causes problems with parameter expansion in bash
- ]
- for old, new in replacements:
- filename = filename.replace(old, new)
- return filename
diff --git a/src/github.py b/src/github.py
deleted file mode 100644
index 96b8fd2cea..0000000000
--- a/src/github.py
+++ /dev/null
@@ -1,87 +0,0 @@
-import requests
-
-
-class GitHubRepo:
-
- def __init__(self, group: str, repo: str, auth_token: str = None) -> None:
- self.group: str = group
- self.repo: str = repo
- self.auth_token: str = auth_token
-
- def comment(self, issue_id: str, text: str) -> None:
- url = f'https://api.github.com/repos/{self.group}/{self.repo}/issues/{issue_id}/comments'
-
- headers = {'Content-Type': 'application/json'}
- if self.auth_token is not None:
- headers['Authorization'] = 'token ' + self.auth_token
-
- requests.post(url, headers=headers, json={'body': text})
-
-
-class Markdown:
- # Source: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
-
- @staticmethod
- def ordered_list(elements: list) -> str:
- return '\n'.join(f'{i+1}. {e}' for i, e in enumerate(elements))
-
- @staticmethod
- def unordered_list(elements: list) -> str:
- return '\n'.join(f'* {e}' for e in elements)
-
- @staticmethod
- def link(text: str, url: str) -> str:
- return f'[{text}]({url})'
-
- @staticmethod
- def image(alt_text: str, url: str) -> str:
- return f'![{alt_text}]({url})'
-
- @staticmethod
- def inline_code(code: str) -> str:
- return f'`{code}`'
-
- @staticmethod
- def code(code: str, language: str = '') -> str:
- return f'```{language}\n{code}\n```'
-
- @staticmethod
- def table(head, body) -> str:
- data = [head, ['---'] * len(head)] + body
- return '\n'.join(' | '.join(row) for row in data)
-
- @staticmethod
- def header(text: str, level: int = 1) -> str:
- if (level < 1) or (level > 6):
- raise Exception('Invalid header level')
- return ('#' * level + ' ' + text + '\n')
-
-
-class HTML:
-
- @staticmethod
- def link(text: str, url: str) -> str:
- return f'{text}'
-
- @staticmethod
- def table(head, body) -> str:
- table = '
'
- table += ''
- table += ''
- for cell in head:
- table += f'{cell} | '
- table += '
'
- table += ''
- table += ''
- for row in body:
- table += ''
- for cell in row:
- table += f'{cell} | '
- table += '
'
- table += ''
- table += '
'
- return table
-
- @staticmethod
- def collapsible(summary: str, details: str) -> str:
- return f'{summary}
{details} '
diff --git a/src/report_tests.py b/src/report_tests.py
deleted file mode 100644
index 5637240c9c..0000000000
--- a/src/report_tests.py
+++ /dev/null
@@ -1,90 +0,0 @@
-import os
-import argparse
-import glob
-from pathlib import Path
-from github import GitHubRepo, Markdown, HTML
-from machine import machine_name
-
-
-class ResultTable:
-
- def __init__(self, artifact_path: str) -> None:
- self.artifact_path = artifact_path
- self.head = ['', 'Test']
- self.body = []
-
- def append(self, status: str, log_file: str, comment: str = '') -> None:
- link = HTML.link(Path(log_file).stem, self.artifact_path + log_file)
- self.body.append([status, f'{link} {comment}'])
-
- def clear(self) -> None:
- self.body = []
-
- def __str__(self) -> str:
- return HTML.table(self.head, self.body)
-
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser()
- parser.add_argument('--auth_token', type=str, required=False)
- parser.add_argument('--build_id', type=str, required=False)
- parser.add_argument('--issue_id', type=str, required=True)
- args = parser.parse_args()
-
- repo = GitHubRepo(group='c2sm',
- repo='spack-c2sm',
- auth_token=args.auth_token)
- table = ResultTable(
- f'https://jenkins-mch.cscs.ch/job/Spack/job/spack_PR/{args.build_id}/artifact/'
- )
-
- # Trigger phrases that cause a test to get a special icon and comment.
- # List[(trigger, icon, comment)]
- triggers = [
- ('Timed out waiting for a write lock', ':lock:',
- 'spack write lock problem'),
- ('Timed out waiting for a read lock', ':lock:',
- 'spack read lock problem'),
- ('gzip: stdin: decompression OK, trailing garbage ignored',
- ':wastebasket:', 'spack cached archive problem'),
- ('DUE TO TIME LIMIT', ':hourglass:', 'slurm time limit'),
- ('timed out after 5 seconds', ':yellow_circle:',
- 'timed out after 5 seconds'),
- ]
-
- report = Markdown.header(machine_name(), level=3)
- any_tests_ran_on_machine = False
- for test_type in ['unit', 'integration', 'system']:
- table.clear()
- all_tests_of_type_passed = True
- any_tests_of_type = False
- for file_name in sorted(
- glob.glob(f'log/{machine_name()}/{test_type}_test/**/*.log',
- recursive=True)):
- any_tests_ran_on_machine = True
- any_tests_of_type = True
- with open(file_name, 'r') as file:
- content = file.read()
- second_last_line = content.split('\n')[-2]
- if 'OK' in second_last_line:
- table.append(':green_circle:', file_name)
- else:
- all_tests_of_type_passed = False
- for trigger, icon, comment in triggers:
- if trigger in content:
- table.append(icon, file_name, comment)
- break
- else:
- table.append(':red_circle:', file_name)
-
- if any_tests_of_type:
- if all_tests_of_type_passed:
- icon = ':green_circle:'
- else:
- icon = ':red_circle:'
- report += HTML.collapsible(f'{icon} {test_type} test', table)
-
- if not any_tests_ran_on_machine:
- report += f'No tests executed.'
-
- repo.comment(args.issue_id, report)
diff --git a/src/scope.py b/src/scope.py
deleted file mode 100644
index f1f66cef45..0000000000
--- a/src/scope.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import os
-
-spack_c2sm_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- '..')
-
-all_machines = ['balfrin']
-all_packages = [
- name for name in os.listdir(
- os.path.join(spack_c2sm_path, 'repos/c2sm/packages')) if os.path.isdir(
- os.path.join(spack_c2sm_path, 'repos/c2sm/packages', name))
-]
-all_packages_underscore = [p.replace('-', '_') for p in all_packages]
-
-
-def explicit_scope(scope: str) -> list:
- "Adds all packages if none is listed, and all machines if none is listed."
-
- scope = scope.split(' ')
-
- if not any(x in scope for x in all_machines):
- scope.extend(all_machines) #no machine means all machines
- if not any(x in scope for x in all_packages):
- scope.extend(all_packages) #no package means all packages
- return scope
-
-
-def package_triggers(scope: list) -> list:
- triggers = []
- for x, y in zip(all_packages, all_packages_underscore):
- if x in scope:
- triggers.append(x)
- triggers.append(y)
-
- return triggers
diff --git a/src/spack_commands.py b/src/spack_commands.py
deleted file mode 100644
index 589288b1ac..0000000000
--- a/src/spack_commands.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import getpass
-import os
-import subprocess
-import time
-from pathlib import Path
-
-spack_c2sm_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- '..')
-
-from .machine import machine_name
-from .format import time_format, sanitized_filename
-
-
-def log_with_spack(command: str,
- test_category: str,
- log_filename: str = None,
- cwd=None,
- env=None,
- srun=False) -> None:
- """
- Executes the given command while spack is loaded and writes the output into the log file.
- If log_filename is None, command is used to create one.
- """
- filename = sanitized_filename(log_filename or command) + '.log'
- log_file = Path(
- spack_c2sm_path) / 'log' / machine_name() / test_category / filename
-
- # Setup spack env
- spack_env = f'. {spack_c2sm_path}/setup-env.sh'
-
- # Distribute work with 'srun'
- if srun and getpass.getuser() == 'jenkins':
- # The '-c' argument should be in sync with
- # sysconfig//config.yaml config:build_jobs for max efficiency
- srun = {
- 'balfrin': '',
- }[machine_name()]
- else:
- srun = ''
-
- # Make Directory
- log_file.parent.mkdir(exist_ok=True, parents=True)
-
- # Log machine name and command
- with log_file.open('a') as f:
- f.write(machine_name())
- f.write('\n')
- f.write(command)
- f.write('\n\n')
-
- env_activate = f'spack env activate -d {env};' if env else ''
- start = time.time()
- # The output is streamed as directly as possible to the log_file to avoid buffering and potentially losing buffered content.
- # '2>&1' redirects stderr to stdout.
- ret = subprocess.run(
- f'{spack_env}; {env_activate} ({srun} {command}) >> {log_file} 2>&1',
- cwd=cwd,
- check=False,
- shell=True)
- end = time.time()
-
- # Log time and success
- with log_file.open('a') as f:
- f.write('\n\n')
- f.write(time_format(end - start))
- f.write('\n')
- f.write('OK' if ret.returncode == 0 else 'FAILED')
- f.write('\n')
-
- ret.check_returncode()
diff --git a/sysconfigs/eiger/compilers.yaml b/sysconfigs/eiger/compilers.yaml
deleted file mode 100644
index 0ff7bbe5ed..0000000000
--- a/sysconfigs/eiger/compilers.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-compilers:
-- compiler:
- spec: gcc@=7.5.0
- paths:
- cc: /usr/bin/gcc
- cxx: /usr/bin/g++
- f77: /usr/bin/gfortran
- fc: /usr/bin/gfortran
- flags: {}
- operating_system: sles15
- target: x86_64
- modules: []
- environment: {}
- extra_rpaths: []
diff --git a/sysconfigs/eiger/concretizer.yaml b/sysconfigs/eiger/concretizer.yaml
deleted file mode 100644
index bae9dedd9b..0000000000
--- a/sysconfigs/eiger/concretizer.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-concretizer:
- reuse: true
\ No newline at end of file
diff --git a/sysconfigs/eiger/config.yaml b/sysconfigs/eiger/config.yaml
deleted file mode 100644
index d242e424c6..0000000000
--- a/sysconfigs/eiger/config.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-config:
- build_stage: '$spack/../spack-build_stage'
- test_stage: '$spack/../spack-test_stage'
- misc_cache: '$spack/../spack-misc_cache'
- build_jobs: 12
- db_lock_timeout: 120
diff --git a/sysconfigs/eiger/packages.yaml b/sysconfigs/eiger/packages.yaml
deleted file mode 100644
index 6ca88b7d53..0000000000
--- a/sysconfigs/eiger/packages.yaml
+++ /dev/null
@@ -1,226 +0,0 @@
-packages:
- autoconf:
- externals:
- - spec: autoconf@2.69
- prefix: /usr
- automake:
- externals:
- - spec: automake@1.15.1
- prefix: /usr
- bash:
- externals:
- - spec: bash@4.4.23
- prefix: /usr
- binutils:
- externals:
- - spec: binutils@2.37.20211103
- prefix: /usr
- bison:
- externals:
- - spec: bison@3.0.4
- prefix: /usr
- bzip2:
- externals:
- - spec: bzip2@1.0.6
- prefix: /usr
- cmake:
- externals:
- - spec: cmake@3.17.0
- prefix: /usr
- coreutils:
- externals:
- - spec: coreutils@8.32
- prefix: /usr
- cpio:
- externals:
- - spec: cpio@2.12
- prefix: /usr
- curl:
- externals:
- - spec: curl@7.66.0+gssapi+ldap+nghttp2
- prefix: /usr
- diffutils:
- externals:
- - spec: diffutils@3.6
- prefix: /usr
- file:
- externals:
- - spec: file@5.32
- prefix: /usr
- findutils:
- externals:
- - spec: findutils@4.8.0
- prefix: /usr
- flex:
- externals:
- - spec: flex@2.6.4+lex
- prefix: /usr
- gawk:
- externals:
- - spec: gawk@4.2.1
- prefix: /usr
- gcc:
- externals:
- - spec: gcc@7.5.0 languages=c,c++,fortran
- prefix: /usr
- extra_attributes:
- compilers:
- c: /usr/bin/gcc-7
- cxx: /usr/bin/g++-7
- fortran: /usr/bin/gfortran-7
- gettext:
- externals:
- - spec: gettext@0.20.2
- prefix: /usr
- ghostscript:
- externals:
- - spec: ghostscript@9.52
- prefix: /usr
- git:
- externals:
- - spec: git@2.35.3~tcltk
- prefix: /usr
- gmake:
- externals:
- - spec: gmake@4.2.1
- prefix: /usr
- groff:
- externals:
- - spec: groff@1.22.3
- prefix: /usr
- hwloc:
- externals:
- - spec: hwloc@2.6.0a1
- prefix: /usr
- openjdk:
- externals:
- - spec: openjdk@11.0.15_10-suse-150000.3.80.1-x8664
- prefix: /usr
- libfuse:
- externals:
- - spec: libfuse@2.9.7
- prefix: /usr
- - spec: libfuse@3.6.1
- prefix: /usr
- libtool:
- externals:
- - spec: libtool@2.4.6
- prefix: /usr
- lustre:
- externals:
- - spec: lustre@2.15.0.2_rc2_cray_150_g8176845
- prefix: /usr
- m4:
- externals:
- - spec: m4@1.4.18
- prefix: /usr
- ncurses:
- externals:
- - spec: ncurses@6.1.20180317+termlib abi=6
- prefix: /usr
- openssh:
- externals:
- - spec: openssh@8.4p1
- prefix: /usr
- openssl:
- externals:
- - spec: openssl@1.1.1d
- prefix: /usr
- perl:
- externals:
- - spec: perl@5.26.1~cpanm+open+shared+threads
- prefix: /usr
- pkg-config:
- externals:
- - spec: pkg-config@0.29.2
- prefix: /usr
- python:
- externals:
- - spec: python@2.7.18+bz2+crypt+ctypes~dbm~lzma+nis+pyexpat+pythoncmd+readline+sqlite3+ssl~tkinter+uuid+zlib
- prefix: /usr
- - spec: python@3.6.15+bz2+crypt+ctypes~dbm+lzma+nis+pyexpat~pythoncmd+readline+sqlite3+ssl~tkinter+uuid+zlib
- prefix: /usr
- rsync:
- externals:
- - spec: rsync@3.1.3
- prefix: /usr
- sed:
- externals:
- - spec: sed@4.4
- prefix: /usr
- slurm:
- externals:
- - spec: slurm@20.11.9
- prefix: /usr
- tar:
- externals:
- - spec: tar@1.34
- prefix: /usr
- texinfo:
- externals:
- - spec: texinfo@6.5
- prefix: /usr
- texlive:
- externals:
- - spec: texlive@20170524
- prefix: /usr
- which:
- externals:
- - spec: which@2.21
- prefix: /usr
- xz:
- externals:
- - spec: xz@5.2.3
- prefix: /usr
- zip:
- externals:
- - spec: zip@3.0
- prefix: /usr
- all:
- compiler: [gcc, intel, pgi, clang, xl, nag, fj, aocc]
- providers:
- awk: [gawk]
- blas: [openblas, amdblis]
- D: [ldc]
- daal: [intel-oneapi-daal]
- elf: [elfutils]
- fftw-api: [fftw, amdfftw]
- flame: [libflame, amdlibflame]
- fuse: [libfuse]
- gl: [glx, osmesa]
- glu: [mesa-glu, openglu]
- golang: [go, gcc]
- go-or-gccgo-bootstrap: [go-bootstrap, gcc]
- iconv: [libiconv]
- ipp: [intel-oneapi-ipp]
- java: [openjdk, jdk, ibm-java]
- jpeg: [libjpeg-turbo, libjpeg]
- lapack: [openblas, amdlibflame]
- libglx: [mesa+glx, mesa18+glx]
- libllvm: [llvm]
- libosmesa: [mesa+osmesa, mesa18+osmesa]
- lua-lang: [lua, lua-luajit-openresty, lua-luajit]
- luajit: [lua-luajit-openresty, lua-luajit]
- mariadb-client: [mariadb-c-client, mariadb]
- mkl: [intel-oneapi-mkl]
- mpe: [mpe2]
- mpi: [openmpi, mpich]
- mysql-client: [mysql, mariadb-c-client]
- opencl: [pocl]
- onedal: [intel-oneapi-dal]
- pbs: [openpbs, torque]
- pil: [py-pillow]
- pkgconfig: [pkgconf, pkg-config]
- rpc: [libtirpc]
- scalapack: [netlib-scalapack, amdscalapack]
- sycl: [hipsycl]
- szip: [libaec, libszip]
- tbb: [intel-tbb]
- unwind: [libunwind]
- uuid: [util-linux-uuid, libuuid]
- xxd: [xxd-standalone, vim]
- yacc: [bison, byacc]
- ziglang: [zig]
- permissions:
- read: world
- write: user
diff --git a/sysconfigs/eiger/repos.yaml b/sysconfigs/eiger/repos.yaml
deleted file mode 100644
index 5a33f43c97..0000000000
--- a/sysconfigs/eiger/repos.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-repos:
- - '$spack/../repos/c2sm'
\ No newline at end of file
diff --git a/sysconfigs/euler/repos.yaml b/sysconfigs/euler/repos.yaml
index aac469c084..f85a832f32 100644
--- a/sysconfigs/euler/repos.yaml
+++ b/sysconfigs/euler/repos.yaml
@@ -1,3 +1,2 @@
repos:
- - '$spack/../repos/c2sm'
- /cluster/software/repo/2024-05
diff --git a/sysconfigs/uenv/concretizer.yaml b/sysconfigs/uenv/concretizer.yaml
deleted file mode 100644
index da9482db15..0000000000
--- a/sysconfigs/uenv/concretizer.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-concretizer:
- reuse: true
diff --git a/sysconfigs/uenv/config.yaml b/sysconfigs/uenv/config.yaml
deleted file mode 100644
index d242e424c6..0000000000
--- a/sysconfigs/uenv/config.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-config:
- build_stage: '$spack/../spack-build_stage'
- test_stage: '$spack/../spack-test_stage'
- misc_cache: '$spack/../spack-misc_cache'
- build_jobs: 12
- db_lock_timeout: 120
diff --git a/sysconfigs/unknown/concretizer.yaml b/sysconfigs/unknown/concretizer.yaml
deleted file mode 100644
index bae9dedd9b..0000000000
--- a/sysconfigs/unknown/concretizer.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-concretizer:
- reuse: true
\ No newline at end of file
diff --git a/sysconfigs/unknown/config.yaml b/sysconfigs/unknown/config.yaml
deleted file mode 100644
index 53ef97f15f..0000000000
--- a/sysconfigs/unknown/config.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-config:
- build_stage: '$spack/../spack-build_stage'
- test_stage: '$spack/../spack-test_stage'
- misc_cache: '$spack/../spack-misc_cache'
diff --git a/sysconfigs/unknown/repos.yaml b/sysconfigs/unknown/repos.yaml
deleted file mode 100644
index 5a33f43c97..0000000000
--- a/sysconfigs/unknown/repos.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-repos:
- - '$spack/../repos/c2sm'
\ No newline at end of file
diff --git a/test/__init__.py b/test/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/test/conftest.py b/test/conftest.py
deleted file mode 100644
index d5d730adcc..0000000000
--- a/test/conftest.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import os
-import sys
-import pytest
-
-spack_c2sm_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- '..')
-sys.path.append(os.path.normpath(spack_c2sm_path))
-from src import machine_name, explicit_scope, package_triggers, all_machines, all_packages_underscore
-
-
-def pytest_configure(config):
- for machine in all_machines:
- config.addinivalue_line(
- 'markers', f'no_{machine}: mark test to not run on {machine}')
- config.addinivalue_line('markers',
- 'serial_only: mark test to only run serial')
- for package in all_packages_underscore:
- config.addinivalue_line('markers',
- f'{package}: mark test to run for {package}')
-
-
-def pytest_addoption(parser):
- parser.addoption('--scope', action='store', default='')
-
-
-def pytest_collection_modifyitems(config, items):
- scope = explicit_scope(config.getoption("--scope"))
-
- triggers = package_triggers(scope)
-
- for item in items:
- keywords = [k.lower() for k in item.keywords]
- if machine_name() not in scope:
- item.add_marker(pytest.mark.skip(reason="machine not in scope"))
- if f'no_{machine_name()}' in keywords:
- item.add_marker(
- pytest.mark.skip(
- reason="test is marked to not run on this machine"))
-
- if not any(k in triggers for k in keywords):
- item.add_marker(pytest.mark.skip(reason="test not in scope"))
diff --git a/test/integration_test.py b/test/integration_test.py
index c668c359e7..3dca6c709e 100644
--- a/test/integration_test.py
+++ b/test/integration_test.py
@@ -1,54 +1,35 @@
import pytest
-import sys
-import os
+from spack_commands import ALL_PACKAGES, spack_info, spack_spec
-spack_c2sm_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- '..')
-sys.path.append(os.path.normpath(spack_c2sm_path))
-from src import log_with_spack, sanitized_filename, all_packages, machine_name
-
-
-def spack_info(spec: str, log_filename: str = None):
- """
- Tests 'spack info' of the given spec and writes the output into the log file.
- """
+@pytest.mark.parametrize("package", ALL_PACKAGES)
+def test_info(package: str):
+ "Tests that the command 'spack info ' works."
+ spack_info(package)
- if log_filename is None:
- log_filename = sanitized_filename(f'{spec}-spack_info')
- log_with_spack(f'spack info {spec}', 'integration_test', log_filename)
+@pytest.mark.parametrize("package", ALL_PACKAGES)
+def test_spec(package: str):
+ "Tests that the command 'spack spec ' works."
+ spack_spec(package)
-def spack_spec(spec: str, log_filename: str = None):
- """
- Tests 'spack info' of the given spec and writes the output into the log file.
- """
- if log_filename is None:
- log_filename = sanitized_filename(f'{spec}-spack_spec')
- log_with_spack(f'spack spec {spec}', 'integration_test', log_filename)
+def test_icon_serialization():
+ spack_spec("icon serialization=create")
-@pytest.mark.parametrize('package', all_packages)
-def test_spack_info(package: str):
- spack_info(package)
+def test_icon_fcgroup():
+ spack_spec("icon fcgroup=DACE.externals/dace_icon.-O1")
-@pytest.mark.parametrize('package', all_packages)
-def test_spack_spec(package: str):
- spack_spec(package)
+def test_icon_extra_config_args():
+ spack_spec(
+ "icon extra-config-args=--disable-new_feature,--enable-old_config_arg")
-@pytest.mark.icon
-@pytest.mark.parametrize('variant', [
- 'serialization=create', 'fcgroup=DACE.externals/dace_icon.-O1',
- 'extra-config-args=--disable-new_feature,--enable-old_config_arg'
-])
-def test_icon_spec_with_variant(variant: str):
- spack_spec(f'icon {variant}')
+def test_int2lm_parallel():
+ spack_spec("int2lm +parallel")
-@pytest.mark.int2lm
-@pytest.mark.parametrize('variant', ['+parallel', '~parallel'])
-def test_int2lm_spec_with_variant(variant: str):
- spack_spec(f'int2lm {variant}')
+def test_int2lm_no_parallel():
+ spack_spec("int2lm ~parallel")
diff --git a/test/spack_commands.py b/test/spack_commands.py
new file mode 100644
index 0000000000..8259ebacc7
--- /dev/null
+++ b/test/spack_commands.py
@@ -0,0 +1,94 @@
+import os
+import subprocess
+import time
+from pathlib import Path
+
+REPO_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
+PACKAGES_DIR = os.path.join(REPO_DIR, "repos", "c2sm", "packages")
+ALL_PACKAGES = [
+ name for name in os.listdir(PACKAGES_DIR)
+ if os.path.isdir(os.path.join(PACKAGES_DIR, name))
+]
+
+
+def time_format(seconds) -> str:
+ "Returns a string formatted as 'XXh YYm ZZ.ZZs'."
+
+ m, s = divmod(seconds, 60)
+ h, m = divmod(m, 60)
+
+ parts = []
+ if h:
+ parts.append(f"{h:.0f}h")
+ if m:
+ parts.append(f"{m:.0f}m")
+ if s:
+ parts.append(f"{s:.2f}s")
+ return " ".join(parts)
+
+
+def log_file(command: str) -> Path:
+ # Filter out flags
+ # and join by underscore, because spaces cause problems in bash.
+ command = "_".join([x for x in command.split() if not x.startswith("-")])
+
+ # Remove % because they cause problems in web browsers
+ command = command.replace("%", "")
+
+ # Remove . because they cause problems in shell commands
+ command = command.replace("%", "")
+
+ return Path(REPO_DIR) / "log" / (command + ".log")
+
+
+def run_with_spack(command: str, log: Path) -> None:
+ log.parent.mkdir(exist_ok=True, parents=True)
+ with log.open("a") as f:
+ f.write(f"{command}\n\n")
+
+ # setup-env.sh may define SPACK_UENV_PATH.
+ if "SPACK_UENV_PATH" in os.environ:
+ uenv = os.environ["SPACK_UENV_PATH"]
+ else:
+ uenv = ""
+
+ start = time.time()
+ # Direct stream to avoid buffering.
+ # 'env -i' clears the environment.
+ # 'bash -l' makes it a login shell.
+ # 'bash -c' reads commands from string.
+ # '2>&1' redirects stderr to stdout.
+ ret = subprocess.run(
+ f'env -i bash -l -c "(. {REPO_DIR}/setup-env.sh {uenv}; {command}) >> {log} 2>&1"',
+ check=False,
+ shell=True,
+ )
+ end = time.time()
+
+ # Log time and success
+ duration = time_format(end - start)
+ success = "OK" if ret.returncode == 0 else "FAILED"
+ with log.open("a") as f:
+ f.write(f"\n\n{duration}\n{success}\n")
+
+ ret.check_returncode()
+
+
+def spack_info(spec: str):
+ log = log_file(f"info {spec}")
+ run_with_spack(f"spack info {spec}", log)
+
+
+def spack_spec(spec: str):
+ log = log_file(f"spec {spec}")
+ run_with_spack(f"spack spec {spec}", log)
+
+
+def spack_install(spec: str, test_root: bool = True):
+ log = log_file(f"install {spec}")
+
+ # A spec at the top of a log helps debugging.
+ run_with_spack(f"spack spec {spec}", log)
+
+ test_arg = "--test=root" if test_root else ""
+ run_with_spack(f"spack install --verbose {test_arg} {spec}", log)
diff --git a/test/system_test.py b/test/system_test.py
index 8866544b72..4f9e6afee8 100644
--- a/test/system_test.py
+++ b/test/system_test.py
@@ -1,126 +1,58 @@
import pytest
-import subprocess
-import sys
-import os
-import uuid
-import shutil
-import inspect
+from spack_commands import spack_install
-spack_c2sm_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- '..')
-sys.path.append(os.path.normpath(spack_c2sm_path))
-from src import machine_name, log_with_spack, sanitized_filename
-
-
-@pytest.fixture(scope='function')
-def devirt_env():
- # pytest is run from a virtual environment that breaks the
- # Python environment setup by Spack. Additionally "deactivate"
- # is not available here, therefore we manually unset
- # VIRTUAL_ENV and PATH
-
- # Remove 'VIRTUAL_ENV/bin'
- try:
- virtual_env_bin = os.path.join(os.environ['VIRTUAL_ENV'], 'bin')
- os.environ.pop('VIRTUAL_ENV')
- os.environ['PATH'] = os.environ['PATH'].replace(virtual_env_bin, '')
-
- # happens if test are run in serial-mode because cannot unset var twice
- except KeyError:
- pass
-
-
-def compose_logfilename(spec):
- func_name = inspect.currentframe().f_back.f_back.f_code.co_name.replace(
- 'test_', '')
- return sanitized_filename(func_name + '-' + spec)
-
-
-def spack_install(spec: str, test_root: bool = True):
- """
- Tests 'spack install' of the given spec and writes the output into the log file.
- """
-
- log_filename = compose_logfilename(spec)
-
- # A spec at the top of a log helps debugging.
- log_with_spack(f'spack spec {spec}',
- 'system_test',
- log_filename,
- srun=False)
-
- test_arg = "--test=root" if test_root else ""
- log_with_spack(f'spack install -n -v {test_arg} {spec}',
- 'system_test',
- log_filename,
- srun=not spec.startswith('icon '))
-
-
-@pytest.mark.libfyaml
def test_install_libfyaml_default():
spack_install('libfyaml', test_root=False)
-@pytest.mark.libtorch
def test_install_libtorch_default():
spack_install('libtorch', test_root=False)
-@pytest.mark.cosmo_eccodes_definitions
@pytest.mark.parametrize("version", ['2.25.0.1', '2.19.0.7'])
def test_install_cosmo_eccodes_definitions_version(version):
spack_install(f'cosmo-eccodes-definitions @{version}', test_root=False)
-@pytest.mark.cosmo
def test_install_cosmo_6_0():
- spack_install('cosmo@6.0%nvhpc', test_root=False)
+ spack_install('cosmo @6.0 %nvhpc', test_root=False)
-@pytest.mark.eccodes
def test_install_eccodes_2_19_0():
spack_install('eccodes @2.19.0', test_root=False)
-@pytest.mark.fdb_fortran
def test_install_fdb_fortran():
spack_install('fdb-fortran')
-@pytest.mark.flexpart_ifs
@pytest.mark.parametrize("version", ['10.4.4', 'fdb'])
def test_install_flexpart_ifs_version(version):
spack_install(f'flexpart-ifs @{version}', test_root=False)
-@pytest.mark.flexpart_cosmo
def test_install_flexpart_cosmo():
spack_install('flexpart-cosmo @V8C4.0')
-@pytest.mark.fdb
def test_install_fdb_5_11_17_gcc():
spack_install('fdb @5.11.17 %gcc')
-@pytest.mark.fdb
def test_install_fdb_5_11_17_nvhpc():
# tests fail because compiler emitted warnings.
spack_install('fdb @5.11.17 %nvhpc', test_root=False)
-@pytest.mark.icon
-def test_install_icon_24_1_gcc():
+def test_install_icon_2024_1_gcc():
spack_install('icon @2024.1-1 %gcc')
-@pytest.mark.icon
-def test_install_2024_1_nvhpc():
+def test_install_icon_2024_1_nvhpc():
spack_install('icon @2024.1-1 %nvhpc')
-@pytest.mark.icon
def test_install_conditional_dependencies():
# +coupling triggers libfyaml, libxml2, netcdf-c
# serialization=create triggers serialbox
@@ -134,123 +66,85 @@ def test_install_conditional_dependencies():
)
-@pytest.mark.icontools
def test_install_icontools():
spack_install('icontools @2.5.2')
-@pytest.mark.no_balfrin # int2lm depends on 'libgrib1 @22-01-2020', which fails.
-@pytest.mark.int2lm
-def test_install_int2ml_version_3_00_gcc():
- spack_install('int2lm @int2lm-3.00 %gcc', test_root=False)
-
-
-@pytest.mark.int2lm
-def test_install_int2lm_version_3_00_nvhpc_fixed_definitions():
- spack_install(
- 'int2lm @int2lm-3.00 %nvhpc ^cosmo-eccodes-definitions@2.19.0.7%nvhpc',
- test_root='balfrin' not in machine_name())
+def test_install_int2lm_3_00_nvhpc():
+ spack_install('int2lm @int2lm-3.00 %nvhpc', test_root=False)
-@pytest.mark.libgrib1
def test_install_libgrib1_22_01_2020_nvhpc():
- spack_install('libgrib1 @22-01-2020%nvhpc')
+ spack_install('libgrib1 @22-01-2020 %nvhpc')
-@pytest.mark.makedepf90
def test_install_makedepf90():
spack_install('makedepf90 @3.0.1', test_root=False)
-@pytest.mark.oasis
def test_install_oasis_version_4_0_nvhpc():
spack_install('oasis @4.0 %nvhpc')
-@pytest.mark.pytorch_fortran
-def test_install_pytorch_fortran_version_0_4(devirt_env):
+def test_install_pytorch_fortran_version_0_4():
spack_install(
'pytorch-fortran@0.4%nvhpc ^pytorch-fortran-proxy@0.4%gcc ^python@3.10 ^gmake%gcc ^cmake%gcc',
test_root=False)
-@pytest.mark.pytorch_fortran_proxy
-def test_install_pytorch_fortran_proxy_version_0_4(devirt_env):
+def test_install_pytorch_fortran_proxy_version_0_4():
spack_install('pytorch-fortran-proxy@0.4%gcc ^python@3.10',
test_root=False)
-@pytest.mark.py_cytoolz
-def test_py_cytoolz_install_default(devirt_env):
+def test_install_py_cytoolz_install_default():
spack_install('py-cytoolz')
-@pytest.mark.py_devtools
-def test_py_devtools_install_default(devirt_env):
+def test_install_py_devtools_install_default():
spack_install('py-devtools')
-@pytest.mark.py_factory_boy
-def test_py_factory_boy_install_default(devirt_env):
+def test_install_py_factory_boy_install_default():
spack_install('py-factory-boy')
-@pytest.mark.py_frozendict
-def test_py_frozendict_install_default(devirt_env):
+def test_install_py_frozendict_install_default():
spack_install('py-frozendict')
-@pytest.mark.py_gridtools_cpp
-def test_py_gridtools_cpp_install_default(devirt_env):
+def test_install_py_gridtools_cpp_install_default():
spack_install('py-gridtools-cpp')
-@pytest.mark.py_gt4py
-@pytest.mark.parametrize("version", ['1.0.3.3', '1.0.3.7', '1.0.3.9'])
-def test_install_py_gt4py_for_version(version, devirt_env):
+@pytest.mark.parametrize("version", ['1.0.3.7', '1.0.3.9'])
+def test_install_py_gt4py_for_version(version):
spack_install(f'py-gt4py @{version}')
-@pytest.mark.py_icon4py
-def test_install_py_icon4py_version_0_0_10(devirt_env):
- spack_install('py-icon4py @ 0.0.10 %gcc ^py-gt4py@1.0.3.3')
-
-
-@pytest.mark.py_icon4py
-def test_install_py_icon4py_version_0_0_11(devirt_env):
- spack_install('py-icon4py @ 0.0.11 %gcc ^py-gt4py@1.0.3.7')
-
-
-@pytest.mark.py_icon4py
-def test_install_py_icon4py_version_0_0_13(devirt_env):
- spack_install('py-icon4py @ 0.0.13 %gcc ^py-gt4py@1.0.3.9')
+def test_install_py_icon4py():
+ spack_install('py-icon4py')
-@pytest.mark.py_hatchling
-def test_install_py_hatchling_default(devirt_env):
+def test_install_py_hatchling_default():
spack_install('py-hatchling')
-@pytest.mark.py_inflection
-def test_install_py_inflection_default(devirt_env):
+def test_install_py_inflection_default():
spack_install('py-inflection')
-@pytest.mark.py_pytest_factoryboy
-def test_install_py_pytest_factoryboy_default(devirt_env):
+def test_install_py_pytest_factoryboy_default():
spack_install('py-pytest-factoryboy')
-@pytest.mark.py_tabulate
-def test_install_py_tabulate_default(devirt_env):
+def test_install_py_tabulate_default():
spack_install('py-tabulate')
-@pytest.mark.py_typing_extensions
-def test_install_py_typing_extensions_default(devirt_env):
+def test_install_py_typing_extensions_default():
spack_install('py-typing-extensions')
-@pytest.mark.yaxt
def test_install_yaxt_default():
spack_install('yaxt')
diff --git a/test/unit_test.py b/test/unit_test.py
index 1569fb7cf6..e024555fe9 100644
--- a/test/unit_test.py
+++ b/test/unit_test.py
@@ -1,135 +1,10 @@
import unittest
-import sys
-import os
-
-spack_c2sm_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- '..')
-sys.path.append(os.path.normpath(spack_c2sm_path))
-from src import machine_name, Markdown, HTML, time_format, sanitized_filename, all_machines, all_packages, explicit_scope, package_triggers
-
-
-class MachineDetection(unittest.TestCase):
-
- @unittest.skipUnless(__name__ == '__main__' and len(sys.argv) > 1,
- 'needs machine_name_from_arg')
- def test_machine_name(self):
- self.assertEqual(machine_name(), machine_name_from_arg)
-
-
-class MarkDownTest(unittest.TestCase):
-
- def test_ordered_list(self):
- self.assertEqual(Markdown.ordered_list(['a', 'b']), '1. a\n2. b')
-
- def test_unordered_list(self):
- self.assertEqual(Markdown.unordered_list(['a', 'b']), '* a\n* b')
-
- def test_link(self):
- self.assertEqual(Markdown.link('text', 'url'), '[text](url)')
-
- def test_image(self):
- self.assertEqual(Markdown.image('text', 'url'), '![text](url)')
-
- def test_inline_code(self):
- self.assertEqual(Markdown.inline_code('code'), '`code`')
-
- def test_code(self):
- self.assertEqual(Markdown.code('code'), '```\ncode\n```')
- self.assertEqual(Markdown.code('code', 'language'),
- '```language\ncode\n```')
-
- def test_table(self):
- self.assertEqual(
- Markdown.table(['title1', 'title2'],
- [['data1', 'data2'], ['data3', 'data4']]),
- 'title1 | title2\n--- | ---\ndata1 | data2\ndata3 | data4')
-
-
-class HTMLTest(unittest.TestCase):
-
- def test_link(self):
- self.assertEqual(HTML.link('text', 'url'), 'text')
-
- def test_table(self):
- self.assertEqual(
- HTML.table(['title1', 'title2'],
- [['data1', 'data2'], ['data3', 'data4']]),
- 'title1 | title2 |
---|
data1 | data2 |
data3 | data4 |
'
- )
-
- def test_collapsible(self):
- self.assertEqual(
- HTML.collapsible('summary', 'details'),
- 'summary
details ')
+from spack_commands import time_format
class TimeFormatTest(unittest.TestCase):
- def test_seconds_only(self):
- self.assertEqual(time_format(1), '1.00s')
-
- def test_minutes_only(self):
- self.assertEqual(time_format(60), '1m')
-
- def test_hours_only(self):
- self.assertEqual(time_format(3600), '1h')
-
- def test_full_combo(self):
- self.assertEqual(time_format(3600 + 23 * 60 + 45.67), '1h 23m 45.67s')
-
-
-class FilenameSanitizerTest(unittest.TestCase):
-
def test_example(self):
- example = 'spack installcosmo --until build --dont-restage --test=root --show-log-on-error -n -v cosmo @6.0 %nvhpc cosmo_target=cpu ~cppdycore ^mpich %nvhpc fflags="-O3"'
-
- sanitized = sanitized_filename(example)
-
- self.assertFalse(' ' in sanitized)
- self.assertFalse('%' in sanitized)
- self.assertFalse('"' in sanitized)
- self.assertEqual(
- sanitized,
- 'spack_installcosmo_cosmo_@6.0_nvhpc_cosmo_target=cpu_~cppdycore_^mpich_nvhpc_fflags=-O3'
- )
-
-
-class ScopeTest(unittest.TestCase):
-
- def test_all_packages(self):
- self.assertTrue('icon' in all_packages)
-
- def test_explicit_scope_1_machine_1_package(self):
- scope = explicit_scope('balfrin cosmo')
- self.assertEqual(sorted(scope), sorted(['balfrin', 'cosmo']))
-
- def test_explicit_scope_2_machines_2_packages(self):
- scope = explicit_scope('balfrin cosmo icon')
- self.assertEqual(sorted(scope), sorted(['balfrin', 'cosmo', 'icon']))
-
- def test_explicit_scope_0_machines_1_package(self):
- scope = explicit_scope('cosmo')
- self.assertEqual(sorted(scope), sorted(all_machines + ['cosmo']))
-
- def test_explicit_scope_0_machines_0_packages(self):
- scope = explicit_scope('launch jenkins')
- self.assertEqual(
- sorted(scope),
- sorted(['launch', 'jenkins'] + all_machines + all_packages))
-
- def test_explicit_scope_allows_unknowns(self):
- scope = explicit_scope('launch jenkins balfrin cosmo')
- self.assertEqual(sorted(scope),
- sorted(['launch', 'jenkins', 'balfrin', 'cosmo']))
-
- def test_package_triggers(self):
- triggers = package_triggers(['py-gt4py'])
- self.assertTrue('py-gt4py' in triggers) # package name included
- self.assertTrue('py_gt4py' in triggers) # marker name included
-
-
-if __name__ == '__main__':
- if len(sys.argv) > 1:
- machine_name_from_arg = sys.argv[-1]
- sys.argv = sys.argv[:-1] # unittest needs this
- unittest.main(verbosity=2)
+ self.assertEqual(time_format(0.123), "0.12s")
+ self.assertEqual(time_format(123.456), "2m 3.46s")
+ self.assertEqual(time_format(123456.789), "34h 17m 36.79s")
diff --git a/tools/summarize_logs.py b/tools/summarize_logs.py
new file mode 100644
index 0000000000..96d2035ab4
--- /dev/null
+++ b/tools/summarize_logs.py
@@ -0,0 +1,16 @@
+from pathlib import Path
+
+with Path('log/artifacts_summary.html').open('w') as f:
+ f.write('\n')
+ f.write('\n')
+ for file in sorted(Path("log").iterdir()):
+ if file.suffix != '.log':
+ continue
+ second_last_line = file.read_text().split('\n')[-2]
+ if 'OK' in second_last_line:
+ circle = '🟢'
+ else:
+ circle = '🔴'
+ f.write(f'{circle} {file.stem}
\n')
+ f.write('\n')
+ f.write('\n')
diff --git a/sysconfigs/euler/config.yaml b/user-config/config.yaml
similarity index 100%
rename from sysconfigs/euler/config.yaml
rename to user-config/config.yaml
diff --git a/sysconfigs/uenv/repos.yaml b/user-config/repos.yaml
similarity index 100%
rename from sysconfigs/uenv/repos.yaml
rename to user-config/repos.yaml