Verified Commit 6bdd72c6 authored by anarcat's avatar anarcat
Browse files

factor out more common git tools to survive gitolite

parent fc8d3d3f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ from fabric_tpa import ui # noqa: F401
collection = []
for mod in [
    "fabric_tpa.ganeti",
    "fabric_tpa.git",
    "fabric_tpa.gitlab",
    "fabric_tpa.gitolite",
    "fabric_tpa.host",
+86 −0
Original line number Diff line number Diff line
@@ -8,6 +8,92 @@ from fabric import task, Connection
from fabric_tpa.ui import yes_no


def list_all_repos(
    con: Connection,
    repos_path: str = "/srv/git.torproject.org/repositories/",
):
    """help function to list repositories in the given directory

    This is separate from the task to be easier to call."""
    logging.info(
        "listing repositories in %s on %s",
        repos_path,
        getattr(con, "host", "localhost"),
    )
    ret = con.run("find %s -type d -a -name '*.git'" % repos_path, hide=True, warn=True)
    if not ret.ok:
        if ret.stdout:
            logging.warn(
                "find failed with status %d, continuing anyway: ",
                ret.exited,
                ret.stderr.strip(),
            )
        else:
            logging.warn(
                "find failed with status %d: %s", ret.exited, ret.stderr.strip()
            )
            return

    for line in ret.stdout.splitlines():
        assert repos_path in line
        line = line.replace(repos_path, "")
        yield line.strip().removesuffix(".git")


def list_public_repos(
    con: Connection,
    repos_path: str = "/srv/git.torproject.org/repositories/",
):
    """help function to list repositories on the remote gitolite server

    This is separate from the task to be easier to call."""
    logging.info(
        "listing repositories with the git-daemon-export-ok flag in %s",
        repos_path,
        getattr(con, "host", "localhost"),
    )
    ret = con.run(
        "find %s -type f -a -name 'git-daemon-export-ok'" % repos_path,
        hide=True,
        warn=True,
    )
    if not ret.ok:
        if ret.stdout:
            logging.warn(
                "find failed with status %d, continuing anyway: ",
                ret.exited,
                ret.stderr.strip(),
            )
        else:
            logging.warn(
                "find failed with status %d: %s", ret.exited, ret.stderr.strip()
            )
            return

    for line in ret.stdout.splitlines():
        assert repos_path in line
        line = line.replace(repos_path, "")
        yield line.strip().removesuffix(".git/git-daemon-export-ok")


@task
def list_repos(
    con: Connection,
    repos_path: str = "/srv/git.torproject.org/repositories/",
    public_only: bool = False,
):
    """list repositories on the given git server"""
    # TODO: this would be prettier if invoke autoprinted generators
    # correctly, and this stub would just not be necessary at all:
    # https://github.com/pyinvoke/invoke/issues/992
    if public_only:
        for repo in list_public_repos(con, repos_path):
            print(repo)
    else:
        for repo in list_all_repos(con, repos_path):
            print(repo)


def commit_and_push(repository: str, path: str, commit_msg):
    try:
        subprocess.check_call(["git", "-C", repository, "diff", path])
+2 −88
Original line number Diff line number Diff line
@@ -63,98 +63,12 @@ import requests
from invoke import Context, Exit
from paramiko.ssh_exception import SSHException

from fabric_tpa.git import commit_and_push, is_empty_repo
from fabric_tpa.git import commit_and_push, is_empty_repo, list_all_repos
from fabric_tpa.gitlab import GitLabConnector, create_project
from fabric_tpa.host import schedule_delete
from fabric_tpa.ui import re_include_exclude, Timer, no_yes, pick, yes_no


def _list_repos(
    con: Connection,
    repos_path: str = "/srv/git.torproject.org/repositories/",
):
    """help function to list repositories in the given directory

    This is separate from the task to be easier to call."""
    logging.info(
        "listing repositories in %s on %s",
        repos_path,
        getattr(con, "host", "localhost"),
    )
    ret = con.run("find %s -type d -a -name '*.git'" % repos_path, hide=True, warn=True)
    if not ret.ok:
        if ret.stdout:
            logging.warn(
                "find failed with status %d, continuing anyway: ",
                ret.exited,
                ret.stderr.strip(),
            )
        else:
            logging.warn(
                "find failed with status %d: %s", ret.exited, ret.stderr.strip()
            )
            return

    for line in ret.stdout.splitlines():
        assert repos_path in line
        line = line.replace(repos_path, "")
        yield line.strip().removesuffix(".git")


def _list_repos_public(
    con: Connection,
    repos_path: str = "/srv/git.torproject.org/repositories/",
):
    """help function to list repositories on the remote gitolite server

    This is separate from the task to be easier to call."""
    logging.info(
        "listing repositories with the git-daemon-export-ok flag in %s",
        repos_path,
        getattr(con, "host", "localhost"),
    )
    ret = con.run(
        "find %s -type f -a -name 'git-daemon-export-ok'" % repos_path,
        hide=True,
        warn=True,
    )
    if not ret.ok:
        if ret.stdout:
            logging.warn(
                "find failed with status %d, continuing anyway: ",
                ret.exited,
                ret.stderr.strip(),
            )
        else:
            logging.warn(
                "find failed with status %d: %s", ret.exited, ret.stderr.strip()
            )
            return

    for line in ret.stdout.splitlines():
        assert repos_path in line
        line = line.replace(repos_path, "")
        yield line.strip().removesuffix(".git/git-daemon-export-ok")


@task
def list_repos(
    con: Connection,
    repos_path: str = "/srv/git.torproject.org/repositories/",
    public_only: bool = False,
):
    """list repositories on the given git server"""
    # TODO: this would be prettier if invoke autoprinted generators
    # correctly, and this stub would just not be necessary at all:
    # https://github.com/pyinvoke/invoke/issues/992
    if public_only:
        for repo in _list_repos_public(con, repos_path):
            print(repo)
    else:
        for repo in _list_repos(con, repos_path):
            print(repo)


@task
def list_conf_repos(
    con: Connection,
@@ -598,7 +512,7 @@ def missing_repos(
    """find repositories missing from gitolite.conf or the remote server"""
    conf_path = Path(local_conf_dir).expanduser() / "conf" / "gitolite.conf"
    local_repos_list = sorted(set(list_conf_repos_str(conf_path.open().read())))
    remote_repos_list = sorted(set(_list_repos(con)))
    remote_repos_list = sorted(set(list_all_repos(con)))
    if local_repos_list == remote_repos_list:
        logging.info("%d repositories found on both, success", len(remote_repos_list))
    else: