Skip to content

Commit

Permalink
build: delete all junctions before calling "git clean"
Browse files Browse the repository at this point in the history
git clean can't deal with junctions and in case there is a loop
it follows them forever (or until stack overflow).
git-for-windows/git#5320

To work around this try to delete all junctions in the clean
re-try code path.

Fixes #108
  • Loading branch information
lazka committed Jan 31, 2025
1 parent bdd38ec commit cc965c4
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
16 changes: 16 additions & 0 deletions msys2_autobuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ def chmod(p: PathLike) -> None:
chmod(fpath)


def remove_junctions(topdir: PathLike) -> None:
# work around a git issue where it can't handle junctions
# https://github.com/git-for-windows/git/issues/5320
if not hasattr(os.path, 'isjunction'): # Python 3.12 only
return
for root, dirs, _ in os.walk(topdir):
no_junctions = []
for d in dirs:
if not os.path.isjunction(os.path.join(root, d)):
no_junctions.append(d)
else:
os.remove(os.path.join(root, d))
dirs[:] = no_junctions


def reset_git_repo(path: PathLike):

def clean():
Expand All @@ -160,6 +175,7 @@ def clean():
if not made_writable:
print("Trying to make files writable")
make_tree_writable(path)
remove_junctions(path)
made_writable = True
except OSError as e:
print("Making files writable failed", e)
Expand Down
17 changes: 16 additions & 1 deletion tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from msys2_autobuild.utils import parse_optional_deps
from msys2_autobuild.queue import parse_buildqueue, get_cycles
from msys2_autobuild.build import make_tree_writable
from msys2_autobuild.build import make_tree_writable, remove_junctions


def test_make_tree_writable():
Expand Down Expand Up @@ -37,6 +37,21 @@ def test_make_tree_writable():
assert os.access(nested_junction, os.W_OK) and os.access(nested_junction, os.R_OK)


def test_remove_junctions():
with tempfile.TemporaryDirectory() as tempdir:
nested_dir = Path(tempdir) / "nested"
nested_junction = nested_dir / "junction"
nested_dir.mkdir()

# Create a junction loop if possible, to make sure we ignore it
if hasattr(os.path, 'isjunction') and os.name == 'nt':
import _winapi
_winapi.CreateJunction(str(nested_dir), str(nested_junction))

remove_junctions(tempdir)
assert not nested_junction.exists()


def test_parse_optional_deps():
assert parse_optional_deps("a:b,c:d,a:x") == {'a': ['b', 'x'], 'c': ['d']}

Expand Down

0 comments on commit cc965c4

Please sign in to comment.