gstreamer/gst-worktree.py
Guillaume Desmottes 4a2e037fd6 gst-worktree: add support for wrap file without 'directory' field
The script is currently not usable because of pango.wrap not having the
'directory' field and relying on the default from the file name.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-build/-/merge_requests/201>
2020-10-07 15:02:23 +02:00

162 lines
6 KiB
Python
Executable file

#!/usr/bin/env python3
import os
import glob
import argparse
import subprocess
import configparser
from scripts.common import git
from scripts.common import Colors
SCRIPTDIR = os.path.normpath(os.path.dirname(__file__))
SUBPROJECTS_DIR = os.path.normpath(os.path.join(SCRIPTDIR, "subprojects"))
def repo_has_branch(repo_dir, branch):
if not branch:
return False
try:
git("describe", branch, repository_path=repo_dir)
except subprocess.CalledProcessError:
return False
return True
def parse_wrapfile(wrapf):
cgp = configparser.ConfigParser()
cgp.read(wrapf)
if 'wrap-git' not in cgp:
return None
section = cgp['wrap-git']
# Default to the wrapper filename if 'directory' field is missing
directory = section.get('directory', os.path.splitext(os.path.basename(wrapf))[0])
return directory, section['revision']
def get_wrap_subprojects(srcdir, gst_branch):
'''
Parses wrap files in the subprojects directory for the specified source
tree and gets the revisions for all common repos.
'''
for wrapf in glob.glob(os.path.join(srcdir, 'subprojects', '*.wrap')):
entries = parse_wrapfile(wrapf)
if not entries:
continue
repo_name, repo_branch = entries
parent_repo_dir = os.path.join(SUBPROJECTS_DIR, repo_name)
if not os.path.exists(os.path.join(parent_repo_dir, '.git')):
continue
# If a branch of the same name exists in the gst subproject, use it
if repo_name.startswith('gst') and repo_has_branch(parent_repo_dir, gst_branch):
repo_branch = gst_branch
yield repo_name, repo_branch, parent_repo_dir
def checkout_worktree(repo_name, repo_dir, worktree_dir, branch, new_branch, force=False):
print('Checking out worktree for project {!r} into {!r} '
'(branch {})'.format(repo_name, worktree_dir, branch))
try:
args = ["worktree", "add"]
if force:
args += ["-f", "-f"]
args += [worktree_dir, branch]
if new_branch:
args += ["-b", new_branch]
git(*args, repository_path=repo_dir)
except subprocess.CalledProcessError as e:
out = getattr(e, "output", b"").decode()
print("\nCould not checkout worktree %s, please fix and try again."
" Error:\n\n%s %s" % (repo_dir, out, e))
return False
commit_message = git("show", "--shortstat", repository_path=repo_dir).split("\n")
print(u" -> %s%s%s - %s" % (Colors.HEADER, repo_dir, Colors.ENDC,
commit_message[4].strip()))
return True
def checkout_subprojects(worktree_dir, branch, new_branch):
worktree_subdir = os.path.join(worktree_dir, "subprojects")
for repo_name, repo_branch, parent_repo_dir in get_wrap_subprojects(worktree_dir, branch):
workdir = os.path.normpath(os.path.join(worktree_subdir, repo_name))
if not checkout_worktree(repo_name, parent_repo_dir, workdir, repo_branch, new_branch, force=True):
return False
return True
def remove_worktree(worktree_dir):
worktree_subdir = os.path.join(worktree_dir, "subprojects")
for repo_name, _, parent_repo_dir in get_wrap_subprojects(worktree_dir, None):
workdir = os.path.normpath(os.path.join(worktree_subdir, repo_name))
if not os.path.exists(workdir):
continue
subprojdir = os.path.normpath(os.path.join(SUBPROJECTS_DIR, repo_name))
if not os.path.exists(subprojdir):
continue
print('Removing worktree {!r}'.format(workdir))
try:
git('worktree', 'remove', '-f', workdir, repository_path=subprojdir)
except subprocess.CalledProcessError as e:
out = getattr(e, "output", b"").decode()
print('Ignoring error while removing worktree {!r}:\n\n{}'.format(workdir, out))
try:
git('worktree', 'remove', '-f', worktree_dir, repository_path=SCRIPTDIR)
except subprocess.CalledProcessError:
print('Failed to remove worktree {!r}'.format(worktree_dir))
return False
return True
if __name__ == "__main__":
parser = argparse.ArgumentParser(prog="gst-worktree")
parser.add_argument("--no-color", default=False, action='store_true',
help="Do not output ANSI colors")
subparsers = parser.add_subparsers(help='The sub-command to run', dest='command')
parser_add = subparsers.add_parser('add',
help='Create a worktree for gst-build and all subprojects')
parser_add.add_argument('worktree_dir', type=str,
help='Directory where to create the new worktree')
parser_add.add_argument('branch', type=str, default=None,
help='Branch to checkout')
parser_add.add_argument('-b', '--new-branch', type=str, default=None,
help='Branch to create')
parser_rm = subparsers.add_parser('rm',
help='Remove a gst-build worktree and the subproject worktrees inside it')
parser_rm.add_argument('worktree_dir', type=str,
help='Worktree directory to remove')
options = parser.parse_args()
if options.no_color or not Colors.can_enable():
Colors.disable()
if not options.command:
parser.print_usage()
exit(1)
worktree_dir = os.path.abspath(options.worktree_dir)
if options.command == 'add':
if not checkout_worktree('gst-build', SCRIPTDIR, worktree_dir, options.branch, options.new_branch):
exit(1)
if not checkout_subprojects(worktree_dir, options.branch, options.new_branch):
exit(1)
elif options.command == 'rm':
if not os.path.exists(worktree_dir):
print('Cannot remove worktree directory {!r}, it does not exist'.format(worktree_dir))
exit(1)
if not remove_worktree(worktree_dir):
exit(1)
else:
# Unreachable code
raise AssertionError