def initialize_git_config_map(): """Initialize the __git_config_map global. """ global __git_config_map # The hooks' configuration is stored on a special branch called # refs/meta/config, inside a file called project.config. Get # that file. (tmp_fd, tmp_file) = mkstemp('tmp-git-hooks-') try: cfg_file = tmp_file try: git.show('refs/meta/config:project.config', _outfile=tmp_fd) except CalledProcessError: # Most likely a project that still uses the repository's # config file to store the hooks configuration, rather # that the controlled project.config file. # # Handle this situation by doing what we used to do, # which is get the configuration from the repository's # config file, after having warned the user about it # (to expedite the transition). # # Note that we cannot use "utils.warn" to do the warning # in this module, as the "utils" module depends on this # module. Do the warning by hand. # # ??? One small issue is the fact that this warning may get # displayed multiple times (once per "phase", eg "update", # then "post-receive"). Given the relatively rare nature # of this event, we'll just accept it, instead of fancying # things up. for l in NO_REFS_META_CONFIG_WARNING.splitlines(): print >> sys.stderr, '*** %s' % l cfg_file = 'config' os.close(tmp_fd) # Get the currently defined config values, all in one go. # Use "--file <cfg_file>" to make sure that we only parse # the file we just retrieved. Otherwise, git also parses # the user's config file. all_configs = git.config('-l', '--file', cfg_file, _split_lines=True) finally: os.unlink(tmp_file) all_configs_map = dict([config.split('=', 1) for config in all_configs]) # Populate the __git_config_map dictionary... __git_config_map = {} for config_name in GIT_CONFIG_OPTS.keys(): # Get the config value from either the all_configs_map # if defined, or else from the default value. if config_name in all_configs_map: config_val = all_configs_map[config_name] else: config_val = GIT_CONFIG_OPTS[config_name]['default'] # Finally, save the config value if __git_config_map __git_config_map[config_name] = config_val
def initialize_git_config_map(): """Initialize the __git_config_map global. """ global __git_config_map # The hooks' configuration is stored in a special reference # (see CONFIG_REF), inside a file whose name is CONFIG_FILENAME. # Get that file. (tmp_fd, tmp_file) = mkstemp('tmp-git-hooks-') try: cfg_file = tmp_file try: git.show(config_commit + ':' + CONFIG_FILENAME, _outfile=tmp_fd) except CalledProcessError: # Either the CONFIG_REF reference does not exist, or # the config file itself does not exist. Either way, # it means that the repository has not been properly # set up for these hooks, which is a fatal error. raise InvalidUpdate(*CANNOT_FIND_CONFIG_FILE_ERROR.splitlines()) os.close(tmp_fd) # Get the currently defined config values, all in one go. # Use "--file <cfg_file>" to make sure that we only parse # the file we just retrieved. Otherwise, git also parses # the user's config file. # # Also, use the nul character as the separator between each # entry (-z option) so as to not confuse them with potential # newlines being used inside the value of an option. all_configs = git.config('-z', '-l', '--file', cfg_file).split('\x00') finally: os.unlink(tmp_file) all_configs_map = {} for config in all_configs: if not config: # "git config -z" adds a nul character at the end of its output, # which cause all_configs to end with an empty entry. Just ignore # those. continue config_name, config_val = config.split('\n', 1) if config_name in GIT_CONFIG_OPTS and \ 'type' in GIT_CONFIG_OPTS[config_name] and \ GIT_CONFIG_OPTS[config_name]['type'] == tuple: # This config is a list of potentially multiple values, and # therefore multiple entries with the same config name can be # provided for each value. Just save them in a list. if config_name not in all_configs_map: all_configs_map[config_name] = () # Also, at least for now, we support coma-separated entries # for this multiple-value configs. So split each entry as well... config_val = to_type(config_val, tuple) all_configs_map[config_name] += config_val else: all_configs_map[config_name] = config_val # Populate the __git_config_map dictionary... __git_config_map = {} for config_name in GIT_CONFIG_OPTS.keys(): # Get the config value from either the all_configs_map # if defined, or else from the default value. if config_name in all_configs_map: config_val = all_configs_map[config_name] else: config_val = GIT_CONFIG_OPTS[config_name]['default'] # Finally, save the config value if __git_config_map __git_config_map[config_name] = config_val
def __check_gitreview_defaultbranch(self): """If .gitreview exists, validate the defaultbranch value. This is meant to catch the situation where a user creates a new branch for a repository hosted on gerrit. Those repositories typically have a .gitreview file at their root, providing various information, one of them being the default branch name when sending patches for review. When creating a new branch, it is very easy (and frequent) for a user to forget to also update the .gitreview file, causing patch reviews to be sent with the wrong branch, which later then causes the patch to be merged (submitted) on the wrong branch once it is approved. We try to avoid that situation by reading the contents of those files at branch creation time, and reporting an error if it exists and points to a branch name different from ours. Note that we only do that for the traditional git branches. We don't worry about the branches in the gerrit-specific special namespaces, for which a user checking out the branch and sending a review is unlikely. """ GITREVIEW_FILENAME = '.gitreview' DEFAULTBRANCH_CONFIG_NAME = 'gerrit.defaultbranch' # Only perform this check for traditional git branches. # See method description above for the reason why. if not self.ref_name.startswith('refs/heads/'): return if self.search_config_option_list('hooks.no-precommit-check')\ is not None: # The user explicitly disabled the .gitreview check # on this branch. return # If the file doesn't exist for that branch, then there is # no problem. if not file_exists(self.new_rev, GITREVIEW_FILENAME): return # Get the contents of the gitreview file, and then get git # to parse its contents. We process it all into a dictionary # rather than just query the value of the one config we are # looking for, for a couple of reasons: # 1. This allows us to avoid having to git returning with # and error status when the file does not have the config # entry we are looking for (git returns error code 1 # in that case); # 2. If we even want to look at other configurations in # that file, the code is already in place to do so. gitreview_contents = git.show('%s:%s' % (self.new_rev, GITREVIEW_FILENAME)) gitreview_configs = git.config('-z', '-l', '--file', '-', _input=gitreview_contents).split('\x00') config_map = {} for config in gitreview_configs: if not config: # "git config -z" adds a nul character at the end of # its output, which cause gitreview_configs to end with # an empty entry. Just ignore those. continue config_name, config_val = config.split('\n', 1) config_map[config_name] = config_val if DEFAULTBRANCH_CONFIG_NAME in config_map and \ config_map[DEFAULTBRANCH_CONFIG_NAME] != self.short_ref_name: raise InvalidUpdate( "Incorrect gerrit default branch name in file `%s'." % GITREVIEW_FILENAME, "You probably forgot to update your %s file following" % GITREVIEW_FILENAME, "the creation of this branch.", '', "Please create a commit which updates the value", "of %s in the file `%s'" % (DEFAULTBRANCH_CONFIG_NAME, GITREVIEW_FILENAME), "and set it to `%s' (instead of `%s')." % (self.short_ref_name, config_map[DEFAULTBRANCH_CONFIG_NAME]))
def initialize_git_config_map(): """Initialize the __git_config_map global. """ global __git_config_map # The hooks' configuration is stored on a special branch called # refs/meta/config, inside a file called project.config. Get # that file. (tmp_fd, tmp_file) = mkstemp('tmp-git-hooks-') try: cfg_file = tmp_file try: git.show('refs/meta/config:project.config', _outfile=tmp_fd) except CalledProcessError: # Most likely a project that still uses the repository's # config file to store the hooks configuration, rather # that the controlled project.config file. # # Handle this situation by doing what we used to do, # which is get the configuration from the repository's # config file, after having warned the user about it # (to expedite the transition). # # Note that we cannot use "utils.warn" to do the warning # in this module, as the "utils" module depends on this # module. Do the warning by hand. # # ??? One small issue is the fact that this warning may get # displayed multiple times (once per "phase", eg "update", # then "post-receive"). Given the relatively rare nature # of this event, we'll just accept it, instead of fancying # things up. for l in NO_REFS_META_CONFIG_WARNING.splitlines(): print >> sys.stderr, '*** %s' % l cfg_file = 'config' os.close(tmp_fd) # Get the currently defined config values, all in one go. # Use "--file <cfg_file>" to make sure that we only parse # the file we just retrieved. Otherwise, git also parses # the user's config file. # # Also, use the nul character as the separator between each # entry (-z option) so as to not confuse them with potential # newlines being used inside the value of an option. all_configs = git.config('-z', '-l', '--file', cfg_file).split('\x00') finally: os.unlink(tmp_file) all_configs_map = {} for config in all_configs: if not config: # "git config -z" adds a nul character at the end of its output, # which cause all_configs to end with an empty entry. Just ignore # those. continue config_name, config_val = config.split('\n', 1) if config_name in GIT_CONFIG_OPTS and \ 'type' in GIT_CONFIG_OPTS[config_name] and \ GIT_CONFIG_OPTS[config_name]['type'] == tuple: # This config is a list of potentially multiple values, and # therefore multiple entries with the same config name can be # provided for each value. Just save them in a list. if config_name not in all_configs_map: all_configs_map[config_name] = () # Also, at least for now, we support coma-separated entries # for this multiple-value configs. So split each entry as well... config_val = to_type(config_val, tuple) all_configs_map[config_name] += config_val else: all_configs_map[config_name] = config_val # Populate the __git_config_map dictionary... __git_config_map = {} for config_name in GIT_CONFIG_OPTS.keys(): # Get the config value from either the all_configs_map # if defined, or else from the default value. if config_name in all_configs_map: config_val = all_configs_map[config_name] else: config_val = GIT_CONFIG_OPTS[config_name]['default'] # Finally, save the config value if __git_config_map __git_config_map[config_name] = config_val