##// END OF EJS Templates
inotify: server: new data structure to keep track of changes....
inotify: server: new data structure to keep track of changes. == Rationale for the new structure == Current structure was a dictionary tree. One directory was tracked as a dictionary: - keys: file/subdir name - values: - for a file, the status (a/r/m/...) - for a subdir, the directory representing the subdir It allowed efficient lookups, no matter of the type of the terminal leaf: for part in path.split('/'): tree = tree[part] However, there is no way to represent a directory and a file with the same name because keys are conflicting in the dictionary. Concrete example: Initial state: root dir |- foo (file) |- bar (file) # data state is: {'foo': 'n', 'bar': 'n'} Remove foo: root dir |- bar (file) # Data becomes {'foo': 'r'} until next commit. Add foo, as a directory, and foo/barbar file: root dir |- bar (file) |-> foo (dir) |- barbar (file) # New state should be represented as: {'foo': {'barbar': 'a'}, 'bar': 'n'} however, the key "foo" is already used and represents the old file. The dirstate: D foo A foo/barbar cannot be represented, hence the need for a new structure. == The new structure == 'directory' class. Represents one directory level. * Notable attributes: Two dictionaries: - 'files' Maps filename -> status for the current dir. - 'dirs' Maps subdir's name -> directory object representing the subdir * methods - walk(), formerly server.walk - lookup(), old server.lookup - dir(), old server.dir This new class allows embedding all the tree walks/lookups in its own class, instead of having everything mixed together in server. Incidently, since files and directories are not stored in the same dictionaries, we are solving the previous key conflict problem. The small drawback is that lookup operation is a bit more complex: for a path a/b/c/d/e we have to check twice the leaf, if e is a directory or a file.

File last commit:

r8296:908c5906 default
r9115:b55d4471 default
Show More
test-archive
121 lines | 3.2 KiB | text/plain | TextLexer
#!/bin/sh
mkdir test
cd test
hg init
echo foo>foo
hg commit -Am 1 -d '1 0'
echo bar>bar
hg commit -Am 2 -d '2 0'
mkdir baz
echo bletch>baz/bletch
hg commit -Am 3 -d '1000000000 0'
echo "[web]" >> .hg/hgrc
echo "name = test-archive" >> .hg/hgrc
cp .hg/hgrc .hg/hgrc-base
# check http return codes
test_archtype() {
echo "allow_archive = $1" >> .hg/hgrc
hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
cat hg.pid >> $DAEMON_PIDS
echo % $1 allowed should give 200
"$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$2" | head -n 1
echo % $3 and $4 disallowed should both give 403
"$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$3" | head -n 1
"$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$4" | head -n 1
"$TESTDIR/killdaemons.py"
cat errors.log
cp .hg/hgrc-base .hg/hgrc
}
echo
test_archtype gz tar.gz tar.bz2 zip
test_archtype bz2 tar.bz2 zip tar.gz
test_archtype zip zip tar.gz tar.bz2
echo "allow_archive = gz bz2 zip" >> .hg/hgrc
hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
cat hg.pid >> $DAEMON_PIDS
echo % invalid arch type should give 404
"$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.invalid" | head -n 1
echo
TIP=`hg id -v | cut -f1 -d' '`
QTIP=`hg id -q`
cat > getarchive.py <<EOF
import os, sys, urllib2
try:
# Set stdout to binary mode for win32 platforms
import msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
except ImportError:
pass
node, archive = sys.argv[1:]
f = urllib2.urlopen('http://127.0.0.1:%s/?cmd=archive;node=%s;type=%s'
% (os.environ['HGPORT'], node, archive))
sys.stdout.write(f.read())
EOF
http_proxy= python getarchive.py "$TIP" gz | gunzip | tar tf - 2>/dev/null | sed "s/$QTIP/TIP/"
http_proxy= python getarchive.py "$TIP" bz2 | bunzip2 | tar tf - 2>/dev/null | sed "s/$QTIP/TIP/"
http_proxy= python getarchive.py "$TIP" zip > archive.zip
unzip -t archive.zip | sed "s/$QTIP/TIP/"
"$TESTDIR/killdaemons.py"
hg archive -t tar test.tar
tar tf test.tar
hg archive -t tbz2 -X baz test.tar.bz2
bunzip2 -dc test.tar.bz2 | tar tf - 2>/dev/null
hg archive -t tgz -p %b-%h test-%h.tar.gz
gzip -dc test-$QTIP.tar.gz | tar tf - 2>/dev/null | sed "s/$QTIP/TIP/"
cat > md5comp.py <<EOF
try:
from hashlib import md5
except ImportError:
from md5 import md5
import sys
f1, f2 = sys.argv[1:3]
h1 = md5(file(f1, 'rb').read()).hexdigest()
h2 = md5(file(f2, 'rb').read()).hexdigest()
print h1 == h2 or "md5 differ: " + repr((h1, h2))
EOF
# archive name is stored in the archive, so create similar
# archives and rename them afterwards.
hg archive -t tgz tip.tar.gz
mv tip.tar.gz tip1.tar.gz
sleep 1
hg archive -t tgz tip.tar.gz
mv tip.tar.gz tip2.tar.gz
python md5comp.py tip1.tar.gz tip2.tar.gz
hg archive -t zip -p /illegal test.zip
hg archive -t zip -p very/../bad test.zip
hg archive --config ui.archivemeta=false -t zip -r 2 test.zip
unzip -t test.zip
hg archive -t tar - | tar tf - 2>/dev/null | sed "s/$QTIP/TIP/"
hg archive -r 0 -t tar rev-%r.tar
if [ -f rev-0.tar ]; then
echo 'rev-0.tar created'
fi
hg archive -t bogus test.bogus
echo % server errors
cat errors.log
echo '% empty repo'
hg init ../empty
cd ../empty
hg archive ../test-empty
exit 0