##// END OF EJS Templates
transaction: include backup file in the "undo" transaction...
Pierre-Yves David -
r23904:d251da5e default
parent child Browse files
Show More
@@ -1,513 +1,540 b''
1 # transaction.py - simple journaling scheme for mercurial
1 # transaction.py - simple journaling scheme for mercurial
2 #
2 #
3 # This transaction scheme is intended to gracefully handle program
3 # This transaction scheme is intended to gracefully handle program
4 # errors and interruptions. More serious failures like system crashes
4 # errors and interruptions. More serious failures like system crashes
5 # can be recovered with an fsck-like tool. As the whole repository is
5 # can be recovered with an fsck-like tool. As the whole repository is
6 # effectively log-structured, this should amount to simply truncating
6 # effectively log-structured, this should amount to simply truncating
7 # anything that isn't referenced in the changelog.
7 # anything that isn't referenced in the changelog.
8 #
8 #
9 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
9 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
10 #
10 #
11 # This software may be used and distributed according to the terms of the
11 # This software may be used and distributed according to the terms of the
12 # GNU General Public License version 2 or any later version.
12 # GNU General Public License version 2 or any later version.
13
13
14 from i18n import _
14 from i18n import _
15 import errno
15 import errno
16 import error, util
16 import error, util
17
17
18 version = 2
18 version = 2
19
19
20 def active(func):
20 def active(func):
21 def _active(self, *args, **kwds):
21 def _active(self, *args, **kwds):
22 if self.count == 0:
22 if self.count == 0:
23 raise error.Abort(_(
23 raise error.Abort(_(
24 'cannot use transaction when it is already committed/aborted'))
24 'cannot use transaction when it is already committed/aborted'))
25 return func(self, *args, **kwds)
25 return func(self, *args, **kwds)
26 return _active
26 return _active
27
27
28 def _playback(journal, report, opener, vfsmap, entries, backupentries,
28 def _playback(journal, report, opener, vfsmap, entries, backupentries,
29 unlink=True):
29 unlink=True):
30 for f, o, _ignore in entries:
30 for f, o, _ignore in entries:
31 if o or not unlink:
31 if o or not unlink:
32 try:
32 try:
33 fp = opener(f, 'a')
33 fp = opener(f, 'a')
34 fp.truncate(o)
34 fp.truncate(o)
35 fp.close()
35 fp.close()
36 except IOError:
36 except IOError:
37 report(_("failed to truncate %s\n") % f)
37 report(_("failed to truncate %s\n") % f)
38 raise
38 raise
39 else:
39 else:
40 try:
40 try:
41 opener.unlink(f)
41 opener.unlink(f)
42 except (IOError, OSError), inst:
42 except (IOError, OSError), inst:
43 if inst.errno != errno.ENOENT:
43 if inst.errno != errno.ENOENT:
44 raise
44 raise
45
45
46 backupfiles = []
46 backupfiles = []
47 for l, f, b, c in backupentries:
47 for l, f, b, c in backupentries:
48 if l not in vfsmap and c:
48 if l not in vfsmap and c:
49 report("couldn't handle %s: unknown cache location %s\n"
49 report("couldn't handle %s: unknown cache location %s\n"
50 % (b, l))
50 % (b, l))
51 vfs = vfsmap[l]
51 vfs = vfsmap[l]
52 try:
52 try:
53 if f and b:
53 if f and b:
54 filepath = vfs.join(f)
54 filepath = vfs.join(f)
55 backuppath = vfs.join(b)
55 backuppath = vfs.join(b)
56 try:
56 try:
57 util.copyfile(backuppath, filepath)
57 util.copyfile(backuppath, filepath)
58 backupfiles.append(b)
58 backupfiles.append(b)
59 except IOError:
59 except IOError:
60 report(_("failed to recover %s\n") % f)
60 report(_("failed to recover %s\n") % f)
61 else:
61 else:
62 target = f or b
62 target = f or b
63 try:
63 try:
64 vfs.unlink(target)
64 vfs.unlink(target)
65 except (IOError, OSError), inst:
65 except (IOError, OSError), inst:
66 if inst.errno != errno.ENOENT:
66 if inst.errno != errno.ENOENT:
67 raise
67 raise
68 except (IOError, OSError, util.Abort), inst:
68 except (IOError, OSError, util.Abort), inst:
69 if not c:
69 if not c:
70 raise
70 raise
71
71
72 opener.unlink(journal)
72 opener.unlink(journal)
73 backuppath = "%s.backupfiles" % journal
73 backuppath = "%s.backupfiles" % journal
74 if opener.exists(backuppath):
74 if opener.exists(backuppath):
75 opener.unlink(backuppath)
75 opener.unlink(backuppath)
76 try:
76 try:
77 for f in backupfiles:
77 for f in backupfiles:
78 if opener.exists(f):
78 if opener.exists(f):
79 opener.unlink(f)
79 opener.unlink(f)
80 except (IOError, OSError, util.Abort), inst:
80 except (IOError, OSError, util.Abort), inst:
81 # only pure backup file remains, it is sage to ignore any error
81 # only pure backup file remains, it is sage to ignore any error
82 pass
82 pass
83
83
84 class transaction(object):
84 class transaction(object):
85 def __init__(self, report, opener, vfsmap, journalname, undoname=None,
85 def __init__(self, report, opener, vfsmap, journalname, undoname=None,
86 after=None, createmode=None):
86 after=None, createmode=None):
87 """Begin a new transaction
87 """Begin a new transaction
88
88
89 Begins a new transaction that allows rolling back writes in the event of
89 Begins a new transaction that allows rolling back writes in the event of
90 an exception.
90 an exception.
91
91
92 * `after`: called after the transaction has been committed
92 * `after`: called after the transaction has been committed
93 * `createmode`: the mode of the journal file that will be created
93 * `createmode`: the mode of the journal file that will be created
94 """
94 """
95 self.count = 1
95 self.count = 1
96 self.usages = 1
96 self.usages = 1
97 self.report = report
97 self.report = report
98 # a vfs to the store content
98 # a vfs to the store content
99 self.opener = opener
99 self.opener = opener
100 # a map to access file in various {location -> vfs}
100 # a map to access file in various {location -> vfs}
101 vfsmap = vfsmap.copy()
101 vfsmap = vfsmap.copy()
102 vfsmap[''] = opener # set default value
102 vfsmap[''] = opener # set default value
103 self._vfsmap = vfsmap
103 self._vfsmap = vfsmap
104 self.after = after
104 self.after = after
105 self.entries = []
105 self.entries = []
106 self.map = {}
106 self.map = {}
107 self.journal = journalname
107 self.journal = journalname
108 self.undoname = undoname
108 self.undoname = undoname
109 self._queue = []
109 self._queue = []
110 # a dict of arguments to be passed to hooks
110 # a dict of arguments to be passed to hooks
111 self.hookargs = {}
111 self.hookargs = {}
112 self.file = opener.open(self.journal, "w")
112 self.file = opener.open(self.journal, "w")
113
113
114 # a list of ('location', 'path', 'backuppath', cache) entries.
114 # a list of ('location', 'path', 'backuppath', cache) entries.
115 # - if 'backuppath' is empty, no file existed at backup time
115 # - if 'backuppath' is empty, no file existed at backup time
116 # - if 'path' is empty, this is a temporary transaction file
116 # - if 'path' is empty, this is a temporary transaction file
117 # - if 'location' is not empty, the path is outside main opener reach.
117 # - if 'location' is not empty, the path is outside main opener reach.
118 # use 'location' value as a key in a vfsmap to find the right 'vfs'
118 # use 'location' value as a key in a vfsmap to find the right 'vfs'
119 # (cache is currently unused)
119 # (cache is currently unused)
120 self._backupentries = []
120 self._backupentries = []
121 self._backupmap = {}
121 self._backupmap = {}
122 self._backupjournal = "%s.backupfiles" % self.journal
122 self._backupjournal = "%s.backupfiles" % self.journal
123 self._backupsfile = opener.open(self._backupjournal, 'w')
123 self._backupsfile = opener.open(self._backupjournal, 'w')
124 self._backupsfile.write('%d\n' % version)
124 self._backupsfile.write('%d\n' % version)
125
125
126 if createmode is not None:
126 if createmode is not None:
127 opener.chmod(self.journal, createmode & 0666)
127 opener.chmod(self.journal, createmode & 0666)
128 opener.chmod(self._backupjournal, createmode & 0666)
128 opener.chmod(self._backupjournal, createmode & 0666)
129
129
130 # hold file generations to be performed on commit
130 # hold file generations to be performed on commit
131 self._filegenerators = {}
131 self._filegenerators = {}
132 # hold callback to write pending data for hooks
132 # hold callback to write pending data for hooks
133 self._pendingcallback = {}
133 self._pendingcallback = {}
134 # True is any pending data have been written ever
134 # True is any pending data have been written ever
135 self._anypending = False
135 self._anypending = False
136 # holds callback to call when writing the transaction
136 # holds callback to call when writing the transaction
137 self._finalizecallback = {}
137 self._finalizecallback = {}
138 # hold callback for post transaction close
138 # hold callback for post transaction close
139 self._postclosecallback = {}
139 self._postclosecallback = {}
140 # holds callbacks to call during abort
140 # holds callbacks to call during abort
141 self._abortcallback = {}
141 self._abortcallback = {}
142
142
143 def __del__(self):
143 def __del__(self):
144 if self.journal:
144 if self.journal:
145 self._abort()
145 self._abort()
146
146
147 @active
147 @active
148 def startgroup(self):
148 def startgroup(self):
149 """delay registration of file entry
149 """delay registration of file entry
150
150
151 This is used by strip to delay vision of strip offset. The transaction
151 This is used by strip to delay vision of strip offset. The transaction
152 sees either none or all of the strip actions to be done."""
152 sees either none or all of the strip actions to be done."""
153 self._queue.append([])
153 self._queue.append([])
154
154
155 @active
155 @active
156 def endgroup(self):
156 def endgroup(self):
157 """apply delayed registration of file entry.
157 """apply delayed registration of file entry.
158
158
159 This is used by strip to delay vision of strip offset. The transaction
159 This is used by strip to delay vision of strip offset. The transaction
160 sees either none or all of the strip actions to be done."""
160 sees either none or all of the strip actions to be done."""
161 q = self._queue.pop()
161 q = self._queue.pop()
162 for f, o, data in q:
162 for f, o, data in q:
163 self._addentry(f, o, data)
163 self._addentry(f, o, data)
164
164
165 @active
165 @active
166 def add(self, file, offset, data=None):
166 def add(self, file, offset, data=None):
167 """record the state of an append-only file before update"""
167 """record the state of an append-only file before update"""
168 if file in self.map or file in self._backupmap:
168 if file in self.map or file in self._backupmap:
169 return
169 return
170 if self._queue:
170 if self._queue:
171 self._queue[-1].append((file, offset, data))
171 self._queue[-1].append((file, offset, data))
172 return
172 return
173
173
174 self._addentry(file, offset, data)
174 self._addentry(file, offset, data)
175
175
176 def _addentry(self, file, offset, data):
176 def _addentry(self, file, offset, data):
177 """add a append-only entry to memory and on-disk state"""
177 """add a append-only entry to memory and on-disk state"""
178 if file in self.map or file in self._backupmap:
178 if file in self.map or file in self._backupmap:
179 return
179 return
180 self.entries.append((file, offset, data))
180 self.entries.append((file, offset, data))
181 self.map[file] = len(self.entries) - 1
181 self.map[file] = len(self.entries) - 1
182 # add enough data to the journal to do the truncate
182 # add enough data to the journal to do the truncate
183 self.file.write("%s\0%d\n" % (file, offset))
183 self.file.write("%s\0%d\n" % (file, offset))
184 self.file.flush()
184 self.file.flush()
185
185
186 @active
186 @active
187 def addbackup(self, file, hardlink=True, location=''):
187 def addbackup(self, file, hardlink=True, location=''):
188 """Adds a backup of the file to the transaction
188 """Adds a backup of the file to the transaction
189
189
190 Calling addbackup() creates a hardlink backup of the specified file
190 Calling addbackup() creates a hardlink backup of the specified file
191 that is used to recover the file in the event of the transaction
191 that is used to recover the file in the event of the transaction
192 aborting.
192 aborting.
193
193
194 * `file`: the file path, relative to .hg/store
194 * `file`: the file path, relative to .hg/store
195 * `hardlink`: use a hardlink to quickly create the backup
195 * `hardlink`: use a hardlink to quickly create the backup
196 """
196 """
197 if self._queue:
197 if self._queue:
198 msg = 'cannot use transaction.addbackup inside "group"'
198 msg = 'cannot use transaction.addbackup inside "group"'
199 raise RuntimeError(msg)
199 raise RuntimeError(msg)
200
200
201 if file in self.map or file in self._backupmap:
201 if file in self.map or file in self._backupmap:
202 return
202 return
203 vfs = self._vfsmap[location]
203 vfs = self._vfsmap[location]
204 dirname, filename = vfs.split(file)
204 dirname, filename = vfs.split(file)
205 backupfilename = "%s.backup.%s" % (self.journal, filename)
205 backupfilename = "%s.backup.%s" % (self.journal, filename)
206 backupfile = vfs.reljoin(dirname, backupfilename)
206 backupfile = vfs.reljoin(dirname, backupfilename)
207 if vfs.exists(file):
207 if vfs.exists(file):
208 filepath = vfs.join(file)
208 filepath = vfs.join(file)
209 backuppath = vfs.join(backupfile)
209 backuppath = vfs.join(backupfile)
210 util.copyfile(filepath, backuppath, hardlink=hardlink)
210 util.copyfile(filepath, backuppath, hardlink=hardlink)
211 else:
211 else:
212 backupfile = ''
212 backupfile = ''
213
213
214 self._addbackupentry((location, file, backupfile, False))
214 self._addbackupentry((location, file, backupfile, False))
215
215
216 def _addbackupentry(self, entry):
216 def _addbackupentry(self, entry):
217 """register a new backup entry and write it to disk"""
217 """register a new backup entry and write it to disk"""
218 self._backupentries.append(entry)
218 self._backupentries.append(entry)
219 self._backupmap[file] = len(self._backupentries) - 1
219 self._backupmap[file] = len(self._backupentries) - 1
220 self._backupsfile.write("%s\0%s\0%s\0%d\n" % entry)
220 self._backupsfile.write("%s\0%s\0%s\0%d\n" % entry)
221 self._backupsfile.flush()
221 self._backupsfile.flush()
222
222
223 @active
223 @active
224 def registertmp(self, tmpfile, location=''):
224 def registertmp(self, tmpfile, location=''):
225 """register a temporary transaction file
225 """register a temporary transaction file
226
226
227 Such files will be deleted when the transaction exits (on both
227 Such files will be deleted when the transaction exits (on both
228 failure and success).
228 failure and success).
229 """
229 """
230 self._addbackupentry((location, '', tmpfile, False))
230 self._addbackupentry((location, '', tmpfile, False))
231
231
232 @active
232 @active
233 def addfilegenerator(self, genid, filenames, genfunc, order=0,
233 def addfilegenerator(self, genid, filenames, genfunc, order=0,
234 location=''):
234 location=''):
235 """add a function to generates some files at transaction commit
235 """add a function to generates some files at transaction commit
236
236
237 The `genfunc` argument is a function capable of generating proper
237 The `genfunc` argument is a function capable of generating proper
238 content of each entry in the `filename` tuple.
238 content of each entry in the `filename` tuple.
239
239
240 At transaction close time, `genfunc` will be called with one file
240 At transaction close time, `genfunc` will be called with one file
241 object argument per entries in `filenames`.
241 object argument per entries in `filenames`.
242
242
243 The transaction itself is responsible for the backup, creation and
243 The transaction itself is responsible for the backup, creation and
244 final write of such file.
244 final write of such file.
245
245
246 The `genid` argument is used to ensure the same set of file is only
246 The `genid` argument is used to ensure the same set of file is only
247 generated once. Call to `addfilegenerator` for a `genid` already
247 generated once. Call to `addfilegenerator` for a `genid` already
248 present will overwrite the old entry.
248 present will overwrite the old entry.
249
249
250 The `order` argument may be used to control the order in which multiple
250 The `order` argument may be used to control the order in which multiple
251 generator will be executed.
251 generator will be executed.
252
252
253 The `location` arguments may be used to indicate the files are located
253 The `location` arguments may be used to indicate the files are located
254 outside of the the standard directory for transaction. It should match
254 outside of the the standard directory for transaction. It should match
255 one of the key of the `transaction.vfsmap` dictionary.
255 one of the key of the `transaction.vfsmap` dictionary.
256 """
256 """
257 # For now, we are unable to do proper backup and restore of custom vfs
257 # For now, we are unable to do proper backup and restore of custom vfs
258 # but for bookmarks that are handled outside this mechanism.
258 # but for bookmarks that are handled outside this mechanism.
259 self._filegenerators[genid] = (order, filenames, genfunc, location)
259 self._filegenerators[genid] = (order, filenames, genfunc, location)
260
260
261 def _generatefiles(self, suffix=''):
261 def _generatefiles(self, suffix=''):
262 # write files registered for generation
262 # write files registered for generation
263 any = False
263 any = False
264 for entry in sorted(self._filegenerators.values()):
264 for entry in sorted(self._filegenerators.values()):
265 any = True
265 any = True
266 order, filenames, genfunc, location = entry
266 order, filenames, genfunc, location = entry
267 vfs = self._vfsmap[location]
267 vfs = self._vfsmap[location]
268 files = []
268 files = []
269 try:
269 try:
270 for name in filenames:
270 for name in filenames:
271 name += suffix
271 name += suffix
272 if suffix:
272 if suffix:
273 self.registertmp(name, location=location)
273 self.registertmp(name, location=location)
274 else:
274 else:
275 self.addbackup(name, location=location)
275 self.addbackup(name, location=location)
276 files.append(vfs(name, 'w', atomictemp=True))
276 files.append(vfs(name, 'w', atomictemp=True))
277 genfunc(*files)
277 genfunc(*files)
278 finally:
278 finally:
279 for f in files:
279 for f in files:
280 f.close()
280 f.close()
281 return any
281 return any
282
282
283 @active
283 @active
284 def find(self, file):
284 def find(self, file):
285 if file in self.map:
285 if file in self.map:
286 return self.entries[self.map[file]]
286 return self.entries[self.map[file]]
287 if file in self._backupmap:
287 if file in self._backupmap:
288 return self._backupentries[self._backupmap[file]]
288 return self._backupentries[self._backupmap[file]]
289 return None
289 return None
290
290
291 @active
291 @active
292 def replace(self, file, offset, data=None):
292 def replace(self, file, offset, data=None):
293 '''
293 '''
294 replace can only replace already committed entries
294 replace can only replace already committed entries
295 that are not pending in the queue
295 that are not pending in the queue
296 '''
296 '''
297
297
298 if file not in self.map:
298 if file not in self.map:
299 raise KeyError(file)
299 raise KeyError(file)
300 index = self.map[file]
300 index = self.map[file]
301 self.entries[index] = (file, offset, data)
301 self.entries[index] = (file, offset, data)
302 self.file.write("%s\0%d\n" % (file, offset))
302 self.file.write("%s\0%d\n" % (file, offset))
303 self.file.flush()
303 self.file.flush()
304
304
305 @active
305 @active
306 def nest(self):
306 def nest(self):
307 self.count += 1
307 self.count += 1
308 self.usages += 1
308 self.usages += 1
309 return self
309 return self
310
310
311 def release(self):
311 def release(self):
312 if self.count > 0:
312 if self.count > 0:
313 self.usages -= 1
313 self.usages -= 1
314 # if the transaction scopes are left without being closed, fail
314 # if the transaction scopes are left without being closed, fail
315 if self.count > 0 and self.usages == 0:
315 if self.count > 0 and self.usages == 0:
316 self._abort()
316 self._abort()
317
317
318 def running(self):
318 def running(self):
319 return self.count > 0
319 return self.count > 0
320
320
321 def addpending(self, category, callback):
321 def addpending(self, category, callback):
322 """add a callback to be called when the transaction is pending
322 """add a callback to be called when the transaction is pending
323
323
324 The transaction will be given as callback's first argument.
324 The transaction will be given as callback's first argument.
325
325
326 Category is a unique identifier to allow overwriting an old callback
326 Category is a unique identifier to allow overwriting an old callback
327 with a newer callback.
327 with a newer callback.
328 """
328 """
329 self._pendingcallback[category] = callback
329 self._pendingcallback[category] = callback
330
330
331 @active
331 @active
332 def writepending(self):
332 def writepending(self):
333 '''write pending file to temporary version
333 '''write pending file to temporary version
334
334
335 This is used to allow hooks to view a transaction before commit'''
335 This is used to allow hooks to view a transaction before commit'''
336 categories = sorted(self._pendingcallback)
336 categories = sorted(self._pendingcallback)
337 for cat in categories:
337 for cat in categories:
338 # remove callback since the data will have been flushed
338 # remove callback since the data will have been flushed
339 any = self._pendingcallback.pop(cat)(self)
339 any = self._pendingcallback.pop(cat)(self)
340 self._anypending = self._anypending or any
340 self._anypending = self._anypending or any
341 self._anypending |= self._generatefiles(suffix='.pending')
341 self._anypending |= self._generatefiles(suffix='.pending')
342 return self._anypending
342 return self._anypending
343
343
344 @active
344 @active
345 def addfinalize(self, category, callback):
345 def addfinalize(self, category, callback):
346 """add a callback to be called when the transaction is closed
346 """add a callback to be called when the transaction is closed
347
347
348 The transaction will be given as callback's first argument.
348 The transaction will be given as callback's first argument.
349
349
350 Category is a unique identifier to allow overwriting old callbacks with
350 Category is a unique identifier to allow overwriting old callbacks with
351 newer callbacks.
351 newer callbacks.
352 """
352 """
353 self._finalizecallback[category] = callback
353 self._finalizecallback[category] = callback
354
354
355 @active
355 @active
356 def addpostclose(self, category, callback):
356 def addpostclose(self, category, callback):
357 """add a callback to be called after the transaction is closed
357 """add a callback to be called after the transaction is closed
358
358
359 The transaction will be given as callback's first argument.
359 The transaction will be given as callback's first argument.
360
360
361 Category is a unique identifier to allow overwriting an old callback
361 Category is a unique identifier to allow overwriting an old callback
362 with a newer callback.
362 with a newer callback.
363 """
363 """
364 self._postclosecallback[category] = callback
364 self._postclosecallback[category] = callback
365
365
366 @active
366 @active
367 def addabort(self, category, callback):
367 def addabort(self, category, callback):
368 """add a callback to be called when the transaction is aborted.
368 """add a callback to be called when the transaction is aborted.
369
369
370 The transaction will be given as the first argument to the callback.
370 The transaction will be given as the first argument to the callback.
371
371
372 Category is a unique identifier to allow overwriting an old callback
372 Category is a unique identifier to allow overwriting an old callback
373 with a newer callback.
373 with a newer callback.
374 """
374 """
375 self._abortcallback[category] = callback
375 self._abortcallback[category] = callback
376
376
377 @active
377 @active
378 def close(self):
378 def close(self):
379 '''commit the transaction'''
379 '''commit the transaction'''
380 if self.count == 1:
380 if self.count == 1:
381 self._generatefiles()
381 self._generatefiles()
382 categories = sorted(self._finalizecallback)
382 categories = sorted(self._finalizecallback)
383 for cat in categories:
383 for cat in categories:
384 self._finalizecallback[cat](self)
384 self._finalizecallback[cat](self)
385
385
386 self.count -= 1
386 self.count -= 1
387 if self.count != 0:
387 if self.count != 0:
388 return
388 return
389 self.file.close()
389 self.file.close()
390 self._backupsfile.close()
390 self._backupsfile.close()
391 # cleanup temporary files
391 # cleanup temporary files
392 for l, f, b, c in self._backupentries:
392 for l, f, b, c in self._backupentries:
393 if l not in self._vfsmap and c:
393 if l not in self._vfsmap and c:
394 self.report("couldn't remote %s: unknown cache location %s\n"
394 self.report("couldn't remote %s: unknown cache location %s\n"
395 % (b, l))
395 % (b, l))
396 continue
396 continue
397 vfs = self._vfsmap[l]
397 vfs = self._vfsmap[l]
398 if not f and b and vfs.exists(b):
398 if not f and b and vfs.exists(b):
399 try:
399 try:
400 vfs.unlink(b)
400 vfs.unlink(b)
401 except (IOError, OSError, util.Abort), inst:
401 except (IOError, OSError, util.Abort), inst:
402 if not c:
402 if not c:
403 raise
403 raise
404 # Abort may be raise by read only opener
404 # Abort may be raise by read only opener
405 self.report("couldn't remote %s: %s\n"
405 self.report("couldn't remote %s: %s\n"
406 % (vfs.join(b), inst))
406 % (vfs.join(b), inst))
407 self.entries = []
407 self.entries = []
408 self._writeundo()
408 if self.after:
409 if self.after:
409 self.after()
410 self.after()
410 if self.opener.isfile(self.journal):
411 if self.opener.isfile(self.journal):
411 self.opener.unlink(self.journal)
412 self.opener.unlink(self.journal)
412 if self.opener.isfile(self._backupjournal):
413 if self.opener.isfile(self._backupjournal):
413 self.opener.unlink(self._backupjournal)
414 self.opener.unlink(self._backupjournal)
414 for l, _f, b, c in self._backupentries:
415 for l, _f, b, c in self._backupentries:
415 if l not in self._vfsmap and c:
416 if l not in self._vfsmap and c:
416 self.report("couldn't remote %s: unknown cache location"
417 self.report("couldn't remote %s: unknown cache location"
417 "%s\n" % (b, l))
418 "%s\n" % (b, l))
418 continue
419 continue
419 vfs = self._vfsmap[l]
420 vfs = self._vfsmap[l]
420 if b and vfs.exists(b):
421 if b and vfs.exists(b):
421 try:
422 try:
422 vfs.unlink(b)
423 vfs.unlink(b)
423 except (IOError, OSError, util.Abort), inst:
424 except (IOError, OSError, util.Abort), inst:
424 if not c:
425 if not c:
425 raise
426 raise
426 # Abort may be raise by read only opener
427 # Abort may be raise by read only opener
427 self.report("couldn't remote %s: %s\n"
428 self.report("couldn't remote %s: %s\n"
428 % (vfs.join(b), inst))
429 % (vfs.join(b), inst))
429 self._backupentries = []
430 self._backupentries = []
430 self.journal = None
431 self.journal = None
431 # run post close action
432 # run post close action
432 categories = sorted(self._postclosecallback)
433 categories = sorted(self._postclosecallback)
433 for cat in categories:
434 for cat in categories:
434 self._postclosecallback[cat](self)
435 self._postclosecallback[cat](self)
435
436
436 @active
437 @active
437 def abort(self):
438 def abort(self):
438 '''abort the transaction (generally called on error, or when the
439 '''abort the transaction (generally called on error, or when the
439 transaction is not explicitly committed before going out of
440 transaction is not explicitly committed before going out of
440 scope)'''
441 scope)'''
441 self._abort()
442 self._abort()
442
443
444 def _writeundo(self):
445 """write transaction data for possible future undo call"""
446 if self.undoname is None:
447 return
448 undobackupfile = self.opener.open("%s.backupfiles" % self.undoname, 'w')
449 undobackupfile.write('%d\n' % version)
450 for l, f, b, c in self._backupentries:
451 if not f: # temporary file
452 continue
453 if not b:
454 u = ''
455 else:
456 if l not in self._vfsmap and c:
457 self.report("couldn't remote %s: unknown cache location"
458 "%s\n" % (b, l))
459 continue
460 vfs = self._vfsmap[l]
461 base, name = vfs.split(b)
462 assert name.startswith(self.journal), name
463 uname = name.replace(self.journal, self.undoname, 1)
464 u = vfs.reljoin(base, uname)
465 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True)
466 undobackupfile.write("%s\0%s\0%s\0%d\n" % (l, f, u, c))
467 undobackupfile.close()
468
469
443 def _abort(self):
470 def _abort(self):
444 self.count = 0
471 self.count = 0
445 self.usages = 0
472 self.usages = 0
446 self.file.close()
473 self.file.close()
447 self._backupsfile.close()
474 self._backupsfile.close()
448
475
449 try:
476 try:
450 if not self.entries and not self._backupentries:
477 if not self.entries and not self._backupentries:
451 if self.journal:
478 if self.journal:
452 self.opener.unlink(self.journal)
479 self.opener.unlink(self.journal)
453 if self._backupjournal:
480 if self._backupjournal:
454 self.opener.unlink(self._backupjournal)
481 self.opener.unlink(self._backupjournal)
455 return
482 return
456
483
457 self.report(_("transaction abort!\n"))
484 self.report(_("transaction abort!\n"))
458
485
459 try:
486 try:
460 for cat in sorted(self._abortcallback):
487 for cat in sorted(self._abortcallback):
461 self._abortcallback[cat](self)
488 self._abortcallback[cat](self)
462 _playback(self.journal, self.report, self.opener, self._vfsmap,
489 _playback(self.journal, self.report, self.opener, self._vfsmap,
463 self.entries, self._backupentries, False)
490 self.entries, self._backupentries, False)
464 self.report(_("rollback completed\n"))
491 self.report(_("rollback completed\n"))
465 except Exception:
492 except Exception:
466 self.report(_("rollback failed - please run hg recover\n"))
493 self.report(_("rollback failed - please run hg recover\n"))
467 finally:
494 finally:
468 self.journal = None
495 self.journal = None
469
496
470
497
471 def rollback(opener, vfsmap, file, report):
498 def rollback(opener, vfsmap, file, report):
472 """Rolls back the transaction contained in the given file
499 """Rolls back the transaction contained in the given file
473
500
474 Reads the entries in the specified file, and the corresponding
501 Reads the entries in the specified file, and the corresponding
475 '*.backupfiles' file, to recover from an incomplete transaction.
502 '*.backupfiles' file, to recover from an incomplete transaction.
476
503
477 * `file`: a file containing a list of entries, specifying where
504 * `file`: a file containing a list of entries, specifying where
478 to truncate each file. The file should contain a list of
505 to truncate each file. The file should contain a list of
479 file\0offset pairs, delimited by newlines. The corresponding
506 file\0offset pairs, delimited by newlines. The corresponding
480 '*.backupfiles' file should contain a list of file\0backupfile
507 '*.backupfiles' file should contain a list of file\0backupfile
481 pairs, delimited by \0.
508 pairs, delimited by \0.
482 """
509 """
483 entries = []
510 entries = []
484 backupentries = []
511 backupentries = []
485
512
486 fp = opener.open(file)
513 fp = opener.open(file)
487 lines = fp.readlines()
514 lines = fp.readlines()
488 fp.close()
515 fp.close()
489 for l in lines:
516 for l in lines:
490 try:
517 try:
491 f, o = l.split('\0')
518 f, o = l.split('\0')
492 entries.append((f, int(o), None))
519 entries.append((f, int(o), None))
493 except ValueError:
520 except ValueError:
494 report(_("couldn't read journal entry %r!\n") % l)
521 report(_("couldn't read journal entry %r!\n") % l)
495
522
496 backupjournal = "%s.backupfiles" % file
523 backupjournal = "%s.backupfiles" % file
497 if opener.exists(backupjournal):
524 if opener.exists(backupjournal):
498 fp = opener.open(backupjournal)
525 fp = opener.open(backupjournal)
499 lines = fp.readlines()
526 lines = fp.readlines()
500 if lines:
527 if lines:
501 ver = lines[0][:-1]
528 ver = lines[0][:-1]
502 if ver == str(version):
529 if ver == str(version):
503 for line in lines[1:]:
530 for line in lines[1:]:
504 if line:
531 if line:
505 # Shave off the trailing newline
532 # Shave off the trailing newline
506 line = line[:-1]
533 line = line[:-1]
507 l, f, b, c = line.split('\0')
534 l, f, b, c = line.split('\0')
508 backupentries.append((l, f, b, bool(c)))
535 backupentries.append((l, f, b, bool(c)))
509 else:
536 else:
510 report(_("journal was created by a different version of "
537 report(_("journal was created by a different version of "
511 "Mercurial"))
538 "Mercurial"))
512
539
513 _playback(file, report, opener, vfsmap, entries, backupentries)
540 _playback(file, report, opener, vfsmap, entries, backupentries)
@@ -1,285 +1,287 b''
1 Init repo1:
1 Init repo1:
2
2
3 $ hg init repo1
3 $ hg init repo1
4 $ cd repo1
4 $ cd repo1
5 $ echo "some text" > a
5 $ echo "some text" > a
6 $ hg add
6 $ hg add
7 adding a
7 adding a
8 $ hg ci -m first
8 $ hg ci -m first
9 $ cat .hg/store/fncache | sort
9 $ cat .hg/store/fncache | sort
10 data/a.i
10 data/a.i
11
11
12 Testing a.i/b:
12 Testing a.i/b:
13
13
14 $ mkdir a.i
14 $ mkdir a.i
15 $ echo "some other text" > a.i/b
15 $ echo "some other text" > a.i/b
16 $ hg add
16 $ hg add
17 adding a.i/b (glob)
17 adding a.i/b (glob)
18 $ hg ci -m second
18 $ hg ci -m second
19 $ cat .hg/store/fncache | sort
19 $ cat .hg/store/fncache | sort
20 data/a.i
20 data/a.i
21 data/a.i.hg/b.i
21 data/a.i.hg/b.i
22
22
23 Testing a.i.hg/c:
23 Testing a.i.hg/c:
24
24
25 $ mkdir a.i.hg
25 $ mkdir a.i.hg
26 $ echo "yet another text" > a.i.hg/c
26 $ echo "yet another text" > a.i.hg/c
27 $ hg add
27 $ hg add
28 adding a.i.hg/c (glob)
28 adding a.i.hg/c (glob)
29 $ hg ci -m third
29 $ hg ci -m third
30 $ cat .hg/store/fncache | sort
30 $ cat .hg/store/fncache | sort
31 data/a.i
31 data/a.i
32 data/a.i.hg.hg/c.i
32 data/a.i.hg.hg/c.i
33 data/a.i.hg/b.i
33 data/a.i.hg/b.i
34
34
35 Testing verify:
35 Testing verify:
36
36
37 $ hg verify
37 $ hg verify
38 checking changesets
38 checking changesets
39 checking manifests
39 checking manifests
40 crosschecking files in changesets and manifests
40 crosschecking files in changesets and manifests
41 checking files
41 checking files
42 3 files, 3 changesets, 3 total revisions
42 3 files, 3 changesets, 3 total revisions
43
43
44 $ rm .hg/store/fncache
44 $ rm .hg/store/fncache
45
45
46 $ hg verify
46 $ hg verify
47 checking changesets
47 checking changesets
48 checking manifests
48 checking manifests
49 crosschecking files in changesets and manifests
49 crosschecking files in changesets and manifests
50 checking files
50 checking files
51 data/a.i@0: missing revlog!
51 data/a.i@0: missing revlog!
52 data/a.i.hg/c.i@2: missing revlog!
52 data/a.i.hg/c.i@2: missing revlog!
53 data/a.i/b.i@1: missing revlog!
53 data/a.i/b.i@1: missing revlog!
54 3 files, 3 changesets, 3 total revisions
54 3 files, 3 changesets, 3 total revisions
55 3 integrity errors encountered!
55 3 integrity errors encountered!
56 (first damaged changeset appears to be 0)
56 (first damaged changeset appears to be 0)
57 [1]
57 [1]
58 $ cd ..
58 $ cd ..
59
59
60 Non store repo:
60 Non store repo:
61
61
62 $ hg --config format.usestore=False init foo
62 $ hg --config format.usestore=False init foo
63 $ cd foo
63 $ cd foo
64 $ mkdir tst.d
64 $ mkdir tst.d
65 $ echo foo > tst.d/foo
65 $ echo foo > tst.d/foo
66 $ hg ci -Amfoo
66 $ hg ci -Amfoo
67 adding tst.d/foo
67 adding tst.d/foo
68 $ find .hg | sort
68 $ find .hg | sort
69 .hg
69 .hg
70 .hg/00changelog.i
70 .hg/00changelog.i
71 .hg/00manifest.i
71 .hg/00manifest.i
72 .hg/cache
72 .hg/cache
73 .hg/cache/branch2-served
73 .hg/cache/branch2-served
74 .hg/cache/rbc-names-v1
74 .hg/cache/rbc-names-v1
75 .hg/cache/rbc-revs-v1
75 .hg/cache/rbc-revs-v1
76 .hg/data
76 .hg/data
77 .hg/data/tst.d.hg
77 .hg/data/tst.d.hg
78 .hg/data/tst.d.hg/foo.i
78 .hg/data/tst.d.hg/foo.i
79 .hg/dirstate
79 .hg/dirstate
80 .hg/last-message.txt
80 .hg/last-message.txt
81 .hg/phaseroots
81 .hg/phaseroots
82 .hg/requires
82 .hg/requires
83 .hg/undo
83 .hg/undo
84 .hg/undo.backupfiles
84 .hg/undo.bookmarks
85 .hg/undo.bookmarks
85 .hg/undo.branch
86 .hg/undo.branch
86 .hg/undo.desc
87 .hg/undo.desc
87 .hg/undo.dirstate
88 .hg/undo.dirstate
88 .hg/undo.phaseroots
89 .hg/undo.phaseroots
89 $ cd ..
90 $ cd ..
90
91
91 Non fncache repo:
92 Non fncache repo:
92
93
93 $ hg --config format.usefncache=False init bar
94 $ hg --config format.usefncache=False init bar
94 $ cd bar
95 $ cd bar
95 $ mkdir tst.d
96 $ mkdir tst.d
96 $ echo foo > tst.d/Foo
97 $ echo foo > tst.d/Foo
97 $ hg ci -Amfoo
98 $ hg ci -Amfoo
98 adding tst.d/Foo
99 adding tst.d/Foo
99 $ find .hg | sort
100 $ find .hg | sort
100 .hg
101 .hg
101 .hg/00changelog.i
102 .hg/00changelog.i
102 .hg/cache
103 .hg/cache
103 .hg/cache/branch2-served
104 .hg/cache/branch2-served
104 .hg/cache/rbc-names-v1
105 .hg/cache/rbc-names-v1
105 .hg/cache/rbc-revs-v1
106 .hg/cache/rbc-revs-v1
106 .hg/dirstate
107 .hg/dirstate
107 .hg/last-message.txt
108 .hg/last-message.txt
108 .hg/requires
109 .hg/requires
109 .hg/store
110 .hg/store
110 .hg/store/00changelog.i
111 .hg/store/00changelog.i
111 .hg/store/00manifest.i
112 .hg/store/00manifest.i
112 .hg/store/data
113 .hg/store/data
113 .hg/store/data/tst.d.hg
114 .hg/store/data/tst.d.hg
114 .hg/store/data/tst.d.hg/_foo.i
115 .hg/store/data/tst.d.hg/_foo.i
115 .hg/store/phaseroots
116 .hg/store/phaseroots
116 .hg/store/undo
117 .hg/store/undo
118 .hg/store/undo.backupfiles
117 .hg/store/undo.phaseroots
119 .hg/store/undo.phaseroots
118 .hg/undo.bookmarks
120 .hg/undo.bookmarks
119 .hg/undo.branch
121 .hg/undo.branch
120 .hg/undo.desc
122 .hg/undo.desc
121 .hg/undo.dirstate
123 .hg/undo.dirstate
122 $ cd ..
124 $ cd ..
123
125
124 Encoding of reserved / long paths in the store
126 Encoding of reserved / long paths in the store
125
127
126 $ hg init r2
128 $ hg init r2
127 $ cd r2
129 $ cd r2
128 $ cat <<EOF > .hg/hgrc
130 $ cat <<EOF > .hg/hgrc
129 > [ui]
131 > [ui]
130 > portablefilenames = ignore
132 > portablefilenames = ignore
131 > EOF
133 > EOF
132
134
133 $ hg import -q --bypass - <<EOF
135 $ hg import -q --bypass - <<EOF
134 > # HG changeset patch
136 > # HG changeset patch
135 > # User test
137 > # User test
136 > # Date 0 0
138 > # Date 0 0
137 > # Node ID 1c7a2f7cb77be1a0def34e4c7cabc562ad98fbd7
139 > # Node ID 1c7a2f7cb77be1a0def34e4c7cabc562ad98fbd7
138 > # Parent 0000000000000000000000000000000000000000
140 > # Parent 0000000000000000000000000000000000000000
139 > 1
141 > 1
140 >
142 >
141 > diff --git a/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
143 > diff --git a/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
142 > new file mode 100644
144 > new file mode 100644
143 > --- /dev/null
145 > --- /dev/null
144 > +++ b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
146 > +++ b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
145 > @@ -0,0 +1,1 @@
147 > @@ -0,0 +1,1 @@
146 > +foo
148 > +foo
147 > diff --git a/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
149 > diff --git a/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
148 > new file mode 100644
150 > new file mode 100644
149 > --- /dev/null
151 > --- /dev/null
150 > +++ b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
152 > +++ b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
151 > @@ -0,0 +1,1 @@
153 > @@ -0,0 +1,1 @@
152 > +foo
154 > +foo
153 > diff --git a/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
155 > diff --git a/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
154 > new file mode 100644
156 > new file mode 100644
155 > --- /dev/null
157 > --- /dev/null
156 > +++ b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
158 > +++ b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
157 > @@ -0,0 +1,1 @@
159 > @@ -0,0 +1,1 @@
158 > +foo
160 > +foo
159 > diff --git a/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
161 > diff --git a/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
160 > new file mode 100644
162 > new file mode 100644
161 > --- /dev/null
163 > --- /dev/null
162 > +++ b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
164 > +++ b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
163 > @@ -0,0 +1,1 @@
165 > @@ -0,0 +1,1 @@
164 > +foo
166 > +foo
165 > diff --git a/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
167 > diff --git a/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
166 > new file mode 100644
168 > new file mode 100644
167 > --- /dev/null
169 > --- /dev/null
168 > +++ b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
170 > +++ b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
169 > @@ -0,0 +1,1 @@
171 > @@ -0,0 +1,1 @@
170 > +foo
172 > +foo
171 > EOF
173 > EOF
172
174
173 $ find .hg/store -name *.i | sort
175 $ find .hg/store -name *.i | sort
174 .hg/store/00changelog.i
176 .hg/store/00changelog.i
175 .hg/store/00manifest.i
177 .hg/store/00manifest.i
176 .hg/store/data/bla.aux/pr~6e/_p_r_n/lpt/co~6d3/nu~6c/coma/foo._n_u_l/normal.c.i
178 .hg/store/data/bla.aux/pr~6e/_p_r_n/lpt/co~6d3/nu~6c/coma/foo._n_u_l/normal.c.i
177 .hg/store/dh/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxx168e07b38e65eff86ab579afaaa8e30bfbe0f35f.i
179 .hg/store/dh/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxx168e07b38e65eff86ab579afaaa8e30bfbe0f35f.i
178 .hg/store/dh/au~78/second/x.prn/fourth/fi~3afth/sixth/seventh/eighth/nineth/tenth/loremia20419e358ddff1bf8751e38288aff1d7c32ec05.i
180 .hg/store/dh/au~78/second/x.prn/fourth/fi~3afth/sixth/seventh/eighth/nineth/tenth/loremia20419e358ddff1bf8751e38288aff1d7c32ec05.i
179 .hg/store/dh/enterpri/openesba/contrib-/corba-bc/netbeans/wsdlexte/src/main/java/org.net7018f27961fdf338a598a40c4683429e7ffb9743.i
181 .hg/store/dh/enterpri/openesba/contrib-/corba-bc/netbeans/wsdlexte/src/main/java/org.net7018f27961fdf338a598a40c4683429e7ffb9743.i
180 .hg/store/dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilename0d8e1f4187c650e2f1fdca9fd90f786bc0976b6b.i
182 .hg/store/dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilename0d8e1f4187c650e2f1fdca9fd90f786bc0976b6b.i
181
183
182 $ cd ..
184 $ cd ..
183
185
184 Aborting lock does not prevent fncache writes
186 Aborting lock does not prevent fncache writes
185
187
186 $ cat > exceptionext.py <<EOF
188 $ cat > exceptionext.py <<EOF
187 > import os
189 > import os
188 > from mercurial import commands, util
190 > from mercurial import commands, util
189 > from mercurial.extensions import wrapfunction
191 > from mercurial.extensions import wrapfunction
190 >
192 >
191 > def lockexception(orig, vfs, lockname, wait, releasefn, acquirefn, desc):
193 > def lockexception(orig, vfs, lockname, wait, releasefn, acquirefn, desc):
192 > def releasewrap():
194 > def releasewrap():
193 > raise util.Abort("forced lock failure")
195 > raise util.Abort("forced lock failure")
194 > return orig(vfs, lockname, wait, releasewrap, acquirefn, desc)
196 > return orig(vfs, lockname, wait, releasewrap, acquirefn, desc)
195 >
197 >
196 > def reposetup(ui, repo):
198 > def reposetup(ui, repo):
197 > wrapfunction(repo, '_lock', lockexception)
199 > wrapfunction(repo, '_lock', lockexception)
198 >
200 >
199 > cmdtable = {}
201 > cmdtable = {}
200 >
202 >
201 > EOF
203 > EOF
202 $ extpath=`pwd`/exceptionext.py
204 $ extpath=`pwd`/exceptionext.py
203 $ hg init fncachetxn
205 $ hg init fncachetxn
204 $ cd fncachetxn
206 $ cd fncachetxn
205 $ printf "[extensions]\nexceptionext=$extpath\n" >> .hg/hgrc
207 $ printf "[extensions]\nexceptionext=$extpath\n" >> .hg/hgrc
206 $ touch y
208 $ touch y
207 $ hg ci -qAm y
209 $ hg ci -qAm y
208 abort: forced lock failure
210 abort: forced lock failure
209 [255]
211 [255]
210 $ cat .hg/store/fncache
212 $ cat .hg/store/fncache
211 data/y.i
213 data/y.i
212
214
213 Aborting transaction prevents fncache change
215 Aborting transaction prevents fncache change
214
216
215 $ cat > ../exceptionext.py <<EOF
217 $ cat > ../exceptionext.py <<EOF
216 > import os
218 > import os
217 > from mercurial import commands, util, localrepo
219 > from mercurial import commands, util, localrepo
218 > from mercurial.extensions import wrapfunction
220 > from mercurial.extensions import wrapfunction
219 >
221 >
220 > def wrapper(orig, self, *args, **kwargs):
222 > def wrapper(orig, self, *args, **kwargs):
221 > tr = orig(self, *args, **kwargs)
223 > tr = orig(self, *args, **kwargs)
222 > def fail(tr):
224 > def fail(tr):
223 > raise util.Abort("forced transaction failure")
225 > raise util.Abort("forced transaction failure")
224 > # zzz prefix to ensure it sorted after store.write
226 > # zzz prefix to ensure it sorted after store.write
225 > tr.addfinalize('zzz-forcefails', fail)
227 > tr.addfinalize('zzz-forcefails', fail)
226 > return tr
228 > return tr
227 >
229 >
228 > def uisetup(ui):
230 > def uisetup(ui):
229 > wrapfunction(localrepo.localrepository, 'transaction', wrapper)
231 > wrapfunction(localrepo.localrepository, 'transaction', wrapper)
230 >
232 >
231 > cmdtable = {}
233 > cmdtable = {}
232 >
234 >
233 > EOF
235 > EOF
234 $ rm -f "${extpath}c"
236 $ rm -f "${extpath}c"
235 $ touch z
237 $ touch z
236 $ hg ci -qAm z
238 $ hg ci -qAm z
237 transaction abort!
239 transaction abort!
238 rollback completed
240 rollback completed
239 abort: forced transaction failure
241 abort: forced transaction failure
240 [255]
242 [255]
241 $ cat .hg/store/fncache
243 $ cat .hg/store/fncache
242 data/y.i
244 data/y.i
243
245
244 Aborted transactions can be recovered later
246 Aborted transactions can be recovered later
245
247
246 $ cat > ../exceptionext.py <<EOF
248 $ cat > ../exceptionext.py <<EOF
247 > import os
249 > import os
248 > from mercurial import commands, util, transaction, localrepo
250 > from mercurial import commands, util, transaction, localrepo
249 > from mercurial.extensions import wrapfunction
251 > from mercurial.extensions import wrapfunction
250 >
252 >
251 > def trwrapper(orig, self, *args, **kwargs):
253 > def trwrapper(orig, self, *args, **kwargs):
252 > tr = orig(self, *args, **kwargs)
254 > tr = orig(self, *args, **kwargs)
253 > def fail(tr):
255 > def fail(tr):
254 > raise util.Abort("forced transaction failure")
256 > raise util.Abort("forced transaction failure")
255 > # zzz prefix to ensure it sorted after store.write
257 > # zzz prefix to ensure it sorted after store.write
256 > tr.addfinalize('zzz-forcefails', fail)
258 > tr.addfinalize('zzz-forcefails', fail)
257 > return tr
259 > return tr
258 >
260 >
259 > def abortwrapper(orig, self, *args, **kwargs):
261 > def abortwrapper(orig, self, *args, **kwargs):
260 > raise util.Abort("forced transaction failure")
262 > raise util.Abort("forced transaction failure")
261 >
263 >
262 > def uisetup(ui):
264 > def uisetup(ui):
263 > wrapfunction(localrepo.localrepository, 'transaction', trwrapper)
265 > wrapfunction(localrepo.localrepository, 'transaction', trwrapper)
264 > wrapfunction(transaction.transaction, '_abort', abortwrapper)
266 > wrapfunction(transaction.transaction, '_abort', abortwrapper)
265 >
267 >
266 > cmdtable = {}
268 > cmdtable = {}
267 >
269 >
268 > EOF
270 > EOF
269 $ rm -f "${extpath}c"
271 $ rm -f "${extpath}c"
270 $ hg up -q 1
272 $ hg up -q 1
271 $ touch z
273 $ touch z
272 $ hg ci -qAm z 2>/dev/null
274 $ hg ci -qAm z 2>/dev/null
273 [255]
275 [255]
274 $ cat .hg/store/fncache | sort
276 $ cat .hg/store/fncache | sort
275 data/y.i
277 data/y.i
276 data/z.i
278 data/z.i
277 $ hg recover
279 $ hg recover
278 rolling back interrupted transaction
280 rolling back interrupted transaction
279 checking changesets
281 checking changesets
280 checking manifests
282 checking manifests
281 crosschecking files in changesets and manifests
283 crosschecking files in changesets and manifests
282 checking files
284 checking files
283 1 files, 1 changesets, 1 total revisions
285 1 files, 1 changesets, 1 total revisions
284 $ cat .hg/store/fncache
286 $ cat .hg/store/fncache
285 data/y.i
287 data/y.i
@@ -1,353 +1,367 b''
1 #require hardlink
1 #require hardlink
2
2
3 $ cat > nlinks.py <<EOF
3 $ cat > nlinks.py <<EOF
4 > import sys
4 > import sys
5 > from mercurial import util
5 > from mercurial import util
6 > for f in sorted(sys.stdin.readlines()):
6 > for f in sorted(sys.stdin.readlines()):
7 > f = f[:-1]
7 > f = f[:-1]
8 > print util.nlinks(f), f
8 > print util.nlinks(f), f
9 > EOF
9 > EOF
10
10
11 $ nlinksdir()
11 $ nlinksdir()
12 > {
12 > {
13 > find $1 -type f | python $TESTTMP/nlinks.py
13 > find $1 -type f | python $TESTTMP/nlinks.py
14 > }
14 > }
15
15
16 Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
16 Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
17
17
18 $ cat > linkcp.py <<EOF
18 $ cat > linkcp.py <<EOF
19 > from mercurial import util
19 > from mercurial import util
20 > import sys
20 > import sys
21 > util.copyfiles(sys.argv[1], sys.argv[2], hardlink=True)
21 > util.copyfiles(sys.argv[1], sys.argv[2], hardlink=True)
22 > EOF
22 > EOF
23
23
24 $ linkcp()
24 $ linkcp()
25 > {
25 > {
26 > python $TESTTMP/linkcp.py $1 $2
26 > python $TESTTMP/linkcp.py $1 $2
27 > }
27 > }
28
28
29 Prepare repo r1:
29 Prepare repo r1:
30
30
31 $ hg init r1
31 $ hg init r1
32 $ cd r1
32 $ cd r1
33
33
34 $ echo c1 > f1
34 $ echo c1 > f1
35 $ hg add f1
35 $ hg add f1
36 $ hg ci -m0
36 $ hg ci -m0
37
37
38 $ mkdir d1
38 $ mkdir d1
39 $ cd d1
39 $ cd d1
40 $ echo c2 > f2
40 $ echo c2 > f2
41 $ hg add f2
41 $ hg add f2
42 $ hg ci -m1
42 $ hg ci -m1
43 $ cd ../..
43 $ cd ../..
44
44
45 $ nlinksdir r1/.hg/store
45 $ nlinksdir r1/.hg/store
46 1 r1/.hg/store/00changelog.i
46 1 r1/.hg/store/00changelog.i
47 1 r1/.hg/store/00manifest.i
47 1 r1/.hg/store/00manifest.i
48 1 r1/.hg/store/data/d1/f2.i
48 1 r1/.hg/store/data/d1/f2.i
49 1 r1/.hg/store/data/f1.i
49 1 r1/.hg/store/data/f1.i
50 1 r1/.hg/store/fncache
50 1 r1/.hg/store/fncache
51 1 r1/.hg/store/phaseroots
51 1 r1/.hg/store/phaseroots
52 1 r1/.hg/store/undo
52 1 r1/.hg/store/undo
53 1 r1/.hg/store/undo.backup.fncache
54 1 r1/.hg/store/undo.backupfiles
53 1 r1/.hg/store/undo.phaseroots
55 1 r1/.hg/store/undo.phaseroots
54
56
55
57
56 Create hardlinked clone r2:
58 Create hardlinked clone r2:
57
59
58 $ hg clone -U --debug r1 r2
60 $ hg clone -U --debug r1 r2
59 linked 7 files
61 linked 7 files
60
62
61 Create non-hardlinked clone r3:
63 Create non-hardlinked clone r3:
62
64
63 $ hg clone --pull r1 r3
65 $ hg clone --pull r1 r3
64 requesting all changes
66 requesting all changes
65 adding changesets
67 adding changesets
66 adding manifests
68 adding manifests
67 adding file changes
69 adding file changes
68 added 2 changesets with 2 changes to 2 files
70 added 2 changesets with 2 changes to 2 files
69 updating to branch default
71 updating to branch default
70 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
72 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
71
73
72
74
73 Repos r1 and r2 should now contain hardlinked files:
75 Repos r1 and r2 should now contain hardlinked files:
74
76
75 $ nlinksdir r1/.hg/store
77 $ nlinksdir r1/.hg/store
76 2 r1/.hg/store/00changelog.i
78 2 r1/.hg/store/00changelog.i
77 2 r1/.hg/store/00manifest.i
79 2 r1/.hg/store/00manifest.i
78 2 r1/.hg/store/data/d1/f2.i
80 2 r1/.hg/store/data/d1/f2.i
79 2 r1/.hg/store/data/f1.i
81 2 r1/.hg/store/data/f1.i
80 2 r1/.hg/store/fncache
82 2 r1/.hg/store/fncache
81 1 r1/.hg/store/phaseroots
83 1 r1/.hg/store/phaseroots
82 1 r1/.hg/store/undo
84 1 r1/.hg/store/undo
85 1 r1/.hg/store/undo.backup.fncache
86 1 r1/.hg/store/undo.backupfiles
83 1 r1/.hg/store/undo.phaseroots
87 1 r1/.hg/store/undo.phaseroots
84
88
85 $ nlinksdir r2/.hg/store
89 $ nlinksdir r2/.hg/store
86 2 r2/.hg/store/00changelog.i
90 2 r2/.hg/store/00changelog.i
87 2 r2/.hg/store/00manifest.i
91 2 r2/.hg/store/00manifest.i
88 2 r2/.hg/store/data/d1/f2.i
92 2 r2/.hg/store/data/d1/f2.i
89 2 r2/.hg/store/data/f1.i
93 2 r2/.hg/store/data/f1.i
90 2 r2/.hg/store/fncache
94 2 r2/.hg/store/fncache
91
95
92 Repo r3 should not be hardlinked:
96 Repo r3 should not be hardlinked:
93
97
94 $ nlinksdir r3/.hg/store
98 $ nlinksdir r3/.hg/store
95 1 r3/.hg/store/00changelog.i
99 1 r3/.hg/store/00changelog.i
96 1 r3/.hg/store/00manifest.i
100 1 r3/.hg/store/00manifest.i
97 1 r3/.hg/store/data/d1/f2.i
101 1 r3/.hg/store/data/d1/f2.i
98 1 r3/.hg/store/data/f1.i
102 1 r3/.hg/store/data/f1.i
99 1 r3/.hg/store/fncache
103 1 r3/.hg/store/fncache
100 1 r3/.hg/store/phaseroots
104 1 r3/.hg/store/phaseroots
101 1 r3/.hg/store/undo
105 1 r3/.hg/store/undo
106 1 r3/.hg/store/undo.backupfiles
102 1 r3/.hg/store/undo.phaseroots
107 1 r3/.hg/store/undo.phaseroots
103
108
104
109
105 Create a non-inlined filelog in r3:
110 Create a non-inlined filelog in r3:
106
111
107 $ cd r3/d1
112 $ cd r3/d1
108 >>> f = open('data1', 'wb')
113 >>> f = open('data1', 'wb')
109 >>> for x in range(10000):
114 >>> for x in range(10000):
110 ... f.write("%s\n" % str(x))
115 ... f.write("%s\n" % str(x))
111 >>> f.close()
116 >>> f.close()
112 $ for j in 0 1 2 3 4 5 6 7 8 9; do
117 $ for j in 0 1 2 3 4 5 6 7 8 9; do
113 > cat data1 >> f2
118 > cat data1 >> f2
114 > hg commit -m$j
119 > hg commit -m$j
115 > done
120 > done
116 $ cd ../..
121 $ cd ../..
117
122
118 $ nlinksdir r3/.hg/store
123 $ nlinksdir r3/.hg/store
119 1 r3/.hg/store/00changelog.i
124 1 r3/.hg/store/00changelog.i
120 1 r3/.hg/store/00manifest.i
125 1 r3/.hg/store/00manifest.i
121 1 r3/.hg/store/data/d1/f2.d
126 1 r3/.hg/store/data/d1/f2.d
122 1 r3/.hg/store/data/d1/f2.i
127 1 r3/.hg/store/data/d1/f2.i
123 1 r3/.hg/store/data/f1.i
128 1 r3/.hg/store/data/f1.i
124 1 r3/.hg/store/fncache
129 1 r3/.hg/store/fncache
125 1 r3/.hg/store/phaseroots
130 1 r3/.hg/store/phaseroots
126 1 r3/.hg/store/undo
131 1 r3/.hg/store/undo
132 1 r3/.hg/store/undo.backup.fncache
133 1 r3/.hg/store/undo.backup.phaseroots
134 1 r3/.hg/store/undo.backupfiles
127 1 r3/.hg/store/undo.phaseroots
135 1 r3/.hg/store/undo.phaseroots
128
136
129 Push to repo r1 should break up most hardlinks in r2:
137 Push to repo r1 should break up most hardlinks in r2:
130
138
131 $ hg -R r2 verify
139 $ hg -R r2 verify
132 checking changesets
140 checking changesets
133 checking manifests
141 checking manifests
134 crosschecking files in changesets and manifests
142 crosschecking files in changesets and manifests
135 checking files
143 checking files
136 2 files, 2 changesets, 2 total revisions
144 2 files, 2 changesets, 2 total revisions
137
145
138 $ cd r3
146 $ cd r3
139 $ hg push
147 $ hg push
140 pushing to $TESTTMP/r1 (glob)
148 pushing to $TESTTMP/r1 (glob)
141 searching for changes
149 searching for changes
142 adding changesets
150 adding changesets
143 adding manifests
151 adding manifests
144 adding file changes
152 adding file changes
145 added 10 changesets with 10 changes to 1 files
153 added 10 changesets with 10 changes to 1 files
146
154
147 $ cd ..
155 $ cd ..
148
156
149 $ nlinksdir r2/.hg/store
157 $ nlinksdir r2/.hg/store
150 1 r2/.hg/store/00changelog.i
158 1 r2/.hg/store/00changelog.i
151 1 r2/.hg/store/00manifest.i
159 1 r2/.hg/store/00manifest.i
152 1 r2/.hg/store/data/d1/f2.i
160 1 r2/.hg/store/data/d1/f2.i
153 2 r2/.hg/store/data/f1.i
161 2 r2/.hg/store/data/f1.i
154 1 r2/.hg/store/fncache
162 2 r2/.hg/store/fncache
155
163
156 $ hg -R r2 verify
164 $ hg -R r2 verify
157 checking changesets
165 checking changesets
158 checking manifests
166 checking manifests
159 crosschecking files in changesets and manifests
167 crosschecking files in changesets and manifests
160 checking files
168 checking files
161 2 files, 2 changesets, 2 total revisions
169 2 files, 2 changesets, 2 total revisions
162
170
163
171
164 $ cd r1
172 $ cd r1
165 $ hg up
173 $ hg up
166 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
167
175
168 Committing a change to f1 in r1 must break up hardlink f1.i in r2:
176 Committing a change to f1 in r1 must break up hardlink f1.i in r2:
169
177
170 $ echo c1c1 >> f1
178 $ echo c1c1 >> f1
171 $ hg ci -m00
179 $ hg ci -m00
172 $ cd ..
180 $ cd ..
173
181
174 $ nlinksdir r2/.hg/store
182 $ nlinksdir r2/.hg/store
175 1 r2/.hg/store/00changelog.i
183 1 r2/.hg/store/00changelog.i
176 1 r2/.hg/store/00manifest.i
184 1 r2/.hg/store/00manifest.i
177 1 r2/.hg/store/data/d1/f2.i
185 1 r2/.hg/store/data/d1/f2.i
178 1 r2/.hg/store/data/f1.i
186 1 r2/.hg/store/data/f1.i
179 1 r2/.hg/store/fncache
187 2 r2/.hg/store/fncache
180
188
181
189
182 $ cd r3
190 $ cd r3
183 $ hg tip --template '{rev}:{node|short}\n'
191 $ hg tip --template '{rev}:{node|short}\n'
184 11:a6451b6bc41f
192 11:a6451b6bc41f
185 $ echo bla > f1
193 $ echo bla > f1
186 $ hg ci -m1
194 $ hg ci -m1
187 $ cd ..
195 $ cd ..
188
196
189 Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
197 Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
190
198
191 $ linkcp r3 r4
199 $ linkcp r3 r4
192
200
193 r4 has hardlinks in the working dir (not just inside .hg):
201 r4 has hardlinks in the working dir (not just inside .hg):
194
202
195 $ nlinksdir r4
203 $ nlinksdir r4
196 2 r4/.hg/00changelog.i
204 2 r4/.hg/00changelog.i
197 2 r4/.hg/branch
205 2 r4/.hg/branch
198 2 r4/.hg/cache/branch2-served
206 2 r4/.hg/cache/branch2-served
199 2 r4/.hg/cache/rbc-names-v1
207 2 r4/.hg/cache/rbc-names-v1
200 2 r4/.hg/cache/rbc-revs-v1
208 2 r4/.hg/cache/rbc-revs-v1
201 2 r4/.hg/dirstate
209 2 r4/.hg/dirstate
202 2 r4/.hg/hgrc
210 2 r4/.hg/hgrc
203 2 r4/.hg/last-message.txt
211 2 r4/.hg/last-message.txt
204 2 r4/.hg/requires
212 2 r4/.hg/requires
205 2 r4/.hg/store/00changelog.i
213 2 r4/.hg/store/00changelog.i
206 2 r4/.hg/store/00manifest.i
214 2 r4/.hg/store/00manifest.i
207 2 r4/.hg/store/data/d1/f2.d
215 2 r4/.hg/store/data/d1/f2.d
208 2 r4/.hg/store/data/d1/f2.i
216 2 r4/.hg/store/data/d1/f2.i
209 2 r4/.hg/store/data/f1.i
217 2 r4/.hg/store/data/f1.i
210 2 r4/.hg/store/fncache
218 2 r4/.hg/store/fncache
211 2 r4/.hg/store/phaseroots
219 2 r4/.hg/store/phaseroots
212 2 r4/.hg/store/undo
220 2 r4/.hg/store/undo
221 2 r4/.hg/store/undo.backup.fncache
222 2 r4/.hg/store/undo.backup.phaseroots
223 2 r4/.hg/store/undo.backupfiles
213 2 r4/.hg/store/undo.phaseroots
224 2 r4/.hg/store/undo.phaseroots
214 2 r4/.hg/undo.bookmarks
225 2 r4/.hg/undo.bookmarks
215 2 r4/.hg/undo.branch
226 2 r4/.hg/undo.branch
216 2 r4/.hg/undo.desc
227 2 r4/.hg/undo.desc
217 2 r4/.hg/undo.dirstate
228 2 r4/.hg/undo.dirstate
218 2 r4/d1/data1
229 2 r4/d1/data1
219 2 r4/d1/f2
230 2 r4/d1/f2
220 2 r4/f1
231 2 r4/f1
221
232
222 Update back to revision 11 in r4 should break hardlink of file f1:
233 Update back to revision 11 in r4 should break hardlink of file f1:
223
234
224 $ hg -R r4 up 11
235 $ hg -R r4 up 11
225 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
226
237
227 $ nlinksdir r4
238 $ nlinksdir r4
228 2 r4/.hg/00changelog.i
239 2 r4/.hg/00changelog.i
229 1 r4/.hg/branch
240 1 r4/.hg/branch
230 2 r4/.hg/cache/branch2-served
241 2 r4/.hg/cache/branch2-served
231 2 r4/.hg/cache/rbc-names-v1
242 2 r4/.hg/cache/rbc-names-v1
232 2 r4/.hg/cache/rbc-revs-v1
243 2 r4/.hg/cache/rbc-revs-v1
233 1 r4/.hg/dirstate
244 1 r4/.hg/dirstate
234 2 r4/.hg/hgrc
245 2 r4/.hg/hgrc
235 2 r4/.hg/last-message.txt
246 2 r4/.hg/last-message.txt
236 2 r4/.hg/requires
247 2 r4/.hg/requires
237 2 r4/.hg/store/00changelog.i
248 2 r4/.hg/store/00changelog.i
238 2 r4/.hg/store/00manifest.i
249 2 r4/.hg/store/00manifest.i
239 2 r4/.hg/store/data/d1/f2.d
250 2 r4/.hg/store/data/d1/f2.d
240 2 r4/.hg/store/data/d1/f2.i
251 2 r4/.hg/store/data/d1/f2.i
241 2 r4/.hg/store/data/f1.i
252 2 r4/.hg/store/data/f1.i
242 2 r4/.hg/store/fncache
253 2 r4/.hg/store/fncache
243 2 r4/.hg/store/phaseroots
254 2 r4/.hg/store/phaseroots
244 2 r4/.hg/store/undo
255 2 r4/.hg/store/undo
256 2 r4/.hg/store/undo.backup.fncache
257 2 r4/.hg/store/undo.backup.phaseroots
258 2 r4/.hg/store/undo.backupfiles
245 2 r4/.hg/store/undo.phaseroots
259 2 r4/.hg/store/undo.phaseroots
246 2 r4/.hg/undo.bookmarks
260 2 r4/.hg/undo.bookmarks
247 2 r4/.hg/undo.branch
261 2 r4/.hg/undo.branch
248 2 r4/.hg/undo.desc
262 2 r4/.hg/undo.desc
249 2 r4/.hg/undo.dirstate
263 2 r4/.hg/undo.dirstate
250 2 r4/d1/data1
264 2 r4/d1/data1
251 2 r4/d1/f2
265 2 r4/d1/f2
252 1 r4/f1
266 1 r4/f1
253
267
254
268
255 Test hardlinking outside hg:
269 Test hardlinking outside hg:
256
270
257 $ mkdir x
271 $ mkdir x
258 $ echo foo > x/a
272 $ echo foo > x/a
259
273
260 $ linkcp x y
274 $ linkcp x y
261 $ echo bar >> y/a
275 $ echo bar >> y/a
262
276
263 No diff if hardlink:
277 No diff if hardlink:
264
278
265 $ diff x/a y/a
279 $ diff x/a y/a
266
280
267 Test mq hardlinking:
281 Test mq hardlinking:
268
282
269 $ echo "[extensions]" >> $HGRCPATH
283 $ echo "[extensions]" >> $HGRCPATH
270 $ echo "mq=" >> $HGRCPATH
284 $ echo "mq=" >> $HGRCPATH
271
285
272 $ hg init a
286 $ hg init a
273 $ cd a
287 $ cd a
274
288
275 $ hg qimport -n foo - << EOF
289 $ hg qimport -n foo - << EOF
276 > # HG changeset patch
290 > # HG changeset patch
277 > # Date 1 0
291 > # Date 1 0
278 > diff -r 2588a8b53d66 a
292 > diff -r 2588a8b53d66 a
279 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
293 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
280 > +++ b/a Wed Jul 23 15:54:29 2008 +0200
294 > +++ b/a Wed Jul 23 15:54:29 2008 +0200
281 > @@ -0,0 +1,1 @@
295 > @@ -0,0 +1,1 @@
282 > +a
296 > +a
283 > EOF
297 > EOF
284 adding foo to series file
298 adding foo to series file
285
299
286 $ hg qpush
300 $ hg qpush
287 applying foo
301 applying foo
288 now at: foo
302 now at: foo
289
303
290 $ cd ..
304 $ cd ..
291 $ linkcp a b
305 $ linkcp a b
292 $ cd b
306 $ cd b
293
307
294 $ hg qimport -n bar - << EOF
308 $ hg qimport -n bar - << EOF
295 > # HG changeset patch
309 > # HG changeset patch
296 > # Date 2 0
310 > # Date 2 0
297 > diff -r 2588a8b53d66 a
311 > diff -r 2588a8b53d66 a
298 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
312 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
299 > +++ b/b Wed Jul 23 15:54:29 2008 +0200
313 > +++ b/b Wed Jul 23 15:54:29 2008 +0200
300 > @@ -0,0 +1,1 @@
314 > @@ -0,0 +1,1 @@
301 > +b
315 > +b
302 > EOF
316 > EOF
303 adding bar to series file
317 adding bar to series file
304
318
305 $ hg qpush
319 $ hg qpush
306 applying bar
320 applying bar
307 now at: bar
321 now at: bar
308
322
309 $ cat .hg/patches/status
323 $ cat .hg/patches/status
310 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
324 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
311 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
325 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
312
326
313 $ cat .hg/patches/series
327 $ cat .hg/patches/series
314 foo
328 foo
315 bar
329 bar
316
330
317 $ cat ../a/.hg/patches/status
331 $ cat ../a/.hg/patches/status
318 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
332 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
319
333
320 $ cat ../a/.hg/patches/series
334 $ cat ../a/.hg/patches/series
321 foo
335 foo
322
336
323 Test tags hardlinking:
337 Test tags hardlinking:
324
338
325 $ hg qdel -r qbase:qtip
339 $ hg qdel -r qbase:qtip
326 patch foo finalized without changeset message
340 patch foo finalized without changeset message
327 patch bar finalized without changeset message
341 patch bar finalized without changeset message
328
342
329 $ hg tag -l lfoo
343 $ hg tag -l lfoo
330 $ hg tag foo
344 $ hg tag foo
331
345
332 $ cd ..
346 $ cd ..
333 $ linkcp b c
347 $ linkcp b c
334 $ cd c
348 $ cd c
335
349
336 $ hg tag -l -r 0 lbar
350 $ hg tag -l -r 0 lbar
337 $ hg tag -r 0 bar
351 $ hg tag -r 0 bar
338
352
339 $ cat .hgtags
353 $ cat .hgtags
340 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
354 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
341 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
355 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
342
356
343 $ cat .hg/localtags
357 $ cat .hg/localtags
344 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
358 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
345 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
359 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
346
360
347 $ cat ../b/.hgtags
361 $ cat ../b/.hgtags
348 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
362 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
349
363
350 $ cat ../b/.hg/localtags
364 $ cat ../b/.hg/localtags
351 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
365 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
352
366
353 $ cd ..
367 $ cd ..
@@ -1,660 +1,662 b''
1 commit hooks can see env vars
1 commit hooks can see env vars
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ cat > .hg/hgrc <<EOF
5 $ cat > .hg/hgrc <<EOF
6 > [hooks]
6 > [hooks]
7 > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
7 > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
8 > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
8 > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
9 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
9 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
10 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
10 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
11 > pretxncommit.tip = hg -q tip
11 > pretxncommit.tip = hg -q tip
12 > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
12 > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
13 > pre-cat = python "$TESTDIR/printenv.py" pre-cat
13 > pre-cat = python "$TESTDIR/printenv.py" pre-cat
14 > post-cat = python "$TESTDIR/printenv.py" post-cat
14 > post-cat = python "$TESTDIR/printenv.py" post-cat
15 > EOF
15 > EOF
16 $ echo a > a
16 $ echo a > a
17 $ hg add a
17 $ hg add a
18 $ hg commit -m a
18 $ hg commit -m a
19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
21 0:cb9a9f314b8b
21 0:cb9a9f314b8b
22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
24
24
25 $ hg clone . ../b
25 $ hg clone . ../b
26 updating to branch default
26 updating to branch default
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 $ cd ../b
28 $ cd ../b
29
29
30 changegroup hooks can see env vars
30 changegroup hooks can see env vars
31
31
32 $ cat > .hg/hgrc <<EOF
32 $ cat > .hg/hgrc <<EOF
33 > [hooks]
33 > [hooks]
34 > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
34 > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
35 > changegroup = python "$TESTDIR/printenv.py" changegroup
35 > changegroup = python "$TESTDIR/printenv.py" changegroup
36 > incoming = python "$TESTDIR/printenv.py" incoming
36 > incoming = python "$TESTDIR/printenv.py" incoming
37 > EOF
37 > EOF
38
38
39 pretxncommit and commit hooks can see both parents of merge
39 pretxncommit and commit hooks can see both parents of merge
40
40
41 $ cd ../a
41 $ cd ../a
42 $ echo b >> a
42 $ echo b >> a
43 $ hg commit -m a1 -d "1 0"
43 $ hg commit -m a1 -d "1 0"
44 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
44 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
45 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
45 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
46 1:ab228980c14d
46 1:ab228980c14d
47 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
47 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
48 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
48 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
49 $ hg update -C 0
49 $ hg update -C 0
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 $ echo b > b
51 $ echo b > b
52 $ hg add b
52 $ hg add b
53 $ hg commit -m b -d '1 0'
53 $ hg commit -m b -d '1 0'
54 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
54 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
55 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
55 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
56 2:ee9deb46ab31
56 2:ee9deb46ab31
57 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
57 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
58 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
58 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
59 created new head
59 created new head
60 $ hg merge 1
60 $ hg merge 1
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 (branch merge, don't forget to commit)
62 (branch merge, don't forget to commit)
63 $ hg commit -m merge -d '2 0'
63 $ hg commit -m merge -d '2 0'
64 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
64 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
65 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
65 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
66 3:07f3376c1e65
66 3:07f3376c1e65
67 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
67 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
68 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
68 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
69
69
70 test generic hooks
70 test generic hooks
71
71
72 $ hg id
72 $ hg id
73 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
73 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
74 abort: pre-identify hook exited with status 1
74 abort: pre-identify hook exited with status 1
75 [255]
75 [255]
76 $ hg cat b
76 $ hg cat b
77 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
77 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
78 b
78 b
79 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
79 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
80
80
81 $ cd ../b
81 $ cd ../b
82 $ hg pull ../a
82 $ hg pull ../a
83 pulling from ../a
83 pulling from ../a
84 searching for changes
84 searching for changes
85 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
85 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
86 adding changesets
86 adding changesets
87 adding manifests
87 adding manifests
88 adding file changes
88 adding file changes
89 added 3 changesets with 2 changes to 2 files
89 added 3 changesets with 2 changes to 2 files
90 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
90 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
92 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
92 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
93 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
93 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
94 (run 'hg update' to get a working copy)
94 (run 'hg update' to get a working copy)
95
95
96 tag hooks can see env vars
96 tag hooks can see env vars
97
97
98 $ cd ../a
98 $ cd ../a
99 $ cat >> .hg/hgrc <<EOF
99 $ cat >> .hg/hgrc <<EOF
100 > pretag = python "$TESTDIR/printenv.py" pretag
100 > pretag = python "$TESTDIR/printenv.py" pretag
101 > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
101 > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
102 > EOF
102 > EOF
103 $ hg tag -d '3 0' a
103 $ hg tag -d '3 0' a
104 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
104 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
105 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
105 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
106 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
106 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
107 4:539e4b31b6dc
107 4:539e4b31b6dc
108 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
108 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
109 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
109 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
110 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
110 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
111 $ hg tag -l la
111 $ hg tag -l la
112 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
112 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
113 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
113 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
114
114
115 pretag hook can forbid tagging
115 pretag hook can forbid tagging
116
116
117 $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
117 $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
118 $ hg tag -d '4 0' fa
118 $ hg tag -d '4 0' fa
119 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
119 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
120 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
120 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
121 abort: pretag.forbid hook exited with status 1
121 abort: pretag.forbid hook exited with status 1
122 [255]
122 [255]
123 $ hg tag -l fla
123 $ hg tag -l fla
124 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
124 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
125 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
125 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
126 abort: pretag.forbid hook exited with status 1
126 abort: pretag.forbid hook exited with status 1
127 [255]
127 [255]
128
128
129 pretxncommit hook can see changeset, can roll back txn, changeset no
129 pretxncommit hook can see changeset, can roll back txn, changeset no
130 more there after
130 more there after
131
131
132 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
132 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
133 $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
133 $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
134 $ echo z > z
134 $ echo z > z
135 $ hg add z
135 $ hg add z
136 $ hg -q tip
136 $ hg -q tip
137 4:539e4b31b6dc
137 4:539e4b31b6dc
138 $ hg commit -m 'fail' -d '4 0'
138 $ hg commit -m 'fail' -d '4 0'
139 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
139 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
140 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
140 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
141 5:6f611f8018c1
141 5:6f611f8018c1
142 5:6f611f8018c1
142 5:6f611f8018c1
143 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
143 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
144 transaction abort!
144 transaction abort!
145 rollback completed
145 rollback completed
146 abort: pretxncommit.forbid1 hook exited with status 1
146 abort: pretxncommit.forbid1 hook exited with status 1
147 [255]
147 [255]
148 $ hg -q tip
148 $ hg -q tip
149 4:539e4b31b6dc
149 4:539e4b31b6dc
150
150
151 (Check that no 'changelog.i.a' file were left behind)
151 (Check that no 'changelog.i.a' file were left behind)
152
152
153 $ ls -1 .hg/store/
153 $ ls -1 .hg/store/
154 00changelog.i
154 00changelog.i
155 00manifest.i
155 00manifest.i
156 data
156 data
157 fncache
157 fncache
158 journal.phaseroots
158 journal.phaseroots
159 phaseroots
159 phaseroots
160 undo
160 undo
161 undo.backup.fncache
162 undo.backupfiles
161 undo.phaseroots
163 undo.phaseroots
162
164
163
165
164 precommit hook can prevent commit
166 precommit hook can prevent commit
165
167
166 $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
168 $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
167 $ hg commit -m 'fail' -d '4 0'
169 $ hg commit -m 'fail' -d '4 0'
168 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
170 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
169 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
171 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
170 abort: precommit.forbid hook exited with status 1
172 abort: precommit.forbid hook exited with status 1
171 [255]
173 [255]
172 $ hg -q tip
174 $ hg -q tip
173 4:539e4b31b6dc
175 4:539e4b31b6dc
174
176
175 preupdate hook can prevent update
177 preupdate hook can prevent update
176
178
177 $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
179 $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
178 $ hg update 1
180 $ hg update 1
179 preupdate hook: HG_PARENT1=ab228980c14d
181 preupdate hook: HG_PARENT1=ab228980c14d
180 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
182 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
181
183
182 update hook
184 update hook
183
185
184 $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
186 $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
185 $ hg update
187 $ hg update
186 preupdate hook: HG_PARENT1=539e4b31b6dc
188 preupdate hook: HG_PARENT1=539e4b31b6dc
187 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
189 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
188 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
189
191
190 pushkey hook
192 pushkey hook
191
193
192 $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
194 $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
193 $ cd ../b
195 $ cd ../b
194 $ hg bookmark -r null foo
196 $ hg bookmark -r null foo
195 $ hg push -B foo ../a
197 $ hg push -B foo ../a
196 pushing to ../a
198 pushing to ../a
197 searching for changes
199 searching for changes
198 no changes found
200 no changes found
199 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
201 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
200 exporting bookmark foo
202 exporting bookmark foo
201 [1]
203 [1]
202 $ cd ../a
204 $ cd ../a
203
205
204 listkeys hook
206 listkeys hook
205
207
206 $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
208 $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
207 $ hg bookmark -r null bar
209 $ hg bookmark -r null bar
208 $ cd ../b
210 $ cd ../b
209 $ hg pull -B bar ../a
211 $ hg pull -B bar ../a
210 pulling from ../a
212 pulling from ../a
211 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
213 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
212 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
214 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
213 no changes found
215 no changes found
214 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
216 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
215 adding remote bookmark bar
217 adding remote bookmark bar
216 $ cd ../a
218 $ cd ../a
217
219
218 test that prepushkey can prevent incoming keys
220 test that prepushkey can prevent incoming keys
219
221
220 $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
222 $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
221 $ cd ../b
223 $ cd ../b
222 $ hg bookmark -r null baz
224 $ hg bookmark -r null baz
223 $ hg push -B baz ../a
225 $ hg push -B baz ../a
224 pushing to ../a
226 pushing to ../a
225 searching for changes
227 searching for changes
226 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
228 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
227 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
229 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
228 no changes found
230 no changes found
229 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
231 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
230 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
232 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
231 pushkey-abort: prepushkey hook exited with status 1
233 pushkey-abort: prepushkey hook exited with status 1
232 exporting bookmark baz failed!
234 exporting bookmark baz failed!
233 [1]
235 [1]
234 $ cd ../a
236 $ cd ../a
235
237
236 test that prelistkeys can prevent listing keys
238 test that prelistkeys can prevent listing keys
237
239
238 $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
240 $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
239 $ hg bookmark -r null quux
241 $ hg bookmark -r null quux
240 $ cd ../b
242 $ cd ../b
241 $ hg pull -B quux ../a
243 $ hg pull -B quux ../a
242 pulling from ../a
244 pulling from ../a
243 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
245 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
244 abort: prelistkeys hook exited with status 1
246 abort: prelistkeys hook exited with status 1
245 [255]
247 [255]
246 $ cd ../a
248 $ cd ../a
247 $ rm .hg/hgrc
249 $ rm .hg/hgrc
248
250
249 prechangegroup hook can prevent incoming changes
251 prechangegroup hook can prevent incoming changes
250
252
251 $ cd ../b
253 $ cd ../b
252 $ hg -q tip
254 $ hg -q tip
253 3:07f3376c1e65
255 3:07f3376c1e65
254 $ cat > .hg/hgrc <<EOF
256 $ cat > .hg/hgrc <<EOF
255 > [hooks]
257 > [hooks]
256 > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
258 > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
257 > EOF
259 > EOF
258 $ hg pull ../a
260 $ hg pull ../a
259 pulling from ../a
261 pulling from ../a
260 searching for changes
262 searching for changes
261 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
263 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
262 abort: prechangegroup.forbid hook exited with status 1
264 abort: prechangegroup.forbid hook exited with status 1
263 [255]
265 [255]
264
266
265 pretxnchangegroup hook can see incoming changes, can roll back txn,
267 pretxnchangegroup hook can see incoming changes, can roll back txn,
266 incoming changes no longer there after
268 incoming changes no longer there after
267
269
268 $ cat > .hg/hgrc <<EOF
270 $ cat > .hg/hgrc <<EOF
269 > [hooks]
271 > [hooks]
270 > pretxnchangegroup.forbid0 = hg tip -q
272 > pretxnchangegroup.forbid0 = hg tip -q
271 > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
273 > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
272 > EOF
274 > EOF
273 $ hg pull ../a
275 $ hg pull ../a
274 pulling from ../a
276 pulling from ../a
275 searching for changes
277 searching for changes
276 adding changesets
278 adding changesets
277 adding manifests
279 adding manifests
278 adding file changes
280 adding file changes
279 added 1 changesets with 1 changes to 1 files
281 added 1 changesets with 1 changes to 1 files
280 4:539e4b31b6dc
282 4:539e4b31b6dc
281 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
283 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
282 transaction abort!
284 transaction abort!
283 rollback completed
285 rollback completed
284 abort: pretxnchangegroup.forbid1 hook exited with status 1
286 abort: pretxnchangegroup.forbid1 hook exited with status 1
285 [255]
287 [255]
286 $ hg -q tip
288 $ hg -q tip
287 3:07f3376c1e65
289 3:07f3376c1e65
288
290
289 outgoing hooks can see env vars
291 outgoing hooks can see env vars
290
292
291 $ rm .hg/hgrc
293 $ rm .hg/hgrc
292 $ cat > ../a/.hg/hgrc <<EOF
294 $ cat > ../a/.hg/hgrc <<EOF
293 > [hooks]
295 > [hooks]
294 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
296 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
295 > outgoing = python "$TESTDIR/printenv.py" outgoing
297 > outgoing = python "$TESTDIR/printenv.py" outgoing
296 > EOF
298 > EOF
297 $ hg pull ../a
299 $ hg pull ../a
298 pulling from ../a
300 pulling from ../a
299 searching for changes
301 searching for changes
300 preoutgoing hook: HG_SOURCE=pull
302 preoutgoing hook: HG_SOURCE=pull
301 adding changesets
303 adding changesets
302 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
304 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
303 adding manifests
305 adding manifests
304 adding file changes
306 adding file changes
305 added 1 changesets with 1 changes to 1 files
307 added 1 changesets with 1 changes to 1 files
306 adding remote bookmark quux
308 adding remote bookmark quux
307 (run 'hg update' to get a working copy)
309 (run 'hg update' to get a working copy)
308 $ hg rollback
310 $ hg rollback
309 repository tip rolled back to revision 3 (undo pull)
311 repository tip rolled back to revision 3 (undo pull)
310
312
311 preoutgoing hook can prevent outgoing changes
313 preoutgoing hook can prevent outgoing changes
312
314
313 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
315 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
314 $ hg pull ../a
316 $ hg pull ../a
315 pulling from ../a
317 pulling from ../a
316 searching for changes
318 searching for changes
317 preoutgoing hook: HG_SOURCE=pull
319 preoutgoing hook: HG_SOURCE=pull
318 preoutgoing.forbid hook: HG_SOURCE=pull
320 preoutgoing.forbid hook: HG_SOURCE=pull
319 abort: preoutgoing.forbid hook exited with status 1
321 abort: preoutgoing.forbid hook exited with status 1
320 [255]
322 [255]
321
323
322 outgoing hooks work for local clones
324 outgoing hooks work for local clones
323
325
324 $ cd ..
326 $ cd ..
325 $ cat > a/.hg/hgrc <<EOF
327 $ cat > a/.hg/hgrc <<EOF
326 > [hooks]
328 > [hooks]
327 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
329 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
328 > outgoing = python "$TESTDIR/printenv.py" outgoing
330 > outgoing = python "$TESTDIR/printenv.py" outgoing
329 > EOF
331 > EOF
330 $ hg clone a c
332 $ hg clone a c
331 preoutgoing hook: HG_SOURCE=clone
333 preoutgoing hook: HG_SOURCE=clone
332 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
334 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
333 updating to branch default
335 updating to branch default
334 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
336 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 $ rm -rf c
337 $ rm -rf c
336
338
337 preoutgoing hook can prevent outgoing changes for local clones
339 preoutgoing hook can prevent outgoing changes for local clones
338
340
339 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
341 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
340 $ hg clone a zzz
342 $ hg clone a zzz
341 preoutgoing hook: HG_SOURCE=clone
343 preoutgoing hook: HG_SOURCE=clone
342 preoutgoing.forbid hook: HG_SOURCE=clone
344 preoutgoing.forbid hook: HG_SOURCE=clone
343 abort: preoutgoing.forbid hook exited with status 1
345 abort: preoutgoing.forbid hook exited with status 1
344 [255]
346 [255]
345
347
346 $ cd "$TESTTMP/b"
348 $ cd "$TESTTMP/b"
347
349
348 $ cat > hooktests.py <<EOF
350 $ cat > hooktests.py <<EOF
349 > from mercurial import util
351 > from mercurial import util
350 >
352 >
351 > uncallable = 0
353 > uncallable = 0
352 >
354 >
353 > def printargs(args):
355 > def printargs(args):
354 > args.pop('ui', None)
356 > args.pop('ui', None)
355 > args.pop('repo', None)
357 > args.pop('repo', None)
356 > a = list(args.items())
358 > a = list(args.items())
357 > a.sort()
359 > a.sort()
358 > print 'hook args:'
360 > print 'hook args:'
359 > for k, v in a:
361 > for k, v in a:
360 > print ' ', k, v
362 > print ' ', k, v
361 >
363 >
362 > def passhook(**args):
364 > def passhook(**args):
363 > printargs(args)
365 > printargs(args)
364 >
366 >
365 > def failhook(**args):
367 > def failhook(**args):
366 > printargs(args)
368 > printargs(args)
367 > return True
369 > return True
368 >
370 >
369 > class LocalException(Exception):
371 > class LocalException(Exception):
370 > pass
372 > pass
371 >
373 >
372 > def raisehook(**args):
374 > def raisehook(**args):
373 > raise LocalException('exception from hook')
375 > raise LocalException('exception from hook')
374 >
376 >
375 > def aborthook(**args):
377 > def aborthook(**args):
376 > raise util.Abort('raise abort from hook')
378 > raise util.Abort('raise abort from hook')
377 >
379 >
378 > def brokenhook(**args):
380 > def brokenhook(**args):
379 > return 1 + {}
381 > return 1 + {}
380 >
382 >
381 > def verbosehook(ui, **args):
383 > def verbosehook(ui, **args):
382 > ui.note('verbose output from hook\n')
384 > ui.note('verbose output from hook\n')
383 >
385 >
384 > def printtags(ui, repo, **args):
386 > def printtags(ui, repo, **args):
385 > print sorted(repo.tags())
387 > print sorted(repo.tags())
386 >
388 >
387 > class container:
389 > class container:
388 > unreachable = 1
390 > unreachable = 1
389 > EOF
391 > EOF
390
392
391 test python hooks
393 test python hooks
392
394
393 #if windows
395 #if windows
394 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
396 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
395 #else
397 #else
396 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
398 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
397 #endif
399 #endif
398 $ export PYTHONPATH
400 $ export PYTHONPATH
399
401
400 $ echo '[hooks]' > ../a/.hg/hgrc
402 $ echo '[hooks]' > ../a/.hg/hgrc
401 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
403 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
402 $ hg pull ../a 2>&1 | grep 'raised an exception'
404 $ hg pull ../a 2>&1 | grep 'raised an exception'
403 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
405 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
404
406
405 $ echo '[hooks]' > ../a/.hg/hgrc
407 $ echo '[hooks]' > ../a/.hg/hgrc
406 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
408 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
407 $ hg pull ../a 2>&1 | grep 'raised an exception'
409 $ hg pull ../a 2>&1 | grep 'raised an exception'
408 error: preoutgoing.raise hook raised an exception: exception from hook
410 error: preoutgoing.raise hook raised an exception: exception from hook
409
411
410 $ echo '[hooks]' > ../a/.hg/hgrc
412 $ echo '[hooks]' > ../a/.hg/hgrc
411 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
413 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
412 $ hg pull ../a
414 $ hg pull ../a
413 pulling from ../a
415 pulling from ../a
414 searching for changes
416 searching for changes
415 error: preoutgoing.abort hook failed: raise abort from hook
417 error: preoutgoing.abort hook failed: raise abort from hook
416 abort: raise abort from hook
418 abort: raise abort from hook
417 [255]
419 [255]
418
420
419 $ echo '[hooks]' > ../a/.hg/hgrc
421 $ echo '[hooks]' > ../a/.hg/hgrc
420 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
422 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
421 $ hg pull ../a
423 $ hg pull ../a
422 pulling from ../a
424 pulling from ../a
423 searching for changes
425 searching for changes
424 hook args:
426 hook args:
425 hooktype preoutgoing
427 hooktype preoutgoing
426 source pull
428 source pull
427 abort: preoutgoing.fail hook failed
429 abort: preoutgoing.fail hook failed
428 [255]
430 [255]
429
431
430 $ echo '[hooks]' > ../a/.hg/hgrc
432 $ echo '[hooks]' > ../a/.hg/hgrc
431 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
433 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
432 $ hg pull ../a
434 $ hg pull ../a
433 pulling from ../a
435 pulling from ../a
434 searching for changes
436 searching for changes
435 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
437 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
436 [255]
438 [255]
437
439
438 $ echo '[hooks]' > ../a/.hg/hgrc
440 $ echo '[hooks]' > ../a/.hg/hgrc
439 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
441 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
440 $ hg pull ../a
442 $ hg pull ../a
441 pulling from ../a
443 pulling from ../a
442 searching for changes
444 searching for changes
443 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
445 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
444 [255]
446 [255]
445
447
446 $ echo '[hooks]' > ../a/.hg/hgrc
448 $ echo '[hooks]' > ../a/.hg/hgrc
447 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
449 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
448 $ hg pull ../a
450 $ hg pull ../a
449 pulling from ../a
451 pulling from ../a
450 searching for changes
452 searching for changes
451 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
453 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
452 [255]
454 [255]
453
455
454 $ echo '[hooks]' > ../a/.hg/hgrc
456 $ echo '[hooks]' > ../a/.hg/hgrc
455 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
457 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
456 $ hg pull ../a
458 $ hg pull ../a
457 pulling from ../a
459 pulling from ../a
458 searching for changes
460 searching for changes
459 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
461 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
460 [255]
462 [255]
461
463
462 $ echo '[hooks]' > ../a/.hg/hgrc
464 $ echo '[hooks]' > ../a/.hg/hgrc
463 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
465 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
464 $ hg pull ../a
466 $ hg pull ../a
465 pulling from ../a
467 pulling from ../a
466 searching for changes
468 searching for changes
467 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
469 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
468 [255]
470 [255]
469
471
470 $ echo '[hooks]' > ../a/.hg/hgrc
472 $ echo '[hooks]' > ../a/.hg/hgrc
471 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
473 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
472 $ hg pull ../a
474 $ hg pull ../a
473 pulling from ../a
475 pulling from ../a
474 searching for changes
476 searching for changes
475 hook args:
477 hook args:
476 hooktype preoutgoing
478 hooktype preoutgoing
477 source pull
479 source pull
478 adding changesets
480 adding changesets
479 adding manifests
481 adding manifests
480 adding file changes
482 adding file changes
481 added 1 changesets with 1 changes to 1 files
483 added 1 changesets with 1 changes to 1 files
482 adding remote bookmark quux
484 adding remote bookmark quux
483 (run 'hg update' to get a working copy)
485 (run 'hg update' to get a working copy)
484
486
485 make sure --traceback works
487 make sure --traceback works
486
488
487 $ echo '[hooks]' > .hg/hgrc
489 $ echo '[hooks]' > .hg/hgrc
488 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
490 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
489
491
490 $ echo aa > a
492 $ echo aa > a
491 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
493 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
492 Traceback (most recent call last):
494 Traceback (most recent call last):
493
495
494 $ cd ..
496 $ cd ..
495 $ hg init c
497 $ hg init c
496 $ cd c
498 $ cd c
497
499
498 $ cat > hookext.py <<EOF
500 $ cat > hookext.py <<EOF
499 > def autohook(**args):
501 > def autohook(**args):
500 > print "Automatically installed hook"
502 > print "Automatically installed hook"
501 >
503 >
502 > def reposetup(ui, repo):
504 > def reposetup(ui, repo):
503 > repo.ui.setconfig("hooks", "commit.auto", autohook)
505 > repo.ui.setconfig("hooks", "commit.auto", autohook)
504 > EOF
506 > EOF
505 $ echo '[extensions]' >> .hg/hgrc
507 $ echo '[extensions]' >> .hg/hgrc
506 $ echo 'hookext = hookext.py' >> .hg/hgrc
508 $ echo 'hookext = hookext.py' >> .hg/hgrc
507
509
508 $ touch foo
510 $ touch foo
509 $ hg add foo
511 $ hg add foo
510 $ hg ci -d '0 0' -m 'add foo'
512 $ hg ci -d '0 0' -m 'add foo'
511 Automatically installed hook
513 Automatically installed hook
512 $ echo >> foo
514 $ echo >> foo
513 $ hg ci --debug -d '0 0' -m 'change foo'
515 $ hg ci --debug -d '0 0' -m 'change foo'
514 committing files:
516 committing files:
515 foo
517 foo
516 committing manifest
518 committing manifest
517 committing changelog
519 committing changelog
518 calling hook commit.auto: hgext_hookext.autohook
520 calling hook commit.auto: hgext_hookext.autohook
519 Automatically installed hook
521 Automatically installed hook
520 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
522 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
521
523
522 $ hg showconfig hooks
524 $ hg showconfig hooks
523 hooks.commit.auto=<function autohook at *> (glob)
525 hooks.commit.auto=<function autohook at *> (glob)
524
526
525 test python hook configured with python:[file]:[hook] syntax
527 test python hook configured with python:[file]:[hook] syntax
526
528
527 $ cd ..
529 $ cd ..
528 $ mkdir d
530 $ mkdir d
529 $ cd d
531 $ cd d
530 $ hg init repo
532 $ hg init repo
531 $ mkdir hooks
533 $ mkdir hooks
532
534
533 $ cd hooks
535 $ cd hooks
534 $ cat > testhooks.py <<EOF
536 $ cat > testhooks.py <<EOF
535 > def testhook(**args):
537 > def testhook(**args):
536 > print 'hook works'
538 > print 'hook works'
537 > EOF
539 > EOF
538 $ echo '[hooks]' > ../repo/.hg/hgrc
540 $ echo '[hooks]' > ../repo/.hg/hgrc
539 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
541 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
540
542
541 $ cd ../repo
543 $ cd ../repo
542 $ hg commit -d '0 0'
544 $ hg commit -d '0 0'
543 hook works
545 hook works
544 nothing changed
546 nothing changed
545 [1]
547 [1]
546
548
547 $ echo '[hooks]' > .hg/hgrc
549 $ echo '[hooks]' > .hg/hgrc
548 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
550 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
549 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
551 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
550
552
551 $ hg up null
553 $ hg up null
552 loading update.ne hook failed:
554 loading update.ne hook failed:
553 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
555 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
554 [255]
556 [255]
555
557
556 $ hg id
558 $ hg id
557 loading pre-identify.npmd hook failed:
559 loading pre-identify.npmd hook failed:
558 abort: No module named repo!
560 abort: No module named repo!
559 [255]
561 [255]
560
562
561 $ cd ../../b
563 $ cd ../../b
562
564
563 make sure --traceback works on hook import failure
565 make sure --traceback works on hook import failure
564
566
565 $ cat > importfail.py <<EOF
567 $ cat > importfail.py <<EOF
566 > import somebogusmodule
568 > import somebogusmodule
567 > # dereference something in the module to force demandimport to load it
569 > # dereference something in the module to force demandimport to load it
568 > somebogusmodule.whatever
570 > somebogusmodule.whatever
569 > EOF
571 > EOF
570
572
571 $ echo '[hooks]' > .hg/hgrc
573 $ echo '[hooks]' > .hg/hgrc
572 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
574 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
573
575
574 $ echo a >> a
576 $ echo a >> a
575 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
577 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
576 exception from first failed import attempt:
578 exception from first failed import attempt:
577 Traceback (most recent call last):
579 Traceback (most recent call last):
578 ImportError: No module named somebogusmodule
580 ImportError: No module named somebogusmodule
579 exception from second failed import attempt:
581 exception from second failed import attempt:
580 Traceback (most recent call last):
582 Traceback (most recent call last):
581 ImportError: No module named hgext_importfail
583 ImportError: No module named hgext_importfail
582 Traceback (most recent call last):
584 Traceback (most recent call last):
583 Abort: precommit.importfail hook is invalid (import of "importfail" failed)
585 Abort: precommit.importfail hook is invalid (import of "importfail" failed)
584 abort: precommit.importfail hook is invalid (import of "importfail" failed)
586 abort: precommit.importfail hook is invalid (import of "importfail" failed)
585
587
586 Issue1827: Hooks Update & Commit not completely post operation
588 Issue1827: Hooks Update & Commit not completely post operation
587
589
588 commit and update hooks should run after command completion
590 commit and update hooks should run after command completion
589
591
590 $ echo '[hooks]' > .hg/hgrc
592 $ echo '[hooks]' > .hg/hgrc
591 $ echo 'commit = hg id' >> .hg/hgrc
593 $ echo 'commit = hg id' >> .hg/hgrc
592 $ echo 'update = hg id' >> .hg/hgrc
594 $ echo 'update = hg id' >> .hg/hgrc
593 $ echo bb > a
595 $ echo bb > a
594 $ hg ci -ma
596 $ hg ci -ma
595 223eafe2750c tip
597 223eafe2750c tip
596 $ hg up 0
598 $ hg up 0
597 cb9a9f314b8b
599 cb9a9f314b8b
598 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
600 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
599
601
600 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
602 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
601 that is passed to pre/post hooks
603 that is passed to pre/post hooks
602
604
603 $ echo '[hooks]' > .hg/hgrc
605 $ echo '[hooks]' > .hg/hgrc
604 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
606 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
605 $ hg id
607 $ hg id
606 cb9a9f314b8b
608 cb9a9f314b8b
607 $ hg id --verbose
609 $ hg id --verbose
608 calling hook pre-identify: hooktests.verbosehook
610 calling hook pre-identify: hooktests.verbosehook
609 verbose output from hook
611 verbose output from hook
610 cb9a9f314b8b
612 cb9a9f314b8b
611
613
612 Ensure hooks can be prioritized
614 Ensure hooks can be prioritized
613
615
614 $ echo '[hooks]' > .hg/hgrc
616 $ echo '[hooks]' > .hg/hgrc
615 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
617 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
616 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
618 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
617 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
619 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
618 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
620 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
619 $ hg id --verbose
621 $ hg id --verbose
620 calling hook pre-identify.b: hooktests.verbosehook
622 calling hook pre-identify.b: hooktests.verbosehook
621 verbose output from hook
623 verbose output from hook
622 calling hook pre-identify.a: hooktests.verbosehook
624 calling hook pre-identify.a: hooktests.verbosehook
623 verbose output from hook
625 verbose output from hook
624 calling hook pre-identify.c: hooktests.verbosehook
626 calling hook pre-identify.c: hooktests.verbosehook
625 verbose output from hook
627 verbose output from hook
626 cb9a9f314b8b
628 cb9a9f314b8b
627
629
628 new tags must be visible in pretxncommit (issue3210)
630 new tags must be visible in pretxncommit (issue3210)
629
631
630 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
632 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
631 $ hg tag -f foo
633 $ hg tag -f foo
632 ['a', 'foo', 'tip']
634 ['a', 'foo', 'tip']
633
635
634 new commits must be visible in pretxnchangegroup (issue3428)
636 new commits must be visible in pretxnchangegroup (issue3428)
635
637
636 $ cd ..
638 $ cd ..
637 $ hg init to
639 $ hg init to
638 $ echo '[hooks]' >> to/.hg/hgrc
640 $ echo '[hooks]' >> to/.hg/hgrc
639 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
641 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
640 $ echo a >> to/a
642 $ echo a >> to/a
641 $ hg --cwd to ci -Ama
643 $ hg --cwd to ci -Ama
642 adding a
644 adding a
643 $ hg clone to from
645 $ hg clone to from
644 updating to branch default
646 updating to branch default
645 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
647 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
646 $ echo aa >> from/a
648 $ echo aa >> from/a
647 $ hg --cwd from ci -mb
649 $ hg --cwd from ci -mb
648 $ hg --cwd from push
650 $ hg --cwd from push
649 pushing to $TESTTMP/to (glob)
651 pushing to $TESTTMP/to (glob)
650 searching for changes
652 searching for changes
651 adding changesets
653 adding changesets
652 adding manifests
654 adding manifests
653 adding file changes
655 adding file changes
654 added 1 changesets with 1 changes to 1 files
656 added 1 changesets with 1 changes to 1 files
655 changeset: 1:9836a07b9b9d
657 changeset: 1:9836a07b9b9d
656 tag: tip
658 tag: tip
657 user: test
659 user: test
658 date: Thu Jan 01 00:00:00 1970 +0000
660 date: Thu Jan 01 00:00:00 1970 +0000
659 summary: b
661 summary: b
660
662
@@ -1,154 +1,156 b''
1 #require unix-permissions
1 #require unix-permissions
2
2
3 test that new files created in .hg inherit the permissions from .hg/store
3 test that new files created in .hg inherit the permissions from .hg/store
4
4
5 $ mkdir dir
5 $ mkdir dir
6
6
7 just in case somebody has a strange $TMPDIR
7 just in case somebody has a strange $TMPDIR
8
8
9 $ chmod g-s dir
9 $ chmod g-s dir
10 $ cd dir
10 $ cd dir
11
11
12 $ cat >printmodes.py <<EOF
12 $ cat >printmodes.py <<EOF
13 > import os, sys
13 > import os, sys
14 >
14 >
15 > allnames = []
15 > allnames = []
16 > isdir = {}
16 > isdir = {}
17 > for root, dirs, files in os.walk(sys.argv[1]):
17 > for root, dirs, files in os.walk(sys.argv[1]):
18 > for d in dirs:
18 > for d in dirs:
19 > name = os.path.join(root, d)
19 > name = os.path.join(root, d)
20 > isdir[name] = 1
20 > isdir[name] = 1
21 > allnames.append(name)
21 > allnames.append(name)
22 > for f in files:
22 > for f in files:
23 > name = os.path.join(root, f)
23 > name = os.path.join(root, f)
24 > allnames.append(name)
24 > allnames.append(name)
25 > allnames.sort()
25 > allnames.sort()
26 > for name in allnames:
26 > for name in allnames:
27 > suffix = name in isdir and '/' or ''
27 > suffix = name in isdir and '/' or ''
28 > print '%05o %s%s' % (os.lstat(name).st_mode & 07777, name, suffix)
28 > print '%05o %s%s' % (os.lstat(name).st_mode & 07777, name, suffix)
29 > EOF
29 > EOF
30
30
31 $ cat >mode.py <<EOF
31 $ cat >mode.py <<EOF
32 > import sys
32 > import sys
33 > import os
33 > import os
34 > print '%05o' % os.lstat(sys.argv[1]).st_mode
34 > print '%05o' % os.lstat(sys.argv[1]).st_mode
35 > EOF
35 > EOF
36
36
37 $ umask 077
37 $ umask 077
38
38
39 $ hg init repo
39 $ hg init repo
40 $ cd repo
40 $ cd repo
41
41
42 $ chmod 0770 .hg/store
42 $ chmod 0770 .hg/store
43
43
44 before commit
44 before commit
45 store can be written by the group, other files cannot
45 store can be written by the group, other files cannot
46 store is setgid
46 store is setgid
47
47
48 $ python ../printmodes.py .
48 $ python ../printmodes.py .
49 00700 ./.hg/
49 00700 ./.hg/
50 00600 ./.hg/00changelog.i
50 00600 ./.hg/00changelog.i
51 00600 ./.hg/requires
51 00600 ./.hg/requires
52 00770 ./.hg/store/
52 00770 ./.hg/store/
53
53
54 $ mkdir dir
54 $ mkdir dir
55 $ touch foo dir/bar
55 $ touch foo dir/bar
56 $ hg ci -qAm 'add files'
56 $ hg ci -qAm 'add files'
57
57
58 after commit
58 after commit
59 working dir files can only be written by the owner
59 working dir files can only be written by the owner
60 files created in .hg can be written by the group
60 files created in .hg can be written by the group
61 (in particular, store/**, dirstate, branch cache file, undo files)
61 (in particular, store/**, dirstate, branch cache file, undo files)
62 new directories are setgid
62 new directories are setgid
63
63
64 $ python ../printmodes.py .
64 $ python ../printmodes.py .
65 00700 ./.hg/
65 00700 ./.hg/
66 00600 ./.hg/00changelog.i
66 00600 ./.hg/00changelog.i
67 00770 ./.hg/cache/
67 00770 ./.hg/cache/
68 00660 ./.hg/cache/branch2-served
68 00660 ./.hg/cache/branch2-served
69 00660 ./.hg/cache/rbc-names-v1
69 00660 ./.hg/cache/rbc-names-v1
70 00660 ./.hg/cache/rbc-revs-v1
70 00660 ./.hg/cache/rbc-revs-v1
71 00660 ./.hg/dirstate
71 00660 ./.hg/dirstate
72 00660 ./.hg/last-message.txt
72 00660 ./.hg/last-message.txt
73 00600 ./.hg/requires
73 00600 ./.hg/requires
74 00770 ./.hg/store/
74 00770 ./.hg/store/
75 00660 ./.hg/store/00changelog.i
75 00660 ./.hg/store/00changelog.i
76 00660 ./.hg/store/00manifest.i
76 00660 ./.hg/store/00manifest.i
77 00770 ./.hg/store/data/
77 00770 ./.hg/store/data/
78 00770 ./.hg/store/data/dir/
78 00770 ./.hg/store/data/dir/
79 00660 ./.hg/store/data/dir/bar.i
79 00660 ./.hg/store/data/dir/bar.i
80 00660 ./.hg/store/data/foo.i
80 00660 ./.hg/store/data/foo.i
81 00660 ./.hg/store/fncache
81 00660 ./.hg/store/fncache
82 00660 ./.hg/store/phaseroots
82 00660 ./.hg/store/phaseroots
83 00660 ./.hg/store/undo
83 00660 ./.hg/store/undo
84 00660 ./.hg/store/undo.backupfiles
84 00660 ./.hg/store/undo.phaseroots
85 00660 ./.hg/store/undo.phaseroots
85 00660 ./.hg/undo.bookmarks
86 00660 ./.hg/undo.bookmarks
86 00660 ./.hg/undo.branch
87 00660 ./.hg/undo.branch
87 00660 ./.hg/undo.desc
88 00660 ./.hg/undo.desc
88 00660 ./.hg/undo.dirstate
89 00660 ./.hg/undo.dirstate
89 00700 ./dir/
90 00700 ./dir/
90 00600 ./dir/bar
91 00600 ./dir/bar
91 00600 ./foo
92 00600 ./foo
92
93
93 $ umask 007
94 $ umask 007
94 $ hg init ../push
95 $ hg init ../push
95
96
96 before push
97 before push
97 group can write everything
98 group can write everything
98
99
99 $ python ../printmodes.py ../push
100 $ python ../printmodes.py ../push
100 00770 ../push/.hg/
101 00770 ../push/.hg/
101 00660 ../push/.hg/00changelog.i
102 00660 ../push/.hg/00changelog.i
102 00660 ../push/.hg/requires
103 00660 ../push/.hg/requires
103 00770 ../push/.hg/store/
104 00770 ../push/.hg/store/
104
105
105 $ umask 077
106 $ umask 077
106 $ hg -q push ../push
107 $ hg -q push ../push
107
108
108 after push
109 after push
109 group can still write everything
110 group can still write everything
110
111
111 $ python ../printmodes.py ../push
112 $ python ../printmodes.py ../push
112 00770 ../push/.hg/
113 00770 ../push/.hg/
113 00660 ../push/.hg/00changelog.i
114 00660 ../push/.hg/00changelog.i
114 00770 ../push/.hg/cache/
115 00770 ../push/.hg/cache/
115 00660 ../push/.hg/cache/branch2-base
116 00660 ../push/.hg/cache/branch2-base
116 00660 ../push/.hg/cache/rbc-names-v1
117 00660 ../push/.hg/cache/rbc-names-v1
117 00660 ../push/.hg/cache/rbc-revs-v1
118 00660 ../push/.hg/cache/rbc-revs-v1
118 00660 ../push/.hg/requires
119 00660 ../push/.hg/requires
119 00770 ../push/.hg/store/
120 00770 ../push/.hg/store/
120 00660 ../push/.hg/store/00changelog.i
121 00660 ../push/.hg/store/00changelog.i
121 00660 ../push/.hg/store/00manifest.i
122 00660 ../push/.hg/store/00manifest.i
122 00770 ../push/.hg/store/data/
123 00770 ../push/.hg/store/data/
123 00770 ../push/.hg/store/data/dir/
124 00770 ../push/.hg/store/data/dir/
124 00660 ../push/.hg/store/data/dir/bar.i
125 00660 ../push/.hg/store/data/dir/bar.i
125 00660 ../push/.hg/store/data/foo.i
126 00660 ../push/.hg/store/data/foo.i
126 00660 ../push/.hg/store/fncache
127 00660 ../push/.hg/store/fncache
127 00660 ../push/.hg/store/undo
128 00660 ../push/.hg/store/undo
129 00660 ../push/.hg/store/undo.backupfiles
128 00660 ../push/.hg/store/undo.phaseroots
130 00660 ../push/.hg/store/undo.phaseroots
129 00660 ../push/.hg/undo.bookmarks
131 00660 ../push/.hg/undo.bookmarks
130 00660 ../push/.hg/undo.branch
132 00660 ../push/.hg/undo.branch
131 00660 ../push/.hg/undo.desc
133 00660 ../push/.hg/undo.desc
132 00660 ../push/.hg/undo.dirstate
134 00660 ../push/.hg/undo.dirstate
133
135
134
136
135 Test that we don't lose the setgid bit when we call chmod.
137 Test that we don't lose the setgid bit when we call chmod.
136 Not all systems support setgid directories (e.g. HFS+), so
138 Not all systems support setgid directories (e.g. HFS+), so
137 just check that directories have the same mode.
139 just check that directories have the same mode.
138
140
139 $ cd ..
141 $ cd ..
140 $ hg init setgid
142 $ hg init setgid
141 $ cd setgid
143 $ cd setgid
142 $ chmod g+rwx .hg/store
144 $ chmod g+rwx .hg/store
143 $ chmod g+s .hg/store 2> /dev/null || true
145 $ chmod g+s .hg/store 2> /dev/null || true
144 $ mkdir dir
146 $ mkdir dir
145 $ touch dir/file
147 $ touch dir/file
146 $ hg ci -qAm 'add dir/file'
148 $ hg ci -qAm 'add dir/file'
147 $ storemode=`python ../mode.py .hg/store`
149 $ storemode=`python ../mode.py .hg/store`
148 $ dirmode=`python ../mode.py .hg/store/data/dir`
150 $ dirmode=`python ../mode.py .hg/store/data/dir`
149 $ if [ "$storemode" != "$dirmode" ]; then
151 $ if [ "$storemode" != "$dirmode" ]; then
150 > echo "$storemode != $dirmode"
152 > echo "$storemode != $dirmode"
151 > fi
153 > fi
152 $ cd ..
154 $ cd ..
153
155
154 $ cd .. # g-s dir
156 $ cd .. # g-s dir
General Comments 0
You need to be logged in to leave comments. Login now