annotate upmana/mercurial/store.py @ 39:ed322725b928 ornery-orc tip

Traipse 'OpenRPG' {110114-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Closed) New Features: New to Map, can re-order Grid, Miniatures, and Whiteboard layer draw order New to Server GUI, can now clear log New Earthdawn Dieroller New IronClaw roller, sheet, and image New ShapeShifter PC Sheet Updates: Update to Warhammer PC Sheet. Rollers set as macros. Should work with little maintanence. Update to Browser Server window. Display rooms with ' " & cleaner Update to Server. Handles ' " & cleaner Update to Dieroller. Cleaner, more effecient expression system Update to Hidden Die plugin, allows for non standard dice rolls Update to location.py, allows for more portable references when starting Traipse Update to the Features node Fixes: Fix to InterParse that was causing an Infernal Loop with Namespace Internal Fix to XML data, removed old Minidom and switched to Element Tree Fix to Server that was causing eternal attempt to find a Server ID, in Register Rooms thread Fix to Server, removing wxPython dependencies where not needed Fix to metaservers.xml file not being created Fix to Single and Double quotes in Whiteboard text Fix to Background images not showing when using the Image Server Fix to Duplicate chat names appearing Fix to Server GUI's logging output Fix to FNB.COLORFUL_TABS bug Fix to Gametree for XSLT Sheets Fix to Gametree for locating gametree files Fix to Send to Chat from Gametree Fix to Gametree, renaming and remapping operates correctly Fix to aliaslib, prevents error caused when SafeHTML is sent None
author sirebral
date Fri, 14 Jan 2011 05:24:52 -0600
parents ff154cf3350c
children
rev   line source
28
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
1 # store.py - repository store handling for Mercurial
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
2 #
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
4 #
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
5 # This software may be used and distributed according to the terms of the
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
6 # GNU General Public License version 2, incorporated herein by reference.
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
7
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
8 from i18n import _
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
9 import osutil, util
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
10 import os, stat
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
11
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
12 _sha = util.sha1
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
13
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
14 # This avoids a collision between a file named foo and a dir named
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
15 # foo.i or foo.d
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
16 def encodedir(path):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
17 if not path.startswith('data/'):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
18 return path
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
19 return (path
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
20 .replace(".hg/", ".hg.hg/")
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
21 .replace(".i/", ".i.hg/")
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
22 .replace(".d/", ".d.hg/"))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
23
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
24 def decodedir(path):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
25 if not path.startswith('data/'):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
26 return path
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
27 return (path
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
28 .replace(".d.hg/", ".d/")
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
29 .replace(".i.hg/", ".i/")
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
30 .replace(".hg.hg/", ".hg/"))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
31
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
32 def _buildencodefun():
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
33 e = '_'
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
34 win_reserved = [ord(x) for x in '\\:*?"<>|']
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
35 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
36 for x in (range(32) + range(126, 256) + win_reserved):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
37 cmap[chr(x)] = "~%02x" % x
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
38 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
39 cmap[chr(x)] = e + chr(x).lower()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
40 dmap = {}
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
41 for k, v in cmap.iteritems():
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
42 dmap[v] = k
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
43 def decode(s):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
44 i = 0
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
45 while i < len(s):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
46 for l in xrange(1, 4):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
47 try:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
48 yield dmap[s[i:i+l]]
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
49 i += l
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
50 break
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
51 except KeyError:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
52 pass
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
53 else:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
54 raise KeyError
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
55 return (lambda s: "".join([cmap[c] for c in encodedir(s)]),
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
56 lambda s: decodedir("".join(list(decode(s)))))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
57
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
58 encodefilename, decodefilename = _buildencodefun()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
59
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
60 def _build_lower_encodefun():
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
61 win_reserved = [ord(x) for x in '\\:*?"<>|']
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
62 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
63 for x in (range(32) + range(126, 256) + win_reserved):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
64 cmap[chr(x)] = "~%02x" % x
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
65 for x in range(ord("A"), ord("Z")+1):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
66 cmap[chr(x)] = chr(x).lower()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
67 return lambda s: "".join([cmap[c] for c in s])
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
68
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
69 lowerencode = _build_lower_encodefun()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
70
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
71 _windows_reserved_filenames = '''con prn aux nul
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
72 com1 com2 com3 com4 com5 com6 com7 com8 com9
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
73 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
74 def auxencode(path):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
75 res = []
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
76 for n in path.split('/'):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
77 if n:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
78 base = n.split('.')[0]
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
79 if base and (base in _windows_reserved_filenames):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
80 # encode third letter ('aux' -> 'au~78')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
81 ec = "~%02x" % ord(n[2])
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
82 n = n[0:2] + ec + n[3:]
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
83 if n[-1] in '. ':
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
84 # encode last period or space ('foo...' -> 'foo..~2e')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
85 n = n[:-1] + "~%02x" % ord(n[-1])
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
86 res.append(n)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
87 return '/'.join(res)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
88
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
89 MAX_PATH_LEN_IN_HGSTORE = 120
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
90 DIR_PREFIX_LEN = 8
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
91 _MAX_SHORTENED_DIRS_LEN = 8 * (DIR_PREFIX_LEN + 1) - 4
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
92 def hybridencode(path):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
93 '''encodes path with a length limit
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
94
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
95 Encodes all paths that begin with 'data/', according to the following.
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
96
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
97 Default encoding (reversible):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
98
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
99 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
100 characters are encoded as '~xx', where xx is the two digit hex code
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
101 of the character (see encodefilename).
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
102 Relevant path components consisting of Windows reserved filenames are
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
103 masked by encoding the third character ('aux' -> 'au~78', see auxencode).
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
104
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
105 Hashed encoding (not reversible):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
106
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
107 If the default-encoded path is longer than MAX_PATH_LEN_IN_HGSTORE, a
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
108 non-reversible hybrid hashing of the path is done instead.
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
109 This encoding uses up to DIR_PREFIX_LEN characters of all directory
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
110 levels of the lowerencoded path, but not more levels than can fit into
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
111 _MAX_SHORTENED_DIRS_LEN.
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
112 Then follows the filler followed by the sha digest of the full path.
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
113 The filler is the beginning of the basename of the lowerencoded path
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
114 (the basename is everything after the last path separator). The filler
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
115 is as long as possible, filling in characters from the basename until
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
116 the encoded path has MAX_PATH_LEN_IN_HGSTORE characters (or all chars
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
117 of the basename have been taken).
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
118 The extension (e.g. '.i' or '.d') is preserved.
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
119
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
120 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
121 encoding was used.
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
122 '''
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
123 if not path.startswith('data/'):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
124 return path
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
125 # escape directories ending with .i and .d
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
126 path = encodedir(path)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
127 ndpath = path[len('data/'):]
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
128 res = 'data/' + auxencode(encodefilename(ndpath))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
129 if len(res) > MAX_PATH_LEN_IN_HGSTORE:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
130 digest = _sha(path).hexdigest()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
131 aep = auxencode(lowerencode(ndpath))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
132 _root, ext = os.path.splitext(aep)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
133 parts = aep.split('/')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
134 basename = parts[-1]
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
135 sdirs = []
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
136 for p in parts[:-1]:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
137 d = p[:DIR_PREFIX_LEN]
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
138 if d[-1] in '. ':
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
139 # Windows can't access dirs ending in period or space
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
140 d = d[:-1] + '_'
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
141 t = '/'.join(sdirs) + '/' + d
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
142 if len(t) > _MAX_SHORTENED_DIRS_LEN:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
143 break
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
144 sdirs.append(d)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
145 dirs = '/'.join(sdirs)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
146 if len(dirs) > 0:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
147 dirs += '/'
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
148 res = 'dh/' + dirs + digest + ext
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
149 space_left = MAX_PATH_LEN_IN_HGSTORE - len(res)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
150 if space_left > 0:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
151 filler = basename[:space_left]
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
152 res = 'dh/' + dirs + filler + digest + ext
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
153 return res
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
154
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
155 def _calcmode(path):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
156 try:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
157 # files in .hg/ will be created using this mode
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
158 mode = os.stat(path).st_mode
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
159 # avoid some useless chmods
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
160 if (0777 & ~util.umask) == (0777 & mode):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
161 mode = None
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
162 except OSError:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
163 mode = None
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
164 return mode
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
165
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
166 _data = 'data 00manifest.d 00manifest.i 00changelog.d 00changelog.i'
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
167
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
168 class basicstore(object):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
169 '''base class for local repository stores'''
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
170 def __init__(self, path, opener, pathjoiner):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
171 self.pathjoiner = pathjoiner
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
172 self.path = path
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
173 self.createmode = _calcmode(path)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
174 op = opener(self.path)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
175 op.createmode = self.createmode
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
176 self.opener = lambda f, *args, **kw: op(encodedir(f), *args, **kw)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
177
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
178 def join(self, f):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
179 return self.pathjoiner(self.path, encodedir(f))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
180
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
181 def _walk(self, relpath, recurse):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
182 '''yields (unencoded, encoded, size)'''
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
183 path = self.pathjoiner(self.path, relpath)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
184 striplen = len(self.path) + len(os.sep)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
185 l = []
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
186 if os.path.isdir(path):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
187 visit = [path]
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
188 while visit:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
189 p = visit.pop()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
190 for f, kind, st in osutil.listdir(p, stat=True):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
191 fp = self.pathjoiner(p, f)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
192 if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
193 n = util.pconvert(fp[striplen:])
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
194 l.append((decodedir(n), n, st.st_size))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
195 elif kind == stat.S_IFDIR and recurse:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
196 visit.append(fp)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
197 return sorted(l)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
198
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
199 def datafiles(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
200 return self._walk('data', True)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
201
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
202 def walk(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
203 '''yields (unencoded, encoded, size)'''
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
204 # yield data files first
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
205 for x in self.datafiles():
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
206 yield x
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
207 # yield manifest before changelog
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
208 for x in reversed(self._walk('', False)):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
209 yield x
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
210
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
211 def copylist(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
212 return ['requires'] + _data.split()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
213
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
214 class encodedstore(basicstore):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
215 def __init__(self, path, opener, pathjoiner):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
216 self.pathjoiner = pathjoiner
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
217 self.path = self.pathjoiner(path, 'store')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
218 self.createmode = _calcmode(self.path)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
219 op = opener(self.path)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
220 op.createmode = self.createmode
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
221 self.opener = lambda f, *args, **kw: op(encodefilename(f), *args, **kw)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
222
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
223 def datafiles(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
224 for a, b, size in self._walk('data', True):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
225 try:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
226 a = decodefilename(a)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
227 except KeyError:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
228 a = None
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
229 yield a, b, size
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
230
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
231 def join(self, f):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
232 return self.pathjoiner(self.path, encodefilename(f))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
233
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
234 def copylist(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
235 return (['requires', '00changelog.i'] +
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
236 [self.pathjoiner('store', f) for f in _data.split()])
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
237
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
238 class fncache(object):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
239 # the filename used to be partially encoded
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
240 # hence the encodedir/decodedir dance
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
241 def __init__(self, opener):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
242 self.opener = opener
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
243 self.entries = None
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
244
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
245 def _load(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
246 '''fill the entries from the fncache file'''
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
247 self.entries = set()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
248 try:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
249 fp = self.opener('fncache', mode='rb')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
250 except IOError:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
251 # skip nonexistent file
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
252 return
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
253 for n, line in enumerate(fp):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
254 if (len(line) < 2) or (line[-1] != '\n'):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
255 t = _('invalid entry in fncache, line %s') % (n + 1)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
256 raise util.Abort(t)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
257 self.entries.add(decodedir(line[:-1]))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
258 fp.close()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
259
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
260 def rewrite(self, files):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
261 fp = self.opener('fncache', mode='wb')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
262 for p in files:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
263 fp.write(encodedir(p) + '\n')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
264 fp.close()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
265 self.entries = set(files)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
266
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
267 def add(self, fn):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
268 if self.entries is None:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
269 self._load()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
270 self.opener('fncache', 'ab').write(encodedir(fn) + '\n')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
271
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
272 def __contains__(self, fn):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
273 if self.entries is None:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
274 self._load()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
275 return fn in self.entries
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
276
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
277 def __iter__(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
278 if self.entries is None:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
279 self._load()
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
280 return iter(self.entries)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
281
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
282 class fncachestore(basicstore):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
283 def __init__(self, path, opener, pathjoiner):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
284 self.pathjoiner = pathjoiner
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
285 self.path = self.pathjoiner(path, 'store')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
286 self.createmode = _calcmode(self.path)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
287 op = opener(self.path)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
288 op.createmode = self.createmode
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
289 fnc = fncache(op)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
290 self.fncache = fnc
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
291
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
292 def fncacheopener(path, mode='r', *args, **kw):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
293 if (mode not in ('r', 'rb')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
294 and path.startswith('data/')
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
295 and path not in fnc):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
296 fnc.add(path)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
297 return op(hybridencode(path), mode, *args, **kw)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
298 self.opener = fncacheopener
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
299
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
300 def join(self, f):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
301 return self.pathjoiner(self.path, hybridencode(f))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
302
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
303 def datafiles(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
304 rewrite = False
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
305 existing = []
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
306 pjoin = self.pathjoiner
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
307 spath = self.path
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
308 for f in self.fncache:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
309 ef = hybridencode(f)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
310 try:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
311 st = os.stat(pjoin(spath, ef))
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
312 yield f, ef, st.st_size
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
313 existing.append(f)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
314 except OSError:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
315 # nonexistent entry
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
316 rewrite = True
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
317 if rewrite:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
318 # rewrite fncache to remove nonexistent entries
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
319 # (may be caused by rollback / strip)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
320 self.fncache.rewrite(existing)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
321
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
322 def copylist(self):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
323 d = _data + ' dh fncache'
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
324 return (['requires', '00changelog.i'] +
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
325 [self.pathjoiner('store', f) for f in d.split()])
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
326
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
327 def store(requirements, path, opener, pathjoiner=None):
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
328 pathjoiner = pathjoiner or os.path.join
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
329 if 'store' in requirements:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
330 if 'fncache' in requirements:
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
331 return fncachestore(path, opener, pathjoiner)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
332 return encodedstore(path, opener, pathjoiner)
ff154cf3350c Traipse 'OpenRPG' {100203-00}
sirebral
parents:
diff changeset
333 return basicstore(path, opener, pathjoiner)