Skip to content

Commit dd8b028

Browse files
[update-checkout] fallback to verbose mode if tempdir is too long
1 parent c89a71a commit dd8b028

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

utils/update_checkout/tests/test_clone.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import os
1414

1515
from . import scheme_mock
16+
from unittest import mock
1617

1718

1819
class CloneTestCase(scheme_mock.SchemeMockTestCase):
@@ -42,6 +43,20 @@ def test_clone_with_additional_scheme(self):
4243
# Test that we're actually checking out the 'extra' scheme based on the output
4344
self.assertIn(b"git checkout refs/heads/main", output)
4445

46+
def test_manager_not_called_on_long_socket(self):
47+
fake_tmpdir = '/tmp/very/' + '/long' * 20 + '/tmp'
48+
49+
with mock.patch('tempfile.gettempdir', return_value=fake_tmpdir), \
50+
mock.patch('multiprocessing.Manager') as mock_manager:
51+
52+
self.call([self.update_checkout_path,
53+
'--config', self.config_path,
54+
'--source-root', self.source_root,
55+
'--clone'])
56+
# Ensure that we do not try to create a Manager when the tempdir
57+
# is too long.
58+
mock_manager.assert_not_called()
59+
4560

4661
class SchemeWithMissingRepoTestCase(scheme_mock.SchemeMockTestCase):
4762
def __init__(self, *args, **kwargs):

utils/update_checkout/update_checkout/parallel_runner.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,20 @@ def __init__(
5252
self._terminal_width = shutil.get_terminal_size().columns
5353
self._n_processes = n_processes
5454
self._pool_args = pool_args
55-
manager = Manager()
56-
self._lock = manager.Lock()
57-
self._running_tasks = manager.list()
58-
self._updated_repos = manager.Value("i", 0)
5955
self._fn = fn
6056
self._pool = Pool(processes=self._n_processes)
61-
self._verbose = pool_args[0].verbose
6257
self._output_prefix = pool_args[0].output_prefix
6358
self._nb_repos = len(pool_args)
6459
self._stop_event = Event()
65-
self._monitored_fn = MonitoredFunction(
66-
self._fn, self._running_tasks, self._updated_repos, self._lock
67-
)
60+
self._verbose = pool_args[0].verbose
61+
if not self._verbose:
62+
manager = Manager()
63+
self._lock = manager.Lock()
64+
self._running_tasks = manager.list()
65+
self._updated_repos = manager.Value("i", 0)
66+
self._monitored_fn = MonitoredFunction(
67+
self._fn, self._running_tasks, self._updated_repos, self._lock
68+
)
6869

6970
def run(self) -> List[Any]:
7071
print(

utils/update_checkout/update_checkout/update_checkout.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import os
1414
import platform
1515
import re
16+
import tempfile
1617
import sys
1718
import traceback
1819
from multiprocessing import freeze_support
@@ -27,6 +28,29 @@
2728
SCRIPT_FILE = os.path.abspath(__file__)
2829
SCRIPT_DIR = os.path.dirname(SCRIPT_FILE)
2930

31+
def is_unix_sock_path_too_long() -> bool:
32+
"""Check if the unix socket_path exceeds the 104 limit (108 on Linux).
33+
34+
The multiprocessing module creates a socket in the TEMPDIR folder. The
35+
socket path should not exceed:
36+
- 104 bytes on macOS
37+
- 108 bytes on Linux (https://www.man7.org/linux/man-pages/man7/unix.7.html)
38+
39+
Returns:
40+
bool: Whether the socket path exceeds the limit. Always False on Windows.
41+
"""
42+
43+
if os.name != "posix":
44+
return False
45+
46+
MAX_UNIX_SOCKET_PATH = 104
47+
# `tempfile.mktemp` is deprecated yet that's what the multiprocessing
48+
# module uses internally: https://github.com/python/cpython/blob/c4e7d245d61ac4547ecf3362b28f64fc00aa88c0/Lib/multiprocessing/connection.py#L72
49+
# Since we are not using the resulting file, it is safe to use this
50+
# method.
51+
sock_path = tempfile.mktemp(prefix="sock-", dir=tempfile.gettempdir())
52+
return len(sock_path.encode("utf-8")) > MAX_UNIX_SOCKET_PATH
53+
3054
def confirm_tag_in_repo(tag: str, repo_name: str) -> Optional[str]:
3155
"""Confirm that a given tag exists in a git repository. This function
3256
assumes that the repository is already a current working directory before
@@ -771,6 +795,13 @@ def main():
771795
"specify --scheme=foo")
772796
sys.exit(1)
773797

798+
if is_unix_sock_path_too_long():
799+
print(
800+
f"TEMPDIR={tempfile.gettempdir()} is too long and multiprocessing "
801+
"sockets will exceed the size limit. Falling back to verbose mode."
802+
)
803+
args.verbose = True
804+
774805
clone = args.clone
775806
clone_with_ssh = args.clone_with_ssh
776807
skip_history = args.skip_history

0 commit comments

Comments
 (0)