Skip to content

Commit

Permalink
Merge pull request #223 from neutrinoceros/auto_recompile
Browse files Browse the repository at this point in the history
idfx run now always calls make before running Idefix, unless configured otherwise
  • Loading branch information
neutrinoceros authored Feb 17, 2023
2 parents 44da6a0 + 9052086 commit 8900b10
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 49 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0] - 2023-02-17

ENH: `idfx run` now always calls `make` before running Idefix, unless configured otherwise


## [1.0.1] - 2023-02-10

BUG: fix a used-before-definition error detected by mypy
Expand Down
25 changes: 25 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,31 @@ specified directory. Use `idfx conf` to generate the `Makefile`.
Additional, arbitrary arguments may be passed to the `idefix` executable via this
command.

*new in `idefix_cli` 1.1.0*

By default, `idfx run` will call `make` before running `idefix` on every invoke,
which is essentially free when the binary is already up to date, and desired in
almost every other cases. Alternative behaviours can be enabled with the persistent
configuration file.

```ini
# idefix.cfg
[idfx run]
# default
recompile = always
# check if source files were updated since
# the last successful compilation, and if so,
# ask wether to recompile via a prompt. Skip
# compilation completely if the binary appears to be
# up to date.
recompile = prompt
```

The 'prompt' mode was the default up to `idefix_cli` 1.0


### minimal example: run a test sequentially

```shell
Expand Down
2 changes: 1 addition & 1 deletion idefix_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.0.1"
__version__ = "1.1.0"
128 changes: 81 additions & 47 deletions idefix_cli/_commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import subprocess
import sys
from copy import deepcopy
from enum import Enum, auto
from multiprocessing import cpu_count
from pathlib import Path
from subprocess import CalledProcessError, check_call
Expand All @@ -16,6 +17,8 @@

from idefix_cli.lib import (
files_from_patterns,
get_config_file,
get_option,
print_err,
print_subcommand,
print_warning,
Expand All @@ -24,9 +27,18 @@

if sys.version_info >= (3, 11):
from contextlib import chdir
from typing import assert_never
else:
from typing_extensions import assert_never

from idefix_cli.lib import chdir


class RecompileMode(Enum):
ALWAYS = auto()
PROMPT = auto()


# known end messages in Idefix
KNOWN_SUCCESS: Final = (
"Main: Job completed successfully.",
Expand Down Expand Up @@ -165,59 +177,81 @@ def command(
for entry in output_types:
output_sec[entry] = time_step

compilation_is_required: bool
if not exe.is_file():
compilation_is_required = True
recompile_mode_str: str = get_option("idfx run", "recompile")
if not recompile_mode_str:
recompile_mode_str = "always"

recompile_mode: RecompileMode
if recompile_mode_str == "always":
recompile_mode = RecompileMode.ALWAYS
elif recompile_mode == "prompt":
recompile_mode = RecompileMode.PROMPT
else:
last_compilation_time = os.stat(exe).st_mtime
source_patterns = (
"**/*.hpp",
"**/*.cpp",
"**/*.h",
"**/*.c",
"**/CMakeLists.txt",
"**/Makefile.cmake",
print_warning(
"[idfx run].recompile expects either 'always' (default) or 'prompt'. "
f"Got {recompile_mode} from {get_config_file()}\n"
)
files_to_check = files_from_patterns(d, *source_patterns, recursive=True)
idefix_dir = Path(os.environ["IDEFIX_DIR"])
try:
with chdir(idefix_dir):
git_indexed_idefix_files = [
os.path.abspath(_)
for _ in subprocess.run(["git", "ls-files"], capture_output=True)
.stdout.decode()
.split("\n")
]
except subprocess.CalledProcessError:
# emmit no warning here as Idefix might not be installed as a git copy
pass
else:
source_files = files_from_patterns(
idefix_dir / "src", *source_patterns, recursive=True
)
files_to_check.extend(
set(git_indexed_idefix_files).intersection(source_files)
print_warning("Falling back to 'prompt' mode.")
recompile_mode = RecompileMode.PROMPT

compilation_is_required: bool
if recompile_mode is RecompileMode.ALWAYS:
compilation_is_required = True
elif recompile_mode is RecompileMode.PROMPT:
if exe.is_file():
last_compilation_time = os.stat(exe).st_mtime
source_patterns = (
"**/*.hpp",
"**/*.cpp",
"**/*.h",
"**/*.c",
"**/CMakeLists.txt",
"**/Makefile.cmake",
)
files_to_check = files_from_patterns(d, *source_patterns, recursive=True)
idefix_dir = Path(os.environ["IDEFIX_DIR"])
try:
with chdir(idefix_dir):
git_indexed_idefix_files = [
os.path.abspath(_)
for _ in subprocess.run(
["git", "ls-files"], capture_output=True
)
.stdout.decode()
.split("\n")
]
except subprocess.CalledProcessError:
# emmit no warning here as Idefix might not be installed as a git copy
pass
else:
source_files = files_from_patterns(
idefix_dir / "src", *source_patterns, recursive=True
)
files_to_check.extend(
set(git_indexed_idefix_files).intersection(source_files)
)

source_edit_times = tuple(
(file, os.stat(file).st_mtime) for file in files_to_check
)
time_deltas = tuple(
(file, edit_time - last_compilation_time)
for file, edit_time in source_edit_times
)
if updated_since_compilation := tuple(
file for file, td in time_deltas if td > 0
):
print_warning(
"The following files were updated since last successful compilation:",
source_edit_times = tuple(
(file, os.stat(file).st_mtime) for file in files_to_check
)
print("\n".join(updated_since_compilation), file=sys.stderr)
compilation_is_required = Confirm.ask(
"Would you like to recompile before running the program ?"
time_deltas = tuple(
(file, edit_time - last_compilation_time)
for file, edit_time in source_edit_times
)
else:
compilation_is_required = False
if updated_since_compilation := tuple(
file for file, td in time_deltas if td > 0
):
print_warning(
"The following files were updated since last successful compilation:",
)
print("\n".join(updated_since_compilation), file=sys.stderr)
compilation_is_required = Confirm.ask(
"Would you like to recompile before running the program ?"
)
else:
compilation_is_required = False
else:
assert_never(recompile_mode)

if compilation_is_required and (ret := make(directory)) != 0:
return ret
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "idefix_cli"
version = "1.0.1"
version = "1.1.0"
description = "A CLI to automate mundane tasks with Idefix"
authors = [
{ name = "C.M.T. Robert" },
Expand Down

0 comments on commit 8900b10

Please sign in to comment.