consolidate lock file handling

- adds config_file_lock context manager to re-use
- moves filelock import to module level
- fixes exit codes, stderr messages
This commit is contained in:
Min RK
2024-09-05 11:58:51 +02:00
parent f7118edf48
commit 13c8946d8c

View File

@@ -18,9 +18,11 @@ import re
import sys
import time
from collections.abc import Mapping, Sequence
from contextlib import contextmanager
from copy import deepcopy
import requests
from filelock import FileLock, Timeout
from .yaml import yaml
@@ -32,6 +34,22 @@ CONFIG_DIR = os.path.join(INSTALL_PREFIX, "config")
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.yaml")
@contextmanager
def config_file_lock(config_path, timeout=1):
"""Context manager to acquire the config file lock"""
lock_file = f"{config_path}.lock"
try:
with FileLock(lock_file).acquire(timeout=timeout):
yield
except Timeout:
print(
f"Another instance of tljh-config holds the lock {lock_file}.",
file=sys.stderr,
)
sys.exit(1)
def set_item_in_config(config, property_path, value):
"""
Set key at property_path to value in config & return new config.
@@ -169,9 +187,10 @@ def validate_config(config, validate):
print(
f"Config validation error: {e.message}.\n"
"You can still apply this change without validation by re-running your command with the --no-validate flag.\n"
"If you think this validation error is incorrect, please report it to https://github.com/jupyterhub/the-littlest-jupyterhub/issues."
"If you think this validation error is incorrect, please report it to https://github.com/jupyterhub/the-littlest-jupyterhub/issues.",
file=sys.stderr,
)
exit()
sys.exit(1)
def show_config(config_path):
@@ -186,12 +205,7 @@ def set_config_value(config_path, key_path, value, validate=True):
"""
Set key at key_path in config_path to value
"""
from filelock import FileLock, Timeout
lock_file = f"{config_path}.lock"
lock = FileLock(lock_file)
try:
with lock.acquire(timeout=1):
with config_file_lock(config_path):
config = get_current_config(config_path)
config = set_item_in_config(config, key_path, value)
validate_config(config, validate)
@@ -199,21 +213,12 @@ def set_config_value(config_path, key_path, value, validate=True):
with open(config_path, "w") as f:
yaml.dump(config, f)
except Timeout:
print(f"Another instance of tljh-config holds the lock {lock_file}")
exit(1)
def unset_config_value(config_path, key_path, validate=True):
"""
Unset key at key_path in config_path
"""
from filelock import FileLock, Timeout
lock_file = f"{config_path}.lock"
lock = FileLock(lock_file)
try:
with lock.acquire(timeout=1):
with config_file_lock(config_path):
config = get_current_config(config_path)
config = unset_item_from_config(config, key_path)
validate_config(config, validate)
@@ -221,21 +226,12 @@ def unset_config_value(config_path, key_path, validate=True):
with open(config_path, "w") as f:
yaml.dump(config, f)
except Timeout:
print(f"Another instance of tljh-config holds the lock {lock_file}")
exit(1)
def add_config_value(config_path, key_path, value, validate=True):
"""
Add value to list at key_path
"""
from filelock import FileLock, Timeout
lock_file = f"{config_path}.lock"
lock = FileLock(lock_file)
try:
with lock.acquire(timeout=1):
with config_file_lock(config_path):
config = get_current_config(config_path)
config = add_item_to_config(config, key_path, value)
validate_config(config, validate)
@@ -243,21 +239,12 @@ def add_config_value(config_path, key_path, value, validate=True):
with open(config_path, "w") as f:
yaml.dump(config, f)
except Timeout:
print(f"Another instance of tljh-config holds the lock {lock_file}")
exit(1)
def remove_config_value(config_path, key_path, value, validate=True):
"""
Remove value from list at key_path
"""
from filelock import FileLock, Timeout
lock_file = f"{config_path}.lock"
lock = FileLock(lock_file)
try:
with lock.acquire(timeout=1):
with config_file_lock(config_path):
config = get_current_config(config_path)
config = remove_item_from_config(config, key_path, value)
validate_config(config, validate)
@@ -265,10 +252,6 @@ def remove_config_value(config_path, key_path, value, validate=True):
with open(config_path, "w") as f:
yaml.dump(config, f)
except Timeout:
print(f"Another instance of tljh-config holds the lock {lock_file}")
exit(1)
def get_current_config(config_path):
"""