diff --git a/.hgignore b/.hgignore index 174084f832..f86bd0f243 100644 --- a/.hgignore +++ b/.hgignore @@ -63,6 +63,7 @@ locale/*/LC_MESSAGES/hg.mo hgext/__index__.py hgext/clindex.c hgext/extlib/linelog.c +hgext/patchrmdir.c hgext/traceprof.cpp # Rust libraries and extensions diff --git a/fb-hgext/hgext3rd/patchrmdir.pyx b/fb-hgext/hgext3rd/patchrmdir.pyx deleted file mode 100644 index 3f70ff6937..0000000000 --- a/fb-hgext/hgext3rd/patchrmdir.pyx +++ /dev/null @@ -1,63 +0,0 @@ -# patchrmdir.py -# -# Copyright 2017 Facebook, Inc. -# -# This software may be used and distributed according to the terms of the -# GNU General Public License version 2 or any later version. - -"""patch rmdir - -Check if a directory is empty before trying to call rmdir on it. This works -around some kernel issues. -""" - -from mercurial import ( - extensions, -) -import os -import errno - -cdef extern from "dirent.h": - ctypedef struct DIR - struct dirent: - pass - - DIR *opendir(const char *) - dirent *readdir(DIR *) - int closedir(DIR *) - -cdef int _countdir(const char *path): - """return min(3, the number of entries inside a directory). - return -1 if the directory cannot be opened. - """ - cdef DIR *d = opendir(path) - if d == NULL: - return -1 - - cdef dirent *e - cdef int n = 0 - while True: - e = readdir(d) - if e == NULL: - break - else: - n += 1 - if n > 2: - break - closedir(d) - return n - -def _rmdir(orig, path): - n = _countdir(path) - if n >= 3: - # The number 3 is because most systems have "." and "..". For systems - # without them, we fallback to the original rmdir, the behavior should - # still be correct. - # Choose a slightly different error message other than "Directory not - # empty" so the test could notice the difference. - raise OSError(errno.ENOTEMPTY, 'Non-empty directory: %r' % path) - else: - return orig(path) - -def uisetup(ui): - extensions.wrapfunction(os, 'rmdir', _rmdir) diff --git a/hgext/patchrmdir.pyx b/hgext/patchrmdir.pyx new file mode 100644 index 0000000000..e644440df4 --- /dev/null +++ b/hgext/patchrmdir.pyx @@ -0,0 +1,67 @@ +# patchrmdir.py +# +# Copyright 2017 Facebook, Inc. +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +"""patch rmdir + +Check if a directory is empty before trying to call rmdir on it. This works +around some kernel issues. + +Have no effect on Windows. +""" + +IF UNAME_SYSNAME != "Windows": + from mercurial import ( + extensions, + pycompat, + ) + import os + import errno + + cdef extern from "dirent.h": + ctypedef struct DIR + struct dirent: + pass + + DIR *opendir(const char *) + dirent *readdir(DIR *) + int closedir(DIR *) + + cdef int _countdir(const char *path): + """return min(3, the number of entries inside a directory). + return -1 if the directory cannot be opened. + """ + cdef DIR *d = opendir(path) + if d == NULL: + return -1 + + cdef dirent *e + cdef int n = 0 + while True: + e = readdir(d) + if e == NULL: + break + else: + n += 1 + if n > 2: + break + closedir(d) + return n + + def _rmdir(orig, path): + n = _countdir(path) + if n >= 3: + # The number 3 is because most systems have "." and "..". For systems + # without them, we fallback to the original rmdir, the behavior should + # still be correct. + # Choose a slightly different error message other than "Directory not + # empty" so the test could notice the difference. + raise OSError(errno.ENOTEMPTY, 'Non-empty directory: %r' % path) + else: + return orig(path) + + def uisetup(ui): + extensions.wrapfunction(os, 'rmdir', _rmdir) diff --git a/setup.py b/setup.py index 3279c8d5d1..1af8d7c8fc 100644 --- a/setup.py +++ b/setup.py @@ -1055,6 +1055,9 @@ extmodules += cythonize([ Extension('hgext.clindex', sources=['hgext/clindex.pyx'], extra_compile_args=filter(None, [STDC99, PRODUCEDEBUGSYMBOLS])), + Extension('hgext.patchrmdir', + sources=['hgext/patchrmdir.pyx'], + extra_compile_args=filter(None, [PRODUCEDEBUGSYMBOLS])), Extension('hgext.traceprof', sources=['hgext/traceprof.pyx'], include_dirs=['hgext'],