gst-env: Set the prompt for fish to be same as bash
[platform/upstream/gstreamer.git] / gst-worktree.py
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
17 def repo_has_branch(repo_dir, branch):
18     if not branch:
19         return False
20     try:
21         git("describe", branch, repository_path=repo_dir)
22     except subprocess.CalledProcessError:
23         return False
24     return True
25
26 def parse_wrapfile(wrapf):
27     cgp = configparser.ConfigParser()
28     cgp.read(wrapf)
29     if 'wrap-git' not in cgp:
30         return None
31     section = cgp['wrap-git']
32     return section['directory'], section['revision']
33
34 def get_wrap_subprojects(srcdir, gst_branch):
35     '''
36     Parses wrap files in the subprojects directory for the specified source
37     tree and gets the revisions for all common repos.
38     '''
39     for wrapf in glob.glob(os.path.join(srcdir, 'subprojects', '*.wrap')):
40         entries = parse_wrapfile(wrapf)
41         if not entries:
42             continue
43
44         repo_name, repo_branch = entries
45         parent_repo_dir = os.path.join(SUBPROJECTS_DIR, repo_name)
46         if not os.path.exists(os.path.join(parent_repo_dir, '.git')):
47             continue
48         # If a branch of the same name exists in the gst subproject, use it
49         if repo_name.startswith('gst') and repo_has_branch(parent_repo_dir, gst_branch):
50             repo_branch = gst_branch
51
52         yield repo_name, repo_branch, parent_repo_dir
53
54 def checkout_worktree(repo_name, repo_dir, worktree_dir, branch, force=False):
55     print('Checking out worktree for project {!r} into {!r} '
56           '(branch {})'.format(repo_name, worktree_dir, branch))
57     try:
58         args = ["worktree", "add"]
59         if force:
60             args += ["-f", "-f"]
61         args += [worktree_dir, branch]
62         git(*args, repository_path=repo_dir)
63     except subprocess.CalledProcessError as e:
64         out = getattr(e, "output", b"").decode()
65         print("\nCould not checkout worktree %s, please fix and try again."
66               " Error:\n\n%s %s" % (repo_dir, out, e))
67
68         return False
69
70     commit_message = git("show", "--shortstat", repository_path=repo_dir).split("\n")
71     print(u"  -> %s%s%s - %s" % (Colors.HEADER, repo_dir, Colors.ENDC,
72                                     commit_message[4].strip()))
73     return True
74
75 def checkout_subprojects(worktree_dir, branch):
76     worktree_subdir = os.path.join(worktree_dir, "subprojects")
77
78     for repo_name, repo_branch, parent_repo_dir in get_wrap_subprojects(worktree_dir, branch):
79         workdir = os.path.normpath(os.path.join(worktree_subdir, repo_name))
80         if not checkout_worktree(repo_name, parent_repo_dir, workdir, repo_branch, force=True):
81             return False
82
83     return True
84
85 def remove_worktree(worktree_dir):
86     worktree_subdir = os.path.join(worktree_dir, "subprojects")
87
88     for repo_name, _, parent_repo_dir in get_wrap_subprojects(worktree_dir, None):
89         workdir = os.path.normpath(os.path.join(worktree_subdir, repo_name))
90         if not os.path.exists(workdir):
91             continue
92
93         subprojdir = os.path.normpath(os.path.join(SUBPROJECTS_DIR, repo_name))
94         if not os.path.exists(subprojdir):
95             continue
96
97         print('Removing worktree {!r}'.format(workdir))
98         try:
99             git('worktree', 'remove', '-f', workdir, repository_path=subprojdir)
100         except subprocess.CalledProcessError as e:
101             out = getattr(e, "output", b"").decode()
102             print('Ignoring error while removing worktree {!r}:\n\n{}'.format(workdir, out))
103
104     try:
105         git('worktree', 'remove', '-f', worktree_dir, repository_path=SCRIPTDIR)
106     except subprocess.CalledProcessError:
107         print('Failed to remove worktree {!r}'.format(worktree_dir))
108         return False
109     return True
110
111
112 if __name__ == "__main__":
113     parser = argparse.ArgumentParser(prog="gst-worktree")
114     parser.add_argument("--no-color", default=False, action='store_true',
115                         help="Do not output ANSI colors")
116
117     subparsers = parser.add_subparsers(help='The sub-command to run', dest='command')
118
119     parser_add = subparsers.add_parser('add',
120                                        help='Create a worktree for gst-build and all subprojects')
121     parser_add.add_argument('worktree_dir', type=str,
122                             help='Directory where to create the new worktree')
123     parser_add.add_argument('branch', type=str, default=None,
124                             help='Branch to checkout')
125
126     parser_rm = subparsers.add_parser('rm',
127                                       help='Remove a gst-build worktree and the subproject worktrees inside it')
128     parser_rm.add_argument('worktree_dir', type=str,
129                            help='Worktree directory to remove')
130
131     options = parser.parse_args()
132
133     if options.no_color or not Colors.can_enable():
134         Colors.disable()
135
136     if not options.command:
137         parser.print_usage()
138         exit(1)
139
140     worktree_dir = os.path.abspath(options.worktree_dir)
141
142     if options.command == 'add':
143         if not checkout_worktree('gst-build', SCRIPTDIR, worktree_dir, options.branch):
144             exit(1)
145         if not checkout_subprojects(worktree_dir, options.branch):
146             exit(1)
147     elif options.command == 'rm':
148         if not os.path.exists(worktree_dir):
149             print('Cannot remove worktree directory {!r}, it does not exist'.format(worktree_dir))
150             exit(1)
151         if not remove_worktree(worktree_dir):
152             exit(1)
153     else:
154         # Unreachable code
155         raise AssertionError