def __0_25_1(conf: GitConfigParser, repo: Repo, console: Console): """ Until v0.25.1 inclusive, bossman init changed the git config to add explicit push/fetch refspecs to force git pull/push to also fetch/push notes. This behaviour was changed in favour of an explicit pull and push as part of application logic when relevant (e.g. before bossman status/prerelease/release, before an after bossman apply). The change was largely motivated by the fact that adding the fetch/push refspecs to the config appears to break normal branch tracking, forcing an explicit `git push origin ref`, not great UX. Because notes are critical to bossman, it's also better not to rely on the user remembering to push after apply. """ notes_refspec = "+refs/notes/*:refs/notes/*" for section in conf.sections(): if section.startswith("remote"): push_refspecs = conf.get_values(section, "push", []) if notes_refspec in push_refspecs: conf.remove_option(section, "push") push_refspecs = list(refspec for refspec in push_refspecs if refspec != notes_refspec) for refspec in push_refspecs: conf.add_value(section, "push", refspec) console.print(r"[red]-[/] \[{}] push: {}".format( section, notes_refspec)) fetch_refspecs = conf.get_values(section, "fetch", []) if notes_refspec in fetch_refspecs: conf.remove_option(section, "fetch") fetch_refspecs = list(refspec for refspec in fetch_refspecs if refspec != notes_refspec) for refspec in fetch_refspecs: conf.add_value(section, "fetch", refspec) console.print(r"[red]-[/] \[{}] fetch: {}".format( section, notes_refspec))
def migrate(conf: GitConfigParser, repo: Repo, console: Console): if "bossman" not in conf.sections(): conf.add_section("bossman") console.print("Initializing git configuration [yellow]{}[/]...".format( conf._file_or_files)) conf_version = packaging.version.parse( conf.get_value("bossman", "version", "0.0.0")) for version, migration in MIGRATIONS.items(): if conf_version <= packaging.version.parse(version): migration(conf, repo, console)
def predict_local_user(repo): config = GitConfigParser( [os.path.normpath(os.path.expanduser("~/.gitconfig"))], read_only=True ) writer = repo.config_writer() sections = config.sections() i = 0 is_set = False while i < len(sections) and not is_set: sec = sections[i] if 'multi-user' in sec: # name = re.findall(r'"([^"]*)"', sec)[1] user = dict(config.items(sec)) logging.debug("multi-user: %s", str(user)) if 'url' in user and 'name' in user and 'email' in user: for remote in repo.remotes: logging.debug("remote-url: %s", remote.url) prog = re.compile(user['url']) if prog.match(remote.url): logging.info( "%s found in remote url %s", user['url'], remote.url ) logging.info( "Setting local user.name to %s", user["name"] ) writer.set_value('user', 'name', user['name']) logging.info( "Setting local user.email to %s", user["email"] ) writer.set_value('user', 'email', user['email']) writer.release() is_set = True break elif 'url' not in user: logging.warning('url not set for %s', sec) elif 'name' not in user: logging.warning('name not set for %s', sec) elif 'email' not in user: logging.warning('email not set for %s', sec) i = i + 1 return is_set
def _parse_gitmodules(dspath): gitmodule_path = opj(dspath, ".gitmodules") parser = GitConfigParser(gitmodule_path) mods = {} for sec in parser.sections(): modpath = parser.get_value(sec, 'path', default=0) if not modpath or not sec.startswith('submodule '): continue modpath = normpath(opj(dspath, modpath)) modprops = {'gitmodule_{}'.format(opt): parser.get_value(sec, opt) for opt in parser.options(sec) if not (opt.startswith('__') or opt == 'path')} modprops['gitmodule_name'] = sec[11:-1] mods[modpath] = modprops return mods
def test_multi_line_config(self): file_obj = self._to_memcache(fixture_path("git_config_with_comments")) config = GitConfigParser(file_obj, read_only=False) ev = "ruby -e '\n" ev += " system %(git), %(merge-file), %(--marker-size=%L), %(%A), %(%O), %(%B)\n" ev += " b = File.read(%(%A))\n" ev += " b.sub!(/^<+ .*\\nActiveRecord::Schema\\.define.:version => (\\d+). do\\n=+\\nActiveRecord::Schema\\." ev += "define.:version => (\\d+). do\\n>+ .*/) do\n" ev += " %(ActiveRecord::Schema.define(:version => #{[$1, $2].max}) do)\n" ev += " end\n" ev += " File.open(%(%A), %(w)) {|f| f.write(b)}\n" ev += " exit 1 if b.include?(%(<)*%L)'" assert_equal(config.get('merge "railsschema"', 'driver'), ev) assert_equal(config.get('alias', 'lg'), "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset'" " --abbrev-commit --date=relative") assert len(config.sections()) == 23
def get_author() -> Actor: """ Get the name and email information in the user's .gitconfig. :return: the git author information as an :py:class:`~git.util.Actor` """ info = {} gitconfig = GitConfigParser(os.path.expanduser('~/.gitconfig')) sections = gitconfig.sections() assert 'user' in sections, 'No "user" field in .gitconfig' user_items = gitconfig.items('user') for tup in user_items: info[tup[0]] = tup[1] assert 'name' in info and 'email' in info, 'Incomplete information (name and/or email) in .gitconfig' return Actor(name=info['name'], email=info['email'])
def test_base(self): path_repo = fixture_path("git_config") path_global = fixture_path("git_config_global") r_config = GitConfigParser([path_repo, path_global], read_only=True) assert r_config.read_only num_sections = 0 num_options = 0 # test reader methods assert r_config._is_initialized is False for section in r_config.sections(): num_sections += 1 for option in r_config.options(section): num_options += 1 val = r_config.get(section, option) val_typed = r_config.get_value(section, option) assert isinstance(val_typed, ( bool, int, float, ) + string_types) assert val assert "\n" not in option assert "\n" not in val # writing must fail with self.assertRaises(IOError): r_config.set(section, option, None) with self.assertRaises(IOError): r_config.remove_option(section, option) # END for each option with self.assertRaises(IOError): r_config.remove_section(section) # END for each section assert num_sections and num_options assert r_config._is_initialized is True # get value which doesnt exist, with default default = "my default value" assert r_config.get_value("doesnt", "exist", default) == default # it raises if there is no default though with self.assertRaises(cp.NoSectionError): r_config.get_value("doesnt", "exist")
def test_base(self): path_repo = fixture_path("git_config") path_global = fixture_path("git_config_global") r_config = GitConfigParser([path_repo, path_global], read_only=True) assert r_config.read_only num_sections = 0 num_options = 0 # test reader methods assert r_config._is_initialized is False for section in r_config.sections(): num_sections += 1 for option in r_config.options(section): num_options += 1 val = r_config.get(section, option) val_typed = r_config.get_value(section, option) assert isinstance(val_typed, (bool, int, float, ) + string_types) assert val assert "\n" not in option assert "\n" not in val # writing must fail with self.assertRaises(IOError): r_config.set(section, option, None) with self.assertRaises(IOError): r_config.remove_option(section, option) # END for each option with self.assertRaises(IOError): r_config.remove_section(section) # END for each section assert num_sections and num_options assert r_config._is_initialized is True # get value which doesnt exist, with default default = "my default value" assert r_config.get_value("doesnt", "exist", default) == default # it raises if there is no default though with self.assertRaises(cp.NoSectionError): r_config.get_value("doesnt", "exist")
def _parse_gitmodules(dspath): gitmodule_path = opj(dspath, ".gitmodules") parser = GitConfigParser(gitmodule_path) mods = {} for sec in parser.sections(): try: modpath = parser.get(sec, 'path') except Exception: lgr.debug("Failed to get '%s.path', skipping section", sec) continue if not modpath or not sec.startswith('submodule '): continue modpath = normpath(opj(dspath, modpath)) modprops = {'gitmodule_{}'.format(opt): parser.get_value(sec, opt) for opt in parser.options(sec) if not (opt.startswith('__') or opt == 'path')} modprops['gitmodule_name'] = sec[11:-1] mods[modpath] = modprops # make sure we let go of any resources held be the parser # we cannot rely on __del__ parser.release() return mods