TDengine/packaging/delete_ref_lock.py
haoranchen 5cab74d393
fix: refactor file handling in TDCom class for improved readability (#34680)
* fix: refactor file handling in TDCom class for improved readability

* fix: enhance process cleanup in clean_taos_process to avoid terminating Jenkins agents

* fix: remove redundant safe_rmtree function implementation

* fix: add signal handling for graceful termination of subprocesses in run_win_cases

* fix: declare exit_flag as global in process_pytest_file function

* fix: refactor file handling in TDCom class for improved readability

* fix: refactor file handling in TDCom class for improved readability

* fix: improve code formatting and readability in TDCom class

* fix: update exclusion list for Windows CI compatibility and improve cleanup process

* test: add test_cases.task

* feat: add Windows CI pipeline

* fix: reduce wait time in process_pytest_file function

* fix: update Windows pipeline for Python 3.8 support and improve path handling

* test: delete test task

* fix: enhance pytest command parsing with format validation and error logging
2026-03-08 13:17:49 +08:00

142 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import subprocess
import re
import os
from typing import Optional
from abc import ABC, abstractmethod
class RefLockErrorHandler(ABC):
"""抽象基类,定义处理接口"""
@abstractmethod
def match(self, error_output: str) -> bool:
pass
@abstractmethod
def parse_branch(self, error_output: str) -> Optional[str]:
pass
def handle(self, error_output: str):
branch = self.parse_branch(error_output)
if branch:
print(f"Detected error, attempting to delete ref for branch: {branch}")
self.delete_ref(branch)
else:
print("Error parsing branch name.")
def delete_ref(self, branch_name: str):
try:
subprocess.run(["git", "update-ref", "-d", branch_name], check=True)
except subprocess.CalledProcessError as e:
print(f"git update-ref failed: {e}")
lock_files = [f".git/{branch_name}.lock", f".git/logs/{branch_name}.lock"]
for lock_file in lock_files:
if os.path.exists(lock_file):
try:
os.remove(lock_file)
print(f"Removed lock file: {lock_file}")
except Exception as ex:
print(f"Failed to remove lock file {lock_file}: {ex}")
# retry
try:
subprocess.run(["git", "update-ref", "-d", branch_name], check=True)
except subprocess.CalledProcessError as e2:
print(f"Still failed to delete ref after removing lock: {e2}")
class Type1Handler(RefLockErrorHandler):
# error: cannot lock ref 'refs/remotes/origin/fix/3.0/TD-32817': is at 7af5 but expected eaba
# match the branch name before is at with a regular expression
def match(self, error_output: str) -> bool:
return "is at" in error_output and "but expected" in error_output
def parse_branch(self, error_output: str) -> str:
# 匹配 cannot lock ref 部分,兼容中英文
match = re.search(
r"cannot lock ref '(refs/remotes/origin/[^']+)': is at", error_output
)
return match.group(1) if match else None
class Type2Handler(RefLockErrorHandler):
# match the branch name before exists; cannot create with a regular expression
def match(self, error_output: str) -> bool:
return "exists; cannot create" in error_output
def parse_branch(self, error_output: str) -> str:
match = re.search(r"'(refs/remotes/origin/[^']+)' exists;", error_output)
return match.group(1) if match else None
class Type3Handler(RefLockErrorHandler):
# match the branch name before the first single quote before 'Unable to' with a regular expression
# git error: could not delete references: cannot lock ref 'refs/remotes/origin/test/3.0/TS-4893': Unable to create 'D:/workspace/main/TDinternal/community/.git/refs/remotes/origin/test/3.0/TS-4893.lock': File exists
def match(self, error_output: str) -> bool:
return "Unable to create" in error_output and "File exists" in error_output
def parse_branch(self, error_output: str) -> str:
match = re.search(
r"(?:error|references): cannot lock ref '(refs/remotes/origin/[^']+)': Unable to",
error_output,
)
return match.group(1) if match else None
class RefLockErrorHandlerFactory:
"""工厂类,返回合适的处理器"""
handlers = [Type1Handler(), Type2Handler(), Type3Handler()]
@classmethod
def get_handler(cls, error_output: str):
for handler in cls.handlers:
if handler.match(error_output):
return handler
return None
def handle_error(error_output):
handler = RefLockErrorHandlerFactory.get_handler(error_output)
if handler:
handler.handle(error_output)
else:
print("No handler found for this error.")
def git_fetch():
print("Running: git fetch")
result = subprocess.run(["git", "fetch"], capture_output=True, text=True)
if result.returncode != 0:
print("git fetch failed:")
print(result.stderr)
else:
print("git fetch successful.")
return result
def git_prune():
print("Running: git remote prune origin")
result = subprocess.run(
["git", "remote", "prune", "origin"], capture_output=True, text=True
)
if result.returncode != 0:
print("git remote prune origin failed:")
print(result.stderr)
else:
print("git remote prune origin successful.")
return result
def main():
fetch_result = git_fetch()
if fetch_result.returncode != 0:
handle_error(fetch_result.stderr)
return
prune_result = git_prune()
if prune_result.returncode != 0:
handle_error(prune_result.stderr)
if __name__ == "__main__":
main()