Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 42 additions & 6 deletions .github/scripts/tla_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from os.path import join, normpath, pathsep, dirname
from pathlib import PureWindowsPath
import subprocess
import sys
import re
import glob

Expand Down Expand Up @@ -137,6 +138,23 @@ def get_run_mode(mode):
else:
raise NotImplementedError(f'Undefined model-check mode {mode}')

_CHECK_DEADLOCK_FALSE_RE = re.compile(r'CHECK_DEADLOCK\s+FALSE')

def model_disables_deadlock_check(model_path):
"""
Returns True if the given TLC config file contains a `CHECK_DEADLOCK
FALSE` directive. Used to translate the directive to Apalache's
`--no-deadlock` CLI flag, since Apalache silently ignores it in the
config file. If Apalache ever grows native support for `CHECK_DEADLOCK`
in .cfg files (which seems unlikely), this translation can be dropped.
"""
try:
with open(normpath(model_path), 'r', encoding='utf-8') as f:
text = f.read()
except OSError:
return False
return _CHECK_DEADLOCK_FALSE_RE.search(text) is not None

def get_tlc_feature_flags(module_features):
"""
Selectively enables experimental TLC features according to needs.
Expand All @@ -163,19 +181,37 @@ def check_model(
Model-checks the given model against the given module.
"""
tools_jar_path = normpath(tools_jar_path)
apalache_path = normpath(join(apalache_path, 'bin', 'apalache-mc'))
apalache_jar_path = normpath(join(apalache_path, 'lib', 'apalache.jar'))
# On Windows the launcher is `apalache-mc.bat`, and `subprocess.run`
# cannot exec batch files via CreateProcess directly, so route them
# through `cmd.exe /c`. On Linux/macOS it is the unsuffixed shell script
# `apalache-mc` and we invoke it directly.
if sys.platform == 'win32':
apalache_path = normpath(join(apalache_path, 'bin', 'apalache-mc.bat'))
apalache_launcher = ['cmd.exe', '/c', apalache_path]
else:
apalache_path = normpath(join(apalache_path, 'bin', 'apalache-mc'))
apalache_launcher = [apalache_path]
module_path = normpath(module_path)
model_path = normpath(model_path)
tlapm_lib_path = normpath(tlapm_lib_path)
community_jar_path = normpath(community_jar_path)
try:
if mode == 'symbolic':
apalache = subprocess.run([
apalache_path, 'check',
f'--config={model_path}',
module_path
],
# Cap the bounded-model-checking depth at 5 steps for every
# example. Apalache's own default of 10 is itself an arbitrary
# choice; 5 keeps CI runtimes manageable across the suite while
# still exercising each spec non-trivially.
#
# Apalache silently ignores `CHECK_DEADLOCK FALSE` in .cfg files,
# so translate it to the equivalent CLI flag.
apalache_cmd = (
apalache_launcher + ['check', '--length=5']
+ (['--no-deadlock'] if model_disables_deadlock_check(model_path) else [])
+ [f'--config={model_path}', module_path]
)
apalache = subprocess.run(
apalache_cmd,
timeout=hard_timeout_in_seconds,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
Expand Down
43 changes: 30 additions & 13 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ jobs:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
unicode: [true, false]
# TEMP (Apalache PR): drop unicode variant; Apalache cannot model-check
# unicode-translated specs.
unicode: [false]
fail-fast: false
env:
SCRIPT_DIR: .github/scripts
Expand All @@ -45,23 +47,27 @@ jobs:
if: matrix.os != 'windows-latest'
run: $SCRIPT_DIR/linux-setup.sh $SCRIPT_DIR $DEPS_DIR false
- name: Check manifest.json format
if: false # TEMP (Apalache PR): only run Apalache model checks.
run: |
python "$SCRIPT_DIR/check_manifest_schema.py" \
--schema_path manifest-schema.json
- name: Check manifest files
if: false # TEMP (Apalache PR): only run Apalache model checks.
run: |
python "$SCRIPT_DIR/check_manifest_files.py" \
--ci_ignore_path .ciignore
- name: Check manifest feature flags
if: false # TEMP (Apalache PR): only run Apalache model checks.
run: |
python "$SCRIPT_DIR/check_manifest_features.py" \
--examples_root .
- name: Check README spec table
if: false # TEMP (Apalache PR): only run Apalache model checks.
run: |
python "$SCRIPT_DIR/check_markdown_table.py" \
--readme_path README.md
- name: Convert specs to unicode
if: matrix.unicode
if: false && matrix.unicode # TEMP (Apalache PR): only run Apalache model checks.
Comment thread
lemmy marked this conversation as resolved.
run: |
python "$SCRIPT_DIR/unicode_conversion.py" \
--tlauc_path "$DEPS_DIR/tlauc/tlauc" \
Expand All @@ -75,7 +81,8 @@ jobs:
# discard the results. However, discarding the results with git reset
# also would discard the Unicode translation. So, only execute this
# step if we did not perform Unicode translation.
if: (!matrix.unicode)
# TEMP (Apalache PR): only run Apalache model checks.
if: false && (!matrix.unicode)
run: |
# https://github.com/tlaplus/tlaplus/issues/906
SKIP=(
Expand All @@ -89,6 +96,7 @@ jobs:
--skip "${SKIP[@]}"
git reset --hard HEAD # Restore specs to their original state
- name: Parse all modules
if: false # TEMP (Apalache PR): only run Apalache model checks.
run: |
python $SCRIPT_DIR/parse_modules.py \
--tools_jar_path $DEPS_DIR/tools/tla2tools.jar \
Expand All @@ -97,24 +105,30 @@ jobs:
--community_modules_jar_path $DEPS_DIR/community/modules.jar \
--examples_root .
- name: Check small models
# TEMP (Apalache PR): only run Apalache (`mode: symbolic`) models. The
# `--only` filter restricts check_small_models.py to the AP*.cfg
# configurations introduced by this PR (plus the pre-existing
# EinsteinRiddle Apalache model).
run: |
# Need to have a nonempty list to pass as a skip parameter
# SKIP=("does/not/exist")
# strange issue with parsing TLC output
SKIP=("specifications/ewd840/EWD840.cfg")
if [ ${{ matrix.unicode }} ]; then
# Apalache does not yet support Unicode
SKIP+=("specifications/EinsteinRiddle/Einstein.cfg")
fi
ONLY=()
while IFS= read -r f; do ONLY+=("$f"); done < <(
find specifications -type f \( -name 'AP*.cfg' -o -path '*/EinsteinRiddle/Einstein.cfg' \) | sort
)
echo "Restricting to ${#ONLY[@]} Apalache model(s):"
printf ' %s\n' "${ONLY[@]}"
python $SCRIPT_DIR/check_small_models.py \
--verbose \
--tools_jar_path $DEPS_DIR/tools/tla2tools.jar \
--apalache_path $DEPS_DIR/apalache \
--tlapm_lib_path $DEPS_DIR/tlapm/library \
--community_modules_jar_path $DEPS_DIR/community/modules.jar \
--examples_root . \
--skip "${SKIP[@]}"
--only "${ONLY[@]}"
- name: Smoke-test large models
# TEMP (Apalache PR): only run Apalache model checks; no AP*.cfg
# entry has a runtime above 30s, so this step would have nothing
# Apalache-related to do.
if: false
run: |
# SimKnuthYao requires certain number of states to have been generated
# before termination or else it fails. This makes it not amenable to
Expand All @@ -133,7 +147,8 @@ jobs:
--examples_root . \
--skip "${SKIP[@]}"
- name: Check proofs
if: matrix.os != 'windows-latest' && !matrix.unicode
# TEMP (Apalache PR): only run Apalache model checks.
if: false && matrix.os != 'windows-latest' && !matrix.unicode
run: |
set -o pipefail
find specifications -iname "manifest.json" -print0 \
Expand All @@ -147,11 +162,13 @@ jobs:
| xargs --verbose --null --no-run-if-empty -I {TLA_FILE} \
"$DEPS_DIR/tlapm/bin/tlapm" "{TLA_FILE}" -I "$DEPS_DIR/community" --stretch 5
- name: Smoke-test manifest generation script
if: false # TEMP (Apalache PR): only run Apalache model checks.
run: |
python $SCRIPT_DIR/generate_manifest.py \
--ci_ignore_path .ciignore
git diff -a
- name: Smoke-test state space script
if: false # TEMP (Apalache PR): only run Apalache model checks.
run: |
git reset --hard HEAD
python $SCRIPT_DIR/record_model_state_space.py \
Expand Down
Loading
Loading