Skip to content

Commit 7be7eb4

Browse files
authored
Merge pull request #994 from minrk/consolidate_lock
consolidate lock file handling
2 parents f7118ed + 0c32277 commit 7be7eb4

File tree

5 files changed

+46
-67
lines changed

5 files changed

+46
-67
lines changed

dev-requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
filelock
21
packaging
32
pytest
43
pytest-cov

integration-tests/requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
filelock
21
pytest
32
pytest-cov
43
pytest-asyncio

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"jinja2",
1616
"pluggy==1.*",
1717
"backoff",
18+
"filelock",
1819
"requests",
1920
"bcrypt",
2021
"jupyterhub-traefik-proxy==1.*",

tljh/config.py

Lines changed: 45 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
import sys
1919
import time
2020
from collections.abc import Mapping, Sequence
21+
from contextlib import contextmanager
2122
from copy import deepcopy
2223

2324
import requests
25+
from filelock import FileLock, Timeout
2426

2527
from .yaml import yaml
2628

@@ -32,6 +34,22 @@
3234
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.yaml")
3335

3436

37+
@contextmanager
38+
def config_file_lock(config_path, timeout=1):
39+
"""Context manager to acquire the config file lock"""
40+
lock_file = f"{config_path}.lock"
41+
try:
42+
with FileLock(lock_file).acquire(timeout=timeout):
43+
yield
44+
45+
except Timeout:
46+
print(
47+
f"Another instance of tljh-config holds the lock {lock_file}.",
48+
file=sys.stderr,
49+
)
50+
sys.exit(1)
51+
52+
3553
def set_item_in_config(config, property_path, value):
3654
"""
3755
Set key at property_path to value in config & return new config.
@@ -169,9 +187,10 @@ def validate_config(config, validate):
169187
print(
170188
f"Config validation error: {e.message}.\n"
171189
"You can still apply this change without validation by re-running your command with the --no-validate flag.\n"
172-
"If you think this validation error is incorrect, please report it to https://github.com/jupyterhub/the-littlest-jupyterhub/issues."
190+
"If you think this validation error is incorrect, please report it to https://github.com/jupyterhub/the-littlest-jupyterhub/issues.",
191+
file=sys.stderr,
173192
)
174-
exit()
193+
sys.exit(1)
175194

176195

177196
def show_config(config_path):
@@ -186,88 +205,52 @@ def set_config_value(config_path, key_path, value, validate=True):
186205
"""
187206
Set key at key_path in config_path to value
188207
"""
189-
from filelock import FileLock, Timeout
208+
with config_file_lock(config_path):
209+
config = get_current_config(config_path)
210+
config = set_item_in_config(config, key_path, value)
211+
validate_config(config, validate)
190212

191-
lock_file = f"{config_path}.lock"
192-
lock = FileLock(lock_file)
193-
try:
194-
with lock.acquire(timeout=1):
195-
config = get_current_config(config_path)
196-
config = set_item_in_config(config, key_path, value)
197-
validate_config(config, validate)
198-
199-
with open(config_path, "w") as f:
200-
yaml.dump(config, f)
201-
202-
except Timeout:
203-
print(f"Another instance of tljh-config holds the lock {lock_file}")
204-
exit(1)
213+
with open(config_path, "w") as f:
214+
yaml.dump(config, f)
205215

206216

207217
def unset_config_value(config_path, key_path, validate=True):
208218
"""
209219
Unset key at key_path in config_path
210220
"""
211-
from filelock import FileLock, Timeout
221+
with config_file_lock(config_path):
222+
config = get_current_config(config_path)
223+
config = unset_item_from_config(config, key_path)
224+
validate_config(config, validate)
212225

213-
lock_file = f"{config_path}.lock"
214-
lock = FileLock(lock_file)
215-
try:
216-
with lock.acquire(timeout=1):
217-
config = get_current_config(config_path)
218-
config = unset_item_from_config(config, key_path)
219-
validate_config(config, validate)
220-
221-
with open(config_path, "w") as f:
222-
yaml.dump(config, f)
223-
224-
except Timeout:
225-
print(f"Another instance of tljh-config holds the lock {lock_file}")
226-
exit(1)
226+
with open(config_path, "w") as f:
227+
yaml.dump(config, f)
227228

228229

229230
def add_config_value(config_path, key_path, value, validate=True):
230231
"""
231232
Add value to list at key_path
232233
"""
233-
from filelock import FileLock, Timeout
234+
with config_file_lock(config_path):
235+
config = get_current_config(config_path)
236+
config = add_item_to_config(config, key_path, value)
237+
validate_config(config, validate)
234238

235-
lock_file = f"{config_path}.lock"
236-
lock = FileLock(lock_file)
237-
try:
238-
with lock.acquire(timeout=1):
239-
config = get_current_config(config_path)
240-
config = add_item_to_config(config, key_path, value)
241-
validate_config(config, validate)
242-
243-
with open(config_path, "w") as f:
244-
yaml.dump(config, f)
245-
246-
except Timeout:
247-
print(f"Another instance of tljh-config holds the lock {lock_file}")
248-
exit(1)
239+
with open(config_path, "w") as f:
240+
yaml.dump(config, f)
249241

250242

251243
def remove_config_value(config_path, key_path, value, validate=True):
252244
"""
253245
Remove value from list at key_path
254246
"""
255-
from filelock import FileLock, Timeout
247+
with config_file_lock(config_path):
248+
config = get_current_config(config_path)
249+
config = remove_item_from_config(config, key_path, value)
250+
validate_config(config, validate)
256251

257-
lock_file = f"{config_path}.lock"
258-
lock = FileLock(lock_file)
259-
try:
260-
with lock.acquire(timeout=1):
261-
config = get_current_config(config_path)
262-
config = remove_item_from_config(config, key_path, value)
263-
validate_config(config, validate)
264-
265-
with open(config_path, "w") as f:
266-
yaml.dump(config, f)
267-
268-
except Timeout:
269-
print(f"Another instance of tljh-config holds the lock {lock_file}")
270-
exit(1)
252+
with open(config_path, "w") as f:
253+
yaml.dump(config, f)
271254

272255

273256
def get_current_config(config_path):

tljh/requirements-hub-env.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,3 @@ jupyterhub-idle-culler>=1.2.1,<2
2626
# ref: https://github.com/jupyterhub/the-littlest-jupyterhub/issues/289
2727
#
2828
pycurl>=7.45.2,<8
29-
30-
# filelock is used to help us do atomic operations on config file(s)
31-
filelock>=3.15.4,<4

0 commit comments

Comments
 (0)