D332: repository: formalize peer interface with abstract base class
This revision was automatically updated to reflect the committed changes. Closed by commit rHGf257943e47ab: repository: formalize peer interface with abstract base class (authored by indygreg). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D332?vs=847=931 REVISION DETAIL https://phab.mercurial-scm.org/D332 AFFECTED FILES mercurial/repository.py CHANGE DETAILS diff --git a/mercurial/repository.py b/mercurial/repository.py new file mode 100644 --- /dev/null +++ b/mercurial/repository.py @@ -0,0 +1,71 @@ +# repository.py - Interfaces and base classes for repositories and peers. +# +# Copyright 2017 Gregory Szorc+# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from __future__ import absolute_import + +import abc + +class _basepeer(object): +"""Represents a "connection" to a repository. + +This is the base interface for representing a connection to a repository. +It holds basic properties and methods applicable to all peer types. + +This is not a complete interface definition and should not be used +outside of this module. +""" +__metaclass__ = abc.ABCMeta + +@abc.abstractproperty +def ui(self): +"""ui.ui instance.""" + +@abc.abstractmethod +def url(self): +"""Returns a URL string representing this peer. + +Currently, implementations expose the raw URL used to construct the +instance. It may contain credentials as part of the URL. The +expectations of the value aren't well-defined and this could lead to +data leakage. + +TODO audit/clean consumers and more clearly define the contents of this +value. +""" + +@abc.abstractmethod +def local(self): +"""Returns a local repository instance. + +If the peer represents a local repository, returns an object that +can be used to interface with it. Otherwise returns ``None``. +""" + +@abc.abstractmethod +def peer(self): +"""Returns an object conforming to this interface. + +Most implementations will ``return self``. +""" + +@abc.abstractmethod +def canpush(self): +"""Returns a boolean indicating if this peer can be pushed to.""" + +@abc.abstractmethod +def close(self): +"""Close the connection to this peer. + +This is called when the peer will no longer be used. Resources +associated with the peer should be cleaned up. +""" + +class peer(_basepeer): +"""Unified interface and base class for peer repositories. + +All peer instances must inherit from this class. +""" To: indygreg, #hg-reviewers Cc: durin42, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D332: repository: formalize peer interface with abstract base class
indygreg updated this revision to Diff 847. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D332?vs=757=847 REVISION DETAIL https://phab.mercurial-scm.org/D332 AFFECTED FILES mercurial/repository.py CHANGE DETAILS diff --git a/mercurial/repository.py b/mercurial/repository.py new file mode 100644 --- /dev/null +++ b/mercurial/repository.py @@ -0,0 +1,71 @@ +# repository.py - Interfaces and base classes for repositories and peers. +# +# Copyright 2017 Gregory Szorc+# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from __future__ import absolute_import + +import abc + +class _basepeer(object): +"""Represents a "connection" to a repository. + +This is the base interface for representing a connection to a repository. +It holds basic properties and methods applicable to all peer types. + +This is not a complete interface definition and should not be used +outside of this module. +""" +__metaclass__ = abc.ABCMeta + +@abc.abstractproperty +def ui(self): +"""ui.ui instance.""" + +@abc.abstractmethod +def url(self): +"""Returns a URL string representing this peer. + +Currently, implementations expose the raw URL used to construct the +instance. It may contain credentials as part of the URL. The +expectations of the value aren't well-defined and this could lead to +data leakage. + +TODO audit/clean consumers and more clearly define the contents of this +value. +""" + +@abc.abstractmethod +def local(self): +"""Returns a local repository instance. + +If the peer represents a local repository, returns an object that +can be used to interface with it. Otherwise returns ``None``. +""" + +@abc.abstractmethod +def peer(self): +"""Returns an object conforming to this interface. + +Most implementations will ``return self``. +""" + +@abc.abstractmethod +def canpush(self): +"""Returns a boolean indicating if this peer can be pushed to.""" + +@abc.abstractmethod +def close(self): +"""Close the connection to this peer. + +This is called when the peer will no longer be used. Resources +associated with the peer should be cleaned up. +""" + +class peer(_basepeer): +"""Unified interface and base class for peer repositories. + +All peer instances must inherit from this class. +""" To: indygreg, #hg-reviewers Cc: durin42, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D332: repository: formalize peer interface with abstract base class
indygreg added inline comments. INLINE COMMENTS > durin42 wrote in repository.py:29 > Nit: shouldn't this typically be a connection string with any credentials > potentially redacted? I looked at the code and today we're exposing the raw URL, before any redaction. This raw URL is then fed into things like hooks. We should probably fix this by cleaning up existing usage and making the purpose of the attribute more well-defined. But I think it is outside the scope of this series. I'll add an inline TODO to track it. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D332 To: indygreg, #hg-reviewers Cc: durin42, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D332: repository: formalize peer interface with abstract base class
indygreg added inline comments. INLINE COMMENTS > durin42 wrote in repository.py:43 > In what cases would a _basepeer not be a peer? What value does this part of > the interface provide? TBH, I'm not sure why this exists. I cargo culted it from the existing peer API. Once this series is accepted, I'd like to make some BC changes to the interface. This method is on the chopping block. Another is `close()`. AFAICT we don't call `close()` consistently and I'd like to switch things to context managers. But that's for another day... REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D332 To: indygreg, #hg-reviewers Cc: durin42, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D332: repository: formalize peer interface with abstract base class
durin42 added inline comments. INLINE COMMENTS > repository.py:29 > +def url(self): > +"""Returns a string representing this peer.""" > + Nit: shouldn't this typically be a connection string with any credentials potentially redacted? > repository.py:43 > + > +Most implementations will ``return self``. > +""" In what cases would a _basepeer not be a peer? What value does this part of the interface provide? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D332 To: indygreg, #hg-reviewers Cc: durin42, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D332: repository: formalize peer interface with abstract base class
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY There are various interfaces for interacting with repositories and peers. They form a contract for how one should interact with a repo or peer object. The contracts today aren't very well-defined or enforced. There have been several bugs over the years where peers or repo types have forgotten to implement certain methods. In addition, the inheritance of some classes is wonky. For example, localrepository doesn't inherit from an interface and the god-object nature of that class means the repository interface isn't well-defined. Other repository types inherit from localrepository then stub out methods that don't make sense (e.g. statichttprepository re-defining locking methods to fail fast). Not having well-defined interfaces makes implementing alternate storage backends, wire protocol transports, and repository types difficult because it isn't clear what exactly needs to be implemented. This patch starts the process of attempting to establish more order to the type system around repositories and peers. Our first patch starts with a problem space that already has a partial solution: peers. The peer.peerrepository class already somewhat defines a peer interface. But it is missing a few things and the total interface isn't well-defined because it is combined with wireproto.wirepeer. Our newly-established basepeer class uses the abc module to declare an abstract base class with the properties and methods that a generic peer must implement. We create a new class that inherits from it. This class will hold our other future abstract base classes / interfaces so we can expose a unified base class/interface. We don't yet use the new interface because subsequent additions will break existing code without some refactoring first. A new module (repository.py) was created to hold the interfaces. I could have put things in peer.py. However, I have plans to eventually add interfaces to define repository and storage types. These almost certainly require a new module. And I figured having all the interfaces live in one module makes sense. So I created repository.py to be that future home. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D332 AFFECTED FILES mercurial/repository.py CHANGE DETAILS diff --git a/mercurial/repository.py b/mercurial/repository.py new file mode 100644 --- /dev/null +++ b/mercurial/repository.py @@ -0,0 +1,62 @@ +# repository.py - Interfaces and base classes for repositories and peers. +# +# Copyright 2017 Gregory Szorc+# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from __future__ import absolute_import + +import abc + +class _basepeer(object): +"""Represents a "connection" to a repository. + +This is the base interface for representing a connection to a repository. +It holds basic properties and methods applicable to all peer types. + +This is not a complete interface definition and should not be used +outside of this module. +""" +__metaclass__ = abc.ABCMeta + +@abc.abstractproperty +def ui(self): +"""ui.ui instance.""" + +@abc.abstractmethod +def url(self): +"""Returns a string representing this peer.""" + +@abc.abstractmethod +def local(self): +"""Returns a local repository instance. + +If the peer represents a local repository, returns an object that +can be used to interface with it. Otherwise returns ``None``. +""" + +@abc.abstractmethod +def peer(self): +"""Returns an object conforming to this interface. + +Most implementations will ``return self``. +""" + +@abc.abstractmethod +def canpush(self): +"""Returns a boolean indicating if this peer can be pushed to.""" + +@abc.abstractmethod +def close(self): +"""Close the connection to this peer. + +This is called when the peer will no longer be used. Resources +associated with the peer should be cleaned up. +""" + +class peer(_basepeer): +"""Unified interface and base class for peer repositories. + +All peer instances must inherit from this class. +""" To: indygreg, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel