~edwargix/git.sr.ht

e908b80618f918357c0e87427e7277fe251889f5 — наб 4 years ago e49beb0
Add migration to fix up some broken HEADs found by 0.55.x code
1 files changed, 84 insertions(+), 0 deletions(-)

A gitsrht/alembic/versions/9f72f0dea908_clean_up_broken_heads.py
A gitsrht/alembic/versions/9f72f0dea908_clean_up_broken_heads.py => gitsrht/alembic/versions/9f72f0dea908_clean_up_broken_heads.py +84 -0
@@ 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