-
Notifications
You must be signed in to change notification settings - Fork 127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a class for interacting with git config #69
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -580,6 +580,67 @@ class AutomaticMergeFailed(Exception): | |
self.commit1, self.commit2 = commit1, commit2 | ||
|
||
|
||
class GitConfigError(Exception): | ||
def __init__(self, returncode, output): | ||
Exception.__init__( | ||
self, 'Git config failed with exit code %s: %s' % (returncode, output,) | ||
) | ||
|
||
|
||
def memo(obj): | ||
cache = {} | ||
@functools.wraps(obj) | ||
def wrap(*args, **kwds): | ||
if args not in cache: | ||
cache[args] = obj(*args, **kwds) | ||
return cache[args] | ||
return wrap | ||
|
||
|
||
@memo | ||
class GitConfigStore(object): | ||
def __init__(self, name, config_prefix='imerge'): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thing: depending on what effect |
||
self.config_prefix = config_prefix | ||
self.config = self._get_all_keys() | ||
|
||
def _get_all_keys(self): | ||
d = {} | ||
try: | ||
items_with_prefix = check_output( | ||
['git', 'config', '--get-regex', self.config_prefix] | ||
).rstrip().split('\n') | ||
for row in items_with_prefix: | ||
k, v = row.split() | ||
d[k[len(self.config_prefix + '.'):]] = v | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This storage scheme limits the |
||
return d | ||
except CalledProcessError: | ||
return {} | ||
|
||
def get(self, key): | ||
return self.config.get(key) | ||
|
||
def set(self, key, value): | ||
self.config[key] = value | ||
config_key = '.'.join([self.config_prefix, key]) | ||
try: | ||
check_call(['git', 'config', config_key, value]) | ||
except CalledProcessError as e: | ||
raise GitConfigError(e.returncode, e.output) | ||
|
||
def unset(self, key): | ||
if key in self.config: | ||
del self.config[key] | ||
config_key = '.'.join([self.config_prefix, key]) | ||
try: | ||
check_call(['git', 'config', '--unset', config_key]) | ||
except CalledProcessError as e: | ||
if e.returncode == 5: | ||
# Value was not set | ||
pass | ||
else: | ||
raise GitConfigError(e.returncode, e.output) | ||
|
||
|
||
def automerge(commit1, commit2, msg=None): | ||
"""Attempt an automatic merge of commit1 and commit2. | ||
|
||
|
@@ -1865,27 +1926,17 @@ class MergeState(Block): | |
"""Set the default merge to the specified one. | ||
|
||
name can be None to cause the default to be cleared.""" | ||
|
||
gcs = GitConfigStore(name) | ||
if name is None: | ||
try: | ||
check_call(['git', 'config', '--unset', 'imerge.default']) | ||
except CalledProcessError as e: | ||
if e.returncode == 5: | ||
# Value was not set | ||
pass | ||
else: | ||
raise | ||
gcs.unset("default") | ||
else: | ||
check_call(['git', 'config', 'imerge.default', name]) | ||
gcs.set("default", name) | ||
|
||
@staticmethod | ||
def get_default_name(): | ||
"""Get the name of the default merge, or None if none is currently set.""" | ||
|
||
try: | ||
return check_output(['git', 'config', 'imerge.default']).rstrip() | ||
except CalledProcessError: | ||
return None | ||
gcs = GitConfigStore(None) | ||
return gcs.get("default") | ||
|
||
@staticmethod | ||
def _check_no_merges(commits): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was confusing to me. Let me see if I understand correctly...
This level of memoization is so that if the code tries to create multiple instances of
GitConfigStore
with the samename
andconfig_prefix
arguments, that only one instance is actually created. Right?This is distinct from the caching that occurs within the
GitConfigStore
class itself, which is about reading all of the configuration values in a section of the config file and keeping this cache in sync as values are changed or removed.It seems a bit overengineered to me, especially the fact that
memo
effectively uses a global cache. Wouldn't it be more straightforward to store an instance ofGitConfigStore(name)
in theMergeState
instance? Or will future changes make it necessary to access the config for a givenname
from outside of that class?