[PATCH 6 of 6] scmutil.filecache: support watching over multiple files

Augie Fackler raf at durin42.com
Sun Nov 17 16:19:34 CST 2013


On Sat, Nov 16, 2013 at 03:21:12PM -0800, Siddharth Agarwal wrote:
> # HG changeset patch
> # User Siddharth Agarwal <sid0 at fb.com>
> # Date 1384637379 28800
> #      Sat Nov 16 13:29:39 2013 -0800
> # Node ID c3b07326434223e8957ea6e332d80f4cf5caa84a
> # Parent  c31031f519a1410a7ab92a0a0b8c263cf1e92161
> scmutil.filecache: support watching over multiple files

Queueing these.

>
> diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
> --- a/mercurial/scmutil.py
> +++ b/mercurial/scmutil.py
> @@ -924,23 +924,26 @@
>              entry.refresh()
>
>  class filecache(object):
> -    '''A property like decorator that tracks a file under .hg/ for updates.
> +    '''A property like decorator that tracks files under .hg/ for updates.
>
>      Records stat info when called in _filecache.
>
> -    On subsequent calls, compares old stat info with new info, and recreates
> -    the object when needed, updating the new stat info in _filecache.
> +    On subsequent calls, compares old stat info with new info, and recreates the
> +    object when any of the files changes, updating the new stat info in
> +    _filecache.
>
>      Mercurial either atomic renames or appends for files under .hg,
>      so to ensure the cache is reliable we need the filesystem to be able
>      to tell us if a file has been replaced. If it can't, we fallback to
>      recreating the object on every call (essentially the same behaviour as
> -    propertycache).'''
> -    def __init__(self, path):
> -        self.path = path
> +    propertycache).
> +
> +    '''
> +    def __init__(self, *paths):
> +        self.paths = paths
>
>      def join(self, obj, fname):
> -        """Used to compute the runtime path of the cached file.
> +        """Used to compute the runtime path of a cached file.
>
>          Users should subclass filecache and provide their own version of this
>          function to call the appropriate join function on 'obj' (an instance
> @@ -965,11 +968,11 @@
>              if entry.changed():
>                  entry.obj = self.func(obj)
>          else:
> -            path = self.join(obj, self.path)
> +            paths = [self.join(obj, path) for path in self.paths]
>
>              # We stat -before- creating the object so our cache doesn't lie if
>              # a writer modified between the time we read and stat
> -            entry = filecachesubentry(path, True)
> +            entry = filecacheentry(paths, True)
>              entry.obj = self.func(obj)
>
>              obj._filecache[self.name] = entry
> @@ -981,7 +984,8 @@
>          if self.name not in obj._filecache:
>              # we add an entry for the missing value because X in __dict__
>              # implies X in _filecache
> -            ce = filecachesubentry(self.join(obj, self.path), False)
> +            paths = [self.join(obj, path) for path in self.paths]
> +            ce = filecacheentry(paths, False)
>              obj._filecache[self.name] = ce
>          else:
>              ce = obj._filecache[self.name]
> diff --git a/tests/test-filecache.py b/tests/test-filecache.py
> --- a/tests/test-filecache.py
> +++ b/tests/test-filecache.py
> @@ -18,7 +18,7 @@
>      def sjoin(self, p):
>          return p
>
> -    @filecache('x')
> +    @filecache('x', 'y')
>      def cached(self):
>          print 'creating'
>          return 'string from function'
> @@ -31,12 +31,12 @@
>                  pass
>
>  def basic(repo):
> -    print "* file doesn't exist"
> +    print "* neither file exists"
>      # calls function
>      repo.cached
>
>      repo.invalidate()
> -    print "* file still doesn't exist"
> +    print "* neither file still exists"
>      # uses cache
>      repo.cached
>
> @@ -57,7 +57,7 @@
>      repo.cached
>
>      repo.invalidate()
> -    print "* nothing changed with file x"
> +    print "* nothing changed with either file"
>      # stats file again, reuses object
>      repo.cached
>
> @@ -72,6 +72,41 @@
>      print "* file x changed inode"
>      repo.cached
>
> +    # create empty file y
> +    f = open('y', 'w')
> +    f.close()
> +    repo.invalidate()
> +    print "* empty file y created"
> +    # should recreate the object
> +    repo.cached
> +
> +    f = open('y', 'w')
> +    f.write('A')
> +    f.close()
> +    repo.invalidate()
> +    print "* file y changed size"
> +    # should recreate the object
> +    repo.cached
> +
> +    f = scmutil.opener('.')('y', 'w', atomictemp=True)
> +    f.write('B')
> +    f.close()
> +
> +    repo.invalidate()
> +    print "* file y changed inode"
> +    repo.cached
> +
> +    f = scmutil.opener('.')('x', 'w', atomictemp=True)
> +    f.write('c')
> +    f.close()
> +    f = scmutil.opener('.')('y', 'w', atomictemp=True)
> +    f.write('C')
> +    f.close()
> +
> +    repo.invalidate()
> +    print "* both files changed inode"
> +    repo.cached
> +
>  def fakeuncacheable():
>      def wrapcacheable(orig, *args, **kwargs):
>          return False
> @@ -83,10 +118,11 @@
>      origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable',
>                                              wrapcacheable)
>
> -    try:
> -        os.remove('x')
> -    except OSError:
> -        pass
> +    for fn in ['x', 'y']:
> +        try:
> +            os.remove(fn)
> +        except OSError:
> +            pass
>
>      basic(fakerepo())
>
> @@ -110,9 +146,10 @@
>
>  def setbeforeget(repo):
>      os.remove('x')
> +    os.remove('y')
>      repo.cached = 'string set externally'
>      repo.invalidate()
> -    print "* file x doesn't exist"
> +    print "* neither file exists"
>      print repo.cached
>      repo.invalidate()
>      f = open('x', 'w')
> @@ -121,6 +158,18 @@
>      print "* file x created"
>      print repo.cached
>
> +    repo.cached = 'string 2 set externally'
> +    repo.invalidate()
> +    print "* string set externally again"
> +    print repo.cached
> +
> +    repo.invalidate()
> +    f = open('y', 'w')
> +    f.write('b')
> +    f.close()
> +    print "* file y created"
> +    print repo.cached
> +
>  print 'basic:'
>  print
>  basic(fakerepo())
> diff --git a/tests/test-filecache.py.out b/tests/test-filecache.py.out
> --- a/tests/test-filecache.py.out
> +++ b/tests/test-filecache.py.out
> @@ -1,30 +1,46 @@
>  basic:
>
> -* file doesn't exist
> +* neither file exists
>  creating
> -* file still doesn't exist
> +* neither file still exists
>  * empty file x created
>  creating
>  * file x changed size
>  creating
> -* nothing changed with file x
> +* nothing changed with either file
>  * file x changed inode
>  creating
> +* empty file y created
> +creating
> +* file y changed size
> +creating
> +* file y changed inode
> +creating
> +* both files changed inode
> +creating
>
>  fakeuncacheable:
>
> -* file doesn't exist
> +* neither file exists
>  creating
> -* file still doesn't exist
> +* neither file still exists
>  creating
>  * empty file x created
>  creating
>  * file x changed size
>  creating
> -* nothing changed with file x
> +* nothing changed with either file
>  creating
>  * file x changed inode
>  creating
> +* empty file y created
> +creating
> +* file y changed size
> +creating
> +* file y changed inode
> +creating
> +* both files changed inode
> +creating
>  repository tip rolled back to revision -1 (undo commit)
>  working directory now based on revision -1
>  repository tip rolled back to revision -1 (undo commit)
> @@ -32,8 +48,13 @@
>
>  setbeforeget:
>
> -* file x doesn't exist
> +* neither file exists
>  string set externally
>  * file x created
>  creating
>  string from function
> +* string set externally again
> +string 2 set externally
> +* file y created
> +creating
> +string from function
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list