Mercurial > hg
view tests/test-subrepo-relative-path.t @ 14007:d764463b433e
atomictempfile: avoid infinite recursion in __del__().
The problem is that a programmer using atomictempfile directly can
make an innocent everyday mistake -- not enough args to the
constructor -- which escalates badly. You would expect a simple
TypeError crash in that case, but you actually get an infinite
recursion that is surprisingly difficult to kill: it happens between
__del__() and __getattr__(), and Python does not handle infinite
recursion from __del__() well.
The fix is to not implement __getattr__(), but instead assign instance
attributes for the methods we wish to delegate to the builtin file
type: write() and fileno(). I've audited mercurial.* and hgext.* and
found no users of atomictempfile using methods other than write() and
rename(). I audited third-party extensions and found one (snap)
passing an atomictempfile to util.fstat(), so I also threw in
fileno().
The last time I submitted a similar patch, Matt proposed that we make
atomictempfile a subclass of file instead of wrapping it. Rejected on
grounds of unnecessary complexity: for one thing, it would make the
Windows implementation of posixfile quite a bit more complex. It would
have to become a subclass of file rather than a simple function -- but
since it's written in C, this is non-obvious and non-trivial.
Furthermore, there's nothing wrong with wrapping objects and
delegating methods: it's a well-established pattern that works just
fine in many cases. Subclassing is not the answer to all of life's
problems.
author | Greg Ward <greg@gerg.ca> |
---|---|
date | Sun, 24 Apr 2011 19:25:10 -0400 |
parents | ce05c8130296 |
children | 9bbaafddfa90 |
line wrap: on
line source
Preparing the subrepository 'sub' $ hg init sub $ echo sub > sub/sub $ hg add -R sub adding sub/sub $ hg commit -R sub -m "sub import" Preparing the 'main' repo which depends on the subrepo 'sub' $ hg init main $ echo main > main/main $ echo "sub = ../sub" > main/.hgsub $ hg clone sub main/sub updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg add -R main adding main/.hgsub adding main/main $ hg commit -R main -m "main import" committing subrepository sub Cleaning both repositories, just as a clone -U $ hg up -C -R sub null 0 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg up -C -R main null 0 files updated, 0 files merged, 3 files removed, 0 files unresolved $ rm -rf main/sub Serving them both using hgweb $ printf '[paths]\n/main = main\nsub = sub\n' > webdir.conf $ hg serve --webdir-conf webdir.conf -a localhost -p $HGPORT \ > -A /dev/null -E /dev/null --pid-file hg.pid -d $ cat hg.pid >> $DAEMON_PIDS Clone main from hgweb $ hg clone "http://localhost:$HGPORT/main" cloned requesting all changes adding changesets adding manifests adding file changes added 1 changesets with 3 changes to 3 files updating to branch default pulling subrepo sub from http://localhost:$HGPORT/sub requesting all changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files 3 files updated, 0 files merged, 0 files removed, 0 files unresolved Checking cloned repo ids $ hg id -R cloned fdfeeb3e979e tip $ hg id -R cloned/sub 863c1745b441 tip subrepo debug for 'main' clone $ hg debugsub -R cloned path sub source ../sub revision 863c1745b441bd97a8c4a096e87793073f4fb215 $ "$TESTDIR/killdaemons.py"