[PATCH 3 of 3] util.makedirs: cleanup of termination of recursion

Adrian Buehlmann adrian at cadifra.com
Mon Aug 22 03:07:56 CDT 2011


On 2011-08-22 09:19, Adrian Buehlmann wrote:
> On 2011-08-22 01:07, Mads Kiilerich wrote:
>> # HG changeset patch
>> # User Mads Kiilerich <mads at kiilerich.com>
>> # Date 1313966711 -7200
>> # Branch stable
>> # Node ID e241109d6afd46fb19103b3bbf86bbc9adca53cc
>> # Parent  4191b702114a9bb2b6287ce622060589763ac038
>> util.makedirs: cleanup of termination of recursion
>>
>> The fixes in 2649be11ab0b and adff480db558 for preventing infinite recursion
>> are no longer needed and is removed.
>>
>> Parentdir calculation is now postponed until it is needed.
>>
>> diff --git a/mercurial/util.py b/mercurial/util.py
>> --- a/mercurial/util.py
>> +++ b/mercurial/util.py
>> @@ -757,15 +757,14 @@
>>  
>>  def makedirs(name, mode=None):
>>      """recursive directory creation with parent mode inheritance"""
>> -    parent = os.path.abspath(os.path.dirname(name))
>>      try:
>>          os.mkdir(name)
>>      except OSError, err:
>>          if err.errno == errno.EEXIST:
>>              return
>> -        if not name or parent == name or err.errno != errno.ENOENT:
>> +        if err.errno != errno.ENOENT:
>>              raise
>> -        makedirs(parent, mode)
>> +        makedirs(os.path.dirname(os.path.abspath(name)), mode)
>>          os.mkdir(name)
>>      if mode is not None:
>>          os.chmod(name, mode)
> 
> This one seems to make issue2531 (was previously fixed with my adff480db558)
> failing again:
> 
>   $ N:\
>   The system cannot find the drive specified.
> 
>   $ n:\
>   The system cannot find the drive specified.
> 
>   $ hgc init n:\test
>   --- running hg from C:\Users\adi\hgrepos\hg-crew
>   ** unknown exception encountered, please report by visiting
>   **  http://mercurial.selenic.com/wiki/BugTracker
>   ** Python 2.6.6 (r266:84297, Aug 24 2010, 18:13:38) [MSC v.1500 64 bit (AMD64)]
>   ** Mercurial Distributed SCM (version unknown)
>   ** Extensions loaded: rebase, mq, graphlog, patchbomb
>   Traceback (most recent call last):
>     File "C:\Users\adi\hgrepos\hg-crew\hg", line 38, in <module>
>       mercurial.dispatch.run()
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 27, in run
>       sys.exit(dispatch(request(sys.argv[1:])))
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 64, in dispatch
>       return _runcatch(req)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 87, in _runcatch
>       return _dispatch(req)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 684, in _dispatch
>       cmdpats, cmdoptions)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 466, in runcommand
>       ret = _runcommand(ui, options, cmd, d)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 738, in _runcommand
>       return checkargs()
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 692, in checkargs
>       return cmdfunc()
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 681, in <lambda>
>       d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 441, in check
>       return func(*args, **kwargs)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\extensions.py", line 137, in wrap
>       util.checksignature(origfn), *args, **kwargs)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 441, in check
>       return func(*args, **kwargs)
>     File "C:\Users\adi\hgrepos\hg-crew\hgext\mq.py", line 3201, in mqinit
>       return orig(ui, *args, **kwargs)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 441, in check
>       return func(*args, **kwargs)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\commands.py", line 3290, in init
>       hg.peer(ui, opts, ui.expandpath(dest), create=True)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\hg.py", line 104, in peer
>       return repository(rui, path, create)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\hg.py", line 93, in repository
>       repo = _peerlookup(path).instance(ui, path, create)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\localrepo.py", line 2055, in instance
>       return localrepository(ui, util.urllocalpath(path), create)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\localrepo.py", line 49, in __init__
>       util.makedirs(path)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 790, in makedirs
>       makedirs(os.path.dirname(os.path.abspath(name)), mode)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 790, in makedirs
>       makedirs(os.path.dirname(os.path.abspath(name)), mode)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 790, in makedirs
>       makedirs(os.path.dirname(os.path.abspath(name)), mode)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 790, in makedirs
>       makedirs(os.path.dirname(os.path.abspath(name)), mode)
>     ...
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 790, in makedirs
>       makedirs(os.path.dirname(os.path.abspath(name)), mode)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 790, in makedirs
>       makedirs(os.path.dirname(os.path.abspath(name)), mode)
>     File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 790, in makedirs
>       makedirs(os.path.dirname(os.path.abspath(name)), mode)
>     File "C:\Python26_x64\lib\ntpath.py", line 478, in abspath
>       return normpath(path)
>     File "C:\Python26_x64\lib\ntpath.py", line 401, in normpath
>       backslash, dot = (u'\\', u'.') if isinstance(path, unicode) else ('\\', '.')
>   RuntimeError: maximum recursion depth exceeded while calling a Python object

I tried this:

  $ python
  Python 2.6.6 (r266:84297, Aug 24 2010, 18:13:38) [MSC v.1500 64 bit (AMD64)] on win32
  Type "help", "copyright", "credits" or "license" for more information.
  >>> import os
  >>> name = "n:\\test"
  >>> os.path.abspath(name)
  'n:\\test'
  >>> os.path.dirname(os.path.abspath(name))
  'n:\\'
  >>> os.mkdir('n:\\')
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  WindowsError: [Error 3] The system cannot find the path specified: 'n:\\'

compare with:

  >>> os.mkdir('C:\\Users\\adi\\notexistingdir\\foo')
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  WindowsError: [Error 3] The system cannot find the path specified: 'C:\\Users\\adi\\notexistingdir\\foo'

and with:

  $ n:\
  The system cannot find the drive specified.

If I insert a print:

def makedirs(name, mode=None):
    """recursive directory creation with parent mode inheritance"""
    print name
    try:
        os.mkdir(name)
    except OSError, err:
        if err.errno == errno.EEXIST:
            return
        if err.errno != errno.ENOENT:
            raise
        makedirs(os.path.dirname(os.path.abspath(name)), mode)
        os.mkdir(name)
    if mode is not None:
        os.chmod(name, mode)

I get:

  $ hgc init n:\test
  --- running hg from C:\Users\adi\hgrepos\hg-crew
  n:\test
  n:\
  n:\
  ...
  n:\
  n:\
  n:\
  n:\
  n:\
  n:\
  ** unknown exception encountered, please report by visiting
  **  http://mercurial.selenic.com/wiki/BugTracker
  ** Python 2.6.6 (r266:84297, Aug 24 2010, 18:13:38) [MSC v.1500 64 bit (AMD64)]
  ** Mercurial Distributed SCM (version unknown)
  ** Extensions loaded: rebase, mq, graphlog, patchbomb
  Traceback (most recent call last):
    File "C:\Users\adi\hgrepos\hg-crew\hg", line 38, in <module>
      mercurial.dispatch.run()
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 27, in run
      sys.exit(dispatch(request(sys.argv[1:])))
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 64, in dispatch
      return _runcatch(req)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 87, in _runcatch
      return _dispatch(req)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 684, in _dispatch
      cmdpats, cmdoptions)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 466, in runcommand
      ret = _runcommand(ui, options, cmd, d)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 738, in _runcommand
      return checkargs()
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 692, in checkargs
      return cmdfunc()
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\dispatch.py", line 681, in <lambda>
      d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 441, in check
      return func(*args, **kwargs)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\extensions.py", line 137, in wrap
      util.checksignature(origfn), *args, **kwargs)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 441, in check
      return func(*args, **kwargs)
    File "C:\Users\adi\hgrepos\hg-crew\hgext\mq.py", line 3201, in mqinit
      return orig(ui, *args, **kwargs)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 441, in check
      return func(*args, **kwargs)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\commands.py", line 3290, in init
      hg.peer(ui, opts, ui.expandpath(dest), create=True)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\hg.py", line 104, in peer
      return repository(rui, path, create)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\hg.py", line 93, in repository
      repo = _peerlookup(path).instance(ui, path, create)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\localrepo.py", line 2055, in instance
      return localrepository(ui, util.urllocalpath(path), create)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\localrepo.py", line 49, in __init__
      util.makedirs(path)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 791, in makedirs
      makedirs(os.path.dirname(os.path.abspath(name)), mode)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 791, in makedirs
      makedirs(os.path.dirname(os.path.abspath(name)), mode)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 791, in makedirs
      makedirs(os.path.dirname(os.path.abspath(name)), mode)
    ...
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 791, in makedirs
      makedirs(os.path.dirname(os.path.abspath(name)), mode)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 791, in makedirs
      makedirs(os.path.dirname(os.path.abspath(name)), mode)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 791, in makedirs
      makedirs(os.path.dirname(os.path.abspath(name)), mode)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 791, in makedirs
      makedirs(os.path.dirname(os.path.abspath(name)), mode)
    File "C:\Users\adi\hgrepos\hg-crew\mercurial\util.py", line 791, in makedirs
      makedirs(os.path.dirname(os.path.abspath(name)), mode)
    File "C:\Python26_x64\lib\ntpath.py", line 478, in abspath
      return normpath(path)
    File "C:\Python26_x64\lib\ntpath.py", line 401, in normpath
      backslash, dot = (u'\\', u'.') if isinstance(path, unicode) else ('\\', '.')
  RuntimeError: maximum recursion depth exceeded while calling a Python object


If we want to postpone (and reorder) the parent calculation, we could do:

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -780,12 +780,12 @@
 
 def makedirs(name, mode=None):
     """recursive directory creation with parent mode inheritance"""
-    parent = os.path.abspath(os.path.dirname(name))
     try:
         os.mkdir(name)
     except OSError, err:
         if err.errno == errno.EEXIST:
             return
+        parent = os.path.dirname(os.path.abspath(name))
         if not name or parent == name or err.errno != errno.ENOENT:
             raise
         makedirs(parent, mode)

which seems to work for me:

  $ n:\
  The system cannot find the drive specified.

  $ hgc init n:\test
  --- running hg from C:\Users\adi\hgrepos\hg-crew
  abort: The system cannot find the path specified: n:\

  $ hgc clone --pull a a2
  --- running hg from C:\Users\adi\hgrepos\hg-crew
  requesting all changes
  adding changesets
  adding manifests
  adding file changes
  added 15 changesets with 16 changes to 5 files (+1 heads)
  updating to branch default
  5 files updated, 0 files merged, 0 files removed, 0 files unresolved

  $ hgc -R a2 verify
  --- running hg from C:\Users\adi\hgrepos\hg-crew
  checking changesets
  checking manifests
  crosschecking files in changesets and manifests
  checking files
  5 files, 15 changesets, 16 total revisions


More information about the Mercurial-devel mailing list