[PATCH 1 of 8 RFC] vfs: replace invocation of file APIs of os module by ones via vfs

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Fri Jun 15 09:45:12 CDT 2012


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1339768793 -32400
# Node ID a14b63be9a04e7fac445fea69bbaf840ca3f4063
# Parent  622aa57a90b1d1f09b3204458b087de12ce2de82
vfs: replace invocation of file APIs of os module by ones via vfs

this patch replaces invocation of below file APIs of os module by ones
via vfs.

    - chdir
    - chmod
    - getcwd
    - listdir
    - lstat
    - makedirs
    - mkdir
    - open
    - readlink
    - remove
    - removedirs
    - rename
    - rmdir
    - stat
    - symlink
    - unlink
    - utime
    - walk

replacements of this patch are done in steps below:

    1. replace all invocations of above functions "os.XXXX()" by
        "util.vfs().XXXX()" mechanically: or adding "vfs()." in
        util.py itself

    2. check how many times "vfs()" are invoked in each modified
       functions

    3. introduce "vfs" local var("vfsobj" in util.py itself), and
       replace "util.vfs()" invocations by it, if:

       - vfs() is invoked more than once in the function,
       - vfs() is invoked in the loop, or
       - vfs() is invoked in the internal function invoked repeatedly

diff -r 622aa57a90b1 -r a14b63be9a04 contrib/shrink-revlog.py
--- a/contrib/shrink-revlog.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/contrib/shrink-revlog.py	Fri Jun 15 22:59:53 2012 +0900
@@ -125,11 +125,12 @@
         ui.progress(_('writing'), None)
 
 def report(ui, r1, r2):
+    vfs = util.vfs()
     def getsize(r):
         s = 0
         for fn in (r.indexfile, r.datafile):
             try:
-                s += os.stat(fn).st_size
+                s += vfs.stat(fn).st_size
             except OSError, inst:
                 if inst.errno != errno.ENOENT:
                     raise
@@ -193,8 +194,9 @@
     ui.write(_('shrinking %s\n') % indexfn)
     tmpindexfn = util.mktempcopy(indexfn, emptyok=True)
 
-    r1 = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), indexfn)
-    r2 = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), tmpindexfn)
+    vfs = util.vfs()
+    r1 = revlog.revlog(scmutil.opener(vfs.getcwd(), audit=False), indexfn)
+    r2 = revlog.revlog(scmutil.opener(vfs.getcwd(), audit=False), tmpindexfn)
 
     datafn, tmpdatafn = r1.datafile, r2.datafile
 
@@ -245,7 +247,7 @@
             # deleting them.
             tr.abort()
             for fn in (tmpindexfn, tmpdatafn):
-                ignoremissing(os.unlink)(fn)
+                ignoremissing(vfs.unlink)(fn)
             raise
         if not opts.get('dry_run'):
             # racy, both files cannot be renamed atomically
@@ -256,15 +258,15 @@
             # rename
             util.rename(tmpindexfn, indexfn)
             try:
-                os.chmod(tmpdatafn, os.stat(datafn).st_mode)
+                vfs.chmod(tmpdatafn, vfs.stat(datafn).st_mode)
                 util.rename(tmpdatafn, datafn)
             except OSError, inst:
                 if inst.errno != errno.ENOENT:
                     raise
-                ignoremissing(os.unlink)(datafn)
+                ignoremissing(vfs.unlink)(datafn)
         else:
             for fn in (tmpindexfn, tmpdatafn):
-                ignoremissing(os.unlink)(fn)
+                ignoremissing(vfs.unlink)(fn)
     finally:
         lock.release()
 
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/convert/cvs.py
--- a/hgext/convert/cvs.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/convert/cvs.py	Fri Jun 15 22:59:53 2012 +0900
@@ -49,9 +49,10 @@
                 raise util.Abort(_('revision %s is not a patchset number')
                                  % self.rev)
 
-        d = os.getcwd()
+        vfs = util.vfs()
+        d = vfs.getcwd()
         try:
-            os.chdir(self.path)
+            vfs.chdir(self.path)
             id = None
 
             cache = 'update'
@@ -88,7 +89,7 @@
 
             self.heads = self.lastbranch.values()
         finally:
-            os.chdir(d)
+            vfs.chdir(d)
 
     def _connect(self):
         root = self.cvsroot
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/convert/cvsps.py
--- a/hgext/convert/cvsps.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/convert/cvsps.py	Fri Jun 15 22:59:53 2012 +0900
@@ -151,7 +151,7 @@
     if cache:
         cachedir = os.path.expanduser('~/.hg.cvsps')
         if not os.path.exists(cachedir):
-            os.mkdir(cachedir)
+            util.vfs().mkdir(cachedir)
 
         # The cvsps cache pickle needs a uniquified name, based on the
         # repository location. The address may have all sort of nasties
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/convert/darcs.py
--- a/hgext/convert/darcs.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/convert/darcs.py	Fri Jun 15 22:59:53 2012 +0900
@@ -192,7 +192,7 @@
             raise util.Abort(_('internal calling inconsistency'))
         path = os.path.join(self.tmppath, name)
         data = util.readfile(path)
-        mode = os.lstat(path).st_mode
+        mode = util.vfs().lstat(path).st_mode
         mode = (mode & 0111) and 'x' or ''
         return data, mode
 
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/convert/gnuarch.py
--- a/hgext/convert/gnuarch.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/convert/gnuarch.py	Fri Jun 15 22:59:53 2012 +0900
@@ -205,9 +205,10 @@
             self._parsechangeset(changeset, rev)
 
     def _getfile(self, name, rev):
-        mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
+        vfs = util.vfs()
+        mode = vfs.lstat(os.path.join(self.tmppath, name)).st_mode
         if stat.S_ISLNK(mode):
-            data = os.readlink(os.path.join(self.tmppath, name))
+            data = vfs.readlink(os.path.join(self.tmppath, name))
             mode = mode and 'l' or ''
         else:
             data = open(os.path.join(self.tmppath, name), 'rb').read()
@@ -223,7 +224,8 @@
 
     def _readcontents(self, path):
         files = []
-        contents = os.listdir(path)
+        vfs = util.vfs()
+        contents = vfs.listdir(path)
         while len(contents) > 0:
             c = contents.pop()
             p = os.path.join(path, c)
@@ -231,7 +233,7 @@
             # Arch files and directories, thus saving a lot time.
             if not self._exclude(p):
                 if os.path.isdir(p):
-                    contents += [os.path.join(c, f) for f in os.listdir(p)]
+                    contents += [os.path.join(c, f) for f in vfs.listdir(p)]
                 else:
                     files.append(c)
         return files
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/convert/hg.py
--- a/hgext/convert/hg.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/convert/hg.py	Fri Jun 15 22:59:53 2012 +0900
@@ -32,7 +32,7 @@
         self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
         self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
         self.lastbranch = None
-        if os.path.isdir(path) and len(os.listdir(path)) > 0:
+        if os.path.isdir(path) and len(util.vfs().listdir(path)) > 0:
             try:
                 self.repo = hg.repository(self.ui, path)
                 if not self.repo.local():
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/convert/subversion.py
--- a/hgext/convert/subversion.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/convert/subversion.py	Fri Jun 15 22:59:53 2012 +0900
@@ -987,11 +987,11 @@
 
     def prerun(self):
         if self.wc:
-            os.chdir(self.wc)
+            util.vfs().chdir(self.wc)
 
     def postrun(self):
         if self.wc:
-            os.chdir(self.cwd)
+            util.vfs().chdir(self.cwd)
 
     def join(self, name):
         return os.path.join(self.wc, '.svn', name)
@@ -1011,7 +1011,8 @@
         self.delexec = []
         self.copies = []
         self.wc = None
-        self.cwd = os.getcwd()
+        vfs = util.vfs()
+        self.cwd = vfs.getcwd()
 
         path = os.path.realpath(path)
 
@@ -1020,7 +1021,8 @@
             self.wc = path
             self.run0('update')
         else:
-            wcpath = os.path.join(os.getcwd(), os.path.basename(path) + '-wc')
+            wcpath = os.path.join(vfs.getcwd(),
+                                  os.path.basename(path) + '-wc')
 
             if os.path.isdir(os.path.dirname(path)):
                 if not os.path.exists(os.path.join(path, 'db', 'fs-type')):
@@ -1085,7 +1087,7 @@
         else:
             try:
                 if os.path.islink(self.wjoin(filename)):
-                    os.unlink(filename)
+                    util.vfs().unlink(filename)
             except OSError:
                 pass
             self.wopener.write(filename, data)
@@ -1110,24 +1112,25 @@
         # SVN's copy command pukes if the destination file exists, but
         # our copyfile method expects to record a copy that has
         # already occurred.  Cross the semantic gap.
+        vfs = util.vfs()
         wdest = self.wjoin(dest)
         exists = os.path.lexists(wdest)
         if exists:
             fd, tempname = tempfile.mkstemp(
                 prefix='hg-copy-', dir=os.path.dirname(wdest))
             os.close(fd)
-            os.unlink(tempname)
-            os.rename(wdest, tempname)
+            vfs.unlink(tempname)
+            vfs.rename(wdest, tempname)
         try:
             self.run0('copy', source, dest)
         finally:
             self.manifest.add(dest)
             if exists:
                 try:
-                    os.unlink(wdest)
+                    vfs.unlink(wdest)
                 except OSError:
                     pass
-                os.rename(tempname, wdest)
+                vfs.rename(tempname, wdest)
 
     def dirs_of(self, files):
         dirs = set()
@@ -1155,9 +1158,10 @@
 
     def tidy_dirs(self, names):
         deleted = []
+        vfs = util.vfs()
         for d in sorted(self.dirs_of(names), reverse=True):
             wd = self.wjoin(d)
-            if os.listdir(wd) == '.svn':
+            if vfs.listdir(wd) == '.svn':
                 self.run0('delete', d)
                 self.manifest.remove(d)
                 deleted.append(d)
@@ -1236,7 +1240,7 @@
                 self.addchild(parent, rev)
             return self.revid(rev)
         finally:
-            os.unlink(messagefile)
+            util.vfs().unlink(messagefile)
 
     def puttags(self, tags):
         self.ui.warn(_('writing Subversion tags is not yet implemented\n'))
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/extdiff.py
--- a/hgext/extdiff.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/extdiff.py	Fri Jun 15 22:59:53 2012 +0900
@@ -78,7 +78,8 @@
     if node is not None:
         dirname = '%s.%s' % (dirname, short(node))
     base = os.path.join(tmproot, dirname)
-    os.mkdir(base)
+    vfs = util.vfs()
+    vfs.mkdir(base)
     if node is not None:
         ui.note(_('making snapshot of %d files from rev %s\n') %
                 (len(files), short(node)))
@@ -105,7 +106,7 @@
                 util.setflags(dest, False, True)
         if node is None:
             fns_and_mtime.append((dest, repo.wjoin(fn),
-                                  os.lstat(dest).st_mtime))
+                                  vfs.lstat(dest).st_mtime))
     return dirname, fns_and_mtime
 
 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
@@ -227,8 +228,9 @@
         ui.debug('running %r in %s\n' % (cmdline, tmproot))
         util.system(cmdline, cwd=tmproot, out=ui.fout)
 
+        vfs = util.vfs()
         for copy_fn, working_fn, mtime in fns_and_mtime:
-            if os.lstat(copy_fn).st_mtime != mtime:
+            if vfs.lstat(copy_fn).st_mtime != mtime:
                 ui.debug('file changed while diffing. '
                          'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
                 util.copyfile(copy_fn, working_fn)
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/factotum.py
--- a/hgext/factotum.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/factotum.py	Fri Jun 15 22:59:53 2012 +0900
@@ -62,8 +62,9 @@
 
 def auth_getuserpasswd(self, getkey, params):
     params = 'proto=pass %s' % params
+    vfs = util.vfs()
     while True:
-        fd = os.open('%s/rpc' % _mountpoint, os.O_RDWR)
+        fd = vfs.open('%s/rpc' % _mountpoint, os.O_RDWR)
         try:
             try:
                 os.write(fd, 'start %s' % params)
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/gpg.py
--- a/hgext/gpg.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/gpg.py	Fri Jun 15 22:59:53 2012 +0900
@@ -40,10 +40,11 @@
                       "\"%s\" \"%s\"" % (self.path, sigfile, datafile))
             ret = util.filter("", gpgcmd)
         finally:
+            vfs = util.vfs()
             for f in (sigfile, datafile):
                 try:
                     if f:
-                        os.unlink(f)
+                        vfs.unlink(f)
                 except OSError:
                     pass
         keys = []
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/hgk.py
--- a/hgext/hgk.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/hgk.py	Fri Jun 15 22:59:53 2012 +0900
@@ -34,7 +34,6 @@
 vdiff on hovered and selected revisions.
 '''
 
-import os
 from mercurial import commands, util, patch, revlog, scmutil
 from mercurial.node import nullid, nullrev, short
 from mercurial.i18n import _
@@ -309,7 +308,7 @@
 
 def view(ui, repo, *etc, **opts):
     "start interactive history viewer"
-    os.chdir(repo.root)
+    util.vfs().chdir(repo.root)
     optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
     cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
     ui.debug("running %s\n" % cmd)
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/inotify/client.py
--- a/hgext/inotify/client.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/inotify/client.py	Fri Jun 15 22:59:53 2012 +0900
@@ -8,6 +8,7 @@
 # GNU General Public License version 2 or any later version.
 
 from mercurial.i18n import _
+from mercurial import util
 import common, server
 import errno, os, socket, struct
 
@@ -29,7 +30,8 @@
             if err.args[0] == errno.ECONNREFUSED:
                 self.ui.warn(_('inotify-client: found dead inotify server '
                                'socket; removing it\n'))
-                os.unlink(os.path.join(self.root, '.hg', 'inotify.sock'))
+                util.vfs().unlink(os.path.join(self.root,
+                                               '.hg', 'inotify.sock'))
             if err.args[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
                 try:
                     try:
@@ -74,7 +76,7 @@
             self.sock.connect(sockpath)
         except socket.error, err:
             if err.args[0] == "AF_UNIX path too long":
-                sockpath = os.readlink(sockpath)
+                sockpath = util.vfs().readlink(sockpath)
                 self.sock.connect(sockpath)
             else:
                 raise
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/inotify/linux/watcher.py
--- a/hgext/inotify/linux/watcher.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/inotify/linux/watcher.py	Fri Jun 15 22:59:53 2012 +0900
@@ -21,6 +21,7 @@
 
 __author__ = "Bryan O'Sullivan <bos at serpentine.com>"
 
+from mercurial import util
 import _inotify as inotify
 import array
 import errno
@@ -243,7 +244,8 @@
         except OSError, err:
             if onerror and err.errno not in self.ignored_errors:
                 onerror(err)
-        for root, dirs, names in os.walk(path, topdown=False, onerror=onerror):
+        for root, dirs, names in util.vfs().walk(path, topdown=False,
+                                                 onerror=onerror):
             for d in dirs:
                 try:
                     yield self.add(root + '/' + d, submask)
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/inotify/linuxserver.py
--- a/hgext/inotify/linuxserver.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/inotify/linuxserver.py	Fri Jun 15 22:59:53 2012 +0900
@@ -405,11 +405,12 @@
 
     def shutdown(self):
         self.sock.close()
+        vfs = util.vfs()
         try:
-            os.unlink(self.sockpath)
+            vfs.unlink(self.sockpath)
             if self.realsockpath:
-                os.unlink(self.realsockpath)
-                os.rmdir(os.path.dirname(self.realsockpath))
+                vfs.unlink(self.realsockpath)
+                vfs.rmdir(os.path.dirname(self.realsockpath))
         except OSError, err:
             if err.errno != errno.ENOENT:
                 raise
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/inotify/server.py
--- a/hgext/inotify/server.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/inotify/server.py	Fri Jun 15 22:59:53 2012 +0900
@@ -192,7 +192,7 @@
 
     def dirstate_info(self):
         try:
-            st = os.lstat(self.wprefix + '.hg/dirstate')
+            st = util.vfs().lstat(self.wprefix + '.hg/dirstate')
             return st.st_mtime, st.st_ino
         except OSError, err:
             if err.errno != errno.ENOENT:
@@ -315,7 +315,7 @@
 
     def stat(self, wpath):
         try:
-            st = os.lstat(join(self.wprefix, wpath))
+            st = util.vfs().lstat(join(self.wprefix, wpath))
             ret = st.st_mode, st.st_size, st.st_mtime
             self.statcache[wpath] = ret
             return ret
@@ -334,9 +334,10 @@
         self.sockpath = join(root, '.hg/inotify.sock')
 
         self.realsockpath = self.sockpath
+        vfs = util.vfs()
         if os.path.islink(self.sockpath):
             if os.path.exists(self.sockpath):
-                self.realsockpath = os.readlink(self.sockpath)
+                self.realsockpath = vfs.readlink(self.sockpath)
             else:
                 raise util.Abort('inotify-server: cannot start: '
                                 '.hg/inotify.sock is a broken symlink')
@@ -351,13 +352,13 @@
                 self.realsockpath = os.path.join(tempdir, "inotify.sock")
                 try:
                     self.sock.bind(self.realsockpath)
-                    os.symlink(self.realsockpath, self.sockpath)
+                    vfs.symlink(self.realsockpath, self.sockpath)
                 except (OSError, socket.error), inst:
                     try:
-                        os.unlink(self.realsockpath)
+                        vfs.unlink(self.realsockpath)
                     except OSError:
                         pass
-                    os.rmdir(tempdir)
+                    vfs.rmdir(tempdir)
                     if inst.errno == errno.EEXIST:
                         raise AlreadyStartedException(_('cannot start: tried '
                             'linking .hg/inotify.sock to a temporary socket but'
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/largefiles/lfcommands.py
--- a/hgext/largefiles/lfcommands.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/largefiles/lfcommands.py	Fri Jun 15 22:59:53 2012 +0900
@@ -92,11 +92,12 @@
             if os.path.exists(rdst.wjoin(lfutil.shortname)):
                 shutil.rmtree(rdst.wjoin(lfutil.shortname))
 
+            vfs = util.vfs()
             for f in lfiletohash.keys():
                 if os.path.isfile(rdst.wjoin(f)):
-                    os.unlink(rdst.wjoin(f))
+                    vfs.unlink(rdst.wjoin(f))
                 try:
-                    os.removedirs(os.path.dirname(rdst.wjoin(f)))
+                    vfs.removedirs(os.path.dirname(rdst.wjoin(f)))
                 except OSError:
                     pass
 
@@ -173,6 +174,7 @@
     files = _getchangedfiles(ctx, parents)
 
     dstfiles = []
+    vfs = util.vfs()
     for f in files:
         if f not in lfiles and f not in normalfiles:
             islfile = _islfile(f, ctx, matcher, size)
@@ -218,7 +220,7 @@
                         if fd:
                             fd.close()
                     executable = 'x' in ctx[f].flags()
-                    os.chmod(fullpath, lfutil.getmode(executable))
+                    vfs.chmod(fullpath, lfutil.getmode(executable))
                     lfutil.writestandin(rdst, lfutil.standin(f), hash,
                         executable)
                     lfiletohash[f] = hash
@@ -466,6 +468,7 @@
     ret = 0
     abslfile = repo.wjoin(lfile)
     absstandin = repo.wjoin(lfutil.standin(lfile))
+    vfs = util.vfs()
     if os.path.exists(absstandin):
         if os.path.exists(absstandin+'.orig'):
             shutil.copyfile(abslfile, abslfile+'.orig')
@@ -480,9 +483,9 @@
                 lfdirstate.normallookup(lfile)
                 return None # don't try to set the mode
             ret = 1
-        mode = os.stat(absstandin).st_mode
-        if mode != os.stat(abslfile).st_mode:
-            os.chmod(abslfile, mode)
+        mode = vfs.stat(absstandin).st_mode
+        if mode != vfs.stat(abslfile).st_mode:
+            vfs.chmod(abslfile, mode)
             ret = 1
     else:
         # Remove lfiles for which the standin is deleted, unless the
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/largefiles/lfutil.py
--- a/hgext/largefiles/lfutil.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/largefiles/lfutil.py	Fri Jun 15 22:59:53 2012 +0900
@@ -81,7 +81,7 @@
         for chunk in util.filechunkiter(open(src, 'rb')):
             dst.write(chunk)
         dst.close()
-        os.chmod(dest, os.stat(src).st_mode)
+        util.vfs().chmod(dest, util.vfs().stat(src).st_mode)
 
 def usercachepath(ui, hash):
     path = ui.configpath(longname, 'usercache', None)
@@ -392,10 +392,10 @@
 def writehash(hash, filename, executable):
     util.makedirs(os.path.dirname(filename))
     util.writefile(filename, hash + '\n')
-    os.chmod(filename, getmode(executable))
+    util.vfs().chmod(filename, getmode(executable))
 
 def getexecutable(filename):
-    mode = os.stat(filename).st_mode
+    mode = util.vfs().stat(filename).st_mode
     return ((mode & stat.S_IXUSR) and
             (mode & stat.S_IXGRP) and
             (mode & stat.S_IXOTH))
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/largefiles/overrides.py	Fri Jun 15 22:59:53 2012 +0900
@@ -68,6 +68,7 @@
     m = scmutil.match(repo[None], pats, opts)
     m.bad = lambda x, y: None
     wctx = repo[None]
+    vfs = util.vfs()
     for f in repo.walk(m):
         exact = m.exact(f)
         lfile = lfutil.standin(f) in wctx
@@ -83,7 +84,8 @@
 
         if exact or not exists:
             abovemin = (lfsize and
-                        os.lstat(repo.wjoin(f)).st_size >= lfsize * 1024 * 1024)
+                        vfs.lstat(repo.wjoin(f)).st_size >=
+                        lfsize * 1024 * 1024)
             if large or abovemin or (lfmatcher and lfmatcher(f)):
                 lfnames.append(f)
                 if ui.verbose or not exact:
@@ -418,9 +420,10 @@
     fullpats = scmutil.expandpats(pats)
     dest = fullpats[-1]
 
+    vfs = util.vfs()
     if os.path.isdir(dest):
         if not os.path.isdir(makestandin(dest)):
-            os.makedirs(makestandin(dest))
+            vfs.makedirs(makestandin(dest))
     # This could copy both lfiles and normal files in one command,
     # but we don't want to do that. First replace their matcher to
     # only match normal files and run it, then replace it to just
@@ -510,9 +513,9 @@
                     destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
                     destlfiledir = os.path.dirname(destlfile) or '.'
                     if not os.path.isdir(destlfiledir):
-                        os.makedirs(destlfiledir)
+                        vfs.makedirs(destlfiledir)
                     if rename:
-                        os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
+                        vfs.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
                         lfdirstate.remove(srclfile)
                     else:
                         util.copyfile(srclfile, destlfile)
@@ -553,9 +556,10 @@
             lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
         for lfile in modified:
             lfutil.updatestandin(repo, lfutil.standin(lfile))
+        vfs = util.vfs()
         for lfile in missing:
             if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
-                os.unlink(repo.wjoin(lfutil.standin(lfile)))
+                vfs.unlink(repo.wjoin(lfutil.standin(lfile)))
 
         try:
             ctx = repo[opts.get('rev')]
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/mq.py
--- a/hgext/mq.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/mq.py	Fri Jun 15 22:59:53 2012 +0900
@@ -565,7 +565,7 @@
         if not os.path.exists(undo):
             return
         try:
-            os.unlink(undo)
+            util.vfs().unlink(undo)
         except OSError, inst:
             self.ui.warn(_('error removing undo: %s\n') % str(inst))
 
@@ -825,8 +825,9 @@
             r = self.qrepo()
             if r:
                 r[None].forget(patches)
+            vfs = util.vfs()
             for p in patches:
-                os.unlink(self.join(p))
+                vfs.unlink(self.join(p))
 
         qfinished = []
         if numrevs:
@@ -1084,7 +1085,7 @@
             except Exception:
                 patchpath = self.join(patchfn)
                 try:
-                    os.unlink(patchpath)
+                    util.vfs().unlink(patchpath)
                 except OSError:
                     self.ui.warn(_('error unlinking %s\n') % patchpath)
                 raise
@@ -1661,7 +1662,7 @@
         if not create and os.path.isdir(self.path):
             raise util.Abort(_("patch queue directory already exists"))
         try:
-            os.mkdir(self.path)
+            util.vfs().mkdir(self.path)
         except OSError, inst:
             if inst.errno != errno.EEXIST or not create:
                 raise
@@ -1726,7 +1727,7 @@
                 displayname(pfx, patch, state)
         else:
             msng_list = []
-            for root, dirs, files in os.walk(self.path):
+            for root, dirs, files in util.vfs().walk(self.path):
                 d = root[len(self.path) + 1:]
                 for f in files:
                     fl = os.path.join(d, f)
@@ -2668,7 +2669,7 @@
 
 def lastsavename(path):
     (directory, base) = os.path.split(path)
-    names = os.listdir(directory)
+    names = util.vfs().listdir(directory)
     namere = re.compile("%s.([0-9]+)" % base)
     maxindex = None
     maxname = None
@@ -2812,7 +2813,7 @@
 
     destdir = os.path.dirname(absdest)
     if not os.path.isdir(destdir):
-        os.makedirs(destdir)
+        util.vfs().makedirs(destdir)
     util.rename(q.join(patch), absdest)
     r = q.qrepo()
     if r and patch in r.dirstate:
@@ -3486,7 +3487,7 @@
             raise util.Abort(_('only a local queue repository '
                                'may be initialized'))
     else:
-        repopath = cmdutil.findrepo(os.getcwd())
+        repopath = cmdutil.findrepo(util.vfs().getcwd())
         if not repopath:
             raise util.Abort(_('there is no Mercurial repository here '
                                '(.hg not found)'))
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/patchbomb.py
--- a/hgext/patchbomb.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/patchbomb.py	Fri Jun 15 22:59:53 2012 +0900
@@ -303,11 +303,12 @@
             fp.close()
             return data
         finally:
+            vfs = util.vfs()
             try:
-                os.unlink(tmpfn)
+                vfs.unlink(tmpfn)
             except OSError:
                 pass
-            os.rmdir(tmpdir)
+            vfs.rmdir(tmpdir)
 
     if not (opts.get('test') or mbox):
         # really sending
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/purge.py
--- a/hgext/purge.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/purge.py	Fri Jun 15 22:59:53 2012 +0900
@@ -26,7 +26,7 @@
 
 from mercurial import util, commands, cmdutil, scmutil
 from mercurial.i18n import _
-import os, stat
+import stat
 
 cmdtable = {}
 command = cmdutil.command(cmdtable)
@@ -84,16 +84,17 @@
         else:
             ui.write('%s%s' % (name, eol))
 
+    vfs = util.vfs()
     def removefile(path):
         try:
-            os.remove(path)
+            vfs.remove(path)
         except OSError:
             # read-only files cannot be unlinked under Windows
-            s = os.stat(path)
+            s = vfs.stat(path)
             if (s.st_mode & stat.S_IWRITE) != 0:
                 raise
-            os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
-            os.remove(path)
+            vfs.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
+            vfs.remove(path)
 
     directories = []
     match = scmutil.match(repo[None], dirs, opts)
@@ -105,6 +106,6 @@
         remove(removefile, f)
 
     for f in sorted(directories, reverse=True):
-        if match(f) and not os.listdir(repo.wjoin(f)):
+        if match(f) and not vfs.listdir(repo.wjoin(f)):
             ui.note(_('removing directory %s\n') % f)
-            remove(os.rmdir, f)
+            remove(vfs.rmdir, f)
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/record.py
--- a/hgext/record.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/record.py	Fri Jun 15 22:59:53 2012 +0900
@@ -277,6 +277,7 @@
             return skipall, skipfile, skipall, newpatches
         if skipfile is not None:
             return skipfile, skipfile, skipall, newpatches
+        vfs = util.vfs()
         while True:
             resps = _('[Ynesfdaq?]')
             choices = (_('&Yes, record this change'),
@@ -349,7 +350,7 @@
                     ncpatchfp.seek(0)
                     newpatches = parsepatch(ncpatchfp)
                 finally:
-                    os.unlink(patchfn)
+                    vfs.unlink(patchfn)
                     del ncpatchfp
                 # Signal that the chunk shouldn't be applied as-is, but
                 # provide the new patch to be used instead.
@@ -496,6 +497,7 @@
         raise util.Abort(_('running non-interactively, use %s instead') %
                          cmdsuggest)
 
+    vfs = util.vfs()
     def recordfunc(ui, repo, message, match, opts):
         """This is generic record driver.
 
@@ -556,7 +558,7 @@
         if tobackup:
             backupdir = repo.join('record-backups')
             try:
-                os.mkdir(backupdir)
+                vfs.mkdir(backupdir)
             except OSError, err:
                 if err.errno != errno.EEXIST:
                     raise
@@ -600,12 +602,12 @@
             # it is important to first chdir to repo root -- we'll call
             # a highlevel command with list of pathnames relative to
             # repo root
-            cwd = os.getcwd()
-            os.chdir(repo.root)
+            cwd = vfs.getcwd()
+            vfs.chdir(repo.root)
             try:
                 commitfunc(ui, repo, *newfiles, **opts)
             finally:
-                os.chdir(cwd)
+                vfs.chdir(cwd)
 
             return 0
         finally:
@@ -622,9 +624,9 @@
                     # notice the file's mtime before we've finished
                     # writing it.
                     shutil.copystat(tmpname, repo.wjoin(realname))
-                    os.unlink(tmpname)
+                    vfs.unlink(tmpname)
                 if tobackup:
-                    os.rmdir(backupdir)
+                    vfs.rmdir(backupdir)
             except OSError:
                 pass
 
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/relink.py
--- a/hgext/relink.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/relink.py	Fri Jun 15 22:59:53 2012 +0900
@@ -77,13 +77,14 @@
     pos = 0
     ui.status(_("tip has %d files, estimated total number of files: %s\n")
               % (live, total))
-    for dirpath, dirnames, filenames in os.walk(src):
+    vfs = util.vfs()
+    for dirpath, dirnames, filenames in vfs.walk(src):
         dirnames.sort()
         relpath = dirpath[len(src) + seplen:]
         for filename in sorted(filenames):
             if filename[-2:] not in ('.d', '.i'):
                 continue
-            st = os.stat(os.path.join(dirpath, filename))
+            st = vfs.stat(os.path.join(dirpath, filename))
             if not stat.S_ISREG(st.st_mode):
                 continue
             pos += 1
@@ -97,7 +98,7 @@
 def prune(candidates, src, dst, ui):
     def linkfilter(src, dst, st):
         try:
-            ts = os.stat(dst)
+            ts = util.vfs().stat(dst)
         except OSError:
             # Destination doesn't have this file?
             return False
@@ -130,15 +131,16 @@
     return targets
 
 def do_relink(src, dst, files, ui):
+    vfs = util.vfs()
     def relinkfile(src, dst):
         bak = dst + '.bak'
-        os.rename(dst, bak)
+        vfs.rename(dst, bak)
         try:
             util.oslink(src, dst)
         except OSError:
-            os.rename(bak, dst)
+            vfs.rename(bak, dst)
             raise
-        os.remove(bak)
+        vfs.remove(bak)
 
     CHUNKLEN = 65536
     relinked = 0
diff -r 622aa57a90b1 -r a14b63be9a04 hgext/transplant.py
--- a/hgext/transplant.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/hgext/transplant.py	Fri Jun 15 22:59:53 2012 +0900
@@ -55,7 +55,7 @@
     def write(self):
         if self.dirty and self.transplantfile:
             if not os.path.isdir(self.path):
-                os.mkdir(self.path)
+                util.vfs().mkdir(self.path)
             fp = self.opener(self.transplantfile, 'w')
             for list in self.transplants.itervalues():
                 for t in list:
@@ -115,6 +115,7 @@
             wlock = repo.wlock()
             lock = repo.lock()
             tr = repo.transaction('transplant')
+            vfs = util.vfs()
             for rev in revs:
                 node = revmap[rev]
                 revstr = '%s:%s' % (rev, short(node))
@@ -195,7 +196,7 @@
                                               short(n)))
                     finally:
                         if patchfile:
-                            os.unlink(patchfile)
+                            vfs.unlink(patchfile)
             tr.close()
             if pulls:
                 repo.pull(source, heads=pulls)
@@ -231,7 +232,7 @@
                         out=self.ui.fout)
             user, date, msg = self.parselog(file(headerfile))[1:4]
         finally:
-            os.unlink(headerfile)
+            util.vfs().unlink(headerfile)
 
         return (user, date, msg)
 
@@ -264,7 +265,7 @@
             except Exception, inst:
                 seriespath = os.path.join(self.path, 'series')
                 if os.path.exists(seriespath):
-                    os.unlink(seriespath)
+                    util.vfs().unlink(seriespath)
                 p1 = repo.dirstate.p1()
                 p2 = node
                 self.log(user, date, message, p1, p2, merge=merge)
@@ -310,7 +311,7 @@
         revmap = {}
         for n in nodes:
             revmap[source.changelog.rev(n)] = n
-        os.unlink(seriespath)
+        util.vfs().unlink(seriespath)
 
         self.apply(repo, source, revmap, merges, opts)
 
@@ -371,7 +372,7 @@
             return
 
         if not os.path.isdir(self.path):
-            os.mkdir(self.path)
+            util.vfs().mkdir(self.path)
         series = self.opener('series', 'w')
         for rev in sorted(revmap):
             series.write(revlog.hex(revmap[rev]) + '\n')
@@ -410,7 +411,7 @@
         '''journal changelog metadata for later recover'''
 
         if not os.path.isdir(self.path):
-            os.mkdir(self.path)
+            util.vfs().mkdir(self.path)
         fp = self.opener('journal', 'w')
         fp.write('# User %s\n' % user)
         fp.write('# Date %s\n' % date)
@@ -428,7 +429,7 @@
         '''remove changelog journal'''
         absdst = os.path.join(self.path, 'journal')
         if os.path.exists(absdst):
-            os.unlink(absdst)
+            util.vfs().unlink(absdst)
 
     def transplantfilter(self, repo, source, root):
         def matchfn(node):
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/archival.py
--- a/mercurial/archival.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/archival.py	Fri Jun 15 22:59:53 2012 +0900
@@ -197,7 +197,7 @@
         f.write(data)
         f.close()
         destfile = os.path.join(self.basedir, name)
-        os.chmod(destfile, mode)
+        util.vfs().chmod(destfile, mode)
 
     def done(self):
         pass
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/bookmarks.py
--- a/mercurial/bookmarks.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/bookmarks.py	Fri Jun 15 22:59:53 2012 +0900
@@ -8,7 +8,7 @@
 from mercurial.i18n import _
 from mercurial.node import hex
 from mercurial import encoding, error, util
-import errno, os
+import errno
 
 def valid(mark):
     for c in (':', '\0', '\n', '\r'):
@@ -94,7 +94,7 @@
 
         # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
         try:
-            os.utime(repo.sjoin('00changelog.i'), None)
+            util.vfs().utime(repo.sjoin('00changelog.i'), None)
         except OSError:
             pass
 
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/bundlerepo.py	Fri Jun 15 22:59:53 2012 +0900
@@ -265,7 +265,7 @@
         """Close assigned bundle file immediately."""
         self.bundle.close()
         if self.tempfile is not None:
-            os.unlink(self.tempfile)
+            util.vfs().unlink(self.tempfile)
         if self._tempparent:
             shutil.rmtree(self._tempparent, True)
 
@@ -273,7 +273,7 @@
         return False
 
     def getcwd(self):
-        return os.getcwd() # always outside the repo
+        return util.vfs().getcwd() # always outside the repo
 
     def _writebranchcache(self, branches, tip, tiprev):
         # don't overwrite the disk cache with bundle-augmented data
@@ -283,15 +283,16 @@
     if create:
         raise util.Abort(_('cannot create new bundle repository'))
     parentpath = ui.config("bundle", "mainreporoot", "")
+    vfs = util.vfs()
     if not parentpath:
         # try to find the correct path to the working directory repo
-        parentpath = cmdutil.findrepo(os.getcwd())
+        parentpath = cmdutil.findrepo(vfs.getcwd())
         if parentpath is None:
             parentpath = ''
     if parentpath:
         # Try to make the full path relative so we get a nice, short URL.
         # In particular, we don't want temp dir names in test outputs.
-        cwd = os.getcwd()
+        cwd = vfs.getcwd()
         if parentpath == cwd:
             parentpath = ''
         else:
@@ -334,10 +335,11 @@
     tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
                                        force=force)
     common, incoming, rheads = tmp
+    vfs = util.vfs()
     if not incoming:
         try:
             if bundlename:
-                os.unlink(bundlename)
+                vfs.unlink(bundlename)
         except OSError:
             pass
         return other, [], other.close
@@ -373,7 +375,7 @@
         if bundlerepo:
             bundlerepo.close()
         if bundle:
-            os.unlink(bundle)
+            vfs.unlink(bundle)
         other.close()
 
     return (localrepo, csets, cleanup)
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/byterange.py
--- a/mercurial/byterange.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/byterange.py	Fri Jun 15 22:59:53 2012 +0900
@@ -17,7 +17,7 @@
 
 # $Id: byterange.py,v 1.9 2005/02/14 21:55:07 mstenner Exp $
 
-import os
+import util
 import stat
 import urllib
 import urllib2
@@ -201,7 +201,7 @@
         host = req.get_host()
         file = req.get_selector()
         localfile = urllib.url2pathname(file)
-        stats = os.stat(localfile)
+        stats = util.vfs().stat(localfile)
         size = stats[stat.ST_SIZE]
         modified = email.Utils.formatdate(stats[stat.ST_MTIME])
         mtype = mimetypes.guess_type(file)[0]
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/changegroup.py
--- a/mercurial/changegroup.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/changegroup.py	Fri Jun 15 22:59:53 2012 +0900
@@ -110,7 +110,7 @@
         if fh is not None:
             fh.close()
         if cleanup is not None:
-            os.unlink(cleanup)
+            util.vfs().unlink(cleanup)
 
 def decompressor(fh, alg):
     if alg == 'UN':
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/cmdutil.py
--- a/mercurial/cmdutil.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/cmdutil.py	Fri Jun 15 22:59:53 2012 +0900
@@ -228,7 +228,7 @@
             raise error.CommandError(cmd, _('invalid arguments'))
         if not os.path.isfile(file_):
             raise util.Abort(_("revlog '%s' not found") % file_)
-        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
+        r = revlog.revlog(scmutil.opener(util.vfs().getcwd(), audit=False),
                           file_[:-2] + ".i")
     return r
 
@@ -266,6 +266,7 @@
     # abssrc: hgsep
     # relsrc: ossep
     # otarget: ossep
+    vfs = util.vfs()
     def copyfile(abssrc, relsrc, otarget, exact):
         abstarget = scmutil.canonpath(repo.root, cwd, otarget)
         if '/' in abstarget:
@@ -318,14 +319,14 @@
         elif not dryrun:
             try:
                 if exists:
-                    os.unlink(target)
+                    vfs.unlink(target)
                 targetdir = os.path.dirname(target) or '.'
                 if not os.path.isdir(targetdir):
-                    os.makedirs(targetdir)
+                    vfs.makedirs(targetdir)
                 if samefile:
                     tmp = target + "~hgrename"
-                    os.rename(src, tmp)
-                    os.rename(tmp, target)
+                    vfs.rename(src, tmp)
+                    vfs.rename(tmp, target)
                 else:
                     util.copyfile(src, target)
                 srcexists = True
@@ -462,6 +463,7 @@
     runargs=None, appendpid=False):
     '''Run a command as a service.'''
 
+    vfs = util.vfs()
     if opts['daemon'] and not opts['daemon_pipefds']:
         # Signal child process startup with file removal
         lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
@@ -486,7 +488,7 @@
                 raise util.Abort(_('child process failed to start'))
         finally:
             try:
-                os.unlink(lockpath)
+                vfs.unlink(lockpath)
             except OSError, e:
                 if e.errno != errno.ENOENT:
                     raise
@@ -510,15 +512,15 @@
             os.setsid()
         except AttributeError:
             pass
-        os.unlink(lockpath)
+        vfs.unlink(lockpath)
         util.hidewindow()
         sys.stdout.flush()
         sys.stderr.flush()
 
-        nullfd = os.open(util.nulldev, os.O_RDWR)
+        nullfd = vfs.open(util.nulldev, os.O_RDWR)
         logfilefd = nullfd
         if logfile:
-            logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
+            logfilefd = vfs.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
         os.dup2(nullfd, 0)
         os.dup2(logfilefd, 1)
         os.dup2(logfilefd, 2)
@@ -1448,11 +1450,12 @@
         edittext.append(_("HG: no files changed"))
     edittext.append("")
     # run editor in the repository root
-    olddir = os.getcwd()
-    os.chdir(repo.root)
+    vfs = util.vfs()
+    olddir = vfs.getcwd()
+    vfs.chdir(repo.root)
     text = repo.ui.edit("\n".join(edittext), ctx.user())
     text = re.sub("(?m)^HG:.*(\n|$)", "", text)
-    os.chdir(olddir)
+    vfs.chdir(olddir)
 
     if not text.strip():
         raise util.Abort(_("empty commit message"))
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/commands.py
--- a/mercurial/commands.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/commands.py	Fri Jun 15 22:59:53 2012 +0900
@@ -646,7 +646,7 @@
     if reset:
         p = repo.join("bisect.state")
         if os.path.exists(p):
-            os.unlink(p)
+            util.vfs().unlink(p)
         return
 
     state = hbisect.load_state(repo)
@@ -1398,7 +1398,8 @@
     """find the ancestor revision of two revisions in a given index"""
     if len(args) == 3:
         index, rev1, rev2 = args
-        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
+        r = revlog.revlog(scmutil.opener(util.vfs().getcwd(), audit=False),
+                          index)
         lookup = r.lookup
     elif len(args) == 2:
         if not repo:
@@ -1692,7 +1693,8 @@
     spaces = opts.get('spaces')
     dots = opts.get('dots')
     if file_:
-        rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
+        rlog = revlog.revlog(scmutil.opener(util.vfs().getcwd(), audit=False),
+                             file_)
         revs = set((int(r) for r in revs))
         def events():
             for r in rlog:
@@ -1851,7 +1853,7 @@
     ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
     ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
                                 and 'yes' or 'no'))
-    os.unlink('.debugfsinfo')
+    util.vfs().unlink('.debugfsinfo')
 
 @command('debuggetbundle',
     [('H', 'head', [], _('id of head node'), _('ID')),
@@ -1946,7 +1948,8 @@
         if len(filelog):
             r = filelog
     if not r:
-        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
+        r = revlog.revlog(scmutil.opener(util.vfs().getcwd(), audit=False),
+                          file_)
     ui.write("digraph G {\n")
     for i in r:
         node = r.node(i)
@@ -3618,6 +3621,7 @@
             repo.rollback()
             raise util.Abort(_('patch is damaged or loses information'))
 
+    vfs = util.vfs()
     def tryone(ui, hunk, parents):
         tmpname, message, user, date, branch, nodeid, p1, p2 = \
             patch.extract(ui, hunk)
@@ -3719,7 +3723,7 @@
                 msg = _('created %s') % short(n)
             return (msg, n)
         finally:
-            os.unlink(tmpname)
+            vfs.unlink(tmpname)
 
     try:
         try:
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/commandserver.py
--- a/mercurial/commandserver.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/commandserver.py	Fri Jun 15 22:59:53 2012 +0900
@@ -7,7 +7,7 @@
 
 from i18n import _
 import struct
-import sys, os
+import sys
 import dispatch, encoding, util
 
 logfile = None
@@ -131,7 +131,7 @@
     based stream to stdout.
     """
     def __init__(self, ui, repo, mode):
-        self.cwd = os.getcwd()
+        self.cwd = util.vfs().getcwd()
 
         logpath = ui.config("cmdserver", "log", None)
         if logpath:
@@ -195,7 +195,7 @@
 
         # restore old cwd
         if '--cwd' in args:
-            os.chdir(self.cwd)
+            util.vfs().chdir(self.cwd)
 
         self.cresult.write(struct.pack('>i', int(ret)))
 
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/context.py
--- a/mercurial/context.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/context.py	Fri Jun 15 22:59:53 2012 +0900
@@ -971,11 +971,12 @@
         ui, ds = self._repo.ui, self._repo.dirstate
         try:
             rejected = []
+            vfs = util.vfs()
             for f in list:
                 scmutil.checkportable(ui, join(f))
                 p = self._repo.wjoin(f)
                 try:
-                    st = os.lstat(p)
+                    st = vfs.lstat(p)
                 except OSError:
                     ui.warn(_("%s does not exist!\n") % join(f))
                     rejected.append(f)
@@ -1118,11 +1119,12 @@
         return []
 
     def size(self):
-        return os.lstat(self._repo.wjoin(self._path)).st_size
+        return util.vfs().lstat(self._repo.wjoin(self._path)).st_size
     def date(self):
         t, tz = self._changectx.date()
         try:
-            return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
+            vfs = util.vfs()
+            return (int(vfs.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
         except OSError, err:
             if err.errno != errno.ENOENT:
                 raise
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/dirstate.py
--- a/mercurial/dirstate.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/dirstate.py	Fri Jun 15 22:59:53 2012 +0900
@@ -184,7 +184,7 @@
             return fallback
 
     def getcwd(self):
-        cwd = os.getcwd()
+        cwd = util.vfs().getcwd()
         if cwd == self._root:
             return ''
         # self._root ends with a path separator if self._root is '/' or 'C:\'
@@ -332,7 +332,7 @@
         '''Mark a file normal and clean.'''
         self._dirty = True
         self._addpath(f)
-        s = os.lstat(self._join(f))
+        s = util.vfs().lstat(self._join(f))
         mtime = int(s.st_mtime)
         self._map[f] = ('n', s.st_mode, s.st_size, mtime)
         if f in self._copymap:
@@ -407,7 +407,7 @@
         if self._pl[1] == nullid:
             return self.normallookup(f)
         self._dirty = True
-        s = os.lstat(self._join(f))
+        s = util.vfs().lstat(self._join(f))
         self._addpath(f)
         self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
         if f in self._copymap:
@@ -592,7 +592,7 @@
         dmap = self._map
         normpath = util.normpath
         listdir = osutil.listdir
-        lstat = os.lstat
+        lstat = util.vfs().lstat
         getkind = stat.S_IFMT
         dirkind = stat.S_IFDIR
         regkind = stat.S_IFREG
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/dispatch.py
--- a/mercurial/dispatch.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/dispatch.py	Fri Jun 15 22:59:53 2012 +0900
@@ -522,7 +522,7 @@
     Takes paths in [cwd]/.hg/hgrc into account."
     """
     try:
-        wd = os.getcwd()
+        wd = util.vfs().getcwd()
     except OSError, e:
         raise util.Abort(_("error getting current working directory: %s") %
                          e.strerror)
@@ -582,6 +582,7 @@
 def _dispatch(req):
     args = req.args
     ui = req.ui
+    vfs = util.vfs()
 
     # read --config before doing anything else
     # (e.g. to change trust settings for reading .hg/hgrc)
@@ -590,7 +591,7 @@
     # check for cwd
     cwd = _earlygetopt(['--cwd'], args)
     if cwd:
-        os.chdir(cwd[-1])
+        vfs.chdir(cwd[-1])
 
     rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
     path, lui = _getlocal(ui, rpath)
@@ -723,7 +724,7 @@
                     if not path:
                         raise error.RepoError(_("no repository found in '%s'"
                                                 " (.hg not found)")
-                                              % os.getcwd())
+                                              % vfs.getcwd())
                     raise
         if repo:
             ui = repo.ui
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/extensions.py
--- a/mercurial/extensions.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/extensions.py	Fri Jun 15 22:59:53 2012 +0900
@@ -194,7 +194,7 @@
     import hgext
     extpath = os.path.dirname(os.path.abspath(hgext.__file__))
     try: # might not be a filesystem path
-        files = os.listdir(extpath)
+        files = util.vfs().listdir(extpath)
     except OSError:
         return {}
 
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/filemerge.py
--- a/mercurial/filemerge.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/filemerge.py	Fri Jun 15 22:59:53 2012 +0900
@@ -271,6 +271,7 @@
     fcd = local file context for current/destination file
     """
 
+    vfs = util.vfs()
     def temp(prefix, ctx):
         pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
         (fd, name) = tempfile.mkstemp(prefix=pre)
@@ -325,10 +326,10 @@
             if onfailure:
                 ui.warn(onfailure % fd)
         else:
-            os.unlink(back)
+            vfs.unlink(back)
 
-        os.unlink(b)
-        os.unlink(c)
+        vfs.unlink(b)
+        vfs.unlink(c)
         return r
 
     if not r and (_toolbool(ui, tool, "checkconflicts") or
@@ -359,10 +360,10 @@
         if onfailure:
             ui.warn(onfailure % fd)
     else:
-        os.unlink(back)
+        vfs.unlink(back)
 
-    os.unlink(b)
-    os.unlink(c)
+    vfs.unlink(b)
+    vfs.unlink(c)
     return r
 
 # tell hggettext to extract docstrings from these functions:
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/hg.py
--- a/mercurial/hg.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/hg.py	Fri Jun 15 22:59:53 2012 +0900
@@ -137,7 +137,7 @@
         raise util.Abort(_('destination already exists'))
 
     if not os.path.isdir(root):
-        os.mkdir(root)
+        util.vfs().mkdir(root)
     util.makedir(roothg, notindexed=True)
 
     requirements = ''
@@ -184,6 +184,7 @@
         hardlink = None
         num = 0
         srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
+        vfs = util.vfs()
         for f in srcrepo.store.copylist():
             if srcpublishing and f.endswith('phaseroots'):
                 continue
@@ -191,7 +192,7 @@
             dst = os.path.join(destpath, f)
             dstbase = os.path.dirname(dst)
             if dstbase and not os.path.exists(dstbase):
-                os.mkdir(dstbase)
+                vfs.mkdir(dstbase)
             if os.path.exists(src):
                 if dst.endswith('data'):
                     # lock to avoid premature writing to the target
@@ -244,6 +245,7 @@
     branch: branches to clone
     """
 
+    vfs = util.vfs()
     if isinstance(source, str):
         origsource = ui.expandpath(source)
         source, branch = parseurl(origsource, branch)
@@ -266,7 +268,7 @@
     if os.path.exists(dest):
         if not os.path.isdir(dest):
             raise util.Abort(_("destination '%s' already exists") % dest)
-        elif os.listdir(dest):
+        elif vfs.listdir(dest):
             raise util.Abort(_("destination '%s' is not empty") % dest)
 
     class DirCleanup(object):
@@ -306,7 +308,7 @@
             srcrepo.hook('preoutgoing', throw=True, source='clone')
             hgdir = os.path.realpath(os.path.join(dest, ".hg"))
             if not os.path.exists(dest):
-                os.mkdir(dest)
+                vfs.mkdir(dest)
             else:
                 # only clean up directories we create ourselves
                 dircleanup.dir_ = hgdir
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/hgweb/common.py
--- a/mercurial/hgweb/common.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/hgweb/common.py	Fri Jun 15 22:59:53 2012 +0900
@@ -6,6 +6,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from mercurial import util
 import errno, mimetypes, os
 
 HTTP_OK = 200
@@ -108,10 +109,11 @@
 def get_stat(spath):
     """stat changelog if it exists, spath otherwise"""
     cl_path = os.path.join(spath, "00changelog.i")
+    vfs = util.vfs()
     if os.path.exists(cl_path):
-        return os.stat(cl_path)
+        return vfs.stat(cl_path)
     else:
-        return os.stat(spath)
+        return vfs.stat(spath)
 
 def get_mtime(spath):
     return get_stat(spath).st_mtime
@@ -138,7 +140,7 @@
         if os.path.exists(path):
             break
     try:
-        os.stat(path)
+        util.vfs().stat(path)
         ct = mimetypes.guess_type(path)[0] or "text/plain"
         req.respond(HTTP_OK, ct, length = os.path.getsize(path))
         fp = open(path, 'rb')
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/hook.py
--- a/mercurial/hook.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/hook.py	Fri Jun 15 22:59:53 2012 +0900
@@ -112,7 +112,7 @@
     if repo:
         cwd = repo.root
     else:
-        cwd = os.getcwd()
+        cwd = util.vfs().getcwd()
     if 'HG_URL' in env and env['HG_URL'].startswith('remote:http'):
         r = util.system(cmd, environ=env, cwd=cwd, out=ui)
     else:
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/httprepo.py
--- a/mercurial/httprepo.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/httprepo.py	Fri Jun 15 22:59:53 2012 +0900
@@ -9,7 +9,7 @@
 from node import nullid
 from i18n import _
 import changegroup, statichttprepo, error, httpconnection, url, util, wireproto
-import os, urllib, urllib2, zlib, httplib
+import urllib, urllib2, zlib, httplib
 import errno, socket
 
 def zgenerator(f):
@@ -207,7 +207,7 @@
                 raise util.Abort(err.args[1])
         finally:
             fp.close()
-            os.unlink(tempname)
+            util.vfs().unlink(tempname)
 
     def _abort(self, exception):
         raise exception
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/localrepo.py
--- a/mercurial/localrepo.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/localrepo.py	Fri Jun 15 22:59:53 2012 +0900
@@ -59,7 +59,7 @@
                 util.makedir(self.path, notindexed=True)
                 requirements = ["revlogv1"]
                 if self.ui.configbool('format', 'usestore', True):
-                    os.mkdir(os.path.join(self.path, "store"))
+                    util.vfs().mkdir(os.path.join(self.path, "store"))
                     requirements.append("store")
                     if self.ui.configbool('format', 'usefncache', True):
                         requirements.append("fncache")
@@ -712,7 +712,7 @@
 
     def wread(self, filename):
         if self._link(filename):
-            data = os.readlink(self.wjoin(filename))
+            data = util.vfs().readlink(self.wjoin(filename))
         else:
             data = self.wopener.read(filename)
         return self._filter(self._encodefilterpats, filename, data)
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/merge.py
--- a/mercurial/merge.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/merge.py	Fri Jun 15 22:59:53 2012 +0900
@@ -311,6 +311,7 @@
     ms.reset(wctx.p1().node())
     moves = []
     action.sort(key=actionkey)
+    vfs = util.vfs()
 
     # prescan for merges
     for a in action:
@@ -342,7 +343,7 @@
         if os.path.lexists(repo.wjoin(f)):
             repo.ui.debug("removing %s\n" % f)
             audit(f)
-            os.unlink(repo.wjoin(f))
+            vfs.unlink(repo.wjoin(f))
 
     numupdates = len(action)
     for i, a in enumerate(action):
@@ -382,7 +383,7 @@
                 and os.path.lexists(repo.wjoin(f))):
                 repo.ui.debug("removing %s\n" % f)
                 audit(f)
-                os.unlink(repo.wjoin(f))
+                vfs.unlink(repo.wjoin(f))
         elif m == "g": # get
             flags = a[2]
             repo.ui.note(_("getting %s\n") % f)
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/patch.py
--- a/mercurial/patch.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/patch.py	Fri Jun 15 22:59:53 2012 +0900
@@ -167,6 +167,7 @@
 
     fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
     tmpfp = os.fdopen(fd, 'w')
+    vfs = util.vfs()
     try:
         msg = email.Parser.Parser().parse(fileobj)
 
@@ -247,14 +248,14 @@
                 message += '\n' + payload
     except: # re-raises
         tmpfp.close()
-        os.unlink(tmpname)
+        vfs.unlink(tmpname)
         raise
 
     if subject and not message.startswith(subject):
         message = '%s\n%s' % (subject, message)
     tmpfp.close()
     if not diffs_seen:
-        os.unlink(tmpname)
+        vfs.unlink(tmpname)
         return None, message, user, date, branch, None, None, None
     p1 = parents and parents.pop(0) or None
     p2 = parents and parents.pop(0) or None
@@ -416,11 +417,12 @@
 
     def getfile(self, fname):
         path = self._join(fname)
+        vfs = util.vfs()
         if os.path.islink(path):
-            return (os.readlink(path), (True, False))
+            return (vfs.readlink(path), (True, False))
         isexec = False
         try:
-            isexec = os.lstat(path).st_mode & 0100 != 0
+            isexec = vfs.lstat(path).st_mode & 0100 != 0
         except OSError, e:
             if e.errno != errno.ENOENT:
                 raise
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/pure/osutil.py
--- a/mercurial/pure/osutil.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/pure/osutil.py	Fri Jun 15 22:59:53 2012 +0900
@@ -5,6 +5,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from mercurial import util
 import os
 import stat as statmod
 
@@ -41,12 +42,13 @@
     '''
     result = []
     prefix = path
+    vfs = util.vfs()
     if not prefix.endswith(os.sep):
         prefix += os.sep
-    names = os.listdir(path)
+    names = vfs.listdir(path)
     names.sort()
     for fn in names:
-        st = os.lstat(prefix + fn)
+        st = vfs.lstat(prefix + fn)
         if fn == skip and statmod.S_ISDIR(st.st_mode):
             return []
         if stat:
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/repair.py
--- a/mercurial/repair.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/repair.py	Fri Jun 15 22:59:53 2012 +0900
@@ -6,7 +6,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from mercurial import changegroup, bookmarks
+from mercurial import changegroup, bookmarks, util
 from mercurial.node import short
 from mercurial.i18n import _
 import os
@@ -17,7 +17,7 @@
     cg = repo.changegroupsubset(bases, heads, 'strip')
     backupdir = repo.join("strip-backup")
     if not os.path.isdir(backupdir):
-        os.mkdir(backupdir)
+        util.vfs().mkdir(backupdir)
     name = os.path.join(backupdir, "%s-%s.hg" % (short(node), suffix))
     if compress:
         bundletype = "HG10BZ"
@@ -117,6 +117,7 @@
 
     tr = repo.transaction("strip")
     offset = len(tr.entries)
+    vfs = util.vfs()
 
     try:
         tr.startgroup()
@@ -147,12 +148,12 @@
                 repo.ui.popbuffer()
             f.close()
             if not keeppartialbundle:
-                os.unlink(chgrpfile)
+                vfs.unlink(chgrpfile)
 
         # remove undo files
         for undofile in repo.undofiles():
             try:
-                os.unlink(undofile)
+                vfs.unlink(undofile)
             except OSError, e:
                 if e.errno != errno.ENOENT:
                     ui.warn(_('error removing %s: %s\n') % (undofile, str(e)))
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/scmutil.py
--- a/mercurial/scmutil.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/scmutil.py	Fri Jun 15 22:59:53 2012 +0900
@@ -120,6 +120,7 @@
         parts.pop()
         normparts.pop()
         prefixes = []
+        vfs = util.vfs()
         while parts:
             prefix = os.sep.join(parts)
             normprefix = os.sep.join(normparts)
@@ -127,7 +128,7 @@
                 break
             curpath = os.path.join(self.root, prefix)
             try:
-                st = os.lstat(curpath)
+                st = vfs.lstat(curpath)
             except OSError, err:
                 # EINVAL can be raised as invalid path syntax under win32.
                 # They must be ignored for patterns can be checked too.
@@ -213,7 +214,7 @@
     def _fixfilemode(self, name):
         if self.createmode is None:
             return
-        os.chmod(name, self.createmode & 0666)
+        util.vfs().chmod(name, self.createmode & 0666)
 
     def __call__(self, path, mode="r", text=False, atomictemp=False):
         if self._audit:
@@ -266,8 +267,9 @@
     def symlink(self, src, dst):
         self.auditor(dst)
         linkname = self.join(dst)
+        vfs = util.vfs()
         try:
-            os.unlink(linkname)
+            vfs.unlink(linkname)
         except OSError:
             pass
 
@@ -277,7 +279,7 @@
 
         if self._cansymlink:
             try:
-                os.symlink(src, linkname)
+                vfs.symlink(src, linkname)
             except OSError, err:
                 raise OSError(err.errno, _('could not symlink to %r: %s') %
                               (src, err.strerror), linkname)
@@ -328,11 +330,12 @@
         # `name', compare dev/inode numbers.  If they match, the list `rel'
         # holds the reversed list of components making up the relative file
         # name we want.
-        root_st = os.stat(root)
+        vfs = util.vfs()
+        root_st = vfs.stat(root)
         rel = []
         while True:
             try:
-                name_st = os.stat(name)
+                name_st = vfs.stat(name)
             except OSError:
                 name_st = None
             if name_st and util.samestat(name_st, root_st):
@@ -356,11 +359,12 @@
     def errhandler(err):
         if err.filename == path:
             raise err
+    vfs = util.vfs()
     samestat = getattr(os.path, 'samestat', None)
     if followsym and samestat is not None:
         def adddir(dirlst, dirname):
             match = False
-            dirstat = os.stat(dirname)
+            dirstat = vfs.stat(dirname)
             for lstdirstat in dirlst:
                 if samestat(dirstat, lstdirstat):
                     match = True
@@ -374,7 +378,7 @@
     if (seen_dirs is None) and followsym:
         seen_dirs = []
         adddir(seen_dirs, path)
-    for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
+    for root, dirs, files in vfs.walk(path, topdown=True, onerror=errhandler):
         dirs.sort()
         if '.hg' in dirs:
             yield root # found a repository
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/store.py
--- a/mercurial/store.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/store.py	Fri Jun 15 22:59:53 2012 +0900
@@ -224,7 +224,7 @@
 def _calcmode(path):
     try:
         # files in .hg/ will be created using this mode
-        mode = os.stat(path).st_mode
+        mode = util.vfs().stat(path).st_mode
             # avoid some useless chmods
         if (0777 & ~util.umask) == (0777 & mode):
             mode = None
@@ -394,10 +394,11 @@
         rewrite = False
         existing = []
         spath = self.path
+        vfs = util.vfs()
         for f in self.fncache:
             ef = self.encode(f)
             try:
-                st = os.stat(spath + '/' + ef)
+                st = vfs.stat(spath + '/' + ef)
                 yield f, ef, st.st_size
                 existing.append(f)
             except OSError:
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/subrepo.py
--- a/mercurial/subrepo.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/subrepo.py	Fri Jun 15 22:59:53 2012 +0900
@@ -772,20 +772,21 @@
             return
         self._ui.note(_('removing subrepo %s\n') % self._path)
 
+        vfs = util.vfs()
         def onerror(function, path, excinfo):
-            if function is not os.remove:
+            if function is not vfs.remove:
                 raise
             # read-only files cannot be unlinked under Windows
-            s = os.stat(path)
+            s = vfs.stat(path)
             if (s.st_mode & stat.S_IWRITE) != 0:
                 raise
-            os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
-            os.remove(path)
+            vfs.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
+            vfs.remove(path)
 
         path = self._ctx._repo.wjoin(self._path)
         shutil.rmtree(path, onerror=onerror)
         try:
-            os.removedirs(os.path.dirname(path))
+            vfs.removedirs(os.path.dirname(path))
         except OSError:
             pass
 
@@ -1174,14 +1175,15 @@
         # local-only history
         self._ui.note(_('removing subrepo %s\n') % self._relpath)
         self._gitcommand(['config', 'core.bare', 'true'])
-        for f in os.listdir(self._abspath):
+        vfs = util.vfs()
+        for f in vfs.listdir(self._abspath):
             if f == '.git':
                 continue
             path = os.path.join(self._abspath, f)
             if os.path.isdir(path) and not os.path.islink(path):
                 shutil.rmtree(path)
             else:
-                os.remove(path)
+                vfs.remove(path)
 
     def archive(self, ui, archiver, prefix):
         source, revision = self._state
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/transaction.py
--- a/mercurial/transaction.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/transaction.py	Fri Jun 15 22:59:53 2012 +0900
@@ -58,7 +58,7 @@
 
         self.file = util.posixfile(self.journal, "w")
         if createmode is not None:
-            os.chmod(self.journal, createmode & 0666)
+            util.vfs().chmod(self.journal, createmode & 0666)
 
     def __del__(self):
         if self.journal:
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/ui.py
--- a/mercurial/ui.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/ui.py	Fri Jun 15 22:59:53 2012 +0900
@@ -115,7 +115,7 @@
         if section in (None, 'paths'):
             # expand vars and ~
             # translate paths relative to root (or home) into absolute paths
-            root = root or os.getcwd()
+            root = root or util.vfs().getcwd()
             for c in self._tcfg, self._ucfg, self._ocfg:
                 for n, p in c.items('paths'):
                     if not p:
@@ -675,7 +675,7 @@
             t = f.read()
             f.close()
         finally:
-            os.unlink(name)
+            util.vfs().unlink(name)
 
         return t
 
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/util.py
--- a/mercurial/util.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/util.py	Fri Jun 15 22:59:53 2012 +0900
@@ -283,14 +283,15 @@
         fp.close()
         return r
     finally:
+        vfsobj = vfs()
         try:
             if inname:
-                os.unlink(inname)
+                vfsobj.unlink(inname)
         except OSError:
             pass
         try:
             if outname:
-                os.unlink(outname)
+                vfsobj.unlink(outname)
         except OSError:
             pass
 
@@ -438,7 +439,7 @@
         # subprocess kludge to work around issues in half-baked Python
         # ports, notably bichued/python:
         if not cwd is None:
-            os.chdir(cwd)
+            vfs().chdir(cwd)
         rc = os.system(cmd)
     else:
         env = dict(os.environ)
@@ -482,12 +483,13 @@
 
 def copyfile(src, dest):
     "copy a file, preserving mode and atime/mtime"
+    vfsobj = vfs()
     if os.path.islink(src):
         try:
-            os.unlink(dest)
+            vfsobj.unlink(dest)
         except OSError:
             pass
-        os.symlink(os.readlink(src), dest)
+        vfsobj.symlink(vfsobj.readlink(src), dest)
     else:
         try:
             shutil.copyfile(src, dest)
@@ -498,13 +500,14 @@
 def copyfiles(src, dst, hardlink=None):
     """Copy a directory tree using hardlinks if possible"""
 
+    vfsobj = vfs()
     if hardlink is None:
-        hardlink = (os.stat(src).st_dev ==
-                    os.stat(os.path.dirname(dst)).st_dev)
+        hardlink = (vfsobj.stat(src).st_dev ==
+                    vfsobj.stat(os.path.dirname(dst)).st_dev)
 
     num = 0
     if os.path.isdir(src):
-        os.mkdir(dst)
+        vfsobj.mkdir(dst)
         for name, kind in osutil.listdir(src):
             srcname = os.path.join(src, name)
             dstname = os.path.join(dst, name)
@@ -572,21 +575,22 @@
     checkosfilename = platform.checkosfilename
 
 def makelock(info, pathname):
+    vfsobj = vfs()
     try:
-        return os.symlink(info, pathname)
+        return vfsobj.symlink(info, pathname)
     except OSError, why:
         if why.errno == errno.EEXIST:
             raise
     except AttributeError: # no symlink in os
         pass
 
-    ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
+    ld = vfsobj.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
     os.write(ld, info)
     os.close(ld)
 
 def readlock(pathname):
     try:
-        return os.readlink(pathname)
+        return vfs().readlink(pathname)
     except OSError, why:
         if why.errno not in (errno.EINVAL, errno.ENOSYS):
             raise
@@ -602,7 +606,7 @@
     try:
         return os.fstat(fp.fileno())
     except AttributeError:
-        return os.stat(fp.name)
+        return vfs().stat(fp.name)
 
 # File system features
 
@@ -613,7 +617,8 @@
     Requires a path (like /foo/.hg) ending with a foldable final
     directory component.
     """
-    s1 = os.stat(path)
+    vfsobj = vfs()
+    s1 = vfsobj.stat(path)
     d, b = os.path.split(path)
     b2 = b.upper()
     if b == b2:
@@ -622,7 +627,7 @@
             return True # no evidence against case sensitivity
     p2 = os.path.join(d, b2)
     try:
-        s2 = os.stat(p2)
+        s2 = vfsobj.stat(p2)
         if s2 == s1:
             return False
         return True
@@ -678,20 +683,21 @@
     pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
     dir = os.path.normpath(root)
     result = []
+    vfsobj = vfs()
     for part, sep in pattern.findall(name):
         if sep:
             result.append(sep)
             continue
 
         if dir not in _fspathcache:
-            _fspathcache[dir] = os.listdir(dir)
+            _fspathcache[dir] = vfsobj.listdir(dir)
         contents = _fspathcache[dir]
 
         found = find(part, contents)
         if not found:
             # retry "once per directory" per "dirstate.walk" which
             # may take place for each patches of "hg qpush", for example
-            contents = os.listdir(dir)
+            contents = vfsobj.listdir(dir)
             _fspathcache[dir] = contents
             found = find(part, contents)
 
@@ -730,7 +736,7 @@
             fd.close()
         for f in (f1, f2):
             try:
-                os.unlink(f)
+                vfs().unlink(f)
             except OSError:
                 pass
 
@@ -797,7 +803,7 @@
         ifp.close()
         ofp.close()
     except: # re-raises
-        try: os.unlink(temp)
+        try: vfs().unlink(temp)
         except OSError: pass
         raise
     return temp
@@ -829,7 +835,7 @@
     def discard(self):
         if not self._fp.closed:
             try:
-                os.unlink(self._tempname)
+                vfs().unlink(self._tempname)
             except OSError:
                 pass
             self._fp.close()
@@ -840,8 +846,9 @@
 
 def makedirs(name, mode=None):
     """recursive directory creation with parent mode inheritance"""
+    vfsobj = vfs()
     try:
-        os.mkdir(name)
+        vfsobj.mkdir(name)
     except OSError, err:
         if err.errno == errno.EEXIST:
             return
@@ -851,9 +858,9 @@
         if parent == name:
             raise
         makedirs(parent, mode)
-        os.mkdir(name)
+        vfsobj.mkdir(name)
     if mode is not None:
-        os.chmod(name, mode)
+        vfsobj.chmod(name, mode)
 
 def readfile(path):
     fp = open(path, 'rb')
@@ -1800,3 +1807,48 @@
         return fd.isatty()
     except AttributeError:
         return False
+
+class _vfs(object):
+    def __init__(self):
+        self._osmod = os # rename "os" module for check-code.py
+    def chdir(self, *args, **kwargs):
+        return self._osmod.chdir(*args, **kwargs)
+    def chmod(self, *args, **kwargs):
+        return self._osmod.chmod(*args, **kwargs)
+    def getcwd(self):
+        return self._osmod.getcwd()
+    def listdir(self, *args, **kwargs):
+        return self._osmod.listdir(*args, **kwargs)
+    def lstat(self, *args, **kwargs):
+        return self._osmod.lstat(*args, **kwargs)
+    def makedirs(self, *args, **kwargs):
+        return self._osmod.makedirs(*args, **kwargs)
+    def mkdir(self, *args, **kwargs):
+        return self._osmod.mkdir(*args, **kwargs)
+    def open(self, *args, **kwargs):
+        return self._osmod.open(*args, **kwargs)
+    def readlink(self, *args, **kwargs):
+        return self._osmod.readlink(*args, **kwargs)
+    def remove(self, *args, **kwargs):
+        return self._osmod.remove(*args, **kwargs)
+    def removedirs(self, *args, **kwargs):
+        return self._osmod.removedirs(*args, **kwargs)
+    def rename(self, *args, **kwargs):
+        return self._osmod.rename(*args, **kwargs)
+    def rmdir(self, *args, **kwargs):
+        return self._osmod.rmdir(*args, **kwargs)
+    def stat(self, *args, **kwargs):
+        return self._osmod.stat(*args, **kwargs)
+    def symlink(self, *args, **kwargs):
+        return self._osmod.symlink(*args, **kwargs)
+    def unlink(self, *args, **kwargs):
+        return self._osmod.unlink(*args, **kwargs)
+    def utime(self, *args, **kwargs):
+        return self._osmod.utime(*args, **kwargs)
+    def walk(self, *args, **kwargs):
+        return self._osmod.walk(*args, **kwargs)
+
+_bvfs = _vfs()
+
+def vfs(mode=None):
+    return _bvfs
diff -r 622aa57a90b1 -r a14b63be9a04 mercurial/wireproto.py
--- a/mercurial/wireproto.py	Thu Jun 14 15:13:16 2012 -0500
+++ b/mercurial/wireproto.py	Fri Jun 15 22:59:53 2012 +0900
@@ -594,7 +594,7 @@
 
     finally:
         fp.close()
-        os.unlink(tempname)
+        util.vfs().unlink(tempname)
 
 commands = {
     'batch': (batch, 'cmds *'),


More information about the Mercurial-devel mailing list