mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-27 08:39:12 +00:00
fix(update): clear a stale .git/index.lock before Update Code (#801)
* fix(update): clear a stale .git/index.lock before Update Code A git that subprocess.run's timeout kills (SIGKILL) cannot remove .git/index.lock, so every later update failed with "Unable to create .../.git/index.lock: File exists" until the file was removed by hand. Update Code and the automatic update's rollback now remove the lock when no git process is running in the checkout and the file is more than a few seconds old. While another git is running, Update Code says so instead of failing; when the lock could not be checked, the error names the rm command that fixes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SvFtgthKUNEPhJu6RuX9Sk * fix(update): count a git that names the checkout in its arguments as running git --git-dir/--work-tree can work on the checkout from any working directory, so the cwd check alone could take such a git's live lock for a stale one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SvFtgthKUNEPhJu6RuX9Sk * fix(update): resolve a git's relative path arguments against its cwd `git -C LEDMatrix ...` or a relative --git-dir started outside the checkout works on it too; resolve each argument against the process's working directory before deciding a lock is stale, and count unreadable arguments as naming the checkout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SvFtgthKUNEPhJu6RuX9Sk --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,9 +9,11 @@ Git runs for real against a throwaway origin/device clone pair; systemd, sudo
|
||||
and the health check service are faked.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
@@ -579,6 +581,27 @@ class TestUpdateIsVerified:
|
||||
assert repo.head() == old
|
||||
assert 'rolled back' in result['core_message']
|
||||
|
||||
@pytest.mark.skipif(not Path('/proc/self/comm').exists(), reason='needs /proc')
|
||||
def test_a_pull_killed_by_its_timeout_is_still_rolled_back(self, tmp_path):
|
||||
"""subprocess.run SIGKILLs a timed-out git, which leaves .git/index.lock
|
||||
behind; the rollback's reset would fail on it."""
|
||||
repo = Repo(tmp_path)
|
||||
old = repo.head()
|
||||
repo.publish()
|
||||
pull = real_pull(repo.device)
|
||||
lock = repo.device / '.git' / 'index.lock'
|
||||
|
||||
def killed(**kwargs):
|
||||
pull()
|
||||
lock.write_text('')
|
||||
stale = time.time() - 60
|
||||
os.utime(lock, (stale, stale))
|
||||
raise subprocess.TimeoutExpired(['git', 'pull'], 60)
|
||||
result = Harness(tmp_path, repo, core_update=killed).updater.run()
|
||||
assert repo.head() == old
|
||||
assert 'rolled back' in result['core_message']
|
||||
assert not lock.exists()
|
||||
|
||||
@pytest.mark.parametrize('how', ['partial_pull', 'check_never_started'])
|
||||
def test_a_failed_rollback_leaves_plugins_and_the_display_alone(self, tmp_path, how):
|
||||
"""update_core returns rollback_failed itself on two paths. The device
|
||||
|
||||
Reference in New Issue
Block a user