mirror of
https://github.com/jupyterhub/the-littlest-jupyterhub.git
synced 2025-12-18 21:54:05 +08:00
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:
@@ -18,9 +18,11 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from collections.abc import Mapping, Sequence
|
from collections.abc import Mapping, Sequence
|
||||||
|
from contextlib import contextmanager
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from filelock import FileLock, Timeout
|
||||||
|
|
||||||
from .yaml import yaml
|
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")
|
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):
|
def set_item_in_config(config, property_path, value):
|
||||||
"""
|
"""
|
||||||
Set key at property_path to value in config & return new config.
|
Set key at property_path to value in config & return new config.
|
||||||
@@ -169,9 +187,10 @@ def validate_config(config, validate):
|
|||||||
print(
|
print(
|
||||||
f"Config validation error: {e.message}.\n"
|
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"
|
"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):
|
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
|
Set key at key_path in config_path to value
|
||||||
"""
|
"""
|
||||||
from filelock import FileLock, Timeout
|
with config_file_lock(config_path):
|
||||||
|
|
||||||
lock_file = f"{config_path}.lock"
|
|
||||||
lock = FileLock(lock_file)
|
|
||||||
try:
|
|
||||||
with lock.acquire(timeout=1):
|
|
||||||
config = get_current_config(config_path)
|
config = get_current_config(config_path)
|
||||||
config = set_item_in_config(config, key_path, value)
|
config = set_item_in_config(config, key_path, value)
|
||||||
validate_config(config, validate)
|
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:
|
with open(config_path, "w") as f:
|
||||||
yaml.dump(config, 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):
|
def unset_config_value(config_path, key_path, validate=True):
|
||||||
"""
|
"""
|
||||||
Unset key at key_path in config_path
|
Unset key at key_path in config_path
|
||||||
"""
|
"""
|
||||||
from filelock import FileLock, Timeout
|
with config_file_lock(config_path):
|
||||||
|
|
||||||
lock_file = f"{config_path}.lock"
|
|
||||||
lock = FileLock(lock_file)
|
|
||||||
try:
|
|
||||||
with lock.acquire(timeout=1):
|
|
||||||
config = get_current_config(config_path)
|
config = get_current_config(config_path)
|
||||||
config = unset_item_from_config(config, key_path)
|
config = unset_item_from_config(config, key_path)
|
||||||
validate_config(config, validate)
|
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:
|
with open(config_path, "w") as f:
|
||||||
yaml.dump(config, 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):
|
def add_config_value(config_path, key_path, value, validate=True):
|
||||||
"""
|
"""
|
||||||
Add value to list at key_path
|
Add value to list at key_path
|
||||||
"""
|
"""
|
||||||
from filelock import FileLock, Timeout
|
with config_file_lock(config_path):
|
||||||
|
|
||||||
lock_file = f"{config_path}.lock"
|
|
||||||
lock = FileLock(lock_file)
|
|
||||||
try:
|
|
||||||
with lock.acquire(timeout=1):
|
|
||||||
config = get_current_config(config_path)
|
config = get_current_config(config_path)
|
||||||
config = add_item_to_config(config, key_path, value)
|
config = add_item_to_config(config, key_path, value)
|
||||||
validate_config(config, validate)
|
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:
|
with open(config_path, "w") as f:
|
||||||
yaml.dump(config, 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):
|
def remove_config_value(config_path, key_path, value, validate=True):
|
||||||
"""
|
"""
|
||||||
Remove value from list at key_path
|
Remove value from list at key_path
|
||||||
"""
|
"""
|
||||||
from filelock import FileLock, Timeout
|
with config_file_lock(config_path):
|
||||||
|
|
||||||
lock_file = f"{config_path}.lock"
|
|
||||||
lock = FileLock(lock_file)
|
|
||||||
try:
|
|
||||||
with lock.acquire(timeout=1):
|
|
||||||
config = get_current_config(config_path)
|
config = get_current_config(config_path)
|
||||||
config = remove_item_from_config(config, key_path, value)
|
config = remove_item_from_config(config, key_path, value)
|
||||||
validate_config(config, validate)
|
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:
|
with open(config_path, "w") as f:
|
||||||
yaml.dump(config, 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):
|
def get_current_config(config_path):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user