[PATCH 0 of 1 V2] checking for portable filenames

Adrian Buehlmann adrian at cadifra.com
Tue Apr 19 03:09:03 CDT 2011


On 2011-04-19 04:21, Matt Mackall wrote:
> By the way, people interested in the layering issues should look at
> this:
> 
> http://www.selenic.com/blog/?p=626

Since you bring this up here, I'd like to respond again onto your original
decision, which deemed my original patch a layering violation.

I am obeying that decision since you are the architect in charge of
mercurial, but I still think it would be ok to have functions in util that
call things on ui objects (which you rejected as a layering violation).

I'm referring to your message

On 2011-04-16 17:49, Matt Mackall wrote:
> On Sat, 2011-04-16 at 14:35 +0200, Adrian Buehlmann wrote:
> 
>> diff --git a/mercurial/util.py b/mercurial/util.py
>> --- a/mercurial/util.py
>> +++ b/mercurial/util.py
>> @@ -544,6 +544,23 @@
>>              return _("filename ends with '%s', which is not allowed "
>>                       "on Windows") % t
>>  
>> +def checkportable(ui, f):
> 
> I'm afraid that's a definite layering violation. We'll have to think of
> somewhere to put a helper function.

I don't want to lecture you on design, but let me just point out that I
haven't added any new import in the util module on my original change for
util, which was:

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -544,6 +544,23 @@
             return _("filename ends with '%s', which is not allowed "
                      "on Windows") % t
 
+def checkportable(ui, f):
+    '''Check if filename f is portable and warn or abort depending on config'''
+    checkfilename(f)
+    val = ui.config('ui', 'portablefilenames', 'warn')
+    lval = val.lower()
+    abort = os.name == 'nt' or lval == 'abort'
+    bval = parsebool(val)
+    if abort or lval == 'warn' or bval:
+        msg = checkwinfilename(f)
+        if msg:
+            if abort:
+                raise Abort("%s: %r" % (msg, f))
+            ui.warn(_("warning: %s: %r\n") % (msg, f))
+    elif bval is None and lval != 'ignore':
+        raise error.ConfigError(
+            _("ui.portablefilenames value is invalid ('%s')") % val)
+

I could argue that this piece of code depends on an abstract, opaque interface
of ui objects, using a contract that an ui object has:

- a member function config, which returns a config string, given section
  and config option name
- a function warn

So this piece of code would depend on that abstract interface of ui objects, but
not on the specific implementation of ui objects.

In C++-ish (my home turf), this would be:

  class ui_interface
  {
  public:
    virtual string config(const string& section, const string& name) = 0
    virtual warn(const string& msg) = 0
  };

which could be put in a header "ui_interface.h" and which wouldn't #include "ui.h".
"ui.cpp" *would* #include "ui_interface.h" and implement ui_interface by deriving
from it.

util's checkportable function would then take an ui_interface param (in C++-ish):

  void checkportable(ui_interface& ui, const string& f)
  {
    ..
  }

thus depending on "ui_interface.h" and not on "ui.h" nor "ui.cpp". It would only
depend on the fact that there's *some* kind of implementation of ui_interface.

So the module dependency graph would have:

                     util
                      ¦
                     ui_interface

with ui_interface being a pure abstract module (containing only declarations of
abstract interfaces). Which is not the same as the (truly bad)

                     util
                      ¦
                     ui

Robert C. Martin calls this the dependency inversion principle [1].

Of course, it can be done in Java and C# as well (and most definitely others too).

In Python's duck typing system, this abstract interface is implicit. It doesn't
need to be declared as in C++, but it's not as explicit then as in C++. 

I still think it would be great if we could use ui objects in module util in that
manner in mercurial.

[1] http://www.objectmentor.com/resources/articles/dip.pdf


More information about the Mercurial-devel mailing list