Patchwork [1,of,7,path-configs] ui: create paths classes to hold path information

login
register
mail settings
Submitter Gregory Szorc
Date Feb. 8, 2015, 1:13 a.m.
Message ID <425462525dc5c44de575.1423358017@vm-ubuntu-main.gateway.sonic.net>
Download mbox | patch
Permalink /patch/7762/
State Changes Requested
Headers show

Comments

Gregory Szorc - Feb. 8, 2015, 1:13 a.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@gmail.com>
# Date 1423338328 28800
#      Sat Feb 07 11:45:28 2015 -0800
# Node ID 425462525dc5c44de575084d1516417286c43f51
# Parent  ff5caa8dfd993680d9602ca6ebb14da9de10d5f4
ui: create paths classes to hold path information

Upcoming patches will give paths more features and more flexibility.
We start the process like how we solve many problems in computer
science: by adding a layer of indirection. We introduce a "paths"
class that is a collection and interface to defined paths. We also
introduce the "path" class to hold information about single path
instances.
Sean Farley - Feb. 8, 2015, 9:26 p.m.
Gregory Szorc writes:

> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@gmail.com>
> # Date 1423338328 28800
> #      Sat Feb 07 11:45:28 2015 -0800
> # Node ID 425462525dc5c44de575084d1516417286c43f51
> # Parent  ff5caa8dfd993680d9602ca6ebb14da9de10d5f4
> ui: create paths classes to hold path information
>
> Upcoming patches will give paths more features and more flexibility.
> We start the process like how we solve many problems in computer
> science: by adding a layer of indirection. We introduce a "paths"
> class that is a collection and interface to defined paths. We also
> introduce the "path" class to hold information about single path
> instances.
>
> diff --git a/mercurial/ui.py b/mercurial/ui.py
> --- a/mercurial/ui.py
> +++ b/mercurial/ui.py
> @@ -5,9 +5,9 @@
>  # This software may be used and distributed according to the terms of the
>  # GNU General Public License version 2 or any later version.
>  
>  from i18n import _
> -import errno, getpass, os, socket, sys, tempfile, traceback
> +import errno, getpass, os, socket, sys, tempfile, traceback, weakref
>  import config, scmutil, util, error, formatter
>  from node import hex
>  
>  samplehgrcs = {
> @@ -85,8 +85,9 @@ class ui(object):
>          self._ucfg = config.config() # untrusted
>          self._trustusers = set()
>          self._trustgroups = set()
>          self.callhooks = True
> +        self.paths = paths(self)
>  
>          if src:
>              self.fout = src.fout
>              self.ferr = src.ferr
> @@ -530,12 +531,13 @@ class ui(object):
>          """Return repository location relative to cwd or from [paths]"""
>          if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
>              return loc
>  
> -        path = self.config('paths', loc)
> -        if not path and default is not None:
> -            path = self.config('paths', default)
> -        return path or loc
> +        p = self.paths.getpath(loc, default=default)
> +        if p:
> +            return p.url
> +        else:
> +            return loc

Minor nit: we usually write this as:

if p:
    return p.url
return loc

>      def pushbuffer(self, error=False):
>          """install a buffer to capture standard output of the ui object
>  
> @@ -922,4 +924,39 @@ class ui(object):
>          ui.write(s, 'label') is equivalent to
>          ui.write(ui.label(s, 'label')).
>          '''
>          return msg
> +
> +class paths(object):
> +    """Represents a collection of paths and their configs.
> +
> +    Data is derived from ui instances and the config files they have loaded.
> +    """
> +    def __init__(self, ui):
> +        self._uiref = weakref.ref(ui)
> +
> +    @property
> +    def ui(self):
> +        return self._uiref()
> +
> +    def getpath(self, name, default=None):
> +        """Return a ``path`` for the specified name.
> +
> +        Returns None if the specified path or the default path was not
> +        found.
> +        """
> +        p = self.ui.config('paths', name)
> +        if not p and default is not None:
> +            p = self.ui.config('paths', default)
> +
> +        if p:
> +            return path(name, url=p)
> +        else:
> +            return None

Same here.
Sean Farley - Feb. 8, 2015, 9:31 p.m.
Gregory Szorc writes:

> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@gmail.com>
> # Date 1423338328 28800
> #      Sat Feb 07 11:45:28 2015 -0800
> # Node ID 425462525dc5c44de575084d1516417286c43f51
> # Parent  ff5caa8dfd993680d9602ca6ebb14da9de10d5f4
> ui: create paths classes to hold path information
>
> Upcoming patches will give paths more features and more flexibility.
> We start the process like how we solve many problems in computer
> science: by adding a layer of indirection. We introduce a "paths"
> class that is a collection and interface to defined paths. We also
> introduce the "path" class to hold information about single path
> instances.
>
> diff --git a/mercurial/ui.py b/mercurial/ui.py
> --- a/mercurial/ui.py
> +++ b/mercurial/ui.py
> @@ -5,9 +5,9 @@
>  # This software may be used and distributed according to the terms of the
>  # GNU General Public License version 2 or any later version.
>  
>  from i18n import _
> -import errno, getpass, os, socket, sys, tempfile, traceback
> +import errno, getpass, os, socket, sys, tempfile, traceback, weakref
>  import config, scmutil, util, error, formatter
>  from node import hex
>  
>  samplehgrcs = {
> @@ -85,8 +85,9 @@ class ui(object):
>          self._ucfg = config.config() # untrusted
>          self._trustusers = set()
>          self._trustgroups = set()
>          self.callhooks = True
> +        self.paths = paths(self)
>  
>          if src:
>              self.fout = src.fout
>              self.ferr = src.ferr
> @@ -530,12 +531,13 @@ class ui(object):
>          """Return repository location relative to cwd or from [paths]"""
>          if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
>              return loc
>  
> -        path = self.config('paths', loc)
> -        if not path and default is not None:
> -            path = self.config('paths', default)
> -        return path or loc
> +        p = self.paths.getpath(loc, default=default)
> +        if p:
> +            return p.url
> +        else:
> +            return loc
>  
>      def pushbuffer(self, error=False):
>          """install a buffer to capture standard output of the ui object
>  
> @@ -922,4 +924,39 @@ class ui(object):
>          ui.write(s, 'label') is equivalent to
>          ui.write(ui.label(s, 'label')).
>          '''
>          return msg
> +
> +class paths(object):
> +    """Represents a collection of paths and their configs.
> +
> +    Data is derived from ui instances and the config files they have loaded.
> +    """
> +    def __init__(self, ui):
> +        self._uiref = weakref.ref(ui)

Are you sure weakref is the way to go here? When Ryan and I tried this
(on localrepo) we found that Mercurial uses object proxies which wreck
weakrefs (you still have a pointer to the original object, not the new
wrapper).

Currently, I see colorui, progressui, and blackboxui. Would this not
cause a problem for paths using the wrong ui object?
Augie Fackler - Feb. 9, 2015, 11:11 p.m.
On Sat, Feb 07, 2015 at 05:13:37PM -0800, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@gmail.com>
> # Date 1423338328 28800
> #      Sat Feb 07 11:45:28 2015 -0800
> # Node ID 425462525dc5c44de575084d1516417286c43f51
> # Parent  ff5caa8dfd993680d9602ca6ebb14da9de10d5f4
> ui: create paths classes to hold path information
>
> Upcoming patches will give paths more features and more flexibility.
> We start the process like how we solve many problems in computer
> science: by adding a layer of indirection. We introduce a "paths"
> class that is a collection and interface to defined paths. We also
> introduce the "path" class to hold information about single path
> instances.
>
> diff --git a/mercurial/ui.py b/mercurial/ui.py
> --- a/mercurial/ui.py
> +++ b/mercurial/ui.py
> @@ -5,9 +5,9 @@
>  # This software may be used and distributed according to the terms of the
>  # GNU General Public License version 2 or any later version.
>
>  from i18n import _
> -import errno, getpass, os, socket, sys, tempfile, traceback
> +import errno, getpass, os, socket, sys, tempfile, traceback, weakref
>  import config, scmutil, util, error, formatter
>  from node import hex
>
>  samplehgrcs = {
> @@ -85,8 +85,9 @@ class ui(object):
>          self._ucfg = config.config() # untrusted
>          self._trustusers = set()
>          self._trustgroups = set()
>          self.callhooks = True
> +        self.paths = paths(self)
>
>          if src:
>              self.fout = src.fout
>              self.ferr = src.ferr
> @@ -530,12 +531,13 @@ class ui(object):
>          """Return repository location relative to cwd or from [paths]"""
>          if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
>              return loc
>
> -        path = self.config('paths', loc)
> -        if not path and default is not None:
> -            path = self.config('paths', default)
> -        return path or loc
> +        p = self.paths.getpath(loc, default=default)
> +        if p:
> +            return p.url
> +        else:
> +            return loc
>
>      def pushbuffer(self, error=False):
>          """install a buffer to capture standard output of the ui object
>
> @@ -922,4 +924,39 @@ class ui(object):
>          ui.write(s, 'label') is equivalent to
>          ui.write(ui.label(s, 'label')).
>          '''
>          return msg
> +
> +class paths(object):
> +    """Represents a collection of paths and their configs.
> +
> +    Data is derived from ui instances and the config files they have loaded.
> +    """
> +    def __init__(self, ui):
> +        self._uiref = weakref.ref(ui)
> +
> +    @property
> +    def ui(self):
> +        return self._uiref()
> +
> +    def getpath(self, name, default=None):
> +        """Return a ``path`` for the specified name.
> +
> +        Returns None if the specified path or the default path was not
> +        found.
> +        """
> +        p = self.ui.config('paths', name)
> +        if not p and default is not None:
> +            p = self.ui.config('paths', default)
> +
> +        if p:
> +            return path(name, url=p)
> +        else:
> +            return None
> +
> +class path(object):
> +    """Represents an individual path and its configuration."""
> +
> +    def __init__(self, name, url=None):
> +        """Construct a path from its config options."""
> +        self.name = name
> +        self.url = url

Is it ever sensible to have a path with no url?

> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
Gregory Szorc - Feb. 9, 2015, 11:15 p.m.
On Mon, Feb 9, 2015 at 3:11 PM, Augie Fackler <raf@durin42.com> wrote:

> On Sat, Feb 07, 2015 at 05:13:37PM -0800, Gregory Szorc wrote:
> > # HG changeset patch
> > # User Gregory Szorc <gregory.szorc@gmail.com>
> > # Date 1423338328 28800
> > #      Sat Feb 07 11:45:28 2015 -0800
> > # Node ID 425462525dc5c44de575084d1516417286c43f51
> > # Parent  ff5caa8dfd993680d9602ca6ebb14da9de10d5f4
> > ui: create paths classes to hold path information
> >
> > Upcoming patches will give paths more features and more flexibility.
> > We start the process like how we solve many problems in computer
> > science: by adding a layer of indirection. We introduce a "paths"
> > class that is a collection and interface to defined paths. We also
> > introduce the "path" class to hold information about single path
> > instances.
> >
> > diff --git a/mercurial/ui.py b/mercurial/ui.py
> > --- a/mercurial/ui.py
> > +++ b/mercurial/ui.py
> > @@ -5,9 +5,9 @@
> >  # This software may be used and distributed according to the terms of
> the
> >  # GNU General Public License version 2 or any later version.
> >
> >  from i18n import _
> > -import errno, getpass, os, socket, sys, tempfile, traceback
> > +import errno, getpass, os, socket, sys, tempfile, traceback, weakref
> >  import config, scmutil, util, error, formatter
> >  from node import hex
> >
> >  samplehgrcs = {
> > @@ -85,8 +85,9 @@ class ui(object):
> >          self._ucfg = config.config() # untrusted
> >          self._trustusers = set()
> >          self._trustgroups = set()
> >          self.callhooks = True
> > +        self.paths = paths(self)
> >
> >          if src:
> >              self.fout = src.fout
> >              self.ferr = src.ferr
> > @@ -530,12 +531,13 @@ class ui(object):
> >          """Return repository location relative to cwd or from [paths]"""
> >          if util.hasscheme(loc) or os.path.isdir(os.path.join(loc,
> '.hg')):
> >              return loc
> >
> > -        path = self.config('paths', loc)
> > -        if not path and default is not None:
> > -            path = self.config('paths', default)
> > -        return path or loc
> > +        p = self.paths.getpath(loc, default=default)
> > +        if p:
> > +            return p.url
> > +        else:
> > +            return loc
> >
> >      def pushbuffer(self, error=False):
> >          """install a buffer to capture standard output of the ui object
> >
> > @@ -922,4 +924,39 @@ class ui(object):
> >          ui.write(s, 'label') is equivalent to
> >          ui.write(ui.label(s, 'label')).
> >          '''
> >          return msg
> > +
> > +class paths(object):
> > +    """Represents a collection of paths and their configs.
> > +
> > +    Data is derived from ui instances and the config files they have
> loaded.
> > +    """
> > +    def __init__(self, ui):
> > +        self._uiref = weakref.ref(ui)
> > +
> > +    @property
> > +    def ui(self):
> > +        return self._uiref()
> > +
> > +    def getpath(self, name, default=None):
> > +        """Return a ``path`` for the specified name.
> > +
> > +        Returns None if the specified path or the default path was not
> > +        found.
> > +        """
> > +        p = self.ui.config('paths', name)
> > +        if not p and default is not None:
> > +            p = self.ui.config('paths', default)
> > +
> > +        if p:
> > +            return path(name, url=p)
> > +        else:
> > +            return None
> > +
> > +class path(object):
> > +    """Represents an individual path and its configuration."""
> > +
> > +    def __init__(self, name, url=None):
> > +        """Construct a path from its config options."""
> > +        self.name = name
> > +        self.url = url
>
> Is it ever sensible to have a path with no url?
>

No. In future iterations of this series, paths with empty URLs are
filtered.
Gregory Szorc - Feb. 9, 2015, 11:37 p.m.
The latest version of this series is available at
http://hg.gregoryszorc.com/hg/rev/paths.

It is 20 patches and I've been instructed not to patchbomb the list. So
pull away.

On Sat, Feb 7, 2015 at 5:13 PM, Gregory Szorc <gregory.szorc@gmail.com>
wrote:

> # HG changeset patch
> # User Gregory Szorc <gregory.szorc@gmail.com>
> # Date 1423338328 28800
> #      Sat Feb 07 11:45:28 2015 -0800
> # Node ID 425462525dc5c44de575084d1516417286c43f51
> # Parent  ff5caa8dfd993680d9602ca6ebb14da9de10d5f4
> ui: create paths classes to hold path information
>
> Upcoming patches will give paths more features and more flexibility.
> We start the process like how we solve many problems in computer
> science: by adding a layer of indirection. We introduce a "paths"
> class that is a collection and interface to defined paths. We also
> introduce the "path" class to hold information about single path
> instances.
>
> diff --git a/mercurial/ui.py b/mercurial/ui.py
> --- a/mercurial/ui.py
> +++ b/mercurial/ui.py
> @@ -5,9 +5,9 @@
>  # This software may be used and distributed according to the terms of the
>  # GNU General Public License version 2 or any later version.
>
>  from i18n import _
> -import errno, getpass, os, socket, sys, tempfile, traceback
> +import errno, getpass, os, socket, sys, tempfile, traceback, weakref
>  import config, scmutil, util, error, formatter
>  from node import hex
>
>  samplehgrcs = {
> @@ -85,8 +85,9 @@ class ui(object):
>          self._ucfg = config.config() # untrusted
>          self._trustusers = set()
>          self._trustgroups = set()
>          self.callhooks = True
> +        self.paths = paths(self)
>
>          if src:
>              self.fout = src.fout
>              self.ferr = src.ferr
> @@ -530,12 +531,13 @@ class ui(object):
>          """Return repository location relative to cwd or from [paths]"""
>          if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
>              return loc
>
> -        path = self.config('paths', loc)
> -        if not path and default is not None:
> -            path = self.config('paths', default)
> -        return path or loc
> +        p = self.paths.getpath(loc, default=default)
> +        if p:
> +            return p.url
> +        else:
> +            return loc
>
>      def pushbuffer(self, error=False):
>          """install a buffer to capture standard output of the ui object
>
> @@ -922,4 +924,39 @@ class ui(object):
>          ui.write(s, 'label') is equivalent to
>          ui.write(ui.label(s, 'label')).
>          '''
>          return msg
> +
> +class paths(object):
> +    """Represents a collection of paths and their configs.
> +
> +    Data is derived from ui instances and the config files they have
> loaded.
> +    """
> +    def __init__(self, ui):
> +        self._uiref = weakref.ref(ui)
> +
> +    @property
> +    def ui(self):
> +        return self._uiref()
> +
> +    def getpath(self, name, default=None):
> +        """Return a ``path`` for the specified name.
> +
> +        Returns None if the specified path or the default path was not
> +        found.
> +        """
> +        p = self.ui.config('paths', name)
> +        if not p and default is not None:
> +            p = self.ui.config('paths', default)
> +
> +        if p:
> +            return path(name, url=p)
> +        else:
> +            return None
> +
> +class path(object):
> +    """Represents an individual path and its configuration."""
> +
> +    def __init__(self, name, url=None):
> +        """Construct a path from its config options."""
> +        self.name = name
> +        self.url = url
>

Patch

diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -5,9 +5,9 @@ 
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
 from i18n import _
-import errno, getpass, os, socket, sys, tempfile, traceback
+import errno, getpass, os, socket, sys, tempfile, traceback, weakref
 import config, scmutil, util, error, formatter
 from node import hex
 
 samplehgrcs = {
@@ -85,8 +85,9 @@  class ui(object):
         self._ucfg = config.config() # untrusted
         self._trustusers = set()
         self._trustgroups = set()
         self.callhooks = True
+        self.paths = paths(self)
 
         if src:
             self.fout = src.fout
             self.ferr = src.ferr
@@ -530,12 +531,13 @@  class ui(object):
         """Return repository location relative to cwd or from [paths]"""
         if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
             return loc
 
-        path = self.config('paths', loc)
-        if not path and default is not None:
-            path = self.config('paths', default)
-        return path or loc
+        p = self.paths.getpath(loc, default=default)
+        if p:
+            return p.url
+        else:
+            return loc
 
     def pushbuffer(self, error=False):
         """install a buffer to capture standard output of the ui object
 
@@ -922,4 +924,39 @@  class ui(object):
         ui.write(s, 'label') is equivalent to
         ui.write(ui.label(s, 'label')).
         '''
         return msg
+
+class paths(object):
+    """Represents a collection of paths and their configs.
+
+    Data is derived from ui instances and the config files they have loaded.
+    """
+    def __init__(self, ui):
+        self._uiref = weakref.ref(ui)
+
+    @property
+    def ui(self):
+        return self._uiref()
+
+    def getpath(self, name, default=None):
+        """Return a ``path`` for the specified name.
+
+        Returns None if the specified path or the default path was not
+        found.
+        """
+        p = self.ui.config('paths', name)
+        if not p and default is not None:
+            p = self.ui.config('paths', default)
+
+        if p:
+            return path(name, url=p)
+        else:
+            return None
+
+class path(object):
+    """Represents an individual path and its configuration."""
+
+    def __init__(self, name, url=None):
+        """Construct a path from its config options."""
+        self.name = name
+        self.url = url