| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | 10 | __version__ = 'git' | |
| 11 | 11 | ||
| 12 | + from git.config import GitConfigParser | ||
| 12 | 13 | from git.objects import * | |
| 13 | 14 | from git.refs import * | |
| 14 | 15 | from git.actor import Actor | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,100 @@ | |||
| 1 | + # config.py | ||
| 2 | + # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | ||
| 3 | + # | ||
| 4 | + # This module is part of GitPython and is released under | ||
| 5 | + # the BSD License: http://www.opensource.org/licenses/bsd-license.php | ||
| 6 | + """ | ||
| 7 | + Module containing module parser implementation able to properly read and write | ||
| 8 | + configuration files | ||
| 9 | + """ | ||
| 10 | + | ||
| 11 | + import re | ||
| 12 | + from ConfigParser import RawConfigParser | ||
| 13 | + | ||
| 14 | + class _MetaParserBuilder(type): | ||
| 15 | + """ | ||
| 16 | + Utlity class wrapping methods into decorators that assure read-only properties | ||
| 17 | + """ | ||
| 18 | + | ||
| 19 | + def _needs_values(func): | ||
| 20 | + """Returns method assuring we read values (on demand) before we try to access them""" | ||
| 21 | + return func | ||
| 22 | + | ||
| 23 | + def _ensure_writable(non_const_func): | ||
| 24 | + """Return method that checks whether given non constant function may be called. | ||
| 25 | + If so, the instance will be set dirty""" | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + class GitConfigParser(RawConfigParser, object): | ||
| 30 | + """ | ||
| 31 | + Implements specifics required to read git style configuration files. | ||
| 32 | + | ||
| 33 | + This variation behaves much like the git.config command such that the configuration | ||
| 34 | + will be read on demand based on the filepath given during initialization. | ||
| 35 | + | ||
| 36 | + The changes will automatically be written once the instance goes out of scope, but | ||
| 37 | + can be triggered manually as well. | ||
| 38 | + | ||
| 39 | + The configuration file will be locked if you intend to change values preventing other | ||
| 40 | + instances to write concurrently. | ||
| 41 | + """ | ||
| 42 | + __metaclass__ = _MetaParserBuilder | ||
| 43 | + | ||
| 44 | + OPTCRE = re.compile( | ||
| 45 | + r'\s?(?P<option>[^:=\s][^:=]*)' # very permissive, incuding leading whitespace | ||
| 46 | + r'\s*(?P<vi>[:=])\s*' # any number of space/tab, | ||
| 47 | + # followed by separator | ||
| 48 | + # (either : or =), followed | ||
| 49 | + # by any # space/tab | ||
| 50 | + r'(?P<value>.*)$' # everything up to eol | ||
| 51 | + ) | ||
| 52 | + | ||
| 53 | + # list of RawConfigParser methods able to change the instance | ||
| 54 | + _mutating_methods_ = tuple() | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + def __init__(self, file_or_files, read_only=True): | ||
| 58 | + """ | ||
| 59 | + Initialize a configuration reader to read the given file_or_files and to | ||
| 60 | + possibly allow changes to it by setting read_only False | ||
| 61 | + """ | ||
| 62 | + self._file_or_files = file_or_files | ||
| 63 | + self._read_only = read_only | ||
| 64 | + self._is_initialized = False | ||
| 65 | + self._is_dirty = False | ||
| 66 | + | ||
| 67 | + def __del__(self): | ||
| 68 | + """ | ||
| 69 | + Write pending changes if required and release locks | ||
| 70 | + """ | ||
| 71 | + | ||
| 72 | + def read(self): | ||
| 73 | + """ | ||
| 74 | + Read configuration information from our file or files | ||
| 75 | + """ | ||
| 76 | + if self._is_initialized: | ||
| 77 | + return | ||
| 78 | + | ||
| 79 | + self._is_initialized = True | ||
| 80 | + | ||
| 81 | + @_ensure_writable | ||
| 82 | + def write(self): | ||
| 83 | + """ | ||
| 84 | + Write our changes to our file | ||
| 85 | + | ||
| 86 | + Raise | ||
| 87 | + AssertionError if this is a read-only writer instance | ||
| 88 | + """ | ||
| 89 | + if not self._is_dirty: | ||
| 90 | + return | ||
| 91 | + | ||
| 92 | + self._is_dirty = False | ||
| 93 | + | ||
| 94 | + @property | ||
| 95 | + def read_only(self): | ||
| 96 | + """ | ||
| 97 | + Returns | ||
| 98 | + True if this instance may change the configuration file | ||
| 99 | + """ | ||
| 100 | + return self._read_only | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,7 @@ | |||
| 5 | 5 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php | |
| 6 | 6 | ||
| 7 | 7 | import os | |
| 8 | + import sys | ||
| 8 | 9 | import re | |
| 9 | 10 | import gzip | |
| 10 | 11 | import StringIO | |
@@ -15,7 +16,7 @@ | |||
| 15 | 16 | from actor import Actor | |
| 16 | 17 | from refs import * | |
| 17 | 18 | from objects import * | |
| 18 | - | ||
| 19 | + from config import GitConfigParser | ||
| 19 | 20 | ||
| 20 | 21 | class Repo(object): | |
| 21 | 22 | """ | |
@@ -30,6 +31,10 @@ class Repo(object): | |||
| 30 | 31 | re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$') | |
| 31 | 32 | re_author_committer_start = re.compile(r'^(author|committer)') | |
| 32 | 33 | re_tab_full_line = re.compile(r'^\t(.*)$') | |
| 34 | + | ||
| 35 | + # invariants | ||
| 36 | + # represents the configuration level of a configuration file | ||
| 37 | + config_level = ("system", "global", "repository") | ||
| 33 | 38 | ||
| 34 | 39 | def __init__(self, path=None): | |
| 35 | 40 | """ | |
@@ -125,6 +130,52 @@ def tags(self): | |||
| 125 | 130 | """ | |
| 126 | 131 | return Tag.list_items(self) | |
| 127 | 132 | ||
| 133 | + def _get_config_path(self, config_level ): | ||
| 134 | + # we do not support an absolute path of the gitconfig on windows , | ||
| 135 | + # use the global config instead | ||
| 136 | + if sys.platform == "win32" and config_level == "system": | ||
| 137 | + config_level = "global" | ||
| 138 | + | ||
| 139 | + if config_level == "system": | ||
| 140 | + return "/etc/gitconfig" | ||
| 141 | + elif config_level == "global": | ||
| 142 | + return os.path.expanduser("~/.gitconfig") | ||
| 143 | + elif config_level == "repository": | ||
| 144 | + return "%s/config" % self.git.git_dir | ||
| 145 | + | ||
| 146 | + raise ValueError( "Invalid configuration level: %r" % config_level ) | ||
| 147 | + | ||
| 148 | + @property | ||
| 149 | + def config_reader(self): | ||
| 150 | + """ | ||
| 151 | + Returns | ||
| 152 | + GitConfigParser allowing to read the full git configuration, but not to write it | ||
| 153 | + | ||
| 154 | + The configuration will include values from the system, user and repository | ||
| 155 | + configuration files. | ||
| 156 | + | ||
| 157 | + NOTE: On windows, system configuration cannot currently be read as the path is | ||
| 158 | + unknown, instead the global path will be used. | ||
| 159 | + """ | ||
| 160 | + files = [ self._get_config_path(f) for f in self.config_level ] | ||
| 161 | + return GitConfigParser(files, read_only=True) | ||
| 162 | + | ||
| 163 | + def config_writer(self, config_level="repository"): | ||
| 164 | + """ | ||
| 165 | + Returns | ||
| 166 | + GitConfigParser allowing to write values of the specified configuration file level. | ||
| 167 | + Config writers should be retrieved, used to change the configuration ,and written | ||
| 168 | + right away as they will lock the configuration file in question and prevent other's | ||
| 169 | + to write it. | ||
| 170 | + | ||
| 171 | + ``config_level`` | ||
| 172 | + One of the following values | ||
| 173 | + system = sytem wide configuration file | ||
| 174 | + global = user level configuration file | ||
| 175 | + repository = configuration file for this repostory only | ||
| 176 | + """ | ||
| 177 | + return GitConfigParser(self._get_config_path(config_level), read_only = False) | ||
| 178 | + | ||
| 128 | 179 | def commit(self, rev=None): | |
| 129 | 180 | """ | |
| 130 | 181 | The Commit object for the specified revision | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,23 @@ | |||
| 1 | + [core] | ||
| 2 | + repositoryformatversion = 0 | ||
| 3 | + filemode = true | ||
| 4 | + bare = false | ||
| 5 | + logallrefupdates = true | ||
| 6 | + [remote "origin"] | ||
| 7 | + fetch = +refs/heads/*:refs/remotes/origin/* | ||
| 8 | + url = git://gitorious.org/~byron/git-python/byrons-clone.git | ||
| 9 | + pushurl = git@gitorious.org:~byron/git-python/byrons-clone.git | ||
| 10 | + [branch "master"] | ||
| 11 | + remote = origin | ||
| 12 | + merge = refs/heads/master | ||
| 13 | + [remote "mainline"] | ||
| 14 | + url = git://gitorious.org/git-python/mainline.git | ||
| 15 | + fetch = +refs/heads/*:refs/remotes/mainline/* | ||
| 16 | + [remote "MartinMarcher"] | ||
| 17 | + url = git://gitorious.org/~martin.marcher/git-python/serverhorror.git | ||
| 18 | + fetch = +refs/heads/*:refs/remotes/MartinMarcher/* | ||
| 19 | + [gui] | ||
| 20 | + geometry = 1316x820+219+243 207 192 | ||
| 21 | + [branch "mainline_performance"] | ||
| 22 | + remote = mainline | ||
| 23 | + merge = refs/heads/master | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,18 @@ | |||
| 1 | + # test_config.py | ||
| 2 | + # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | ||
| 3 | + # | ||
| 4 | + # This module is part of GitPython and is released under | ||
| 5 | + # the BSD License: http://www.opensource.org/licenses/bsd-license.php | ||
| 6 | + | ||
| 7 | + from test.testlib import * | ||
| 8 | + from git import * | ||
| 9 | + | ||
| 10 | + class TestBase(TestCase): | ||
| 11 | + | ||
| 12 | + @classmethod | ||
| 13 | + def setUpAll(cls): | ||
| 14 | + cls.repo = Repo(GIT_REPO) | ||
| 15 | + | ||
| 16 | + def test_base(self): | ||
| 17 | + path = fixture_path("git_config") | ||
| 18 | + self.fail("TODO: Base config writer testing") | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,9 +8,11 @@ | |||
| 8 | 8 | from test.testlib import * | |
| 9 | 9 | from git import * | |
| 10 | 10 | ||
| 11 | - class TestRepo(object): | ||
| 12 | - def setup(self): | ||
| 13 | - self.repo = Repo(GIT_REPO) | ||
| 11 | + class TestRepo(TestCase): | ||
| 12 | + | ||
| 13 | + @classmethod | ||
| 14 | + def setUpAll(cls): | ||
| 15 | + cls.repo = Repo(GIT_REPO) | ||
| 14 | 16 | ||
| 15 | 17 | @raises(InvalidGitRepositoryError) | |
| 16 | 18 | def test_new_should_raise_on_invalid_repo_location(self): | |
@@ -219,3 +221,13 @@ def test_untracked_files(self): | |||
| 219 | 221 | # END handle files | |
| 220 | 222 | ||
| 221 | 223 | assert len(self.repo.untracked_files) == (num_recently_untracked - len(files)) | |
| 224 | + | ||
| 225 | + def test_config_reader(self): | ||
| 226 | + reader = self.repo.config_reader | ||
| 227 | + assert reader.read_only | ||
| 228 | + | ||
| 229 | + def test_config_writer(self): | ||
| 230 | + for config_level in self.repo.config_level: | ||
| 231 | + writer = self.repo.config_writer(config_level) | ||
| 232 | + assert not writer.read_only | ||
| 233 | + # END for each config level | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments