2 # Set up the git configuration for contributing to TianoCore projects
4 # Copyright (c) 2019, Linaro Ltd. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
9 from __future__
import print_function
18 print('Unable to load gitpython module - please install and try again.')
22 # Try Python 2 'ConfigParser' module first since helpful lib2to3 will
23 # otherwise automagically load it with the name 'configparser'
26 # Otherwise, try loading the Python 3 'configparser' under an alias
28 import configparser
as ConfigParser
30 print("Unable to load configparser/ConfigParser module - please install and try again!")
34 # Assumptions: Script is in edk2/BaseTools/Scripts,
35 # templates in edk2/BaseTools/Conf
36 CONFDIR
= os
.path
.join(os
.path
.dirname(os
.path
.dirname(os
.path
.realpath(__file__
))),
41 'repo': 'https://github.com/tianocore/edk2.git',
42 'list': 'devel@edk2.groups.io'},
43 {'name': 'edk2-platforms',
44 'repo': 'https://github.com/tianocore/edk2-platforms.git',
45 'list': 'devel@edk2.groups.io', 'prefix': 'edk2-platforms'},
46 {'name': 'edk2-non-osi',
47 'repo': 'https://github.com/tianocore/edk2-non-osi.git',
48 'list': 'devel@edk2.groups.io', 'prefix': 'edk2-non-osi'}
51 # The minimum version required for all of the below options to work
52 MIN_GIT_VERSION
= (1, 9, 0)
54 # Set of options to be set identically for all repositories
56 {'section': 'am', 'option': 'keepcr', 'value': True},
57 {'section': 'am', 'option': 'signoff', 'value': True},
58 {'section': 'cherry-pick', 'option': 'signoff', 'value': True},
59 {'section': 'color', 'option': 'diff', 'value': True},
60 {'section': 'color', 'option': 'grep', 'value': 'auto'},
61 {'section': 'commit', 'option': 'signoff', 'value': True},
62 {'section': 'core', 'option': 'abbrev', 'value': 12},
63 {'section': 'core', 'option': 'attributesFile',
64 'value': os
.path
.join(CONFDIR
, 'gitattributes').replace('\\', '/')},
65 {'section': 'core', 'option': 'whitespace', 'value': 'cr-at-eol'},
66 {'section': 'diff', 'option': 'algorithm', 'value': 'patience'},
67 {'section': 'diff', 'option': 'orderFile',
68 'value': os
.path
.join(CONFDIR
, 'diff.order').replace('\\', '/')},
69 {'section': 'diff', 'option': 'renames', 'value': 'copies'},
70 {'section': 'diff', 'option': 'statGraphWidth', 'value': '20'},
71 {'section': 'diff "ini"', 'option': 'xfuncname',
72 'value': '^\\\\[[A-Za-z0-9_., ]+]'},
73 {'section': 'format', 'option': 'coverLetter', 'value': True},
74 {'section': 'format', 'option': 'numbered', 'value': True},
75 {'section': 'format', 'option': 'signoff', 'value': False},
76 {'section': 'notes', 'option': 'rewriteRef', 'value': 'refs/notes/commits'},
77 {'section': 'sendemail', 'option': 'chainreplyto', 'value': False},
78 {'section': 'sendemail', 'option': 'thread', 'value': True},
83 """Opens a Repo object for the current tree, searching upwards in the directory hierarchy."""
85 repo
= git
.Repo(path
='.', search_parent_directories
=True)
86 except (git
.InvalidGitRepositoryError
, git
.NoSuchPathError
):
87 print("It doesn't look like we're inside a git repository - aborting.")
92 def fuzzy_match_repo_url(one
, other
):
93 """Compares two repository URLs, ignoring protocol and optional trailing '.git'."""
94 oneresult
= re
.match(r
'.*://(?P<oneresult>.*?)(\.git)*$', one
)
95 otherresult
= re
.match(r
'.*://(?P<otherresult>.*?)(\.git)*$', other
)
97 if oneresult
and otherresult
:
98 onestring
= oneresult
.group('oneresult')
99 otherstring
= otherresult
.group('otherresult')
100 if onestring
== otherstring
:
106 def get_upstream(url
):
107 """Extracts the dict for the current repo origin."""
108 for upstream
in UPSTREAMS
:
109 if fuzzy_match_repo_url(upstream
['repo'], url
):
111 print("Unknown upstream '%s' - aborting!" % url
)
115 def check_versions():
116 """Checks versions of dependencies."""
117 version
= git
.cmd
.Git().version_info
119 if version
< MIN_GIT_VERSION
:
120 print('Need git version %d.%d or later!' % (version
[0], version
[1]))
124 def write_config_value(repo
, section
, option
, data
):
126 with repo
.config_writer(config_level
='repository') as configwriter
:
127 configwriter
.set_value(section
, option
, data
)
130 if __name__
== '__main__':
133 PARSER
= argparse
.ArgumentParser(
134 description
='Sets up a git repository according to TianoCore rules.')
135 PARSER
.add_argument('-c', '--check',
136 help='check current config only, printing what would be changed',
139 PARSER
.add_argument('-f', '--force',
140 help='overwrite existing settings conflicting with program defaults',
143 PARSER
.add_argument('-v', '--verbose',
144 help='enable more detailed output',
147 ARGS
= PARSER
.parse_args()
151 print('Bare repo - please check out an upstream one!')
154 URL
= REPO
.remotes
.origin
.url
156 UPSTREAM
= get_upstream(URL
)
158 print("Upstream '%s' unknown, aborting!" % URL
)
161 # Set a list email address if our upstream wants it
162 if 'list' in UPSTREAM
:
163 OPTIONS
.append({'section': 'sendemail', 'option': 'to',
164 'value': UPSTREAM
['list']})
165 # Append a subject prefix entry to OPTIONS if our upstream wants it
166 if 'prefix' in UPSTREAM
:
167 OPTIONS
.append({'section': 'format', 'option': 'subjectPrefix',
168 'value': "PATCH " + UPSTREAM
['prefix']})
170 CONFIG
= REPO
.config_reader(config_level
='repository')
172 for entry
in OPTIONS
:
175 # Make sure to read boolean/int settings as real type rather than strings
176 if isinstance(entry
['value'], bool):
177 value
= CONFIG
.getboolean(entry
['section'], entry
['option'])
178 elif isinstance(entry
['value'], int):
179 value
= CONFIG
.getint(entry
['section'], entry
['option'])
181 value
= CONFIG
.get(entry
['section'], entry
['option'])
184 # Don't bail out from options not already being set
185 except (ConfigParser
.NoSectionError
, ConfigParser
.NoOptionError
):
189 if value
== entry
['value']:
191 print("%s.%s already set (to '%s')" % (entry
['section'],
192 entry
['option'], value
))
195 write_config_value(REPO
, entry
['section'], entry
['option'], entry
['value'])
197 print("Not overwriting existing %s.%s value:" % (entry
['section'],
199 print(" '%s' != '%s'" % (value
, entry
['value']))
200 print(" add '-f' to command line to force overwriting existing settings")
202 print("%s.%s => '%s'" % (entry
['section'], entry
['option'], entry
['value']))
204 write_config_value(REPO
, entry
['section'], entry
['option'], entry
['value'])