Fix watch if compilation fails, update README

This commit is contained in:
Corentin 2022-11-02 19:57:27 +09:00
commit ce74e6135e
2 changed files with 20 additions and 10 deletions

View file

@ -10,6 +10,8 @@ The advantages of this tool are :
* hash system to avoid time check issues (same file content, remote files problems, etc) * hash system to avoid time check issues (same file content, remote files problems, etc)
* watch option to recompile whenever a source is changed
## Use ## Use
@ -25,15 +27,14 @@ This repository is meant to be used as a submodule of a C/C++ project.
By default 3 targets can be used `make` (or `make all` as usual default of makefiles), `make debug` and `make clean`. By default 3 targets can be used `make` (or `make all` as usual default of makefiles), `make debug` and `make clean`.
**Be careful** : `clean` will delete the object and binary output directories defined in `make.py`.
**Example :** from the root folder of a project : **Example :** from the root folder of a project :
``` ```
git submodule add https://gitlab.com/corentin-pro/umake.git && cp umake/make* . git submodule add https://gitlab.com/corentin-pro/umake.git && cp umake/make* .
``` ```
Then change the configuration in `make.py` and a simple `make` command will build your project!
## How it works ## How it works

View file

@ -128,18 +128,18 @@ class Builder:
def make(self): def make(self):
self._populate_todo_dict() self._populate_todo_dict()
self._compile_sources()
if self._config.WATCH: if self._config.WATCH:
from watch import Watcher, WatchFlag # pylint: disable=import-outside-toplevel from watch import Watcher, WatchFlag # pylint: disable=import-outside-toplevel
def callback(path: Path, _flags: WatchFlag): def callback(path: Path, _flags: WatchFlag):
source_hash = get_hash(path) source_hash = get_hash(path)
if source_hash != self._hash_dict[str(path)]: if str(path) not in self._hash_dict or source_hash != self._hash_dict[str(path)]:
print(f'{ConsoleColor.ORANGE}Source file changed : {path} {ConsoleColor.ENDCOLOR}') print(f'{ConsoleColor.ORANGE}Source file changed : {path} {ConsoleColor.ENDCOLOR}')
self._populate_todo_dict() self._populate_todo_dict()
self._compile_sources() self._compile_sources()
self._compile_sources()
watcher = Watcher() watcher = Watcher()
for source_path in self._compile_dict: for source_path in self._compile_dict:
watcher.register(source_path, WatchFlag.MODIFY, callback) watcher.register(source_path, WatchFlag.MODIFY, callback)
@ -147,6 +147,8 @@ class Builder:
watcher.watch() watcher.watch()
except KeyboardInterrupt: except KeyboardInterrupt:
print('\rExit') print('\rExit')
elif not self._compile_sources():
sys.exit(1)
def _populate_todo_dict(self): def _populate_todo_dict(self):
"""Check source file and generate compilation commands to execute.""" """Check source file and generate compilation commands to execute."""
@ -170,12 +172,12 @@ class Builder:
return ' '.join([self._config.CC, self._config.COMMON_FLAGS, self._config.COMPILE_FLAGS, return ' '.join([self._config.CC, self._config.COMMON_FLAGS, self._config.COMPILE_FLAGS,
str(source_path), '-c', '-o', str(object_path)]) str(source_path), '-c', '-o', str(object_path)])
def _compile_sources(self): def _compile_sources(self) -> bool:
if not self._todo_dict and all( if not self._todo_dict and all(
(self._config.BIN_DIR / app_path).exists() (self._config.BIN_DIR / app_path).exists()
for app_path in self._config.APPS if app_path not in self._config.IGNORE_APPS): for app_path in self._config.APPS if app_path not in self._config.IGNORE_APPS):
print(f'{ConsoleColor.GREEN}Nothing to do{ConsoleColor.ENDCOLOR}') print(f'{ConsoleColor.GREEN}Nothing to do{ConsoleColor.ENDCOLOR}')
return return True
# Running compilation processes # Running compilation processes
if not os.path.exists(self._config.OBJECT_DIR): if not os.path.exists(self._config.OBJECT_DIR):
@ -194,11 +196,13 @@ class Builder:
oldest_job.wait() oldest_job.wait()
if oldest_job.returncode != 0: if oldest_job.returncode != 0:
error_paths.append((job_path, oldest_job.stdout.read() + oldest_job.stderr.read())) error_paths.append((job_path, oldest_job.stdout.read() + oldest_job.stderr.read()))
if str(job_path) in self._hash_dict:
del self._hash_dict[str(job_path)]
break break
# Update hash if no error # Update hash if no error
for dependency_path in self._dependency_dict[str(job_path)]: for dependency_path in self._dependency_dict[str(job_path)]:
self._hash_dict[str(dependency_path)] = get_hash(dependency_path) self._hash_dict[str(dependency_path)] = get_hash(dependency_path)
completed_paths.append(source_path) completed_paths.append(job_path)
for source_path in completed_paths: for source_path in completed_paths:
del self._todo_dict[source_path] del self._todo_dict[source_path]
@ -206,6 +210,8 @@ class Builder:
job.wait() job.wait()
if job.returncode != 0: if job.returncode != 0:
error_paths.append((job_path, job.stdout.read() + job.stderr.read())) error_paths.append((job_path, job.stdout.read() + job.stderr.read()))
if str(job_path) in self._hash_dict:
del self._hash_dict[str(job_path)]
else: else:
# Update hash if no error # Update hash if no error
for dependency_path in self._dependency_dict[str(job_path)]: for dependency_path in self._dependency_dict[str(job_path)]:
@ -219,6 +225,8 @@ class Builder:
universal_newlines=True, shell=True) universal_newlines=True, shell=True)
if job.returncode != 0: if job.returncode != 0:
error_paths.append((source_path, job.stdout + job.stderr)) error_paths.append((source_path, job.stdout + job.stderr))
if str(source_path) in self._hash_dict:
del self._hash_dict[str(source_path)]
break break
# Update hash if no error # Update hash if no error
for dependency_path in self._dependency_dict[str(source_path)]: for dependency_path in self._dependency_dict[str(source_path)]:
@ -232,7 +240,7 @@ class Builder:
print(ConsoleColor.RED + f'Error compiling {error_path}:\n' + ConsoleColor.ENDCOLOR + error_text) print(ConsoleColor.RED + f'Error compiling {error_path}:\n' + ConsoleColor.ENDCOLOR + error_text)
with open(self._config.OBJECT_DIR / 'hash.json', 'w', encoding='utf-8') as hash_file: with open(self._config.OBJECT_DIR / 'hash.json', 'w', encoding='utf-8') as hash_file:
hash_file.write(json.dumps(self._hash_dict, indent=1)) hash_file.write(json.dumps(self._hash_dict, indent=1))
sys.exit(1) return False
# Running linking processes # Running linking processes
if not self._config.BIN_DIR.exists(): if not self._config.BIN_DIR.exists():
@ -288,9 +296,10 @@ class Builder:
print(ConsoleColor.RED + f'Error linking {error_path}:\n' + ConsoleColor.ENDCOLOR + error_text) print(ConsoleColor.RED + f'Error linking {error_path}:\n' + ConsoleColor.ENDCOLOR + error_text)
with open(os.path.join(self._config.OBJECT_DIR, 'hash.json'), 'w', encoding='utf-8') as hash_file: with open(os.path.join(self._config.OBJECT_DIR, 'hash.json'), 'w', encoding='utf-8') as hash_file:
hash_file.write(json.dumps(self._hash_dict, indent=1)) hash_file.write(json.dumps(self._hash_dict, indent=1))
sys.exit(1) return False
with open(self._config.OBJECT_DIR / 'hash.json', 'w', encoding='utf-8') as hash_file: with open(self._config.OBJECT_DIR / 'hash.json', 'w', encoding='utf-8') as hash_file:
hash_file.write(json.dumps(self._hash_dict, indent=1)) hash_file.write(json.dumps(self._hash_dict, indent=1))
print(f'{ConsoleColor.GREEN}Compilation done{ConsoleColor.ENDCOLOR}') print(f'{ConsoleColor.GREEN}Compilation done{ConsoleColor.ENDCOLOR}')
return True