2 # Set up the git configuration for contributing to TianoCore projects
4 # Copyright (c) 2019, Linaro Ltd. All rights reserved.<BR>
5 # Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
7 # SPDX-License-Identifier: BSD-2-Clause-Patent
10 from __future__
import print_function
19 print('Unable to load gitpython module - please install and try again.')
23 # Try Python 2 'ConfigParser' module first since helpful lib2to3 will
24 # otherwise automagically load it with the name 'configparser'
27 # Otherwise, try loading the Python 3 'configparser' under an alias
29 import configparser
as ConfigParser
31 print("Unable to load configparser/ConfigParser module - please install and try again!")
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__
))),
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'},
51 'repo': 'https://github.com/tianocore/edk2-test.git',
52 'list': 'devel@edk2.groups.io', 'prefix': 'edk2-test'}
55 # The minimum version required for all of the below options to work
56 MIN_GIT_VERSION
= (1, 9, 0)
58 # Set of options to be set identically for all repositories
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'},
89 """Opens a Repo object for the current tree, searching upwards in the directory hierarchy."""
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.")
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
)
103 if oneresult
and otherresult
:
104 onestring
= oneresult
.group('oneresult')
105 otherstring
= otherresult
.group('otherresult')
106 if onestring
== otherstring
:
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
):
118 print("Unknown upstream '%s' - aborting!" % url
)
122 def check_versions():
123 """Checks versions of dependencies."""
124 version
= git
.cmd
.Git().version_info
126 if version
< MIN_GIT_VERSION
:
127 print('Need git version %d.%d or later!' % (version
[0], version
[1]))
131 def write_config_value(repo
, section
, option
, data
):
133 with repo
.config_writer(config_level
='repository') as configwriter
:
134 configwriter
.set_value(section
, option
, data
)
137 if __name__
== '__main__':
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',
146 PARSER
.add_argument('-f', '--force',
147 help='overwrite existing settings conflicting with program defaults',
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',
155 PARSER
.add_argument('-v', '--verbose',
156 help='enable more detailed output',
159 ARGS
= PARSER
.parse_args()
163 print('Bare repo - please check out an upstream one!')
166 URL
= REPO
.remotes
.origin
.url
168 UPSTREAM
= get_upstream(URL
, ARGS
.name
)
170 print("Upstream '%s' unknown, aborting!" % URL
)
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']})
182 CONFIG
= REPO
.config_reader(config_level
='repository')
184 for entry
in OPTIONS
:
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'])
193 value
= CONFIG
.get(entry
['section'], entry
['option'])
196 # Don't bail out from options not already being set
197 except (ConfigParser
.NoSectionError
, ConfigParser
.NoOptionError
):
201 if value
== entry
['value']:
203 print("%s.%s already set (to '%s')" % (entry
['section'],
204 entry
['option'], value
))
207 write_config_value(REPO
, entry
['section'], entry
['option'], entry
['value'])
209 print("Not overwriting existing %s.%s value:" % (entry
['section'],
211 print(" '%s' != '%s'" % (value
, entry
['value']))
212 print(" add '-f' to command line to force overwriting existing settings")
214 print("%s.%s => '%s'" % (entry
['section'], entry
['option'], entry
['value']))
216 write_config_value(REPO
, entry
['section'], entry
['option'], entry
['value'])