summaryrefslogtreecommitdiff
path: root/lib/git/remote.py
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2009-10-19 21:32:34 +0200
committerSebastian Thiel <byronimo@gmail.com>2009-10-19 21:32:34 +0200
commit985093bae160419782b3d3cb9151e2e58625fd52 (patch)
tree2f19b97289d9d0af2eeea894dcc1f51e627261cf /lib/git/remote.py
parent8f42db54c6b2cfbd7d68e6d34ac2ed70578402f7 (diff)
parent53d26977f1aff8289f13c02ee672349d78eeb2f0 (diff)
downloadgitpython-985093bae160419782b3d3cb9151e2e58625fd52.tar.gz
Merge branch 'remotes' into improvements
* remotes: remote: added tests for creation and removal, finishing the remote interface remote: base tests succeed now config: fixed serious issues that would cause it to see initial tabs as continuation lines - this leads to very incorrect results when parsing git config files. Now the complete reading is overridden to make it work as there was no other way Added configuration access including tests to remote Added remote module and test cases - about to implement remote option handling added initial frame for remote handling- remotes are somewhat related to either parsing the command output or to reading the repo configuration which would be faster
Diffstat (limited to 'lib/git/remote.py')
-rw-r--r--lib/git/remote.py225
1 files changed, 225 insertions, 0 deletions
diff --git a/lib/git/remote.py b/lib/git/remote.py
new file mode 100644
index 00000000..24efd900
--- /dev/null
+++ b/lib/git/remote.py
@@ -0,0 +1,225 @@
+# remote.py
+# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
+#
+# This module is part of GitPython and is released under
+# the BSD License: http://www.opensource.org/licenses/bsd-license.php
+"""
+Module implementing a remote object allowing easy access to git remotes
+"""
+
+from git.utils import LazyMixin, Iterable
+from refs import RemoteRef
+
+class _SectionConstraint(object):
+ """
+ Constrains a ConfigParser to only option commands which are constrained to
+ always use the section we have been initialized with.
+
+ It supports all ConfigParser methods that operate on an option
+ """
+ __slots__ = ("_config", "_section_name")
+ _valid_attrs_ = ("get", "set", "getint", "getfloat", "getboolean", "has_option")
+
+ def __init__(self, config, section):
+ self._config = config
+ self._section_name = section
+
+ def __getattr__(self, attr):
+ if attr in self._valid_attrs_:
+ return lambda *args: self._call_config(attr, *args)
+ return super(_SectionConstraint,self).__getattribute__(attr)
+
+ def _call_config(self, method, *args):
+ """Call the configuration at the given method which must take a section name
+ as first argument"""
+ return getattr(self._config, method)(self._section_name, *args)
+
+
+class Remote(LazyMixin, Iterable):
+ """
+ Provides easy read and write access to a git remote.
+
+ Everything not part of this interface is considered an option for the current
+ remote, allowing constructs like remote.pushurl to query the pushurl.
+
+ NOTE: When querying configuration, the configuration accessor will be cached
+ to speed up subsequent accesses.
+ """
+
+ __slots__ = ( "repo", "name", "_config_reader" )
+
+ def __init__(self, repo, name):
+ """
+ Initialize a remote instance
+
+ ``repo``
+ The repository we are a remote of
+
+ ``name``
+ the name of the remote, i.e. 'origin'
+ """
+ self.repo = repo
+ self.name = name
+
+ def __getattr__(self, attr):
+ """
+ Allows to call this instance like
+ remote.special( *args, **kwargs) to call git-remote special self.name
+ """
+ if attr == "_config_reader":
+ return super(Remote, self).__getattr__(attr)
+
+ return self._config_reader.get(attr)
+
+ def _config_section_name(self):
+ return 'remote "%s"' % self.name
+
+ def _set_cache_(self, attr):
+ if attr == "_config_reader":
+ self._config_reader = _SectionConstraint(self.repo.config_reader, self._config_section_name())
+ else:
+ super(Remote, self)._set_cache_(attr)
+
+
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return '<git.%s "%s">' % (self.__class__.__name__, self.name)
+
+ def __eq__(self, other):
+ return self.name == other.name
+
+ def __ne__(self, other):
+ return not ( self == other )
+
+ def __hash__(self):
+ return hash(self.name)
+
+ @classmethod
+ def iter_items(cls, repo):
+ """
+ Returns
+ Iterator yielding Remote objects of the given repository
+ """
+ # parse them using refs, as their query can be faster as it is
+ # purely based on the file system
+ seen_remotes = set()
+ for ref in RemoteRef.iter_items(repo):
+ remote_name = ref.remote_name
+ if remote_name in seen_remotes:
+ continue
+ # END if remote done already
+ seen_remotes.add(remote_name)
+ yield Remote(repo, remote_name)
+ # END for each ref
+
+ @property
+ def refs(self):
+ """
+ Returns
+ List of RemoteRef objects
+ """
+ out_refs = list()
+ for ref in RemoteRef.list_items(self.repo):
+ if ref.remote_name == self.name:
+ out_refs.append(ref)
+ # END if names match
+ # END for each ref
+ assert out_refs, "Remote %s did not have any references" % self.name
+ return out_refs
+
+ @classmethod
+ def create(cls, repo, name, url, **kwargs):
+ """
+ Create a new remote to the given repository
+ ``repo``
+ Repository instance that is to receive the new remote
+
+ ``name``
+ Desired name of the remote
+
+ ``url``
+ URL which corresponds to the remote's name
+
+ ``**kwargs``
+ Additional arguments to be passed to the git-remote add command
+
+ Returns
+ New Remote instance
+
+ Raise
+ GitCommandError in case an origin with that name already exists
+ """
+ repo.git.remote( "add", name, url, **kwargs )
+ return cls(repo, name)
+
+ # add is an alias
+ add = create
+
+ @classmethod
+ def remove(cls, repo, name ):
+ """
+ Remove the remote with the given name
+ """
+ repo.git.remote("rm", name)
+
+ # alias
+ rm = remove
+
+ def rename(self, new_name):
+ """
+ Rename self to the given new_name
+
+ Returns
+ self
+ """
+ if self.name == new_name:
+ return self
+
+ self.repo.git.remote("rename", self.name, new_name)
+ self.name = new_name
+ del(self._config_reader) # it contains cached values, section names are different now
+ return self
+
+ def update(self, **kwargs):
+ """
+ Fetch all changes for this remote, including new branches
+
+ ``kwargs``
+ Additional arguments passed to git-remote update
+
+ Returns
+ self
+ """
+ self.repo.git.remote("update", self.name)
+ return self
+
+ @property
+ def config_reader(self):
+ """
+ Returns
+ GitConfigParser compatible object able to read options for only our remote.
+ Hence you may simple type config.get("pushurl") to obtain the information
+ """
+ return self._config_reader
+
+ @property
+ def config_writer(self):
+ """
+ Return
+ GitConfigParser compatible object able to write options for this remote.
+
+ Note
+ You can only own one writer at a time - delete it to release the
+ configuration file and make it useable by others.
+
+ To assure consistent results, you should only query options through the
+ writer. Once you are done writing, you are free to use the config reader
+ once again.
+ """
+ writer = self.repo.config_writer()
+
+ # clear our cache to assure we re-read the possibly changed configuration
+ del(self._config_reader)
+ return _SectionConstraint(writer, self._config_section_name())