git-worktree: Allow multiple worktrees for subproject branches
[platform/upstream/gstreamer.git] / checkout-branch-worktree
1 #!/usr/bin/env python3
2
3 import os
4 import glob
5 import argparse
6 import subprocess
7 import configparser
8
9 from scripts.common import git
10 from scripts.common import Colors
11
12
13 SCRIPTDIR = os.path.normpath(os.path.dirname(__file__))
14 SUBPROJECTS_DIR = os.path.normpath(os.path.join(SCRIPTDIR, "subprojects"))
15
16 def repo_has_branch(repo_dir, branch):
17     try:
18         git("describe", branch, repository_path=repo_dir)
19     except subprocess.CalledProcessError:
20         return False
21     return True
22
23 def parse_wrapfile(wrapf):
24     cgp = configparser.ConfigParser()
25     cgp.read(wrapf)
26     if 'wrap-git' not in cgp:
27         return None
28     section = cgp['wrap-git']
29     return section['directory'], section['revision']
30
31 def get_wrap_subprojects(srcdir, gst_branch):
32     '''
33     Parses wrap files in the subprojects directory for the specified source
34     tree and gets the revisions for all common repos.
35     '''
36     for wrapf in glob.glob(os.path.join(srcdir, 'subprojects', '*.wrap')):
37         entries = parse_wrapfile(wrapf)
38         if not entries:
39             continue
40
41         repo_name, repo_branch = entries
42         parent_repo_dir = os.path.join(SUBPROJECTS_DIR, repo_name)
43         if not os.path.exists(os.path.join(parent_repo_dir, '.git')):
44             continue
45         # If a branch of the same name exists in the gst subproject, use it
46         if repo_name.startswith('gst') and repo_has_branch(parent_repo_dir, gst_branch):
47             repo_branch = gst_branch
48
49         yield repo_name, repo_branch, parent_repo_dir
50
51 def checkout_worktree(repo_name, repo_dir, worktree_dir, branch, force=False):
52     print('Checking out worktree for project {!r} into {!r} '
53           '(branch {})'.format(repo_name, worktree_dir, branch))
54     try:
55         args = ["worktree", "add"]
56         if force:
57             args += ["-f", "-f"]
58         args += [worktree_dir, branch]
59         git(*args, repository_path=repo_dir)
60     except Exception as e:
61         out = getattr(e, "output", b"").decode()
62         print("\nCould not checkout worktree %s, please fix and try again."
63               " Error:\n\n%s %s" % (repo_dir, out, e))
64
65         return False
66
67     commit_message = git("show", "--shortstat", repository_path=repo_dir).split("\n")
68     print(u"  -> %s%s%s - %s" % (Colors.HEADER, repo_dir, Colors.ENDC,
69                                     commit_message[4].strip()))
70     return True
71
72 def checkout_subprojects(worktree_dir, branch):
73     worktree_subdir = os.path.join(worktree_dir, "subprojects")
74
75     for repo_name, repo_branch, parent_repo_dir in get_wrap_subprojects(worktree_dir, branch):
76         workdir = os.path.normpath(os.path.join(worktree_subdir, repo_name))
77         if not checkout_worktree(repo_name, parent_repo_dir, workdir, repo_branch, force=True):
78             return False
79
80     return True
81
82
83 if __name__ == "__main__":
84     parser = argparse.ArgumentParser(prog="git-worktree")
85
86
87     parser.add_argument('worktree_dir', metavar='worktree_dir', type=str,
88                         help='The directory where to checkout the new worktree')
89     parser.add_argument('branch', metavar='branch', type=str,
90                         help='The branch to checkout')
91     parser.add_argument("--no-color",
92                         default=False,
93                         action='store_true',
94                         help="Do not output ansi colors.")
95     options = parser.parse_args()
96
97     if options.no_color or not Colors.can_enable():
98         Colors.disable()
99
100     options.worktree_dir = os.path.abspath(options.worktree_dir)
101     if not checkout_worktree('gst-build', SCRIPTDIR, options.worktree_dir, options.branch):
102         exit(1)
103     if not checkout_subprojects(options.worktree_dir, options.branch):
104         exit(1)