mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[update-checkout] add a check for locked repositories
This commit is contained in:
@@ -145,10 +145,11 @@ def setup_mock_remote(base_dir, base_config):
|
|||||||
|
|
||||||
BASEDIR_ENV_VAR = 'UPDATECHECKOUT_TEST_WORKSPACE_DIR'
|
BASEDIR_ENV_VAR = 'UPDATECHECKOUT_TEST_WORKSPACE_DIR'
|
||||||
CURRENT_FILE_DIR = os.path.dirname(os.path.abspath(__file__))
|
CURRENT_FILE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
UPDATE_CHECKOUT_EXECUTABLE = 'update-checkout.cmd' if os.name == 'nt' else 'update-checkout'
|
||||||
UPDATE_CHECKOUT_PATH = os.path.abspath(os.path.join(CURRENT_FILE_DIR,
|
UPDATE_CHECKOUT_PATH = os.path.abspath(os.path.join(CURRENT_FILE_DIR,
|
||||||
os.path.pardir,
|
os.path.pardir,
|
||||||
os.path.pardir,
|
os.path.pardir,
|
||||||
'update-checkout'))
|
UPDATE_CHECKOUT_EXECUTABLE))
|
||||||
|
|
||||||
|
|
||||||
class SchemeMockTestCase(unittest.TestCase):
|
class SchemeMockTestCase(unittest.TestCase):
|
||||||
|
|||||||
89
utils/update_checkout/tests/test_locked_repository.py
Normal file
89
utils/update_checkout/tests/test_locked_repository.py
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import unittest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from update_checkout.update_checkout import _is_any_repository_locked
|
||||||
|
|
||||||
|
class TestIsAnyRepositoryLocked(unittest.TestCase):
|
||||||
|
@patch("os.path.exists")
|
||||||
|
@patch("os.path.isdir")
|
||||||
|
@patch("os.listdir")
|
||||||
|
def test_repository_with_lock_file(self, mock_listdir, mock_isdir, mock_exists):
|
||||||
|
pool_args = [
|
||||||
|
("/fake_path", None, "repo1"),
|
||||||
|
("/fake_path", None, "repo2"),
|
||||||
|
]
|
||||||
|
|
||||||
|
def listdir_side_effect(path):
|
||||||
|
if "repo1" in path:
|
||||||
|
return ["index.lock", "config"]
|
||||||
|
elif "repo2" in path:
|
||||||
|
return ["HEAD", "config"]
|
||||||
|
return []
|
||||||
|
|
||||||
|
mock_exists.return_value = True
|
||||||
|
mock_isdir.return_value = True
|
||||||
|
mock_listdir.side_effect = listdir_side_effect
|
||||||
|
|
||||||
|
result = _is_any_repository_locked(pool_args)
|
||||||
|
self.assertEqual(result, {"repo1"})
|
||||||
|
|
||||||
|
@patch("os.path.exists")
|
||||||
|
@patch("os.path.isdir")
|
||||||
|
@patch("os.listdir")
|
||||||
|
def test_repository_without_git_dir(self, mock_listdir, mock_isdir, mock_exists):
|
||||||
|
pool_args = [
|
||||||
|
("/fake_path", None, "repo1"),
|
||||||
|
]
|
||||||
|
|
||||||
|
mock_exists.return_value = False
|
||||||
|
mock_isdir.return_value = False
|
||||||
|
mock_listdir.return_value = []
|
||||||
|
|
||||||
|
result = _is_any_repository_locked(pool_args)
|
||||||
|
self.assertEqual(result, set())
|
||||||
|
|
||||||
|
@patch("os.path.exists")
|
||||||
|
@patch("os.path.isdir")
|
||||||
|
@patch("os.listdir")
|
||||||
|
def test_repository_with_git_file(self, mock_listdir, mock_isdir, mock_exists):
|
||||||
|
pool_args = [
|
||||||
|
("/fake_path", None, "repo1"),
|
||||||
|
]
|
||||||
|
|
||||||
|
mock_exists.return_value = True
|
||||||
|
mock_isdir.return_value = False
|
||||||
|
mock_listdir.return_value = []
|
||||||
|
|
||||||
|
result = _is_any_repository_locked(pool_args)
|
||||||
|
self.assertEqual(result, set())
|
||||||
|
|
||||||
|
@patch("os.path.exists")
|
||||||
|
@patch("os.path.isdir")
|
||||||
|
@patch("os.listdir")
|
||||||
|
def test_repository_with_multiple_lock_files(self, mock_listdir, mock_isdir, mock_exists):
|
||||||
|
pool_args = [
|
||||||
|
("/fake_path", None, "repo1"),
|
||||||
|
]
|
||||||
|
|
||||||
|
mock_exists.return_value = True
|
||||||
|
mock_isdir.return_value = True
|
||||||
|
mock_listdir.return_value = ["index.lock", "merge.lock", "HEAD"]
|
||||||
|
|
||||||
|
result = _is_any_repository_locked(pool_args)
|
||||||
|
self.assertEqual(result, {"repo1"})
|
||||||
|
|
||||||
|
@patch("os.path.exists")
|
||||||
|
@patch("os.path.isdir")
|
||||||
|
@patch("os.listdir")
|
||||||
|
def test_repository_with_no_lock_files(self, mock_listdir, mock_isdir, mock_exists):
|
||||||
|
pool_args = [
|
||||||
|
("/fake_path", None, "repo1"),
|
||||||
|
]
|
||||||
|
|
||||||
|
mock_exists.return_value = True
|
||||||
|
mock_isdir.return_value = True
|
||||||
|
mock_listdir.return_value = ["HEAD", "config", "logs"]
|
||||||
|
|
||||||
|
result = _is_any_repository_locked(pool_args)
|
||||||
|
self.assertEqual(result, set())
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from multiprocessing import Lock, Pool, cpu_count, freeze_support
|
from multiprocessing import Lock, Pool, cpu_count, freeze_support
|
||||||
|
from typing import Set, List, Any
|
||||||
|
|
||||||
from build_swift.build_swift.constants import SWIFT_SOURCE_ROOT
|
from build_swift.build_swift.constants import SWIFT_SOURCE_ROOT
|
||||||
|
|
||||||
@@ -67,8 +68,11 @@ def check_parallel_results(results, op):
|
|||||||
if r is not None:
|
if r is not None:
|
||||||
if fail_count == 0:
|
if fail_count == 0:
|
||||||
print("======%s FAILURES======" % op)
|
print("======%s FAILURES======" % op)
|
||||||
print("%s failed (ret=%d): %s" % (r.repo_path, r.ret, r))
|
|
||||||
fail_count += 1
|
fail_count += 1
|
||||||
|
if isinstance(r, str):
|
||||||
|
print(r)
|
||||||
|
continue
|
||||||
|
print("%s failed (ret=%d): %s" % (r.repo_path, r.ret, r))
|
||||||
if r.stderr:
|
if r.stderr:
|
||||||
print(r.stderr)
|
print(r.stderr)
|
||||||
return fail_count
|
return fail_count
|
||||||
@@ -329,6 +333,30 @@ def get_scheme_map(config, scheme_name):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _is_any_repository_locked(pool_args: List[Any]) -> Set[str]:
|
||||||
|
"""Returns the set of locked repositories.
|
||||||
|
|
||||||
|
A repository is considered to be locked if its .git directory contains a
|
||||||
|
file ending in ".lock".
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pool_args (List[Any]): List of arguments passed to the
|
||||||
|
`update_single_repository` function.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Set[str]: The names of the locked repositories if any.
|
||||||
|
"""
|
||||||
|
|
||||||
|
repos = [(x[0], x[2]) for x in pool_args]
|
||||||
|
locked_repositories = set()
|
||||||
|
for source_root, repo_name in repos:
|
||||||
|
dot_git_path = os.path.join(source_root, repo_name, ".git")
|
||||||
|
if not os.path.exists(dot_git_path) or not os.path.isdir(dot_git_path):
|
||||||
|
continue
|
||||||
|
for file in os.listdir(dot_git_path):
|
||||||
|
if file.endswith(".lock"):
|
||||||
|
locked_repositories.add(repo_name)
|
||||||
|
return locked_repositories
|
||||||
|
|
||||||
def update_all_repositories(args, config, scheme_name, scheme_map, cross_repos_pr):
|
def update_all_repositories(args, config, scheme_name, scheme_map, cross_repos_pr):
|
||||||
pool_args = []
|
pool_args = []
|
||||||
@@ -363,6 +391,12 @@ def update_all_repositories(args, config, scheme_name, scheme_map, cross_repos_p
|
|||||||
cross_repos_pr]
|
cross_repos_pr]
|
||||||
pool_args.append(my_args)
|
pool_args.append(my_args)
|
||||||
|
|
||||||
|
locked_repositories: set[str] = _is_any_repository_locked(pool_args)
|
||||||
|
if len(locked_repositories) > 0:
|
||||||
|
return [
|
||||||
|
f"'{repo_name}' is locked by git. Cannot update it."
|
||||||
|
for repo_name in locked_repositories
|
||||||
|
]
|
||||||
return run_parallel(update_single_repository, pool_args, args.n_processes)
|
return run_parallel(update_single_repository, pool_args, args.n_processes)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user