From e908b80618f918357c0e87427e7277fe251889f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Wed, 5 Aug 2020 22:48:57 +0200 Subject: [PATCH] Add migration to fix up some broken HEADs found by 0.55.x code --- .../9f72f0dea908_clean_up_broken_heads.py | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 gitsrht/alembic/versions/9f72f0dea908_clean_up_broken_heads.py diff --git a/gitsrht/alembic/versions/9f72f0dea908_clean_up_broken_heads.py b/gitsrht/alembic/versions/9f72f0dea908_clean_up_broken_heads.py new file mode 100644 index 0000000..40cb7a8 --- /dev/null +++ b/gitsrht/alembic/versions/9f72f0dea908_clean_up_broken_heads.py @@ -0,0 +1,84 @@ +"""Clean up broken HEADs + +Revision ID: 9f72f0dea908 +Revises: 3c1285bb23e2 +Create Date: 2020-07-28 12:04:39.751225 + +""" + +# revision identifiers, used by Alembic. +revision = '9f72f0dea908' +down_revision = '3c1285bb23e2' + +import os.path +import subprocess +from alembic import op +from sqlalchemy.orm import sessionmaker +from pygit2 import GitError, Repository as GitRepository +from gitsrht.types import Repository +from srht.config import cfg +try: + from tqdm import tqdm +except ImportError: + def tqdm(iterable): + yield from iterable + +Session = sessionmaker() + +post_update = cfg("git.sr.ht", "post-update-script") + + +def upgrade(): + bind = op.get_bind() + session = Session(bind=bind) + print("Fixing repositories with broken HEADs") + for repo in tqdm(session.query(Repository).all()): + # Sometimes HEAD doesn't exist *at all*, + # some repositories are also plain uninitialised; + # git-init(1) says that running it on an existing repository is safe, + # so do that to try to sort out any unpleasantries + subprocess.run(["git", "-C", repo.path, "init", "--bare"], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.run(["git", "-C", repo.path, "config", "srht.repo-id", str(repo.id)], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.run(["git", "-C", repo.path, "config", "receive.denyDeleteCurrent", "ignore"], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.run(["ln", "-f", "-s", + post_update, + os.path.join(repo.path, "hooks", "pre-receive") + ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.run(["ln", "-f", "-s", + post_update, + os.path.join(repo.path, "hooks", "update") + ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.run(["ln", "-f", "-s", + post_update, + os.path.join(repo.path, "hooks", "post-update") + ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + git_repo = GitRepository(repo.path) + + try: + git_repo.lookup_reference("HEAD") + except GitError: + # Most likely "corrupted loose reference file: HEAD" + # This can happen if HEAD is zero-length for some reason, + # at this point no library solution will work + # and git(1) will refuse to acknowledge the repository + with open(os.path.join(repo.path, "HEAD"), "w") as head: + print("ref: refs/heads/master", file=head) + + # Ensure that dangling HEAD (no default branch) is equivalent to + # no branches at all; if there are branches but HEAD is dangling, + # bake in the pre-0.55.0 behaviour of choosing the first branch + # in iteration order + if len(list(git_repo.branches.local)) != 0: + head = git_repo.lookup_reference("HEAD") + default_branch = git_repo.branches.get(head.target[len("refs/heads/"):]) + if not default_branch: + branch = list(git_repo.branches.local)[0] + head.set_target(git_repo.branches[branch].name) + + +def downgrade(): + pass -- 2.38.4