]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/SetupGit.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Scripts / SetupGit.py
1 ## @file
2 # Set up the git configuration for contributing to TianoCore projects
3 #
4 # Copyright (c) 2019, Linaro Ltd. All rights reserved.<BR>
5 # Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6 #
7 # SPDX-License-Identifier: BSD-2-Clause-Patent
8 #
9
10 from __future__ import print_function
11 import argparse
12 import os.path
13 import re
14 import sys
15
16 try:
17 import git
18 except ImportError:
19 print('Unable to load gitpython module - please install and try again.')
20 sys.exit(1)
21
22 try:
23 # Try Python 2 'ConfigParser' module first since helpful lib2to3 will
24 # otherwise automagically load it with the name 'configparser'
25 import ConfigParser
26 except ImportError:
27 # Otherwise, try loading the Python 3 'configparser' under an alias
28 try:
29 import configparser as ConfigParser
30 except ImportError:
31 print("Unable to load configparser/ConfigParser module - please install and try again!")
32 sys.exit(1)
33
34
35 # Assumptions: Script is in edk2/BaseTools/Scripts,
36 # templates in edk2/BaseTools/Conf
37 CONFDIR = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
38 'Conf')
39
40 UPSTREAMS = [
41 {'name': 'edk2',
42 'repo': 'https://github.com/tianocore/edk2.git',
43 'list': 'devel@edk2.groups.io'},
44 {'name': 'edk2-platforms',
45 'repo': 'https://github.com/tianocore/edk2-platforms.git',
46 'list': 'devel@edk2.groups.io', 'prefix': 'edk2-platforms'},
47 {'name': 'edk2-non-osi',
48 'repo': 'https://github.com/tianocore/edk2-non-osi.git',
49 'list': 'devel@edk2.groups.io', 'prefix': 'edk2-non-osi'},
50 {'name': 'edk2-test',
51 'repo': 'https://github.com/tianocore/edk2-test.git',
52 'list': 'devel@edk2.groups.io', 'prefix': 'edk2-test'}
53 ]
54
55 # The minimum version required for all of the below options to work
56 MIN_GIT_VERSION = (1, 9, 0)
57
58 # Set of options to be set identically for all repositories
59 OPTIONS = [
60 {'section': 'am', 'option': 'keepcr', 'value': True},
61 {'section': 'am', 'option': 'signoff', 'value': True},
62 {'section': 'cherry-pick', 'option': 'signoff', 'value': True},
63 {'section': 'color', 'option': 'diff', 'value': True},
64 {'section': 'color', 'option': 'grep', 'value': 'auto'},
65 {'section': 'commit', 'option': 'signoff', 'value': True},
66 {'section': 'core', 'option': 'abbrev', 'value': 12},
67 {'section': 'core', 'option': 'attributesFile',
68 'value': os.path.join(CONFDIR, 'gitattributes').replace('\\', '/')},
69 {'section': 'core', 'option': 'whitespace', 'value': 'cr-at-eol'},
70 {'section': 'diff', 'option': 'algorithm', 'value': 'patience'},
71 {'section': 'diff', 'option': 'orderFile',
72 'value': os.path.join(CONFDIR, 'diff.order').replace('\\', '/')},
73 {'section': 'diff', 'option': 'renames', 'value': 'copies'},
74 {'section': 'diff', 'option': 'statGraphWidth', 'value': '20'},
75 {'section': 'diff "ini"', 'option': 'xfuncname',
76 'value': '^\\\\[[A-Za-z0-9_., ]+]'},
77 {'section': 'format', 'option': 'coverLetter', 'value': True},
78 {'section': 'format', 'option': 'numbered', 'value': True},
79 {'section': 'format', 'option': 'signoff', 'value': False},
80 {'section': 'log', 'option': 'mailmap', 'value': True},
81 {'section': 'notes', 'option': 'rewriteRef', 'value': 'refs/notes/commits'},
82 {'section': 'sendemail', 'option': 'chainreplyto', 'value': False},
83 {'section': 'sendemail', 'option': 'thread', 'value': True},
84 {'section': 'sendemail', 'option': 'transferEncoding', 'value': '8bit'},
85 ]
86
87
88 def locate_repo():
89 """Opens a Repo object for the current tree, searching upwards in the directory hierarchy."""
90 try:
91 repo = git.Repo(path='.', search_parent_directories=True)
92 except (git.InvalidGitRepositoryError, git.NoSuchPathError):
93 print("It doesn't look like we're inside a git repository - aborting.")
94 sys.exit(2)
95 return repo
96
97
98 def fuzzy_match_repo_url(one, other):
99 """Compares two repository URLs, ignoring protocol and optional trailing '.git'."""
100 oneresult = re.match(r'.*://(?P<oneresult>.*?)(\.git)*$', one)
101 otherresult = re.match(r'.*://(?P<otherresult>.*?)(\.git)*$', other)
102
103 if oneresult and otherresult:
104 onestring = oneresult.group('oneresult')
105 otherstring = otherresult.group('otherresult')
106 if onestring == otherstring:
107 return True
108
109 return False
110
111
112 def get_upstream(url, name):
113 """Extracts the dict for the current repo origin."""
114 for upstream in UPSTREAMS:
115 if (fuzzy_match_repo_url(upstream['repo'], url) or
116 upstream['name'] == name):
117 return upstream
118 print("Unknown upstream '%s' - aborting!" % url)
119 sys.exit(3)
120
121
122 def check_versions():
123 """Checks versions of dependencies."""
124 version = git.cmd.Git().version_info
125
126 if version < MIN_GIT_VERSION:
127 print('Need git version %d.%d or later!' % (version[0], version[1]))
128 sys.exit(4)
129
130
131 def write_config_value(repo, section, option, data):
132 """."""
133 with repo.config_writer(config_level='repository') as configwriter:
134 configwriter.set_value(section, option, data)
135
136
137 if __name__ == '__main__':
138 check_versions()
139
140 PARSER = argparse.ArgumentParser(
141 description='Sets up a git repository according to TianoCore rules.')
142 PARSER.add_argument('-c', '--check',
143 help='check current config only, printing what would be changed',
144 action='store_true',
145 required=False)
146 PARSER.add_argument('-f', '--force',
147 help='overwrite existing settings conflicting with program defaults',
148 action='store_true',
149 required=False)
150 PARSER.add_argument('-n', '--name', type=str, metavar='repo',
151 choices=['edk2', 'edk2-platforms', 'edk2-non-osi'],
152 help='set the repo name to configure for, if not '
153 'detected automatically',
154 required=False)
155 PARSER.add_argument('-v', '--verbose',
156 help='enable more detailed output',
157 action='store_true',
158 required=False)
159 ARGS = PARSER.parse_args()
160
161 REPO = locate_repo()
162 if REPO.bare:
163 print('Bare repo - please check out an upstream one!')
164 sys.exit(6)
165
166 URL = REPO.remotes.origin.url
167
168 UPSTREAM = get_upstream(URL, ARGS.name)
169 if not UPSTREAM:
170 print("Upstream '%s' unknown, aborting!" % URL)
171 sys.exit(7)
172
173 # Set a list email address if our upstream wants it
174 if 'list' in UPSTREAM:
175 OPTIONS.append({'section': 'sendemail', 'option': 'to',
176 'value': UPSTREAM['list']})
177 # Append a subject prefix entry to OPTIONS if our upstream wants it
178 if 'prefix' in UPSTREAM:
179 OPTIONS.append({'section': 'format', 'option': 'subjectPrefix',
180 'value': "PATCH " + UPSTREAM['prefix']})
181
182 CONFIG = REPO.config_reader(config_level='repository')
183
184 for entry in OPTIONS:
185 exists = False
186 try:
187 # Make sure to read boolean/int settings as real type rather than strings
188 if isinstance(entry['value'], bool):
189 value = CONFIG.getboolean(entry['section'], entry['option'])
190 elif isinstance(entry['value'], int):
191 value = CONFIG.getint(entry['section'], entry['option'])
192 else:
193 value = CONFIG.get(entry['section'], entry['option'])
194
195 exists = True
196 # Don't bail out from options not already being set
197 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
198 pass
199
200 if exists:
201 if value == entry['value']:
202 if ARGS.verbose:
203 print("%s.%s already set (to '%s')" % (entry['section'],
204 entry['option'], value))
205 else:
206 if ARGS.force:
207 write_config_value(REPO, entry['section'], entry['option'], entry['value'])
208 else:
209 print("Not overwriting existing %s.%s value:" % (entry['section'],
210 entry['option']))
211 print(" '%s' != '%s'" % (value, entry['value']))
212 print(" add '-f' to command line to force overwriting existing settings")
213 else:
214 print("%s.%s => '%s'" % (entry['section'], entry['option'], entry['value']))
215 if not ARGS.check:
216 write_config_value(REPO, entry['section'], entry['option'], entry['value'])