Patchwork [1,of,2,v3] ui: add a configbytes method, for space configuration

login
register
mail settings
Submitter Bryan O'Sullivan
Date April 18, 2013, 11:18 p.m.
Message ID <9e8a9d8500cfcd07c0b3.1366327099@australite.local>
Download mbox | patch
Permalink /patch/1449/
State Accepted
Commit 2c4cd1c42365b9dda6a1115ec60f713991d992c3
Headers show

Comments

Bryan O'Sullivan - April 18, 2013, 11:18 p.m.
# HG changeset patch
# User Bryan O'Sullivan <bryano@fb.com>
# Date 1366315108 25200
#      Thu Apr 18 12:58:28 2013 -0700
# Node ID 9e8a9d8500cfcd07c0b3e0bd942cfebb7b0210bd
# Parent  63a783d1ac852d60e60669b2f8551a9b26de2947
ui: add a configbytes method, for space configuration

This accepts a floating point number, followed by optional whitespace,
followed by an optional one- or two-letter unit specifier (for
bytes, kilobytes, megabytes, or gigabytes).
Mads Kiilerich - April 19, 2013, 4:56 p.m.
On 04/19/2013 01:18 AM, Bryan O'Sullivan wrote:
> # HG changeset patch
> # User Bryan O'Sullivan <bryano@fb.com>
> # Date 1366315108 25200
> #      Thu Apr 18 12:58:28 2013 -0700
> # Node ID 9e8a9d8500cfcd07c0b3e0bd942cfebb7b0210bd
> # Parent  63a783d1ac852d60e60669b2f8551a9b26de2947
> ui: add a configbytes method, for space configuration
>
> This accepts a floating point number, followed by optional whitespace,
> followed by an optional one- or two-letter unit specifier (for
> bytes, kilobytes, megabytes, or gigabytes).
>
> diff --git a/mercurial/ui.py b/mercurial/ui.py
> --- a/mercurial/ui.py
> +++ b/mercurial/ui.py
> @@ -6,7 +6,7 @@
>   # 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, re, socket, sys, tempfile, traceback
>   import config, scmutil, util, error, formatter
>   
>   class ui(object):
> @@ -262,6 +262,45 @@ class ui(object):
>               raise error.ConfigError(_("%s.%s is not an integer ('%s')")
>                                       % (section, name, v))
>   
> +    def configbytes(self, section, name, default=0, untrusted=False):
> +        """parse a configuration element as a quantity in bytes
> +
> +        Units can be specified as b (bytes), k or kb (kilobytes), m or
> +        mb (megabytes), g or gb (gigabytes).
> +
> +        >>> u = ui(); s = 'foo'
> +        >>> u.setconfig(s, 'val1', '42')
> +        >>> u.configbytes(s, 'val1')
> +        42
> +        >>> u.setconfig(s, 'val2', '42.5 kb')
> +        >>> u.configbytes(s, 'val2')
> +        43520
> +        >>> u.configbytes(s, 'unknown', '7 MB')
> +        7340032
> +        >>> u.setconfig(s, 'invalid', 'somevalue')
> +        >>> u.configbytes(s, 'invalid')
> +        Traceback (most recent call last):
> +            ...
> +        ConfigError: foo.invalid is not a byte quantity ('somevalue')
> +        """
> +
> +        orig = string = self.config(section, name)
> +        if orig is None:
> +            if not isinstance(default, str):
> +                return default
> +            orig = string = default
> +        multiple = 1
> +        m = re.match(r'([^kmbg]+?)\s*([kmg]?)b?$', string, re.I)
> +        if m:
> +            string, key = m.groups()
> +            key = key.lower()
> +            multiple = dict(k=1024, m=1048576, g=1073741824).get(key, 1)
> +        try:
> +            return int(float(string) * multiple)
> +        except ValueError:
> +            raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
> +                                    % (section, name, orig))

This seems so be a re-implementation of what we already have in 
fileset.py . I suggest making a common util function.

largefiles could also use it for 'minsize' (in a backward compatible way).

Do we have other places where we specify sizes?

/Mads
Bryan O'Sullivan - April 19, 2013, 5:51 p.m.
On Fri, Apr 19, 2013 at 9:56 AM, Mads Kiilerich <mads@kiilerich.com> wrote:

> This seems so be a re-implementation of what we already have in fileset.py
> . I suggest making a common util function.
>

You're right, I didn't know that code existed in fileset. Nicely spotted.

Patch

diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -6,7 +6,7 @@ 
 # 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, re, socket, sys, tempfile, traceback
 import config, scmutil, util, error, formatter
 
 class ui(object):
@@ -262,6 +262,45 @@  class ui(object):
             raise error.ConfigError(_("%s.%s is not an integer ('%s')")
                                     % (section, name, v))
 
+    def configbytes(self, section, name, default=0, untrusted=False):
+        """parse a configuration element as a quantity in bytes
+
+        Units can be specified as b (bytes), k or kb (kilobytes), m or
+        mb (megabytes), g or gb (gigabytes).
+
+        >>> u = ui(); s = 'foo'
+        >>> u.setconfig(s, 'val1', '42')
+        >>> u.configbytes(s, 'val1')
+        42
+        >>> u.setconfig(s, 'val2', '42.5 kb')
+        >>> u.configbytes(s, 'val2')
+        43520
+        >>> u.configbytes(s, 'unknown', '7 MB')
+        7340032
+        >>> u.setconfig(s, 'invalid', 'somevalue')
+        >>> u.configbytes(s, 'invalid')
+        Traceback (most recent call last):
+            ...
+        ConfigError: foo.invalid is not a byte quantity ('somevalue')
+        """
+
+        orig = string = self.config(section, name)
+        if orig is None:
+            if not isinstance(default, str):
+                return default
+            orig = string = default
+        multiple = 1
+        m = re.match(r'([^kmbg]+?)\s*([kmg]?)b?$', string, re.I)
+        if m:
+            string, key = m.groups()
+            key = key.lower()
+            multiple = dict(k=1024, m=1048576, g=1073741824).get(key, 1)
+        try:
+            return int(float(string) * multiple)
+        except ValueError:
+            raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
+                                    % (section, name, orig))
+
     def configlist(self, section, name, default=None, untrusted=False):
         """parse a configuration element as a list of comma/space separated
         strings