##// END OF EJS Templates
obsolete: disable other evolution config options if createmarkers is off...
av6 -
r48579:b1e1559f default
parent child Browse files
Show More
@@ -1,1154 +1,1150
1 # obsolete.py - obsolete markers handling
1 # obsolete.py - obsolete markers handling
2 #
2 #
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
4 # Logilab SA <contact@logilab.fr>
4 # Logilab SA <contact@logilab.fr>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 """Obsolete marker handling
9 """Obsolete marker handling
10
10
11 An obsolete marker maps an old changeset to a list of new
11 An obsolete marker maps an old changeset to a list of new
12 changesets. If the list of new changesets is empty, the old changeset
12 changesets. If the list of new changesets is empty, the old changeset
13 is said to be "killed". Otherwise, the old changeset is being
13 is said to be "killed". Otherwise, the old changeset is being
14 "replaced" by the new changesets.
14 "replaced" by the new changesets.
15
15
16 Obsolete markers can be used to record and distribute changeset graph
16 Obsolete markers can be used to record and distribute changeset graph
17 transformations performed by history rewrite operations, and help
17 transformations performed by history rewrite operations, and help
18 building new tools to reconcile conflicting rewrite actions. To
18 building new tools to reconcile conflicting rewrite actions. To
19 facilitate conflict resolution, markers include various annotations
19 facilitate conflict resolution, markers include various annotations
20 besides old and news changeset identifiers, such as creation date or
20 besides old and news changeset identifiers, such as creation date or
21 author name.
21 author name.
22
22
23 The old obsoleted changeset is called a "predecessor" and possible
23 The old obsoleted changeset is called a "predecessor" and possible
24 replacements are called "successors". Markers that used changeset X as
24 replacements are called "successors". Markers that used changeset X as
25 a predecessor are called "successor markers of X" because they hold
25 a predecessor are called "successor markers of X" because they hold
26 information about the successors of X. Markers that use changeset Y as
26 information about the successors of X. Markers that use changeset Y as
27 a successors are call "predecessor markers of Y" because they hold
27 a successors are call "predecessor markers of Y" because they hold
28 information about the predecessors of Y.
28 information about the predecessors of Y.
29
29
30 Examples:
30 Examples:
31
31
32 - When changeset A is replaced by changeset A', one marker is stored:
32 - When changeset A is replaced by changeset A', one marker is stored:
33
33
34 (A, (A',))
34 (A, (A',))
35
35
36 - When changesets A and B are folded into a new changeset C, two markers are
36 - When changesets A and B are folded into a new changeset C, two markers are
37 stored:
37 stored:
38
38
39 (A, (C,)) and (B, (C,))
39 (A, (C,)) and (B, (C,))
40
40
41 - When changeset A is simply "pruned" from the graph, a marker is created:
41 - When changeset A is simply "pruned" from the graph, a marker is created:
42
42
43 (A, ())
43 (A, ())
44
44
45 - When changeset A is split into B and C, a single marker is used:
45 - When changeset A is split into B and C, a single marker is used:
46
46
47 (A, (B, C))
47 (A, (B, C))
48
48
49 We use a single marker to distinguish the "split" case from the "divergence"
49 We use a single marker to distinguish the "split" case from the "divergence"
50 case. If two independent operations rewrite the same changeset A in to A' and
50 case. If two independent operations rewrite the same changeset A in to A' and
51 A'', we have an error case: divergent rewriting. We can detect it because
51 A'', we have an error case: divergent rewriting. We can detect it because
52 two markers will be created independently:
52 two markers will be created independently:
53
53
54 (A, (B,)) and (A, (C,))
54 (A, (B,)) and (A, (C,))
55
55
56 Format
56 Format
57 ------
57 ------
58
58
59 Markers are stored in an append-only file stored in
59 Markers are stored in an append-only file stored in
60 '.hg/store/obsstore'.
60 '.hg/store/obsstore'.
61
61
62 The file starts with a version header:
62 The file starts with a version header:
63
63
64 - 1 unsigned byte: version number, starting at zero.
64 - 1 unsigned byte: version number, starting at zero.
65
65
66 The header is followed by the markers. Marker format depend of the version. See
66 The header is followed by the markers. Marker format depend of the version. See
67 comment associated with each format for details.
67 comment associated with each format for details.
68
68
69 """
69 """
70 from __future__ import absolute_import
70 from __future__ import absolute_import
71
71
72 import errno
72 import errno
73 import struct
73 import struct
74
74
75 from .i18n import _
75 from .i18n import _
76 from .node import (
76 from .node import (
77 bin,
77 bin,
78 hex,
78 hex,
79 )
79 )
80 from .pycompat import getattr
80 from .pycompat import getattr
81 from .node import (
81 from .node import (
82 bin,
82 bin,
83 hex,
83 hex,
84 )
84 )
85 from . import (
85 from . import (
86 encoding,
86 encoding,
87 error,
87 error,
88 obsutil,
88 obsutil,
89 phases,
89 phases,
90 policy,
90 policy,
91 pycompat,
91 pycompat,
92 util,
92 util,
93 )
93 )
94 from .utils import (
94 from .utils import (
95 dateutil,
95 dateutil,
96 hashutil,
96 hashutil,
97 )
97 )
98
98
99 parsers = policy.importmod('parsers')
99 parsers = policy.importmod('parsers')
100
100
101 _pack = struct.pack
101 _pack = struct.pack
102 _unpack = struct.unpack
102 _unpack = struct.unpack
103 _calcsize = struct.calcsize
103 _calcsize = struct.calcsize
104 propertycache = util.propertycache
104 propertycache = util.propertycache
105
105
106 # Options for obsolescence
106 # Options for obsolescence
107 createmarkersopt = b'createmarkers'
107 createmarkersopt = b'createmarkers'
108 allowunstableopt = b'allowunstable'
108 allowunstableopt = b'allowunstable'
109 allowdivergenceopt = b'allowdivergence'
109 allowdivergenceopt = b'allowdivergence'
110 exchangeopt = b'exchange'
110 exchangeopt = b'exchange'
111
111
112
112
113 def _getoptionvalue(repo, option):
113 def _getoptionvalue(repo, option):
114 """Returns True if the given repository has the given obsolete option
114 """Returns True if the given repository has the given obsolete option
115 enabled.
115 enabled.
116 """
116 """
117 configkey = b'evolution.%s' % option
117 configkey = b'evolution.%s' % option
118 newconfig = repo.ui.configbool(b'experimental', configkey)
118 newconfig = repo.ui.configbool(b'experimental', configkey)
119
119
120 # Return the value only if defined
120 # Return the value only if defined
121 if newconfig is not None:
121 if newconfig is not None:
122 return newconfig
122 return newconfig
123
123
124 # Fallback on generic option
124 # Fallback on generic option
125 try:
125 try:
126 return repo.ui.configbool(b'experimental', b'evolution')
126 return repo.ui.configbool(b'experimental', b'evolution')
127 except (error.ConfigError, AttributeError):
127 except (error.ConfigError, AttributeError):
128 # Fallback on old-fashion config
128 # Fallback on old-fashion config
129 # inconsistent config: experimental.evolution
129 # inconsistent config: experimental.evolution
130 result = set(repo.ui.configlist(b'experimental', b'evolution'))
130 result = set(repo.ui.configlist(b'experimental', b'evolution'))
131
131
132 if b'all' in result:
132 if b'all' in result:
133 return True
133 return True
134
134
135 # Temporary hack for next check
135 # Temporary hack for next check
136 newconfig = repo.ui.config(b'experimental', b'evolution.createmarkers')
136 newconfig = repo.ui.config(b'experimental', b'evolution.createmarkers')
137 if newconfig:
137 if newconfig:
138 result.add(b'createmarkers')
138 result.add(b'createmarkers')
139
139
140 return option in result
140 return option in result
141
141
142
142
143 def getoptions(repo):
143 def getoptions(repo):
144 """Returns dicts showing state of obsolescence features."""
144 """Returns dicts showing state of obsolescence features."""
145
145
146 createmarkersvalue = _getoptionvalue(repo, createmarkersopt)
146 createmarkersvalue = _getoptionvalue(repo, createmarkersopt)
147 if createmarkersvalue:
147 unstablevalue = _getoptionvalue(repo, allowunstableopt)
148 unstablevalue = _getoptionvalue(repo, allowunstableopt)
148 divergencevalue = _getoptionvalue(repo, allowdivergenceopt)
149 divergencevalue = _getoptionvalue(repo, allowdivergenceopt)
149 exchangevalue = _getoptionvalue(repo, exchangeopt)
150 exchangevalue = _getoptionvalue(repo, exchangeopt)
150
151 else:
151 # createmarkers must be enabled if other options are enabled
152 # if we cannot create obsolescence markers, we shouldn't exchange them
152 if (
153 # or perform operations that lead to instability or divergence
153 unstablevalue or divergencevalue or exchangevalue
154 unstablevalue = False
154 ) and not createmarkersvalue:
155 divergencevalue = False
155 raise error.Abort(
156 exchangevalue = False
156 _(
157 b"'createmarkers' obsolete option must be enabled "
158 b"if other obsolete options are enabled"
159 )
160 )
161
157
162 return {
158 return {
163 createmarkersopt: createmarkersvalue,
159 createmarkersopt: createmarkersvalue,
164 allowunstableopt: unstablevalue,
160 allowunstableopt: unstablevalue,
165 allowdivergenceopt: divergencevalue,
161 allowdivergenceopt: divergencevalue,
166 exchangeopt: exchangevalue,
162 exchangeopt: exchangevalue,
167 }
163 }
168
164
169
165
170 def isenabled(repo, option):
166 def isenabled(repo, option):
171 """Returns True if the given repository has the given obsolete option
167 """Returns True if the given repository has the given obsolete option
172 enabled.
168 enabled.
173 """
169 """
174 return getoptions(repo)[option]
170 return getoptions(repo)[option]
175
171
176
172
177 # Creating aliases for marker flags because evolve extension looks for
173 # Creating aliases for marker flags because evolve extension looks for
178 # bumpedfix in obsolete.py
174 # bumpedfix in obsolete.py
179 bumpedfix = obsutil.bumpedfix
175 bumpedfix = obsutil.bumpedfix
180 usingsha256 = obsutil.usingsha256
176 usingsha256 = obsutil.usingsha256
181
177
182 ## Parsing and writing of version "0"
178 ## Parsing and writing of version "0"
183 #
179 #
184 # The header is followed by the markers. Each marker is made of:
180 # The header is followed by the markers. Each marker is made of:
185 #
181 #
186 # - 1 uint8 : number of new changesets "N", can be zero.
182 # - 1 uint8 : number of new changesets "N", can be zero.
187 #
183 #
188 # - 1 uint32: metadata size "M" in bytes.
184 # - 1 uint32: metadata size "M" in bytes.
189 #
185 #
190 # - 1 byte: a bit field. It is reserved for flags used in common
186 # - 1 byte: a bit field. It is reserved for flags used in common
191 # obsolete marker operations, to avoid repeated decoding of metadata
187 # obsolete marker operations, to avoid repeated decoding of metadata
192 # entries.
188 # entries.
193 #
189 #
194 # - 20 bytes: obsoleted changeset identifier.
190 # - 20 bytes: obsoleted changeset identifier.
195 #
191 #
196 # - N*20 bytes: new changesets identifiers.
192 # - N*20 bytes: new changesets identifiers.
197 #
193 #
198 # - M bytes: metadata as a sequence of nul-terminated strings. Each
194 # - M bytes: metadata as a sequence of nul-terminated strings. Each
199 # string contains a key and a value, separated by a colon ':', without
195 # string contains a key and a value, separated by a colon ':', without
200 # additional encoding. Keys cannot contain '\0' or ':' and values
196 # additional encoding. Keys cannot contain '\0' or ':' and values
201 # cannot contain '\0'.
197 # cannot contain '\0'.
202 _fm0version = 0
198 _fm0version = 0
203 _fm0fixed = b'>BIB20s'
199 _fm0fixed = b'>BIB20s'
204 _fm0node = b'20s'
200 _fm0node = b'20s'
205 _fm0fsize = _calcsize(_fm0fixed)
201 _fm0fsize = _calcsize(_fm0fixed)
206 _fm0fnodesize = _calcsize(_fm0node)
202 _fm0fnodesize = _calcsize(_fm0node)
207
203
208
204
209 def _fm0readmarkers(data, off, stop):
205 def _fm0readmarkers(data, off, stop):
210 # Loop on markers
206 # Loop on markers
211 while off < stop:
207 while off < stop:
212 # read fixed part
208 # read fixed part
213 cur = data[off : off + _fm0fsize]
209 cur = data[off : off + _fm0fsize]
214 off += _fm0fsize
210 off += _fm0fsize
215 numsuc, mdsize, flags, pre = _unpack(_fm0fixed, cur)
211 numsuc, mdsize, flags, pre = _unpack(_fm0fixed, cur)
216 # read replacement
212 # read replacement
217 sucs = ()
213 sucs = ()
218 if numsuc:
214 if numsuc:
219 s = _fm0fnodesize * numsuc
215 s = _fm0fnodesize * numsuc
220 cur = data[off : off + s]
216 cur = data[off : off + s]
221 sucs = _unpack(_fm0node * numsuc, cur)
217 sucs = _unpack(_fm0node * numsuc, cur)
222 off += s
218 off += s
223 # read metadata
219 # read metadata
224 # (metadata will be decoded on demand)
220 # (metadata will be decoded on demand)
225 metadata = data[off : off + mdsize]
221 metadata = data[off : off + mdsize]
226 if len(metadata) != mdsize:
222 if len(metadata) != mdsize:
227 raise error.Abort(
223 raise error.Abort(
228 _(
224 _(
229 b'parsing obsolete marker: metadata is too '
225 b'parsing obsolete marker: metadata is too '
230 b'short, %d bytes expected, got %d'
226 b'short, %d bytes expected, got %d'
231 )
227 )
232 % (mdsize, len(metadata))
228 % (mdsize, len(metadata))
233 )
229 )
234 off += mdsize
230 off += mdsize
235 metadata = _fm0decodemeta(metadata)
231 metadata = _fm0decodemeta(metadata)
236 try:
232 try:
237 when, offset = metadata.pop(b'date', b'0 0').split(b' ')
233 when, offset = metadata.pop(b'date', b'0 0').split(b' ')
238 date = float(when), int(offset)
234 date = float(when), int(offset)
239 except ValueError:
235 except ValueError:
240 date = (0.0, 0)
236 date = (0.0, 0)
241 parents = None
237 parents = None
242 if b'p2' in metadata:
238 if b'p2' in metadata:
243 parents = (metadata.pop(b'p1', None), metadata.pop(b'p2', None))
239 parents = (metadata.pop(b'p1', None), metadata.pop(b'p2', None))
244 elif b'p1' in metadata:
240 elif b'p1' in metadata:
245 parents = (metadata.pop(b'p1', None),)
241 parents = (metadata.pop(b'p1', None),)
246 elif b'p0' in metadata:
242 elif b'p0' in metadata:
247 parents = ()
243 parents = ()
248 if parents is not None:
244 if parents is not None:
249 try:
245 try:
250 parents = tuple(bin(p) for p in parents)
246 parents = tuple(bin(p) for p in parents)
251 # if parent content is not a nodeid, drop the data
247 # if parent content is not a nodeid, drop the data
252 for p in parents:
248 for p in parents:
253 if len(p) != 20:
249 if len(p) != 20:
254 parents = None
250 parents = None
255 break
251 break
256 except TypeError:
252 except TypeError:
257 # if content cannot be translated to nodeid drop the data.
253 # if content cannot be translated to nodeid drop the data.
258 parents = None
254 parents = None
259
255
260 metadata = tuple(sorted(pycompat.iteritems(metadata)))
256 metadata = tuple(sorted(pycompat.iteritems(metadata)))
261
257
262 yield (pre, sucs, flags, metadata, date, parents)
258 yield (pre, sucs, flags, metadata, date, parents)
263
259
264
260
265 def _fm0encodeonemarker(marker):
261 def _fm0encodeonemarker(marker):
266 pre, sucs, flags, metadata, date, parents = marker
262 pre, sucs, flags, metadata, date, parents = marker
267 if flags & usingsha256:
263 if flags & usingsha256:
268 raise error.Abort(_(b'cannot handle sha256 with old obsstore format'))
264 raise error.Abort(_(b'cannot handle sha256 with old obsstore format'))
269 metadata = dict(metadata)
265 metadata = dict(metadata)
270 time, tz = date
266 time, tz = date
271 metadata[b'date'] = b'%r %i' % (time, tz)
267 metadata[b'date'] = b'%r %i' % (time, tz)
272 if parents is not None:
268 if parents is not None:
273 if not parents:
269 if not parents:
274 # mark that we explicitly recorded no parents
270 # mark that we explicitly recorded no parents
275 metadata[b'p0'] = b''
271 metadata[b'p0'] = b''
276 for i, p in enumerate(parents, 1):
272 for i, p in enumerate(parents, 1):
277 metadata[b'p%i' % i] = hex(p)
273 metadata[b'p%i' % i] = hex(p)
278 metadata = _fm0encodemeta(metadata)
274 metadata = _fm0encodemeta(metadata)
279 numsuc = len(sucs)
275 numsuc = len(sucs)
280 format = _fm0fixed + (_fm0node * numsuc)
276 format = _fm0fixed + (_fm0node * numsuc)
281 data = [numsuc, len(metadata), flags, pre]
277 data = [numsuc, len(metadata), flags, pre]
282 data.extend(sucs)
278 data.extend(sucs)
283 return _pack(format, *data) + metadata
279 return _pack(format, *data) + metadata
284
280
285
281
286 def _fm0encodemeta(meta):
282 def _fm0encodemeta(meta):
287 """Return encoded metadata string to string mapping.
283 """Return encoded metadata string to string mapping.
288
284
289 Assume no ':' in key and no '\0' in both key and value."""
285 Assume no ':' in key and no '\0' in both key and value."""
290 for key, value in pycompat.iteritems(meta):
286 for key, value in pycompat.iteritems(meta):
291 if b':' in key or b'\0' in key:
287 if b':' in key or b'\0' in key:
292 raise ValueError(b"':' and '\0' are forbidden in metadata key'")
288 raise ValueError(b"':' and '\0' are forbidden in metadata key'")
293 if b'\0' in value:
289 if b'\0' in value:
294 raise ValueError(b"':' is forbidden in metadata value'")
290 raise ValueError(b"':' is forbidden in metadata value'")
295 return b'\0'.join([b'%s:%s' % (k, meta[k]) for k in sorted(meta)])
291 return b'\0'.join([b'%s:%s' % (k, meta[k]) for k in sorted(meta)])
296
292
297
293
298 def _fm0decodemeta(data):
294 def _fm0decodemeta(data):
299 """Return string to string dictionary from encoded version."""
295 """Return string to string dictionary from encoded version."""
300 d = {}
296 d = {}
301 for l in data.split(b'\0'):
297 for l in data.split(b'\0'):
302 if l:
298 if l:
303 key, value = l.split(b':', 1)
299 key, value = l.split(b':', 1)
304 d[key] = value
300 d[key] = value
305 return d
301 return d
306
302
307
303
308 ## Parsing and writing of version "1"
304 ## Parsing and writing of version "1"
309 #
305 #
310 # The header is followed by the markers. Each marker is made of:
306 # The header is followed by the markers. Each marker is made of:
311 #
307 #
312 # - uint32: total size of the marker (including this field)
308 # - uint32: total size of the marker (including this field)
313 #
309 #
314 # - float64: date in seconds since epoch
310 # - float64: date in seconds since epoch
315 #
311 #
316 # - int16: timezone offset in minutes
312 # - int16: timezone offset in minutes
317 #
313 #
318 # - uint16: a bit field. It is reserved for flags used in common
314 # - uint16: a bit field. It is reserved for flags used in common
319 # obsolete marker operations, to avoid repeated decoding of metadata
315 # obsolete marker operations, to avoid repeated decoding of metadata
320 # entries.
316 # entries.
321 #
317 #
322 # - uint8: number of successors "N", can be zero.
318 # - uint8: number of successors "N", can be zero.
323 #
319 #
324 # - uint8: number of parents "P", can be zero.
320 # - uint8: number of parents "P", can be zero.
325 #
321 #
326 # 0: parents data stored but no parent,
322 # 0: parents data stored but no parent,
327 # 1: one parent stored,
323 # 1: one parent stored,
328 # 2: two parents stored,
324 # 2: two parents stored,
329 # 3: no parent data stored
325 # 3: no parent data stored
330 #
326 #
331 # - uint8: number of metadata entries M
327 # - uint8: number of metadata entries M
332 #
328 #
333 # - 20 or 32 bytes: predecessor changeset identifier.
329 # - 20 or 32 bytes: predecessor changeset identifier.
334 #
330 #
335 # - N*(20 or 32) bytes: successors changesets identifiers.
331 # - N*(20 or 32) bytes: successors changesets identifiers.
336 #
332 #
337 # - P*(20 or 32) bytes: parents of the predecessors changesets.
333 # - P*(20 or 32) bytes: parents of the predecessors changesets.
338 #
334 #
339 # - M*(uint8, uint8): size of all metadata entries (key and value)
335 # - M*(uint8, uint8): size of all metadata entries (key and value)
340 #
336 #
341 # - remaining bytes: the metadata, each (key, value) pair after the other.
337 # - remaining bytes: the metadata, each (key, value) pair after the other.
342 _fm1version = 1
338 _fm1version = 1
343 _fm1fixed = b'>IdhHBBB'
339 _fm1fixed = b'>IdhHBBB'
344 _fm1nodesha1 = b'20s'
340 _fm1nodesha1 = b'20s'
345 _fm1nodesha256 = b'32s'
341 _fm1nodesha256 = b'32s'
346 _fm1nodesha1size = _calcsize(_fm1nodesha1)
342 _fm1nodesha1size = _calcsize(_fm1nodesha1)
347 _fm1nodesha256size = _calcsize(_fm1nodesha256)
343 _fm1nodesha256size = _calcsize(_fm1nodesha256)
348 _fm1fsize = _calcsize(_fm1fixed)
344 _fm1fsize = _calcsize(_fm1fixed)
349 _fm1parentnone = 3
345 _fm1parentnone = 3
350 _fm1parentshift = 14
346 _fm1parentshift = 14
351 _fm1parentmask = _fm1parentnone << _fm1parentshift
347 _fm1parentmask = _fm1parentnone << _fm1parentshift
352 _fm1metapair = b'BB'
348 _fm1metapair = b'BB'
353 _fm1metapairsize = _calcsize(_fm1metapair)
349 _fm1metapairsize = _calcsize(_fm1metapair)
354
350
355
351
356 def _fm1purereadmarkers(data, off, stop):
352 def _fm1purereadmarkers(data, off, stop):
357 # make some global constants local for performance
353 # make some global constants local for performance
358 noneflag = _fm1parentnone
354 noneflag = _fm1parentnone
359 sha2flag = usingsha256
355 sha2flag = usingsha256
360 sha1size = _fm1nodesha1size
356 sha1size = _fm1nodesha1size
361 sha2size = _fm1nodesha256size
357 sha2size = _fm1nodesha256size
362 sha1fmt = _fm1nodesha1
358 sha1fmt = _fm1nodesha1
363 sha2fmt = _fm1nodesha256
359 sha2fmt = _fm1nodesha256
364 metasize = _fm1metapairsize
360 metasize = _fm1metapairsize
365 metafmt = _fm1metapair
361 metafmt = _fm1metapair
366 fsize = _fm1fsize
362 fsize = _fm1fsize
367 unpack = _unpack
363 unpack = _unpack
368
364
369 # Loop on markers
365 # Loop on markers
370 ufixed = struct.Struct(_fm1fixed).unpack
366 ufixed = struct.Struct(_fm1fixed).unpack
371
367
372 while off < stop:
368 while off < stop:
373 # read fixed part
369 # read fixed part
374 o1 = off + fsize
370 o1 = off + fsize
375 t, secs, tz, flags, numsuc, numpar, nummeta = ufixed(data[off:o1])
371 t, secs, tz, flags, numsuc, numpar, nummeta = ufixed(data[off:o1])
376
372
377 if flags & sha2flag:
373 if flags & sha2flag:
378 nodefmt = sha2fmt
374 nodefmt = sha2fmt
379 nodesize = sha2size
375 nodesize = sha2size
380 else:
376 else:
381 nodefmt = sha1fmt
377 nodefmt = sha1fmt
382 nodesize = sha1size
378 nodesize = sha1size
383
379
384 (prec,) = unpack(nodefmt, data[o1 : o1 + nodesize])
380 (prec,) = unpack(nodefmt, data[o1 : o1 + nodesize])
385 o1 += nodesize
381 o1 += nodesize
386
382
387 # read 0 or more successors
383 # read 0 or more successors
388 if numsuc == 1:
384 if numsuc == 1:
389 o2 = o1 + nodesize
385 o2 = o1 + nodesize
390 sucs = (data[o1:o2],)
386 sucs = (data[o1:o2],)
391 else:
387 else:
392 o2 = o1 + nodesize * numsuc
388 o2 = o1 + nodesize * numsuc
393 sucs = unpack(nodefmt * numsuc, data[o1:o2])
389 sucs = unpack(nodefmt * numsuc, data[o1:o2])
394
390
395 # read parents
391 # read parents
396 if numpar == noneflag:
392 if numpar == noneflag:
397 o3 = o2
393 o3 = o2
398 parents = None
394 parents = None
399 elif numpar == 1:
395 elif numpar == 1:
400 o3 = o2 + nodesize
396 o3 = o2 + nodesize
401 parents = (data[o2:o3],)
397 parents = (data[o2:o3],)
402 else:
398 else:
403 o3 = o2 + nodesize * numpar
399 o3 = o2 + nodesize * numpar
404 parents = unpack(nodefmt * numpar, data[o2:o3])
400 parents = unpack(nodefmt * numpar, data[o2:o3])
405
401
406 # read metadata
402 # read metadata
407 off = o3 + metasize * nummeta
403 off = o3 + metasize * nummeta
408 metapairsize = unpack(b'>' + (metafmt * nummeta), data[o3:off])
404 metapairsize = unpack(b'>' + (metafmt * nummeta), data[o3:off])
409 metadata = []
405 metadata = []
410 for idx in pycompat.xrange(0, len(metapairsize), 2):
406 for idx in pycompat.xrange(0, len(metapairsize), 2):
411 o1 = off + metapairsize[idx]
407 o1 = off + metapairsize[idx]
412 o2 = o1 + metapairsize[idx + 1]
408 o2 = o1 + metapairsize[idx + 1]
413 metadata.append((data[off:o1], data[o1:o2]))
409 metadata.append((data[off:o1], data[o1:o2]))
414 off = o2
410 off = o2
415
411
416 yield (prec, sucs, flags, tuple(metadata), (secs, tz * 60), parents)
412 yield (prec, sucs, flags, tuple(metadata), (secs, tz * 60), parents)
417
413
418
414
419 def _fm1encodeonemarker(marker):
415 def _fm1encodeonemarker(marker):
420 pre, sucs, flags, metadata, date, parents = marker
416 pre, sucs, flags, metadata, date, parents = marker
421 # determine node size
417 # determine node size
422 _fm1node = _fm1nodesha1
418 _fm1node = _fm1nodesha1
423 if flags & usingsha256:
419 if flags & usingsha256:
424 _fm1node = _fm1nodesha256
420 _fm1node = _fm1nodesha256
425 numsuc = len(sucs)
421 numsuc = len(sucs)
426 numextranodes = 1 + numsuc
422 numextranodes = 1 + numsuc
427 if parents is None:
423 if parents is None:
428 numpar = _fm1parentnone
424 numpar = _fm1parentnone
429 else:
425 else:
430 numpar = len(parents)
426 numpar = len(parents)
431 numextranodes += numpar
427 numextranodes += numpar
432 formatnodes = _fm1node * numextranodes
428 formatnodes = _fm1node * numextranodes
433 formatmeta = _fm1metapair * len(metadata)
429 formatmeta = _fm1metapair * len(metadata)
434 format = _fm1fixed + formatnodes + formatmeta
430 format = _fm1fixed + formatnodes + formatmeta
435 # tz is stored in minutes so we divide by 60
431 # tz is stored in minutes so we divide by 60
436 tz = date[1] // 60
432 tz = date[1] // 60
437 data = [None, date[0], tz, flags, numsuc, numpar, len(metadata), pre]
433 data = [None, date[0], tz, flags, numsuc, numpar, len(metadata), pre]
438 data.extend(sucs)
434 data.extend(sucs)
439 if parents is not None:
435 if parents is not None:
440 data.extend(parents)
436 data.extend(parents)
441 totalsize = _calcsize(format)
437 totalsize = _calcsize(format)
442 for key, value in metadata:
438 for key, value in metadata:
443 lk = len(key)
439 lk = len(key)
444 lv = len(value)
440 lv = len(value)
445 if lk > 255:
441 if lk > 255:
446 msg = (
442 msg = (
447 b'obsstore metadata key cannot be longer than 255 bytes'
443 b'obsstore metadata key cannot be longer than 255 bytes'
448 b' (key "%s" is %u bytes)'
444 b' (key "%s" is %u bytes)'
449 ) % (key, lk)
445 ) % (key, lk)
450 raise error.ProgrammingError(msg)
446 raise error.ProgrammingError(msg)
451 if lv > 255:
447 if lv > 255:
452 msg = (
448 msg = (
453 b'obsstore metadata value cannot be longer than 255 bytes'
449 b'obsstore metadata value cannot be longer than 255 bytes'
454 b' (value "%s" for key "%s" is %u bytes)'
450 b' (value "%s" for key "%s" is %u bytes)'
455 ) % (value, key, lv)
451 ) % (value, key, lv)
456 raise error.ProgrammingError(msg)
452 raise error.ProgrammingError(msg)
457 data.append(lk)
453 data.append(lk)
458 data.append(lv)
454 data.append(lv)
459 totalsize += lk + lv
455 totalsize += lk + lv
460 data[0] = totalsize
456 data[0] = totalsize
461 data = [_pack(format, *data)]
457 data = [_pack(format, *data)]
462 for key, value in metadata:
458 for key, value in metadata:
463 data.append(key)
459 data.append(key)
464 data.append(value)
460 data.append(value)
465 return b''.join(data)
461 return b''.join(data)
466
462
467
463
468 def _fm1readmarkers(data, off, stop):
464 def _fm1readmarkers(data, off, stop):
469 native = getattr(parsers, 'fm1readmarkers', None)
465 native = getattr(parsers, 'fm1readmarkers', None)
470 if not native:
466 if not native:
471 return _fm1purereadmarkers(data, off, stop)
467 return _fm1purereadmarkers(data, off, stop)
472 return native(data, off, stop)
468 return native(data, off, stop)
473
469
474
470
475 # mapping to read/write various marker formats
471 # mapping to read/write various marker formats
476 # <version> -> (decoder, encoder)
472 # <version> -> (decoder, encoder)
477 formats = {
473 formats = {
478 _fm0version: (_fm0readmarkers, _fm0encodeonemarker),
474 _fm0version: (_fm0readmarkers, _fm0encodeonemarker),
479 _fm1version: (_fm1readmarkers, _fm1encodeonemarker),
475 _fm1version: (_fm1readmarkers, _fm1encodeonemarker),
480 }
476 }
481
477
482
478
483 def _readmarkerversion(data):
479 def _readmarkerversion(data):
484 return _unpack(b'>B', data[0:1])[0]
480 return _unpack(b'>B', data[0:1])[0]
485
481
486
482
487 @util.nogc
483 @util.nogc
488 def _readmarkers(data, off=None, stop=None):
484 def _readmarkers(data, off=None, stop=None):
489 """Read and enumerate markers from raw data"""
485 """Read and enumerate markers from raw data"""
490 diskversion = _readmarkerversion(data)
486 diskversion = _readmarkerversion(data)
491 if not off:
487 if not off:
492 off = 1 # skip 1 byte version number
488 off = 1 # skip 1 byte version number
493 if stop is None:
489 if stop is None:
494 stop = len(data)
490 stop = len(data)
495 if diskversion not in formats:
491 if diskversion not in formats:
496 msg = _(b'parsing obsolete marker: unknown version %r') % diskversion
492 msg = _(b'parsing obsolete marker: unknown version %r') % diskversion
497 raise error.UnknownVersion(msg, version=diskversion)
493 raise error.UnknownVersion(msg, version=diskversion)
498 return diskversion, formats[diskversion][0](data, off, stop)
494 return diskversion, formats[diskversion][0](data, off, stop)
499
495
500
496
501 def encodeheader(version=_fm0version):
497 def encodeheader(version=_fm0version):
502 return _pack(b'>B', version)
498 return _pack(b'>B', version)
503
499
504
500
505 def encodemarkers(markers, addheader=False, version=_fm0version):
501 def encodemarkers(markers, addheader=False, version=_fm0version):
506 # Kept separate from flushmarkers(), it will be reused for
502 # Kept separate from flushmarkers(), it will be reused for
507 # markers exchange.
503 # markers exchange.
508 encodeone = formats[version][1]
504 encodeone = formats[version][1]
509 if addheader:
505 if addheader:
510 yield encodeheader(version)
506 yield encodeheader(version)
511 for marker in markers:
507 for marker in markers:
512 yield encodeone(marker)
508 yield encodeone(marker)
513
509
514
510
515 @util.nogc
511 @util.nogc
516 def _addsuccessors(successors, markers):
512 def _addsuccessors(successors, markers):
517 for mark in markers:
513 for mark in markers:
518 successors.setdefault(mark[0], set()).add(mark)
514 successors.setdefault(mark[0], set()).add(mark)
519
515
520
516
521 @util.nogc
517 @util.nogc
522 def _addpredecessors(predecessors, markers):
518 def _addpredecessors(predecessors, markers):
523 for mark in markers:
519 for mark in markers:
524 for suc in mark[1]:
520 for suc in mark[1]:
525 predecessors.setdefault(suc, set()).add(mark)
521 predecessors.setdefault(suc, set()).add(mark)
526
522
527
523
528 @util.nogc
524 @util.nogc
529 def _addchildren(children, markers):
525 def _addchildren(children, markers):
530 for mark in markers:
526 for mark in markers:
531 parents = mark[5]
527 parents = mark[5]
532 if parents is not None:
528 if parents is not None:
533 for p in parents:
529 for p in parents:
534 children.setdefault(p, set()).add(mark)
530 children.setdefault(p, set()).add(mark)
535
531
536
532
537 def _checkinvalidmarkers(repo, markers):
533 def _checkinvalidmarkers(repo, markers):
538 """search for marker with invalid data and raise error if needed
534 """search for marker with invalid data and raise error if needed
539
535
540 Exist as a separated function to allow the evolve extension for a more
536 Exist as a separated function to allow the evolve extension for a more
541 subtle handling.
537 subtle handling.
542 """
538 """
543 for mark in markers:
539 for mark in markers:
544 if repo.nullid in mark[1]:
540 if repo.nullid in mark[1]:
545 raise error.Abort(
541 raise error.Abort(
546 _(
542 _(
547 b'bad obsolescence marker detected: '
543 b'bad obsolescence marker detected: '
548 b'invalid successors nullid'
544 b'invalid successors nullid'
549 )
545 )
550 )
546 )
551
547
552
548
553 class obsstore(object):
549 class obsstore(object):
554 """Store obsolete markers
550 """Store obsolete markers
555
551
556 Markers can be accessed with two mappings:
552 Markers can be accessed with two mappings:
557 - predecessors[x] -> set(markers on predecessors edges of x)
553 - predecessors[x] -> set(markers on predecessors edges of x)
558 - successors[x] -> set(markers on successors edges of x)
554 - successors[x] -> set(markers on successors edges of x)
559 - children[x] -> set(markers on predecessors edges of children(x)
555 - children[x] -> set(markers on predecessors edges of children(x)
560 """
556 """
561
557
562 fields = (b'prec', b'succs', b'flag', b'meta', b'date', b'parents')
558 fields = (b'prec', b'succs', b'flag', b'meta', b'date', b'parents')
563 # prec: nodeid, predecessors changesets
559 # prec: nodeid, predecessors changesets
564 # succs: tuple of nodeid, successor changesets (0-N length)
560 # succs: tuple of nodeid, successor changesets (0-N length)
565 # flag: integer, flag field carrying modifier for the markers (see doc)
561 # flag: integer, flag field carrying modifier for the markers (see doc)
566 # meta: binary blob in UTF-8, encoded metadata dictionary
562 # meta: binary blob in UTF-8, encoded metadata dictionary
567 # date: (float, int) tuple, date of marker creation
563 # date: (float, int) tuple, date of marker creation
568 # parents: (tuple of nodeid) or None, parents of predecessors
564 # parents: (tuple of nodeid) or None, parents of predecessors
569 # None is used when no data has been recorded
565 # None is used when no data has been recorded
570
566
571 def __init__(self, repo, svfs, defaultformat=_fm1version, readonly=False):
567 def __init__(self, repo, svfs, defaultformat=_fm1version, readonly=False):
572 # caches for various obsolescence related cache
568 # caches for various obsolescence related cache
573 self.caches = {}
569 self.caches = {}
574 self.svfs = svfs
570 self.svfs = svfs
575 self.repo = repo
571 self.repo = repo
576 self._defaultformat = defaultformat
572 self._defaultformat = defaultformat
577 self._readonly = readonly
573 self._readonly = readonly
578
574
579 def __iter__(self):
575 def __iter__(self):
580 return iter(self._all)
576 return iter(self._all)
581
577
582 def __len__(self):
578 def __len__(self):
583 return len(self._all)
579 return len(self._all)
584
580
585 def __nonzero__(self):
581 def __nonzero__(self):
586 if not self._cached('_all'):
582 if not self._cached('_all'):
587 try:
583 try:
588 return self.svfs.stat(b'obsstore').st_size > 1
584 return self.svfs.stat(b'obsstore').st_size > 1
589 except OSError as inst:
585 except OSError as inst:
590 if inst.errno != errno.ENOENT:
586 if inst.errno != errno.ENOENT:
591 raise
587 raise
592 # just build an empty _all list if no obsstore exists, which
588 # just build an empty _all list if no obsstore exists, which
593 # avoids further stat() syscalls
589 # avoids further stat() syscalls
594 return bool(self._all)
590 return bool(self._all)
595
591
596 __bool__ = __nonzero__
592 __bool__ = __nonzero__
597
593
598 @property
594 @property
599 def readonly(self):
595 def readonly(self):
600 """True if marker creation is disabled
596 """True if marker creation is disabled
601
597
602 Remove me in the future when obsolete marker is always on."""
598 Remove me in the future when obsolete marker is always on."""
603 return self._readonly
599 return self._readonly
604
600
605 def create(
601 def create(
606 self,
602 self,
607 transaction,
603 transaction,
608 prec,
604 prec,
609 succs=(),
605 succs=(),
610 flag=0,
606 flag=0,
611 parents=None,
607 parents=None,
612 date=None,
608 date=None,
613 metadata=None,
609 metadata=None,
614 ui=None,
610 ui=None,
615 ):
611 ):
616 """obsolete: add a new obsolete marker
612 """obsolete: add a new obsolete marker
617
613
618 * ensuring it is hashable
614 * ensuring it is hashable
619 * check mandatory metadata
615 * check mandatory metadata
620 * encode metadata
616 * encode metadata
621
617
622 If you are a human writing code creating marker you want to use the
618 If you are a human writing code creating marker you want to use the
623 `createmarkers` function in this module instead.
619 `createmarkers` function in this module instead.
624
620
625 return True if a new marker have been added, False if the markers
621 return True if a new marker have been added, False if the markers
626 already existed (no op).
622 already existed (no op).
627 """
623 """
628 flag = int(flag)
624 flag = int(flag)
629 if metadata is None:
625 if metadata is None:
630 metadata = {}
626 metadata = {}
631 if date is None:
627 if date is None:
632 if b'date' in metadata:
628 if b'date' in metadata:
633 # as a courtesy for out-of-tree extensions
629 # as a courtesy for out-of-tree extensions
634 date = dateutil.parsedate(metadata.pop(b'date'))
630 date = dateutil.parsedate(metadata.pop(b'date'))
635 elif ui is not None:
631 elif ui is not None:
636 date = ui.configdate(b'devel', b'default-date')
632 date = ui.configdate(b'devel', b'default-date')
637 if date is None:
633 if date is None:
638 date = dateutil.makedate()
634 date = dateutil.makedate()
639 else:
635 else:
640 date = dateutil.makedate()
636 date = dateutil.makedate()
641 if flag & usingsha256:
637 if flag & usingsha256:
642 if len(prec) != 32:
638 if len(prec) != 32:
643 raise ValueError(prec)
639 raise ValueError(prec)
644 for succ in succs:
640 for succ in succs:
645 if len(succ) != 32:
641 if len(succ) != 32:
646 raise ValueError(succ)
642 raise ValueError(succ)
647 else:
643 else:
648 if len(prec) != 20:
644 if len(prec) != 20:
649 raise ValueError(prec)
645 raise ValueError(prec)
650 for succ in succs:
646 for succ in succs:
651 if len(succ) != 20:
647 if len(succ) != 20:
652 raise ValueError(succ)
648 raise ValueError(succ)
653 if prec in succs:
649 if prec in succs:
654 raise ValueError(
650 raise ValueError(
655 'in-marker cycle with %s' % pycompat.sysstr(hex(prec))
651 'in-marker cycle with %s' % pycompat.sysstr(hex(prec))
656 )
652 )
657
653
658 metadata = tuple(sorted(pycompat.iteritems(metadata)))
654 metadata = tuple(sorted(pycompat.iteritems(metadata)))
659 for k, v in metadata:
655 for k, v in metadata:
660 try:
656 try:
661 # might be better to reject non-ASCII keys
657 # might be better to reject non-ASCII keys
662 k.decode('utf-8')
658 k.decode('utf-8')
663 v.decode('utf-8')
659 v.decode('utf-8')
664 except UnicodeDecodeError:
660 except UnicodeDecodeError:
665 raise error.ProgrammingError(
661 raise error.ProgrammingError(
666 b'obsstore metadata must be valid UTF-8 sequence '
662 b'obsstore metadata must be valid UTF-8 sequence '
667 b'(key = %r, value = %r)'
663 b'(key = %r, value = %r)'
668 % (pycompat.bytestr(k), pycompat.bytestr(v))
664 % (pycompat.bytestr(k), pycompat.bytestr(v))
669 )
665 )
670
666
671 marker = (bytes(prec), tuple(succs), flag, metadata, date, parents)
667 marker = (bytes(prec), tuple(succs), flag, metadata, date, parents)
672 return bool(self.add(transaction, [marker]))
668 return bool(self.add(transaction, [marker]))
673
669
674 def add(self, transaction, markers):
670 def add(self, transaction, markers):
675 """Add new markers to the store
671 """Add new markers to the store
676
672
677 Take care of filtering duplicate.
673 Take care of filtering duplicate.
678 Return the number of new marker."""
674 Return the number of new marker."""
679 if self._readonly:
675 if self._readonly:
680 raise error.Abort(
676 raise error.Abort(
681 _(b'creating obsolete markers is not enabled on this repo')
677 _(b'creating obsolete markers is not enabled on this repo')
682 )
678 )
683 known = set()
679 known = set()
684 getsuccessors = self.successors.get
680 getsuccessors = self.successors.get
685 new = []
681 new = []
686 for m in markers:
682 for m in markers:
687 if m not in getsuccessors(m[0], ()) and m not in known:
683 if m not in getsuccessors(m[0], ()) and m not in known:
688 known.add(m)
684 known.add(m)
689 new.append(m)
685 new.append(m)
690 if new:
686 if new:
691 f = self.svfs(b'obsstore', b'ab')
687 f = self.svfs(b'obsstore', b'ab')
692 try:
688 try:
693 offset = f.tell()
689 offset = f.tell()
694 transaction.add(b'obsstore', offset)
690 transaction.add(b'obsstore', offset)
695 # offset == 0: new file - add the version header
691 # offset == 0: new file - add the version header
696 data = b''.join(encodemarkers(new, offset == 0, self._version))
692 data = b''.join(encodemarkers(new, offset == 0, self._version))
697 f.write(data)
693 f.write(data)
698 finally:
694 finally:
699 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
695 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
700 # call 'filecacheentry.refresh()' here
696 # call 'filecacheentry.refresh()' here
701 f.close()
697 f.close()
702 addedmarkers = transaction.changes.get(b'obsmarkers')
698 addedmarkers = transaction.changes.get(b'obsmarkers')
703 if addedmarkers is not None:
699 if addedmarkers is not None:
704 addedmarkers.update(new)
700 addedmarkers.update(new)
705 self._addmarkers(new, data)
701 self._addmarkers(new, data)
706 # new marker *may* have changed several set. invalidate the cache.
702 # new marker *may* have changed several set. invalidate the cache.
707 self.caches.clear()
703 self.caches.clear()
708 # records the number of new markers for the transaction hooks
704 # records the number of new markers for the transaction hooks
709 previous = int(transaction.hookargs.get(b'new_obsmarkers', b'0'))
705 previous = int(transaction.hookargs.get(b'new_obsmarkers', b'0'))
710 transaction.hookargs[b'new_obsmarkers'] = b'%d' % (previous + len(new))
706 transaction.hookargs[b'new_obsmarkers'] = b'%d' % (previous + len(new))
711 return len(new)
707 return len(new)
712
708
713 def mergemarkers(self, transaction, data):
709 def mergemarkers(self, transaction, data):
714 """merge a binary stream of markers inside the obsstore
710 """merge a binary stream of markers inside the obsstore
715
711
716 Returns the number of new markers added."""
712 Returns the number of new markers added."""
717 version, markers = _readmarkers(data)
713 version, markers = _readmarkers(data)
718 return self.add(transaction, markers)
714 return self.add(transaction, markers)
719
715
720 @propertycache
716 @propertycache
721 def _data(self):
717 def _data(self):
722 return self.svfs.tryread(b'obsstore')
718 return self.svfs.tryread(b'obsstore')
723
719
724 @propertycache
720 @propertycache
725 def _version(self):
721 def _version(self):
726 if len(self._data) >= 1:
722 if len(self._data) >= 1:
727 return _readmarkerversion(self._data)
723 return _readmarkerversion(self._data)
728 else:
724 else:
729 return self._defaultformat
725 return self._defaultformat
730
726
731 @propertycache
727 @propertycache
732 def _all(self):
728 def _all(self):
733 data = self._data
729 data = self._data
734 if not data:
730 if not data:
735 return []
731 return []
736 self._version, markers = _readmarkers(data)
732 self._version, markers = _readmarkers(data)
737 markers = list(markers)
733 markers = list(markers)
738 _checkinvalidmarkers(self.repo, markers)
734 _checkinvalidmarkers(self.repo, markers)
739 return markers
735 return markers
740
736
741 @propertycache
737 @propertycache
742 def successors(self):
738 def successors(self):
743 successors = {}
739 successors = {}
744 _addsuccessors(successors, self._all)
740 _addsuccessors(successors, self._all)
745 return successors
741 return successors
746
742
747 @propertycache
743 @propertycache
748 def predecessors(self):
744 def predecessors(self):
749 predecessors = {}
745 predecessors = {}
750 _addpredecessors(predecessors, self._all)
746 _addpredecessors(predecessors, self._all)
751 return predecessors
747 return predecessors
752
748
753 @propertycache
749 @propertycache
754 def children(self):
750 def children(self):
755 children = {}
751 children = {}
756 _addchildren(children, self._all)
752 _addchildren(children, self._all)
757 return children
753 return children
758
754
759 def _cached(self, attr):
755 def _cached(self, attr):
760 return attr in self.__dict__
756 return attr in self.__dict__
761
757
762 def _addmarkers(self, markers, rawdata):
758 def _addmarkers(self, markers, rawdata):
763 markers = list(markers) # to allow repeated iteration
759 markers = list(markers) # to allow repeated iteration
764 self._data = self._data + rawdata
760 self._data = self._data + rawdata
765 self._all.extend(markers)
761 self._all.extend(markers)
766 if self._cached('successors'):
762 if self._cached('successors'):
767 _addsuccessors(self.successors, markers)
763 _addsuccessors(self.successors, markers)
768 if self._cached('predecessors'):
764 if self._cached('predecessors'):
769 _addpredecessors(self.predecessors, markers)
765 _addpredecessors(self.predecessors, markers)
770 if self._cached('children'):
766 if self._cached('children'):
771 _addchildren(self.children, markers)
767 _addchildren(self.children, markers)
772 _checkinvalidmarkers(self.repo, markers)
768 _checkinvalidmarkers(self.repo, markers)
773
769
774 def relevantmarkers(self, nodes):
770 def relevantmarkers(self, nodes):
775 """return a set of all obsolescence markers relevant to a set of nodes.
771 """return a set of all obsolescence markers relevant to a set of nodes.
776
772
777 "relevant" to a set of nodes mean:
773 "relevant" to a set of nodes mean:
778
774
779 - marker that use this changeset as successor
775 - marker that use this changeset as successor
780 - prune marker of direct children on this changeset
776 - prune marker of direct children on this changeset
781 - recursive application of the two rules on predecessors of these
777 - recursive application of the two rules on predecessors of these
782 markers
778 markers
783
779
784 It is a set so you cannot rely on order."""
780 It is a set so you cannot rely on order."""
785
781
786 pendingnodes = set(nodes)
782 pendingnodes = set(nodes)
787 seenmarkers = set()
783 seenmarkers = set()
788 seennodes = set(pendingnodes)
784 seennodes = set(pendingnodes)
789 precursorsmarkers = self.predecessors
785 precursorsmarkers = self.predecessors
790 succsmarkers = self.successors
786 succsmarkers = self.successors
791 children = self.children
787 children = self.children
792 while pendingnodes:
788 while pendingnodes:
793 direct = set()
789 direct = set()
794 for current in pendingnodes:
790 for current in pendingnodes:
795 direct.update(precursorsmarkers.get(current, ()))
791 direct.update(precursorsmarkers.get(current, ()))
796 pruned = [m for m in children.get(current, ()) if not m[1]]
792 pruned = [m for m in children.get(current, ()) if not m[1]]
797 direct.update(pruned)
793 direct.update(pruned)
798 pruned = [m for m in succsmarkers.get(current, ()) if not m[1]]
794 pruned = [m for m in succsmarkers.get(current, ()) if not m[1]]
799 direct.update(pruned)
795 direct.update(pruned)
800 direct -= seenmarkers
796 direct -= seenmarkers
801 pendingnodes = {m[0] for m in direct}
797 pendingnodes = {m[0] for m in direct}
802 seenmarkers |= direct
798 seenmarkers |= direct
803 pendingnodes -= seennodes
799 pendingnodes -= seennodes
804 seennodes |= pendingnodes
800 seennodes |= pendingnodes
805 return seenmarkers
801 return seenmarkers
806
802
807
803
808 def makestore(ui, repo):
804 def makestore(ui, repo):
809 """Create an obsstore instance from a repo."""
805 """Create an obsstore instance from a repo."""
810 # read default format for new obsstore.
806 # read default format for new obsstore.
811 # developer config: format.obsstore-version
807 # developer config: format.obsstore-version
812 defaultformat = ui.configint(b'format', b'obsstore-version')
808 defaultformat = ui.configint(b'format', b'obsstore-version')
813 # rely on obsstore class default when possible.
809 # rely on obsstore class default when possible.
814 kwargs = {}
810 kwargs = {}
815 if defaultformat is not None:
811 if defaultformat is not None:
816 kwargs['defaultformat'] = defaultformat
812 kwargs['defaultformat'] = defaultformat
817 readonly = not isenabled(repo, createmarkersopt)
813 readonly = not isenabled(repo, createmarkersopt)
818 store = obsstore(repo, repo.svfs, readonly=readonly, **kwargs)
814 store = obsstore(repo, repo.svfs, readonly=readonly, **kwargs)
819 if store and readonly:
815 if store and readonly:
820 ui.warn(
816 ui.warn(
821 _(b'obsolete feature not enabled but %i markers found!\n')
817 _(b'obsolete feature not enabled but %i markers found!\n')
822 % len(list(store))
818 % len(list(store))
823 )
819 )
824 return store
820 return store
825
821
826
822
827 def commonversion(versions):
823 def commonversion(versions):
828 """Return the newest version listed in both versions and our local formats.
824 """Return the newest version listed in both versions and our local formats.
829
825
830 Returns None if no common version exists.
826 Returns None if no common version exists.
831 """
827 """
832 versions.sort(reverse=True)
828 versions.sort(reverse=True)
833 # search for highest version known on both side
829 # search for highest version known on both side
834 for v in versions:
830 for v in versions:
835 if v in formats:
831 if v in formats:
836 return v
832 return v
837 return None
833 return None
838
834
839
835
840 # arbitrary picked to fit into 8K limit from HTTP server
836 # arbitrary picked to fit into 8K limit from HTTP server
841 # you have to take in account:
837 # you have to take in account:
842 # - the version header
838 # - the version header
843 # - the base85 encoding
839 # - the base85 encoding
844 _maxpayload = 5300
840 _maxpayload = 5300
845
841
846
842
847 def _pushkeyescape(markers):
843 def _pushkeyescape(markers):
848 """encode markers into a dict suitable for pushkey exchange
844 """encode markers into a dict suitable for pushkey exchange
849
845
850 - binary data is base85 encoded
846 - binary data is base85 encoded
851 - split in chunks smaller than 5300 bytes"""
847 - split in chunks smaller than 5300 bytes"""
852 keys = {}
848 keys = {}
853 parts = []
849 parts = []
854 currentlen = _maxpayload * 2 # ensure we create a new part
850 currentlen = _maxpayload * 2 # ensure we create a new part
855 for marker in markers:
851 for marker in markers:
856 nextdata = _fm0encodeonemarker(marker)
852 nextdata = _fm0encodeonemarker(marker)
857 if len(nextdata) + currentlen > _maxpayload:
853 if len(nextdata) + currentlen > _maxpayload:
858 currentpart = []
854 currentpart = []
859 currentlen = 0
855 currentlen = 0
860 parts.append(currentpart)
856 parts.append(currentpart)
861 currentpart.append(nextdata)
857 currentpart.append(nextdata)
862 currentlen += len(nextdata)
858 currentlen += len(nextdata)
863 for idx, part in enumerate(reversed(parts)):
859 for idx, part in enumerate(reversed(parts)):
864 data = b''.join([_pack(b'>B', _fm0version)] + part)
860 data = b''.join([_pack(b'>B', _fm0version)] + part)
865 keys[b'dump%i' % idx] = util.b85encode(data)
861 keys[b'dump%i' % idx] = util.b85encode(data)
866 return keys
862 return keys
867
863
868
864
869 def listmarkers(repo):
865 def listmarkers(repo):
870 """List markers over pushkey"""
866 """List markers over pushkey"""
871 if not repo.obsstore:
867 if not repo.obsstore:
872 return {}
868 return {}
873 return _pushkeyescape(sorted(repo.obsstore))
869 return _pushkeyescape(sorted(repo.obsstore))
874
870
875
871
876 def pushmarker(repo, key, old, new):
872 def pushmarker(repo, key, old, new):
877 """Push markers over pushkey"""
873 """Push markers over pushkey"""
878 if not key.startswith(b'dump'):
874 if not key.startswith(b'dump'):
879 repo.ui.warn(_(b'unknown key: %r') % key)
875 repo.ui.warn(_(b'unknown key: %r') % key)
880 return False
876 return False
881 if old:
877 if old:
882 repo.ui.warn(_(b'unexpected old value for %r') % key)
878 repo.ui.warn(_(b'unexpected old value for %r') % key)
883 return False
879 return False
884 data = util.b85decode(new)
880 data = util.b85decode(new)
885 with repo.lock(), repo.transaction(b'pushkey: obsolete markers') as tr:
881 with repo.lock(), repo.transaction(b'pushkey: obsolete markers') as tr:
886 repo.obsstore.mergemarkers(tr, data)
882 repo.obsstore.mergemarkers(tr, data)
887 repo.invalidatevolatilesets()
883 repo.invalidatevolatilesets()
888 return True
884 return True
889
885
890
886
891 # mapping of 'set-name' -> <function to compute this set>
887 # mapping of 'set-name' -> <function to compute this set>
892 cachefuncs = {}
888 cachefuncs = {}
893
889
894
890
895 def cachefor(name):
891 def cachefor(name):
896 """Decorator to register a function as computing the cache for a set"""
892 """Decorator to register a function as computing the cache for a set"""
897
893
898 def decorator(func):
894 def decorator(func):
899 if name in cachefuncs:
895 if name in cachefuncs:
900 msg = b"duplicated registration for volatileset '%s' (existing: %r)"
896 msg = b"duplicated registration for volatileset '%s' (existing: %r)"
901 raise error.ProgrammingError(msg % (name, cachefuncs[name]))
897 raise error.ProgrammingError(msg % (name, cachefuncs[name]))
902 cachefuncs[name] = func
898 cachefuncs[name] = func
903 return func
899 return func
904
900
905 return decorator
901 return decorator
906
902
907
903
908 def getrevs(repo, name):
904 def getrevs(repo, name):
909 """Return the set of revision that belong to the <name> set
905 """Return the set of revision that belong to the <name> set
910
906
911 Such access may compute the set and cache it for future use"""
907 Such access may compute the set and cache it for future use"""
912 repo = repo.unfiltered()
908 repo = repo.unfiltered()
913 with util.timedcm('getrevs %s', name):
909 with util.timedcm('getrevs %s', name):
914 if not repo.obsstore:
910 if not repo.obsstore:
915 return frozenset()
911 return frozenset()
916 if name not in repo.obsstore.caches:
912 if name not in repo.obsstore.caches:
917 repo.obsstore.caches[name] = cachefuncs[name](repo)
913 repo.obsstore.caches[name] = cachefuncs[name](repo)
918 return repo.obsstore.caches[name]
914 return repo.obsstore.caches[name]
919
915
920
916
921 # To be simple we need to invalidate obsolescence cache when:
917 # To be simple we need to invalidate obsolescence cache when:
922 #
918 #
923 # - new changeset is added:
919 # - new changeset is added:
924 # - public phase is changed
920 # - public phase is changed
925 # - obsolescence marker are added
921 # - obsolescence marker are added
926 # - strip is used a repo
922 # - strip is used a repo
927 def clearobscaches(repo):
923 def clearobscaches(repo):
928 """Remove all obsolescence related cache from a repo
924 """Remove all obsolescence related cache from a repo
929
925
930 This remove all cache in obsstore is the obsstore already exist on the
926 This remove all cache in obsstore is the obsstore already exist on the
931 repo.
927 repo.
932
928
933 (We could be smarter here given the exact event that trigger the cache
929 (We could be smarter here given the exact event that trigger the cache
934 clearing)"""
930 clearing)"""
935 # only clear cache is there is obsstore data in this repo
931 # only clear cache is there is obsstore data in this repo
936 if b'obsstore' in repo._filecache:
932 if b'obsstore' in repo._filecache:
937 repo.obsstore.caches.clear()
933 repo.obsstore.caches.clear()
938
934
939
935
940 def _mutablerevs(repo):
936 def _mutablerevs(repo):
941 """the set of mutable revision in the repository"""
937 """the set of mutable revision in the repository"""
942 return repo._phasecache.getrevset(repo, phases.mutablephases)
938 return repo._phasecache.getrevset(repo, phases.mutablephases)
943
939
944
940
945 @cachefor(b'obsolete')
941 @cachefor(b'obsolete')
946 def _computeobsoleteset(repo):
942 def _computeobsoleteset(repo):
947 """the set of obsolete revisions"""
943 """the set of obsolete revisions"""
948 getnode = repo.changelog.node
944 getnode = repo.changelog.node
949 notpublic = _mutablerevs(repo)
945 notpublic = _mutablerevs(repo)
950 isobs = repo.obsstore.successors.__contains__
946 isobs = repo.obsstore.successors.__contains__
951 obs = {r for r in notpublic if isobs(getnode(r))}
947 obs = {r for r in notpublic if isobs(getnode(r))}
952 return obs
948 return obs
953
949
954
950
955 @cachefor(b'orphan')
951 @cachefor(b'orphan')
956 def _computeorphanset(repo):
952 def _computeorphanset(repo):
957 """the set of non obsolete revisions with obsolete parents"""
953 """the set of non obsolete revisions with obsolete parents"""
958 pfunc = repo.changelog.parentrevs
954 pfunc = repo.changelog.parentrevs
959 mutable = _mutablerevs(repo)
955 mutable = _mutablerevs(repo)
960 obsolete = getrevs(repo, b'obsolete')
956 obsolete = getrevs(repo, b'obsolete')
961 others = mutable - obsolete
957 others = mutable - obsolete
962 unstable = set()
958 unstable = set()
963 for r in sorted(others):
959 for r in sorted(others):
964 # A rev is unstable if one of its parent is obsolete or unstable
960 # A rev is unstable if one of its parent is obsolete or unstable
965 # this works since we traverse following growing rev order
961 # this works since we traverse following growing rev order
966 for p in pfunc(r):
962 for p in pfunc(r):
967 if p in obsolete or p in unstable:
963 if p in obsolete or p in unstable:
968 unstable.add(r)
964 unstable.add(r)
969 break
965 break
970 return unstable
966 return unstable
971
967
972
968
973 @cachefor(b'suspended')
969 @cachefor(b'suspended')
974 def _computesuspendedset(repo):
970 def _computesuspendedset(repo):
975 """the set of obsolete parents with non obsolete descendants"""
971 """the set of obsolete parents with non obsolete descendants"""
976 suspended = repo.changelog.ancestors(getrevs(repo, b'orphan'))
972 suspended = repo.changelog.ancestors(getrevs(repo, b'orphan'))
977 return {r for r in getrevs(repo, b'obsolete') if r in suspended}
973 return {r for r in getrevs(repo, b'obsolete') if r in suspended}
978
974
979
975
980 @cachefor(b'extinct')
976 @cachefor(b'extinct')
981 def _computeextinctset(repo):
977 def _computeextinctset(repo):
982 """the set of obsolete parents without non obsolete descendants"""
978 """the set of obsolete parents without non obsolete descendants"""
983 return getrevs(repo, b'obsolete') - getrevs(repo, b'suspended')
979 return getrevs(repo, b'obsolete') - getrevs(repo, b'suspended')
984
980
985
981
986 @cachefor(b'phasedivergent')
982 @cachefor(b'phasedivergent')
987 def _computephasedivergentset(repo):
983 def _computephasedivergentset(repo):
988 """the set of revs trying to obsolete public revisions"""
984 """the set of revs trying to obsolete public revisions"""
989 bumped = set()
985 bumped = set()
990 # util function (avoid attribute lookup in the loop)
986 # util function (avoid attribute lookup in the loop)
991 phase = repo._phasecache.phase # would be faster to grab the full list
987 phase = repo._phasecache.phase # would be faster to grab the full list
992 public = phases.public
988 public = phases.public
993 cl = repo.changelog
989 cl = repo.changelog
994 torev = cl.index.get_rev
990 torev = cl.index.get_rev
995 tonode = cl.node
991 tonode = cl.node
996 obsstore = repo.obsstore
992 obsstore = repo.obsstore
997 for rev in repo.revs(b'(not public()) and (not obsolete())'):
993 for rev in repo.revs(b'(not public()) and (not obsolete())'):
998 # We only evaluate mutable, non-obsolete revision
994 # We only evaluate mutable, non-obsolete revision
999 node = tonode(rev)
995 node = tonode(rev)
1000 # (future) A cache of predecessors may worth if split is very common
996 # (future) A cache of predecessors may worth if split is very common
1001 for pnode in obsutil.allpredecessors(
997 for pnode in obsutil.allpredecessors(
1002 obsstore, [node], ignoreflags=bumpedfix
998 obsstore, [node], ignoreflags=bumpedfix
1003 ):
999 ):
1004 prev = torev(pnode) # unfiltered! but so is phasecache
1000 prev = torev(pnode) # unfiltered! but so is phasecache
1005 if (prev is not None) and (phase(repo, prev) <= public):
1001 if (prev is not None) and (phase(repo, prev) <= public):
1006 # we have a public predecessor
1002 # we have a public predecessor
1007 bumped.add(rev)
1003 bumped.add(rev)
1008 break # Next draft!
1004 break # Next draft!
1009 return bumped
1005 return bumped
1010
1006
1011
1007
1012 @cachefor(b'contentdivergent')
1008 @cachefor(b'contentdivergent')
1013 def _computecontentdivergentset(repo):
1009 def _computecontentdivergentset(repo):
1014 """the set of rev that compete to be the final successors of some revision."""
1010 """the set of rev that compete to be the final successors of some revision."""
1015 divergent = set()
1011 divergent = set()
1016 obsstore = repo.obsstore
1012 obsstore = repo.obsstore
1017 newermap = {}
1013 newermap = {}
1018 tonode = repo.changelog.node
1014 tonode = repo.changelog.node
1019 for rev in repo.revs(b'(not public()) - obsolete()'):
1015 for rev in repo.revs(b'(not public()) - obsolete()'):
1020 node = tonode(rev)
1016 node = tonode(rev)
1021 mark = obsstore.predecessors.get(node, ())
1017 mark = obsstore.predecessors.get(node, ())
1022 toprocess = set(mark)
1018 toprocess = set(mark)
1023 seen = set()
1019 seen = set()
1024 while toprocess:
1020 while toprocess:
1025 prec = toprocess.pop()[0]
1021 prec = toprocess.pop()[0]
1026 if prec in seen:
1022 if prec in seen:
1027 continue # emergency cycle hanging prevention
1023 continue # emergency cycle hanging prevention
1028 seen.add(prec)
1024 seen.add(prec)
1029 if prec not in newermap:
1025 if prec not in newermap:
1030 obsutil.successorssets(repo, prec, cache=newermap)
1026 obsutil.successorssets(repo, prec, cache=newermap)
1031 newer = [n for n in newermap[prec] if n]
1027 newer = [n for n in newermap[prec] if n]
1032 if len(newer) > 1:
1028 if len(newer) > 1:
1033 divergent.add(rev)
1029 divergent.add(rev)
1034 break
1030 break
1035 toprocess.update(obsstore.predecessors.get(prec, ()))
1031 toprocess.update(obsstore.predecessors.get(prec, ()))
1036 return divergent
1032 return divergent
1037
1033
1038
1034
1039 def makefoldid(relation, user):
1035 def makefoldid(relation, user):
1040
1036
1041 folddigest = hashutil.sha1(user)
1037 folddigest = hashutil.sha1(user)
1042 for p in relation[0] + relation[1]:
1038 for p in relation[0] + relation[1]:
1043 folddigest.update(b'%d' % p.rev())
1039 folddigest.update(b'%d' % p.rev())
1044 folddigest.update(p.node())
1040 folddigest.update(p.node())
1045 # Since fold only has to compete against fold for the same successors, it
1041 # Since fold only has to compete against fold for the same successors, it
1046 # seems fine to use a small ID. Smaller ID save space.
1042 # seems fine to use a small ID. Smaller ID save space.
1047 return hex(folddigest.digest())[:8]
1043 return hex(folddigest.digest())[:8]
1048
1044
1049
1045
1050 def createmarkers(
1046 def createmarkers(
1051 repo, relations, flag=0, date=None, metadata=None, operation=None
1047 repo, relations, flag=0, date=None, metadata=None, operation=None
1052 ):
1048 ):
1053 """Add obsolete markers between changesets in a repo
1049 """Add obsolete markers between changesets in a repo
1054
1050
1055 <relations> must be an iterable of ((<old>,...), (<new>, ...)[,{metadata}])
1051 <relations> must be an iterable of ((<old>,...), (<new>, ...)[,{metadata}])
1056 tuple. `old` and `news` are changectx. metadata is an optional dictionary
1052 tuple. `old` and `news` are changectx. metadata is an optional dictionary
1057 containing metadata for this marker only. It is merged with the global
1053 containing metadata for this marker only. It is merged with the global
1058 metadata specified through the `metadata` argument of this function.
1054 metadata specified through the `metadata` argument of this function.
1059 Any string values in metadata must be UTF-8 bytes.
1055 Any string values in metadata must be UTF-8 bytes.
1060
1056
1061 Trying to obsolete a public changeset will raise an exception.
1057 Trying to obsolete a public changeset will raise an exception.
1062
1058
1063 Current user and date are used except if specified otherwise in the
1059 Current user and date are used except if specified otherwise in the
1064 metadata attribute.
1060 metadata attribute.
1065
1061
1066 This function operates within a transaction of its own, but does
1062 This function operates within a transaction of its own, but does
1067 not take any lock on the repo.
1063 not take any lock on the repo.
1068 """
1064 """
1069 # prepare metadata
1065 # prepare metadata
1070 if metadata is None:
1066 if metadata is None:
1071 metadata = {}
1067 metadata = {}
1072 if b'user' not in metadata:
1068 if b'user' not in metadata:
1073 luser = (
1069 luser = (
1074 repo.ui.config(b'devel', b'user.obsmarker') or repo.ui.username()
1070 repo.ui.config(b'devel', b'user.obsmarker') or repo.ui.username()
1075 )
1071 )
1076 metadata[b'user'] = encoding.fromlocal(luser)
1072 metadata[b'user'] = encoding.fromlocal(luser)
1077
1073
1078 # Operation metadata handling
1074 # Operation metadata handling
1079 useoperation = repo.ui.configbool(
1075 useoperation = repo.ui.configbool(
1080 b'experimental', b'evolution.track-operation'
1076 b'experimental', b'evolution.track-operation'
1081 )
1077 )
1082 if useoperation and operation:
1078 if useoperation and operation:
1083 metadata[b'operation'] = operation
1079 metadata[b'operation'] = operation
1084
1080
1085 # Effect flag metadata handling
1081 # Effect flag metadata handling
1086 saveeffectflag = repo.ui.configbool(
1082 saveeffectflag = repo.ui.configbool(
1087 b'experimental', b'evolution.effect-flags'
1083 b'experimental', b'evolution.effect-flags'
1088 )
1084 )
1089
1085
1090 with repo.transaction(b'add-obsolescence-marker') as tr:
1086 with repo.transaction(b'add-obsolescence-marker') as tr:
1091 markerargs = []
1087 markerargs = []
1092 for rel in relations:
1088 for rel in relations:
1093 predecessors = rel[0]
1089 predecessors = rel[0]
1094 if not isinstance(predecessors, tuple):
1090 if not isinstance(predecessors, tuple):
1095 # preserve compat with old API until all caller are migrated
1091 # preserve compat with old API until all caller are migrated
1096 predecessors = (predecessors,)
1092 predecessors = (predecessors,)
1097 if len(predecessors) > 1 and len(rel[1]) != 1:
1093 if len(predecessors) > 1 and len(rel[1]) != 1:
1098 msg = b'Fold markers can only have 1 successors, not %d'
1094 msg = b'Fold markers can only have 1 successors, not %d'
1099 raise error.ProgrammingError(msg % len(rel[1]))
1095 raise error.ProgrammingError(msg % len(rel[1]))
1100 foldid = None
1096 foldid = None
1101 foldsize = len(predecessors)
1097 foldsize = len(predecessors)
1102 if 1 < foldsize:
1098 if 1 < foldsize:
1103 foldid = makefoldid(rel, metadata[b'user'])
1099 foldid = makefoldid(rel, metadata[b'user'])
1104 for foldidx, prec in enumerate(predecessors, 1):
1100 for foldidx, prec in enumerate(predecessors, 1):
1105 sucs = rel[1]
1101 sucs = rel[1]
1106 localmetadata = metadata.copy()
1102 localmetadata = metadata.copy()
1107 if len(rel) > 2:
1103 if len(rel) > 2:
1108 localmetadata.update(rel[2])
1104 localmetadata.update(rel[2])
1109 if foldid is not None:
1105 if foldid is not None:
1110 localmetadata[b'fold-id'] = foldid
1106 localmetadata[b'fold-id'] = foldid
1111 localmetadata[b'fold-idx'] = b'%d' % foldidx
1107 localmetadata[b'fold-idx'] = b'%d' % foldidx
1112 localmetadata[b'fold-size'] = b'%d' % foldsize
1108 localmetadata[b'fold-size'] = b'%d' % foldsize
1113
1109
1114 if not prec.mutable():
1110 if not prec.mutable():
1115 raise error.Abort(
1111 raise error.Abort(
1116 _(b"cannot obsolete public changeset: %s") % prec,
1112 _(b"cannot obsolete public changeset: %s") % prec,
1117 hint=b"see 'hg help phases' for details",
1113 hint=b"see 'hg help phases' for details",
1118 )
1114 )
1119 nprec = prec.node()
1115 nprec = prec.node()
1120 nsucs = tuple(s.node() for s in sucs)
1116 nsucs = tuple(s.node() for s in sucs)
1121 npare = None
1117 npare = None
1122 if not nsucs:
1118 if not nsucs:
1123 npare = tuple(p.node() for p in prec.parents())
1119 npare = tuple(p.node() for p in prec.parents())
1124 if nprec in nsucs:
1120 if nprec in nsucs:
1125 raise error.Abort(
1121 raise error.Abort(
1126 _(b"changeset %s cannot obsolete itself") % prec
1122 _(b"changeset %s cannot obsolete itself") % prec
1127 )
1123 )
1128
1124
1129 # Effect flag can be different by relation
1125 # Effect flag can be different by relation
1130 if saveeffectflag:
1126 if saveeffectflag:
1131 # The effect flag is saved in a versioned field name for
1127 # The effect flag is saved in a versioned field name for
1132 # future evolution
1128 # future evolution
1133 effectflag = obsutil.geteffectflag(prec, sucs)
1129 effectflag = obsutil.geteffectflag(prec, sucs)
1134 localmetadata[obsutil.EFFECTFLAGFIELD] = b"%d" % effectflag
1130 localmetadata[obsutil.EFFECTFLAGFIELD] = b"%d" % effectflag
1135
1131
1136 # Creating the marker causes the hidden cache to become
1132 # Creating the marker causes the hidden cache to become
1137 # invalid, which causes recomputation when we ask for
1133 # invalid, which causes recomputation when we ask for
1138 # prec.parents() above. Resulting in n^2 behavior. So let's
1134 # prec.parents() above. Resulting in n^2 behavior. So let's
1139 # prepare all of the args first, then create the markers.
1135 # prepare all of the args first, then create the markers.
1140 markerargs.append((nprec, nsucs, npare, localmetadata))
1136 markerargs.append((nprec, nsucs, npare, localmetadata))
1141
1137
1142 for args in markerargs:
1138 for args in markerargs:
1143 nprec, nsucs, npare, localmetadata = args
1139 nprec, nsucs, npare, localmetadata = args
1144 repo.obsstore.create(
1140 repo.obsstore.create(
1145 tr,
1141 tr,
1146 nprec,
1142 nprec,
1147 nsucs,
1143 nsucs,
1148 flag,
1144 flag,
1149 parents=npare,
1145 parents=npare,
1150 date=date,
1146 date=date,
1151 metadata=localmetadata,
1147 metadata=localmetadata,
1152 ui=repo.ui,
1148 ui=repo.ui,
1153 )
1149 )
1154 repo.filteredrevcache.clear()
1150 repo.filteredrevcache.clear()
@@ -1,1308 +1,1326
1 #testcases sshv1 sshv2
1 #testcases sshv1 sshv2
2
2
3 #if sshv2
3 #if sshv2
4 $ cat >> $HGRCPATH << EOF
4 $ cat >> $HGRCPATH << EOF
5 > [experimental]
5 > [experimental]
6 > sshpeer.advertise-v2 = true
6 > sshpeer.advertise-v2 = true
7 > sshserver.support-v2 = true
7 > sshserver.support-v2 = true
8 > EOF
8 > EOF
9 #endif
9 #endif
10
10
11 Prepare repo a:
11 Prepare repo a:
12
12
13 $ hg init a
13 $ hg init a
14 $ cd a
14 $ cd a
15 $ echo a > a
15 $ echo a > a
16 $ hg add a
16 $ hg add a
17 $ hg commit -m test
17 $ hg commit -m test
18 $ echo first line > b
18 $ echo first line > b
19 $ hg add b
19 $ hg add b
20
20
21 Create a non-inlined filelog:
21 Create a non-inlined filelog:
22
22
23 $ "$PYTHON" -c 'open("data1", "wb").write(b"".join(b"%d\n" % x for x in range(10000)))'
23 $ "$PYTHON" -c 'open("data1", "wb").write(b"".join(b"%d\n" % x for x in range(10000)))'
24 $ for j in 0 1 2 3 4 5 6 7 8 9; do
24 $ for j in 0 1 2 3 4 5 6 7 8 9; do
25 > cat data1 >> b
25 > cat data1 >> b
26 > hg commit -m test
26 > hg commit -m test
27 > done
27 > done
28
28
29 List files in store/data (should show a 'b.d'):
29 List files in store/data (should show a 'b.d'):
30
30
31 #if reporevlogstore
31 #if reporevlogstore
32 $ for i in .hg/store/data/*; do
32 $ for i in .hg/store/data/*; do
33 > echo $i
33 > echo $i
34 > done
34 > done
35 .hg/store/data/a.i
35 .hg/store/data/a.i
36 .hg/store/data/b.d
36 .hg/store/data/b.d
37 .hg/store/data/b.i
37 .hg/store/data/b.i
38 #endif
38 #endif
39
39
40 Trigger branchcache creation:
40 Trigger branchcache creation:
41
41
42 $ hg branches
42 $ hg branches
43 default 10:a7949464abda
43 default 10:a7949464abda
44 $ ls .hg/cache
44 $ ls .hg/cache
45 branch2-served
45 branch2-served
46 rbc-names-v1
46 rbc-names-v1
47 rbc-revs-v1
47 rbc-revs-v1
48
48
49 Default operation:
49 Default operation:
50
50
51 $ hg clone . ../b
51 $ hg clone . ../b
52 updating to branch default
52 updating to branch default
53 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
53 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
54 $ cd ../b
54 $ cd ../b
55
55
56 Ensure branchcache got copied over:
56 Ensure branchcache got copied over:
57
57
58 $ ls .hg/cache
58 $ ls .hg/cache
59 branch2-base
59 branch2-base
60 branch2-immutable
60 branch2-immutable
61 branch2-served
61 branch2-served
62 branch2-served.hidden
62 branch2-served.hidden
63 branch2-visible
63 branch2-visible
64 branch2-visible-hidden
64 branch2-visible-hidden
65 rbc-names-v1
65 rbc-names-v1
66 rbc-revs-v1
66 rbc-revs-v1
67 tags2
67 tags2
68 tags2-served
68 tags2-served
69
69
70 $ cat a
70 $ cat a
71 a
71 a
72 $ hg verify
72 $ hg verify
73 checking changesets
73 checking changesets
74 checking manifests
74 checking manifests
75 crosschecking files in changesets and manifests
75 crosschecking files in changesets and manifests
76 checking files
76 checking files
77 checked 11 changesets with 11 changes to 2 files
77 checked 11 changesets with 11 changes to 2 files
78
78
79 Invalid dest '' must abort:
79 Invalid dest '' must abort:
80
80
81 $ hg clone . ''
81 $ hg clone . ''
82 abort: empty destination path is not valid
82 abort: empty destination path is not valid
83 [10]
83 [10]
84
84
85 No update, with debug option:
85 No update, with debug option:
86
86
87 #if hardlink
87 #if hardlink
88 $ hg --debug clone -U . ../c --config progress.debug=true
88 $ hg --debug clone -U . ../c --config progress.debug=true
89 linking: 1/15 files (6.67%)
89 linking: 1/15 files (6.67%)
90 linking: 2/15 files (13.33%)
90 linking: 2/15 files (13.33%)
91 linking: 3/15 files (20.00%)
91 linking: 3/15 files (20.00%)
92 linking: 4/15 files (26.67%)
92 linking: 4/15 files (26.67%)
93 linking: 5/15 files (33.33%)
93 linking: 5/15 files (33.33%)
94 linking: 6/15 files (40.00%)
94 linking: 6/15 files (40.00%)
95 linking: 7/15 files (46.67%)
95 linking: 7/15 files (46.67%)
96 linking: 8/15 files (53.33%)
96 linking: 8/15 files (53.33%)
97 linking: 9/15 files (60.00%)
97 linking: 9/15 files (60.00%)
98 linking: 10/15 files (66.67%)
98 linking: 10/15 files (66.67%)
99 linking: 11/15 files (73.33%)
99 linking: 11/15 files (73.33%)
100 linking: 12/15 files (80.00%)
100 linking: 12/15 files (80.00%)
101 linking: 13/15 files (86.67%)
101 linking: 13/15 files (86.67%)
102 linking: 14/15 files (93.33%)
102 linking: 14/15 files (93.33%)
103 linking: 15/15 files (100.00%)
103 linking: 15/15 files (100.00%)
104 linked 15 files
104 linked 15 files
105 updating the branch cache
105 updating the branch cache
106 #else
106 #else
107 $ hg --debug clone -U . ../c --config progress.debug=true
107 $ hg --debug clone -U . ../c --config progress.debug=true
108 linking: 1 files
108 linking: 1 files
109 copying: 2 files
109 copying: 2 files
110 copying: 3 files
110 copying: 3 files
111 copying: 4 files
111 copying: 4 files
112 copying: 5 files
112 copying: 5 files
113 copying: 6 files
113 copying: 6 files
114 copying: 7 files
114 copying: 7 files
115 copying: 8 files
115 copying: 8 files
116 #endif
116 #endif
117 $ cd ../c
117 $ cd ../c
118
118
119 Ensure branchcache got copied over:
119 Ensure branchcache got copied over:
120
120
121 $ ls .hg/cache
121 $ ls .hg/cache
122 branch2-base
122 branch2-base
123 branch2-immutable
123 branch2-immutable
124 branch2-served
124 branch2-served
125 branch2-served.hidden
125 branch2-served.hidden
126 branch2-visible
126 branch2-visible
127 branch2-visible-hidden
127 branch2-visible-hidden
128 rbc-names-v1
128 rbc-names-v1
129 rbc-revs-v1
129 rbc-revs-v1
130 tags2
130 tags2
131 tags2-served
131 tags2-served
132
132
133 $ cat a 2>/dev/null || echo "a not present"
133 $ cat a 2>/dev/null || echo "a not present"
134 a not present
134 a not present
135 $ hg verify
135 $ hg verify
136 checking changesets
136 checking changesets
137 checking manifests
137 checking manifests
138 crosschecking files in changesets and manifests
138 crosschecking files in changesets and manifests
139 checking files
139 checking files
140 checked 11 changesets with 11 changes to 2 files
140 checked 11 changesets with 11 changes to 2 files
141
141
142 Default destination:
142 Default destination:
143
143
144 $ mkdir ../d
144 $ mkdir ../d
145 $ cd ../d
145 $ cd ../d
146 $ hg clone ../a
146 $ hg clone ../a
147 destination directory: a
147 destination directory: a
148 updating to branch default
148 updating to branch default
149 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 $ cd a
150 $ cd a
151 $ hg cat a
151 $ hg cat a
152 a
152 a
153 $ cd ../..
153 $ cd ../..
154
154
155 Check that we drop the 'file:' from the path before writing the .hgrc:
155 Check that we drop the 'file:' from the path before writing the .hgrc:
156
156
157 $ hg clone file:a e
157 $ hg clone file:a e
158 updating to branch default
158 updating to branch default
159 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 $ grep 'file:' e/.hg/hgrc
160 $ grep 'file:' e/.hg/hgrc
161 [1]
161 [1]
162
162
163 Check that path aliases are expanded:
163 Check that path aliases are expanded:
164
164
165 $ hg clone -q -U --config 'paths.foobar=a#0' foobar f
165 $ hg clone -q -U --config 'paths.foobar=a#0' foobar f
166 $ hg -R f showconfig paths.default
166 $ hg -R f showconfig paths.default
167 $TESTTMP/a#0
167 $TESTTMP/a#0
168
168
169 Use --pull:
169 Use --pull:
170
170
171 $ hg clone --pull a g
171 $ hg clone --pull a g
172 requesting all changes
172 requesting all changes
173 adding changesets
173 adding changesets
174 adding manifests
174 adding manifests
175 adding file changes
175 adding file changes
176 added 11 changesets with 11 changes to 2 files
176 added 11 changesets with 11 changes to 2 files
177 new changesets acb14030fe0a:a7949464abda
177 new changesets acb14030fe0a:a7949464abda
178 updating to branch default
178 updating to branch default
179 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
179 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
180 $ hg -R g verify
180 $ hg -R g verify
181 checking changesets
181 checking changesets
182 checking manifests
182 checking manifests
183 crosschecking files in changesets and manifests
183 crosschecking files in changesets and manifests
184 checking files
184 checking files
185 checked 11 changesets with 11 changes to 2 files
185 checked 11 changesets with 11 changes to 2 files
186
186
187 Invalid dest '' with --pull must abort (issue2528):
187 Invalid dest '' with --pull must abort (issue2528):
188
188
189 $ hg clone --pull a ''
189 $ hg clone --pull a ''
190 abort: empty destination path is not valid
190 abort: empty destination path is not valid
191 [10]
191 [10]
192
192
193 Clone to '.':
193 Clone to '.':
194
194
195 $ mkdir h
195 $ mkdir h
196 $ cd h
196 $ cd h
197 $ hg clone ../a .
197 $ hg clone ../a .
198 updating to branch default
198 updating to branch default
199 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 $ cd ..
200 $ cd ..
201
201
202
202
203 *** Tests for option -u ***
203 *** Tests for option -u ***
204
204
205 Adding some more history to repo a:
205 Adding some more history to repo a:
206
206
207 $ cd a
207 $ cd a
208 $ hg tag ref1
208 $ hg tag ref1
209 $ echo the quick brown fox >a
209 $ echo the quick brown fox >a
210 $ hg ci -m "hacked default"
210 $ hg ci -m "hacked default"
211 $ hg up ref1
211 $ hg up ref1
212 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
212 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
213 $ hg branch stable
213 $ hg branch stable
214 marked working directory as branch stable
214 marked working directory as branch stable
215 (branches are permanent and global, did you want a bookmark?)
215 (branches are permanent and global, did you want a bookmark?)
216 $ echo some text >a
216 $ echo some text >a
217 $ hg ci -m "starting branch stable"
217 $ hg ci -m "starting branch stable"
218 $ hg tag ref2
218 $ hg tag ref2
219 $ echo some more text >a
219 $ echo some more text >a
220 $ hg ci -m "another change for branch stable"
220 $ hg ci -m "another change for branch stable"
221 $ hg up ref2
221 $ hg up ref2
222 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
222 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
223 $ hg parents
223 $ hg parents
224 changeset: 13:e8ece76546a6
224 changeset: 13:e8ece76546a6
225 branch: stable
225 branch: stable
226 tag: ref2
226 tag: ref2
227 parent: 10:a7949464abda
227 parent: 10:a7949464abda
228 user: test
228 user: test
229 date: Thu Jan 01 00:00:00 1970 +0000
229 date: Thu Jan 01 00:00:00 1970 +0000
230 summary: starting branch stable
230 summary: starting branch stable
231
231
232
232
233 Repo a has two heads:
233 Repo a has two heads:
234
234
235 $ hg heads
235 $ hg heads
236 changeset: 15:0aae7cf88f0d
236 changeset: 15:0aae7cf88f0d
237 branch: stable
237 branch: stable
238 tag: tip
238 tag: tip
239 user: test
239 user: test
240 date: Thu Jan 01 00:00:00 1970 +0000
240 date: Thu Jan 01 00:00:00 1970 +0000
241 summary: another change for branch stable
241 summary: another change for branch stable
242
242
243 changeset: 12:f21241060d6a
243 changeset: 12:f21241060d6a
244 user: test
244 user: test
245 date: Thu Jan 01 00:00:00 1970 +0000
245 date: Thu Jan 01 00:00:00 1970 +0000
246 summary: hacked default
246 summary: hacked default
247
247
248
248
249 $ cd ..
249 $ cd ..
250
250
251
251
252 Testing --noupdate with --updaterev (must abort):
252 Testing --noupdate with --updaterev (must abort):
253
253
254 $ hg clone --noupdate --updaterev 1 a ua
254 $ hg clone --noupdate --updaterev 1 a ua
255 abort: cannot specify both --noupdate and --updaterev
255 abort: cannot specify both --noupdate and --updaterev
256 [10]
256 [10]
257
257
258
258
259 Testing clone -u:
259 Testing clone -u:
260
260
261 $ hg clone -u . a ua
261 $ hg clone -u . a ua
262 updating to branch stable
262 updating to branch stable
263 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
264
264
265 Repo ua has both heads:
265 Repo ua has both heads:
266
266
267 $ hg -R ua heads
267 $ hg -R ua heads
268 changeset: 15:0aae7cf88f0d
268 changeset: 15:0aae7cf88f0d
269 branch: stable
269 branch: stable
270 tag: tip
270 tag: tip
271 user: test
271 user: test
272 date: Thu Jan 01 00:00:00 1970 +0000
272 date: Thu Jan 01 00:00:00 1970 +0000
273 summary: another change for branch stable
273 summary: another change for branch stable
274
274
275 changeset: 12:f21241060d6a
275 changeset: 12:f21241060d6a
276 user: test
276 user: test
277 date: Thu Jan 01 00:00:00 1970 +0000
277 date: Thu Jan 01 00:00:00 1970 +0000
278 summary: hacked default
278 summary: hacked default
279
279
280
280
281 Same revision checked out in repo a and ua:
281 Same revision checked out in repo a and ua:
282
282
283 $ hg -R a parents --template "{node|short}\n"
283 $ hg -R a parents --template "{node|short}\n"
284 e8ece76546a6
284 e8ece76546a6
285 $ hg -R ua parents --template "{node|short}\n"
285 $ hg -R ua parents --template "{node|short}\n"
286 e8ece76546a6
286 e8ece76546a6
287
287
288 $ rm -r ua
288 $ rm -r ua
289
289
290
290
291 Testing clone --pull -u:
291 Testing clone --pull -u:
292
292
293 $ hg clone --pull -u . a ua
293 $ hg clone --pull -u . a ua
294 requesting all changes
294 requesting all changes
295 adding changesets
295 adding changesets
296 adding manifests
296 adding manifests
297 adding file changes
297 adding file changes
298 added 16 changesets with 16 changes to 3 files (+1 heads)
298 added 16 changesets with 16 changes to 3 files (+1 heads)
299 new changesets acb14030fe0a:0aae7cf88f0d
299 new changesets acb14030fe0a:0aae7cf88f0d
300 updating to branch stable
300 updating to branch stable
301 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
301 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
302
302
303 Repo ua has both heads:
303 Repo ua has both heads:
304
304
305 $ hg -R ua heads
305 $ hg -R ua heads
306 changeset: 15:0aae7cf88f0d
306 changeset: 15:0aae7cf88f0d
307 branch: stable
307 branch: stable
308 tag: tip
308 tag: tip
309 user: test
309 user: test
310 date: Thu Jan 01 00:00:00 1970 +0000
310 date: Thu Jan 01 00:00:00 1970 +0000
311 summary: another change for branch stable
311 summary: another change for branch stable
312
312
313 changeset: 12:f21241060d6a
313 changeset: 12:f21241060d6a
314 user: test
314 user: test
315 date: Thu Jan 01 00:00:00 1970 +0000
315 date: Thu Jan 01 00:00:00 1970 +0000
316 summary: hacked default
316 summary: hacked default
317
317
318
318
319 Same revision checked out in repo a and ua:
319 Same revision checked out in repo a and ua:
320
320
321 $ hg -R a parents --template "{node|short}\n"
321 $ hg -R a parents --template "{node|short}\n"
322 e8ece76546a6
322 e8ece76546a6
323 $ hg -R ua parents --template "{node|short}\n"
323 $ hg -R ua parents --template "{node|short}\n"
324 e8ece76546a6
324 e8ece76546a6
325
325
326 $ rm -r ua
326 $ rm -r ua
327
327
328
328
329 Testing clone -u <branch>:
329 Testing clone -u <branch>:
330
330
331 $ hg clone -u stable a ua
331 $ hg clone -u stable a ua
332 updating to branch stable
332 updating to branch stable
333 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
333 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
334
334
335 Repo ua has both heads:
335 Repo ua has both heads:
336
336
337 $ hg -R ua heads
337 $ hg -R ua heads
338 changeset: 15:0aae7cf88f0d
338 changeset: 15:0aae7cf88f0d
339 branch: stable
339 branch: stable
340 tag: tip
340 tag: tip
341 user: test
341 user: test
342 date: Thu Jan 01 00:00:00 1970 +0000
342 date: Thu Jan 01 00:00:00 1970 +0000
343 summary: another change for branch stable
343 summary: another change for branch stable
344
344
345 changeset: 12:f21241060d6a
345 changeset: 12:f21241060d6a
346 user: test
346 user: test
347 date: Thu Jan 01 00:00:00 1970 +0000
347 date: Thu Jan 01 00:00:00 1970 +0000
348 summary: hacked default
348 summary: hacked default
349
349
350
350
351 Branch 'stable' is checked out:
351 Branch 'stable' is checked out:
352
352
353 $ hg -R ua parents
353 $ hg -R ua parents
354 changeset: 15:0aae7cf88f0d
354 changeset: 15:0aae7cf88f0d
355 branch: stable
355 branch: stable
356 tag: tip
356 tag: tip
357 user: test
357 user: test
358 date: Thu Jan 01 00:00:00 1970 +0000
358 date: Thu Jan 01 00:00:00 1970 +0000
359 summary: another change for branch stable
359 summary: another change for branch stable
360
360
361
361
362 $ rm -r ua
362 $ rm -r ua
363
363
364
364
365 Testing default checkout:
365 Testing default checkout:
366
366
367 $ hg clone a ua
367 $ hg clone a ua
368 updating to branch default
368 updating to branch default
369 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
370
370
371 Repo ua has both heads:
371 Repo ua has both heads:
372
372
373 $ hg -R ua heads
373 $ hg -R ua heads
374 changeset: 15:0aae7cf88f0d
374 changeset: 15:0aae7cf88f0d
375 branch: stable
375 branch: stable
376 tag: tip
376 tag: tip
377 user: test
377 user: test
378 date: Thu Jan 01 00:00:00 1970 +0000
378 date: Thu Jan 01 00:00:00 1970 +0000
379 summary: another change for branch stable
379 summary: another change for branch stable
380
380
381 changeset: 12:f21241060d6a
381 changeset: 12:f21241060d6a
382 user: test
382 user: test
383 date: Thu Jan 01 00:00:00 1970 +0000
383 date: Thu Jan 01 00:00:00 1970 +0000
384 summary: hacked default
384 summary: hacked default
385
385
386
386
387 Branch 'default' is checked out:
387 Branch 'default' is checked out:
388
388
389 $ hg -R ua parents
389 $ hg -R ua parents
390 changeset: 12:f21241060d6a
390 changeset: 12:f21241060d6a
391 user: test
391 user: test
392 date: Thu Jan 01 00:00:00 1970 +0000
392 date: Thu Jan 01 00:00:00 1970 +0000
393 summary: hacked default
393 summary: hacked default
394
394
395 Test clone with a branch named "@" (issue3677)
395 Test clone with a branch named "@" (issue3677)
396
396
397 $ hg -R ua branch @
397 $ hg -R ua branch @
398 marked working directory as branch @
398 marked working directory as branch @
399 $ hg -R ua commit -m 'created branch @'
399 $ hg -R ua commit -m 'created branch @'
400 $ hg clone ua atbranch
400 $ hg clone ua atbranch
401 updating to branch default
401 updating to branch default
402 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 $ hg -R atbranch heads
403 $ hg -R atbranch heads
404 changeset: 16:798b6d97153e
404 changeset: 16:798b6d97153e
405 branch: @
405 branch: @
406 tag: tip
406 tag: tip
407 parent: 12:f21241060d6a
407 parent: 12:f21241060d6a
408 user: test
408 user: test
409 date: Thu Jan 01 00:00:00 1970 +0000
409 date: Thu Jan 01 00:00:00 1970 +0000
410 summary: created branch @
410 summary: created branch @
411
411
412 changeset: 15:0aae7cf88f0d
412 changeset: 15:0aae7cf88f0d
413 branch: stable
413 branch: stable
414 user: test
414 user: test
415 date: Thu Jan 01 00:00:00 1970 +0000
415 date: Thu Jan 01 00:00:00 1970 +0000
416 summary: another change for branch stable
416 summary: another change for branch stable
417
417
418 changeset: 12:f21241060d6a
418 changeset: 12:f21241060d6a
419 user: test
419 user: test
420 date: Thu Jan 01 00:00:00 1970 +0000
420 date: Thu Jan 01 00:00:00 1970 +0000
421 summary: hacked default
421 summary: hacked default
422
422
423 $ hg -R atbranch parents
423 $ hg -R atbranch parents
424 changeset: 12:f21241060d6a
424 changeset: 12:f21241060d6a
425 user: test
425 user: test
426 date: Thu Jan 01 00:00:00 1970 +0000
426 date: Thu Jan 01 00:00:00 1970 +0000
427 summary: hacked default
427 summary: hacked default
428
428
429
429
430 $ rm -r ua atbranch
430 $ rm -r ua atbranch
431
431
432
432
433 Testing #<branch>:
433 Testing #<branch>:
434
434
435 $ hg clone -u . a#stable ua
435 $ hg clone -u . a#stable ua
436 adding changesets
436 adding changesets
437 adding manifests
437 adding manifests
438 adding file changes
438 adding file changes
439 added 14 changesets with 14 changes to 3 files
439 added 14 changesets with 14 changes to 3 files
440 new changesets acb14030fe0a:0aae7cf88f0d
440 new changesets acb14030fe0a:0aae7cf88f0d
441 updating to branch stable
441 updating to branch stable
442 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
442 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
443
443
444 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
444 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
445
445
446 $ hg -R ua heads
446 $ hg -R ua heads
447 changeset: 13:0aae7cf88f0d
447 changeset: 13:0aae7cf88f0d
448 branch: stable
448 branch: stable
449 tag: tip
449 tag: tip
450 user: test
450 user: test
451 date: Thu Jan 01 00:00:00 1970 +0000
451 date: Thu Jan 01 00:00:00 1970 +0000
452 summary: another change for branch stable
452 summary: another change for branch stable
453
453
454 changeset: 10:a7949464abda
454 changeset: 10:a7949464abda
455 user: test
455 user: test
456 date: Thu Jan 01 00:00:00 1970 +0000
456 date: Thu Jan 01 00:00:00 1970 +0000
457 summary: test
457 summary: test
458
458
459
459
460 Same revision checked out in repo a and ua:
460 Same revision checked out in repo a and ua:
461
461
462 $ hg -R a parents --template "{node|short}\n"
462 $ hg -R a parents --template "{node|short}\n"
463 e8ece76546a6
463 e8ece76546a6
464 $ hg -R ua parents --template "{node|short}\n"
464 $ hg -R ua parents --template "{node|short}\n"
465 e8ece76546a6
465 e8ece76546a6
466
466
467 $ rm -r ua
467 $ rm -r ua
468
468
469
469
470 Testing -u -r <branch>:
470 Testing -u -r <branch>:
471
471
472 $ hg clone -u . -r stable a ua
472 $ hg clone -u . -r stable a ua
473 adding changesets
473 adding changesets
474 adding manifests
474 adding manifests
475 adding file changes
475 adding file changes
476 added 14 changesets with 14 changes to 3 files
476 added 14 changesets with 14 changes to 3 files
477 new changesets acb14030fe0a:0aae7cf88f0d
477 new changesets acb14030fe0a:0aae7cf88f0d
478 updating to branch stable
478 updating to branch stable
479 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
479 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
480
480
481 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
481 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
482
482
483 $ hg -R ua heads
483 $ hg -R ua heads
484 changeset: 13:0aae7cf88f0d
484 changeset: 13:0aae7cf88f0d
485 branch: stable
485 branch: stable
486 tag: tip
486 tag: tip
487 user: test
487 user: test
488 date: Thu Jan 01 00:00:00 1970 +0000
488 date: Thu Jan 01 00:00:00 1970 +0000
489 summary: another change for branch stable
489 summary: another change for branch stable
490
490
491 changeset: 10:a7949464abda
491 changeset: 10:a7949464abda
492 user: test
492 user: test
493 date: Thu Jan 01 00:00:00 1970 +0000
493 date: Thu Jan 01 00:00:00 1970 +0000
494 summary: test
494 summary: test
495
495
496
496
497 Same revision checked out in repo a and ua:
497 Same revision checked out in repo a and ua:
498
498
499 $ hg -R a parents --template "{node|short}\n"
499 $ hg -R a parents --template "{node|short}\n"
500 e8ece76546a6
500 e8ece76546a6
501 $ hg -R ua parents --template "{node|short}\n"
501 $ hg -R ua parents --template "{node|short}\n"
502 e8ece76546a6
502 e8ece76546a6
503
503
504 $ rm -r ua
504 $ rm -r ua
505
505
506
506
507 Testing -r <branch>:
507 Testing -r <branch>:
508
508
509 $ hg clone -r stable a ua
509 $ hg clone -r stable a ua
510 adding changesets
510 adding changesets
511 adding manifests
511 adding manifests
512 adding file changes
512 adding file changes
513 added 14 changesets with 14 changes to 3 files
513 added 14 changesets with 14 changes to 3 files
514 new changesets acb14030fe0a:0aae7cf88f0d
514 new changesets acb14030fe0a:0aae7cf88f0d
515 updating to branch stable
515 updating to branch stable
516 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
516 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
517
517
518 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
518 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
519
519
520 $ hg -R ua heads
520 $ hg -R ua heads
521 changeset: 13:0aae7cf88f0d
521 changeset: 13:0aae7cf88f0d
522 branch: stable
522 branch: stable
523 tag: tip
523 tag: tip
524 user: test
524 user: test
525 date: Thu Jan 01 00:00:00 1970 +0000
525 date: Thu Jan 01 00:00:00 1970 +0000
526 summary: another change for branch stable
526 summary: another change for branch stable
527
527
528 changeset: 10:a7949464abda
528 changeset: 10:a7949464abda
529 user: test
529 user: test
530 date: Thu Jan 01 00:00:00 1970 +0000
530 date: Thu Jan 01 00:00:00 1970 +0000
531 summary: test
531 summary: test
532
532
533
533
534 Branch 'stable' is checked out:
534 Branch 'stable' is checked out:
535
535
536 $ hg -R ua parents
536 $ hg -R ua parents
537 changeset: 13:0aae7cf88f0d
537 changeset: 13:0aae7cf88f0d
538 branch: stable
538 branch: stable
539 tag: tip
539 tag: tip
540 user: test
540 user: test
541 date: Thu Jan 01 00:00:00 1970 +0000
541 date: Thu Jan 01 00:00:00 1970 +0000
542 summary: another change for branch stable
542 summary: another change for branch stable
543
543
544
544
545 $ rm -r ua
545 $ rm -r ua
546
546
547
547
548 Issue2267: Error in 1.6 hg.py: TypeError: 'NoneType' object is not
548 Issue2267: Error in 1.6 hg.py: TypeError: 'NoneType' object is not
549 iterable in addbranchrevs()
549 iterable in addbranchrevs()
550
550
551 $ cat <<EOF > simpleclone.py
551 $ cat <<EOF > simpleclone.py
552 > from mercurial import hg, ui as uimod
552 > from mercurial import hg, ui as uimod
553 > myui = uimod.ui.load()
553 > myui = uimod.ui.load()
554 > repo = hg.repository(myui, b'a')
554 > repo = hg.repository(myui, b'a')
555 > hg.clone(myui, {}, repo, dest=b"ua")
555 > hg.clone(myui, {}, repo, dest=b"ua")
556 > EOF
556 > EOF
557
557
558 $ "$PYTHON" simpleclone.py
558 $ "$PYTHON" simpleclone.py
559 updating to branch default
559 updating to branch default
560 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
560 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
561
561
562 $ rm -r ua
562 $ rm -r ua
563
563
564 $ cat <<EOF > branchclone.py
564 $ cat <<EOF > branchclone.py
565 > from mercurial import extensions, hg, ui as uimod
565 > from mercurial import extensions, hg, ui as uimod
566 > myui = uimod.ui.load()
566 > myui = uimod.ui.load()
567 > extensions.loadall(myui)
567 > extensions.loadall(myui)
568 > extensions.populateui(myui)
568 > extensions.populateui(myui)
569 > repo = hg.repository(myui, b'a')
569 > repo = hg.repository(myui, b'a')
570 > hg.clone(myui, {}, repo, dest=b"ua", branch=[b"stable"])
570 > hg.clone(myui, {}, repo, dest=b"ua", branch=[b"stable"])
571 > EOF
571 > EOF
572
572
573 $ "$PYTHON" branchclone.py
573 $ "$PYTHON" branchclone.py
574 adding changesets
574 adding changesets
575 adding manifests
575 adding manifests
576 adding file changes
576 adding file changes
577 added 14 changesets with 14 changes to 3 files
577 added 14 changesets with 14 changes to 3 files
578 new changesets acb14030fe0a:0aae7cf88f0d
578 new changesets acb14030fe0a:0aae7cf88f0d
579 updating to branch stable
579 updating to branch stable
580 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
580 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
581 $ rm -r ua
581 $ rm -r ua
582
582
583 Local clones don't get confused by unusual experimental.evolution options
584
585 $ hg clone \
586 > --config experimental.evolution=allowunstable,allowdivergence,exchange \
587 > a ua
588 updating to branch default
589 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
590 $ rm -r ua
591
592 $ hg clone \
593 > --config experimental.evolution.createmarkers=no \
594 > --config experimental.evolution.allowunstable=yes \
595 > --config experimental.evolution.allowdivergence=yes \
596 > --config experimental.evolution.exchange=yes \
597 > a ua
598 updating to branch default
599 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
600 $ rm -r ua
583
601
584 Test clone with special '@' bookmark:
602 Test clone with special '@' bookmark:
585 $ cd a
603 $ cd a
586 $ hg bookmark -r a7949464abda @ # branch point of stable from default
604 $ hg bookmark -r a7949464abda @ # branch point of stable from default
587 $ hg clone . ../i
605 $ hg clone . ../i
588 updating to bookmark @
606 updating to bookmark @
589 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
607 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
590 $ hg id -i ../i
608 $ hg id -i ../i
591 a7949464abda
609 a7949464abda
592 $ rm -r ../i
610 $ rm -r ../i
593
611
594 $ hg bookmark -f -r stable @
612 $ hg bookmark -f -r stable @
595 $ hg bookmarks
613 $ hg bookmarks
596 @ 15:0aae7cf88f0d
614 @ 15:0aae7cf88f0d
597 $ hg clone . ../i
615 $ hg clone . ../i
598 updating to bookmark @ on branch stable
616 updating to bookmark @ on branch stable
599 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
617 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
600 $ hg id -i ../i
618 $ hg id -i ../i
601 0aae7cf88f0d
619 0aae7cf88f0d
602 $ cd "$TESTTMP"
620 $ cd "$TESTTMP"
603
621
604
622
605 Testing failures:
623 Testing failures:
606
624
607 $ mkdir fail
625 $ mkdir fail
608 $ cd fail
626 $ cd fail
609
627
610 No local source
628 No local source
611
629
612 $ hg clone a b
630 $ hg clone a b
613 abort: repository a not found
631 abort: repository a not found
614 [255]
632 [255]
615
633
616 Invalid URL
634 Invalid URL
617
635
618 $ hg clone http://invalid:url/a b
636 $ hg clone http://invalid:url/a b
619 abort: error: nonnumeric port: 'url'
637 abort: error: nonnumeric port: 'url'
620 [100]
638 [100]
621
639
622 No remote source
640 No remote source
623
641
624 #if windows
642 #if windows
625 $ hg clone http://$LOCALIP:3121/a b
643 $ hg clone http://$LOCALIP:3121/a b
626 abort: error: * (glob)
644 abort: error: * (glob)
627 [100]
645 [100]
628 #else
646 #else
629 $ hg clone http://$LOCALIP:3121/a b
647 $ hg clone http://$LOCALIP:3121/a b
630 abort: error: *refused* (glob)
648 abort: error: *refused* (glob)
631 [100]
649 [100]
632 #endif
650 #endif
633 $ rm -rf b # work around bug with http clone
651 $ rm -rf b # work around bug with http clone
634
652
635
653
636 #if unix-permissions no-root
654 #if unix-permissions no-root
637
655
638 Inaccessible source
656 Inaccessible source
639
657
640 $ mkdir a
658 $ mkdir a
641 $ chmod 000 a
659 $ chmod 000 a
642 $ hg clone a b
660 $ hg clone a b
643 abort: Permission denied: *$TESTTMP/fail/a/.hg* (glob)
661 abort: Permission denied: *$TESTTMP/fail/a/.hg* (glob)
644 [255]
662 [255]
645
663
646 Inaccessible destination
664 Inaccessible destination
647
665
648 $ hg init b
666 $ hg init b
649 $ cd b
667 $ cd b
650 $ hg clone . ../a
668 $ hg clone . ../a
651 abort: Permission denied: *../a* (glob)
669 abort: Permission denied: *../a* (glob)
652 [255]
670 [255]
653 $ cd ..
671 $ cd ..
654 $ chmod 700 a
672 $ chmod 700 a
655 $ rm -r a b
673 $ rm -r a b
656
674
657 #endif
675 #endif
658
676
659
677
660 #if fifo
678 #if fifo
661
679
662 Source of wrong type
680 Source of wrong type
663
681
664 $ mkfifo a
682 $ mkfifo a
665 $ hg clone a b
683 $ hg clone a b
666 abort: $ENOTDIR$: *$TESTTMP/fail/a/.hg* (glob)
684 abort: $ENOTDIR$: *$TESTTMP/fail/a/.hg* (glob)
667 [255]
685 [255]
668 $ rm a
686 $ rm a
669
687
670 #endif
688 #endif
671
689
672 Default destination, same directory
690 Default destination, same directory
673
691
674 $ hg init q
692 $ hg init q
675 $ hg clone q
693 $ hg clone q
676 destination directory: q
694 destination directory: q
677 abort: destination 'q' is not empty
695 abort: destination 'q' is not empty
678 [10]
696 [10]
679
697
680 destination directory not empty
698 destination directory not empty
681
699
682 $ mkdir a
700 $ mkdir a
683 $ echo stuff > a/a
701 $ echo stuff > a/a
684 $ hg clone q a
702 $ hg clone q a
685 abort: destination 'a' is not empty
703 abort: destination 'a' is not empty
686 [10]
704 [10]
687
705
688
706
689 #if unix-permissions no-root
707 #if unix-permissions no-root
690
708
691 leave existing directory in place after clone failure
709 leave existing directory in place after clone failure
692
710
693 $ hg init c
711 $ hg init c
694 $ cd c
712 $ cd c
695 $ echo c > c
713 $ echo c > c
696 $ hg commit -A -m test
714 $ hg commit -A -m test
697 adding c
715 adding c
698 $ chmod -rx .hg/store/data
716 $ chmod -rx .hg/store/data
699 $ cd ..
717 $ cd ..
700 $ mkdir d
718 $ mkdir d
701 $ hg clone c d 2> err
719 $ hg clone c d 2> err
702 [255]
720 [255]
703 $ test -d d
721 $ test -d d
704 $ test -d d/.hg
722 $ test -d d/.hg
705 [1]
723 [1]
706
724
707 re-enable perm to allow deletion
725 re-enable perm to allow deletion
708
726
709 $ chmod +rx c/.hg/store/data
727 $ chmod +rx c/.hg/store/data
710
728
711 #endif
729 #endif
712
730
713 $ cd ..
731 $ cd ..
714
732
715 Test clone from the repository in (emulated) revlog format 0 (issue4203):
733 Test clone from the repository in (emulated) revlog format 0 (issue4203):
716
734
717 $ mkdir issue4203
735 $ mkdir issue4203
718 $ mkdir -p src/.hg
736 $ mkdir -p src/.hg
719 $ echo foo > src/foo
737 $ echo foo > src/foo
720 $ hg -R src add src/foo
738 $ hg -R src add src/foo
721 $ hg -R src commit -m '#0'
739 $ hg -R src commit -m '#0'
722 $ hg -R src log -q
740 $ hg -R src log -q
723 0:e1bab28bca43
741 0:e1bab28bca43
724 $ hg -R src debugrevlog -c | egrep 'format|flags'
742 $ hg -R src debugrevlog -c | egrep 'format|flags'
725 format : 0
743 format : 0
726 flags : (none)
744 flags : (none)
727 $ hg root -R src -T json | sed 's|\\\\|\\|g'
745 $ hg root -R src -T json | sed 's|\\\\|\\|g'
728 [
746 [
729 {
747 {
730 "hgpath": "$TESTTMP/src/.hg",
748 "hgpath": "$TESTTMP/src/.hg",
731 "reporoot": "$TESTTMP/src",
749 "reporoot": "$TESTTMP/src",
732 "storepath": "$TESTTMP/src/.hg"
750 "storepath": "$TESTTMP/src/.hg"
733 }
751 }
734 ]
752 ]
735 $ hg clone -U -q src dst
753 $ hg clone -U -q src dst
736 $ hg -R dst log -q
754 $ hg -R dst log -q
737 0:e1bab28bca43
755 0:e1bab28bca43
738
756
739 Create repositories to test auto sharing functionality
757 Create repositories to test auto sharing functionality
740
758
741 $ cat >> $HGRCPATH << EOF
759 $ cat >> $HGRCPATH << EOF
742 > [extensions]
760 > [extensions]
743 > share=
761 > share=
744 > EOF
762 > EOF
745
763
746 $ hg init empty
764 $ hg init empty
747 $ hg init source1a
765 $ hg init source1a
748 $ cd source1a
766 $ cd source1a
749 $ echo initial1 > foo
767 $ echo initial1 > foo
750 $ hg -q commit -A -m initial
768 $ hg -q commit -A -m initial
751 $ echo second > foo
769 $ echo second > foo
752 $ hg commit -m second
770 $ hg commit -m second
753 $ cd ..
771 $ cd ..
754
772
755 $ hg init filteredrev0
773 $ hg init filteredrev0
756 $ cd filteredrev0
774 $ cd filteredrev0
757 $ cat >> .hg/hgrc << EOF
775 $ cat >> .hg/hgrc << EOF
758 > [experimental]
776 > [experimental]
759 > evolution.createmarkers=True
777 > evolution.createmarkers=True
760 > EOF
778 > EOF
761 $ echo initial1 > foo
779 $ echo initial1 > foo
762 $ hg -q commit -A -m initial0
780 $ hg -q commit -A -m initial0
763 $ hg -q up -r null
781 $ hg -q up -r null
764 $ echo initial2 > foo
782 $ echo initial2 > foo
765 $ hg -q commit -A -m initial1
783 $ hg -q commit -A -m initial1
766 $ hg debugobsolete c05d5c47a5cf81401869999f3d05f7d699d2b29a e082c1832e09a7d1e78b7fd49a592d372de854c8
784 $ hg debugobsolete c05d5c47a5cf81401869999f3d05f7d699d2b29a e082c1832e09a7d1e78b7fd49a592d372de854c8
767 1 new obsolescence markers
785 1 new obsolescence markers
768 obsoleted 1 changesets
786 obsoleted 1 changesets
769 $ cd ..
787 $ cd ..
770
788
771 $ hg -q clone --pull source1a source1b
789 $ hg -q clone --pull source1a source1b
772 $ cd source1a
790 $ cd source1a
773 $ hg bookmark bookA
791 $ hg bookmark bookA
774 $ echo 1a > foo
792 $ echo 1a > foo
775 $ hg commit -m 1a
793 $ hg commit -m 1a
776 $ cd ../source1b
794 $ cd ../source1b
777 $ hg -q up -r 0
795 $ hg -q up -r 0
778 $ echo head1 > foo
796 $ echo head1 > foo
779 $ hg commit -m head1
797 $ hg commit -m head1
780 created new head
798 created new head
781 $ hg bookmark head1
799 $ hg bookmark head1
782 $ hg -q up -r 0
800 $ hg -q up -r 0
783 $ echo head2 > foo
801 $ echo head2 > foo
784 $ hg commit -m head2
802 $ hg commit -m head2
785 created new head
803 created new head
786 $ hg bookmark head2
804 $ hg bookmark head2
787 $ hg -q up -r 0
805 $ hg -q up -r 0
788 $ hg branch branch1
806 $ hg branch branch1
789 marked working directory as branch branch1
807 marked working directory as branch branch1
790 (branches are permanent and global, did you want a bookmark?)
808 (branches are permanent and global, did you want a bookmark?)
791 $ echo branch1 > foo
809 $ echo branch1 > foo
792 $ hg commit -m branch1
810 $ hg commit -m branch1
793 $ hg -q up -r 0
811 $ hg -q up -r 0
794 $ hg branch branch2
812 $ hg branch branch2
795 marked working directory as branch branch2
813 marked working directory as branch branch2
796 $ echo branch2 > foo
814 $ echo branch2 > foo
797 $ hg commit -m branch2
815 $ hg commit -m branch2
798 $ cd ..
816 $ cd ..
799 $ hg init source2
817 $ hg init source2
800 $ cd source2
818 $ cd source2
801 $ echo initial2 > foo
819 $ echo initial2 > foo
802 $ hg -q commit -A -m initial2
820 $ hg -q commit -A -m initial2
803 $ echo second > foo
821 $ echo second > foo
804 $ hg commit -m second
822 $ hg commit -m second
805 $ cd ..
823 $ cd ..
806
824
807 Clone with auto share from an empty repo should not result in share
825 Clone with auto share from an empty repo should not result in share
808
826
809 $ mkdir share
827 $ mkdir share
810 $ hg --config share.pool=share clone empty share-empty
828 $ hg --config share.pool=share clone empty share-empty
811 (not using pooled storage: remote appears to be empty)
829 (not using pooled storage: remote appears to be empty)
812 updating to branch default
830 updating to branch default
813 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
831 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
814 $ ls share
832 $ ls share
815 $ test -d share-empty/.hg/store
833 $ test -d share-empty/.hg/store
816 $ test -f share-empty/.hg/sharedpath
834 $ test -f share-empty/.hg/sharedpath
817 [1]
835 [1]
818
836
819 Clone with auto share from a repo with filtered revision 0 should not result in share
837 Clone with auto share from a repo with filtered revision 0 should not result in share
820
838
821 $ hg --config share.pool=share clone filteredrev0 share-filtered
839 $ hg --config share.pool=share clone filteredrev0 share-filtered
822 (not using pooled storage: unable to resolve identity of remote)
840 (not using pooled storage: unable to resolve identity of remote)
823 requesting all changes
841 requesting all changes
824 adding changesets
842 adding changesets
825 adding manifests
843 adding manifests
826 adding file changes
844 adding file changes
827 added 1 changesets with 1 changes to 1 files
845 added 1 changesets with 1 changes to 1 files
828 new changesets e082c1832e09
846 new changesets e082c1832e09
829 updating to branch default
847 updating to branch default
830 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
848 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
831
849
832 Clone from repo with content should result in shared store being created
850 Clone from repo with content should result in shared store being created
833
851
834 $ hg --config share.pool=share clone source1a share-dest1a
852 $ hg --config share.pool=share clone source1a share-dest1a
835 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
853 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
836 requesting all changes
854 requesting all changes
837 adding changesets
855 adding changesets
838 adding manifests
856 adding manifests
839 adding file changes
857 adding file changes
840 added 3 changesets with 3 changes to 1 files
858 added 3 changesets with 3 changes to 1 files
841 new changesets b5f04eac9d8f:e5bfe23c0b47
859 new changesets b5f04eac9d8f:e5bfe23c0b47
842 searching for changes
860 searching for changes
843 no changes found
861 no changes found
844 adding remote bookmark bookA
862 adding remote bookmark bookA
845 updating working directory
863 updating working directory
846 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
864 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
847
865
848 The shared repo should have been created
866 The shared repo should have been created
849
867
850 $ ls share
868 $ ls share
851 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
869 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
852
870
853 The destination should point to it
871 The destination should point to it
854
872
855 $ cat share-dest1a/.hg/sharedpath; echo
873 $ cat share-dest1a/.hg/sharedpath; echo
856 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg
874 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg
857
875
858 The destination should have bookmarks
876 The destination should have bookmarks
859
877
860 $ hg -R share-dest1a bookmarks
878 $ hg -R share-dest1a bookmarks
861 bookA 2:e5bfe23c0b47
879 bookA 2:e5bfe23c0b47
862
880
863 The default path should be the remote, not the share
881 The default path should be the remote, not the share
864
882
865 $ hg -R share-dest1a config paths.default
883 $ hg -R share-dest1a config paths.default
866 $TESTTMP/source1a
884 $TESTTMP/source1a
867
885
868 Clone with existing share dir should result in pull + share
886 Clone with existing share dir should result in pull + share
869
887
870 $ hg --config share.pool=share clone source1b share-dest1b
888 $ hg --config share.pool=share clone source1b share-dest1b
871 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
889 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
872 searching for changes
890 searching for changes
873 adding changesets
891 adding changesets
874 adding manifests
892 adding manifests
875 adding file changes
893 adding file changes
876 adding remote bookmark head1
894 adding remote bookmark head1
877 adding remote bookmark head2
895 adding remote bookmark head2
878 added 4 changesets with 4 changes to 1 files (+4 heads)
896 added 4 changesets with 4 changes to 1 files (+4 heads)
879 new changesets 4a8dc1ab4c13:6bacf4683960
897 new changesets 4a8dc1ab4c13:6bacf4683960
880 updating working directory
898 updating working directory
881 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
899 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
882
900
883 $ ls share
901 $ ls share
884 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
902 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
885
903
886 $ cat share-dest1b/.hg/sharedpath; echo
904 $ cat share-dest1b/.hg/sharedpath; echo
887 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg
905 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg
888
906
889 We only get bookmarks from the remote, not everything in the share
907 We only get bookmarks from the remote, not everything in the share
890
908
891 $ hg -R share-dest1b bookmarks
909 $ hg -R share-dest1b bookmarks
892 head1 3:4a8dc1ab4c13
910 head1 3:4a8dc1ab4c13
893 head2 4:99f71071f117
911 head2 4:99f71071f117
894
912
895 Default path should be source, not share.
913 Default path should be source, not share.
896
914
897 $ hg -R share-dest1b config paths.default
915 $ hg -R share-dest1b config paths.default
898 $TESTTMP/source1b
916 $TESTTMP/source1b
899
917
900 Checked out revision should be head of default branch
918 Checked out revision should be head of default branch
901
919
902 $ hg -R share-dest1b log -r .
920 $ hg -R share-dest1b log -r .
903 changeset: 4:99f71071f117
921 changeset: 4:99f71071f117
904 bookmark: head2
922 bookmark: head2
905 parent: 0:b5f04eac9d8f
923 parent: 0:b5f04eac9d8f
906 user: test
924 user: test
907 date: Thu Jan 01 00:00:00 1970 +0000
925 date: Thu Jan 01 00:00:00 1970 +0000
908 summary: head2
926 summary: head2
909
927
910
928
911 Clone from unrelated repo should result in new share
929 Clone from unrelated repo should result in new share
912
930
913 $ hg --config share.pool=share clone source2 share-dest2
931 $ hg --config share.pool=share clone source2 share-dest2
914 (sharing from new pooled repository 22aeff664783fd44c6d9b435618173c118c3448e)
932 (sharing from new pooled repository 22aeff664783fd44c6d9b435618173c118c3448e)
915 requesting all changes
933 requesting all changes
916 adding changesets
934 adding changesets
917 adding manifests
935 adding manifests
918 adding file changes
936 adding file changes
919 added 2 changesets with 2 changes to 1 files
937 added 2 changesets with 2 changes to 1 files
920 new changesets 22aeff664783:63cf6c3dba4a
938 new changesets 22aeff664783:63cf6c3dba4a
921 searching for changes
939 searching for changes
922 no changes found
940 no changes found
923 updating working directory
941 updating working directory
924 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
942 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
925
943
926 $ ls share
944 $ ls share
927 22aeff664783fd44c6d9b435618173c118c3448e
945 22aeff664783fd44c6d9b435618173c118c3448e
928 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
946 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
929
947
930 remote naming mode works as advertised
948 remote naming mode works as advertised
931
949
932 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1a share-remote1a
950 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1a share-remote1a
933 (sharing from new pooled repository 195bb1fcdb595c14a6c13e0269129ed78f6debde)
951 (sharing from new pooled repository 195bb1fcdb595c14a6c13e0269129ed78f6debde)
934 requesting all changes
952 requesting all changes
935 adding changesets
953 adding changesets
936 adding manifests
954 adding manifests
937 adding file changes
955 adding file changes
938 added 3 changesets with 3 changes to 1 files
956 added 3 changesets with 3 changes to 1 files
939 new changesets b5f04eac9d8f:e5bfe23c0b47
957 new changesets b5f04eac9d8f:e5bfe23c0b47
940 searching for changes
958 searching for changes
941 no changes found
959 no changes found
942 adding remote bookmark bookA
960 adding remote bookmark bookA
943 updating working directory
961 updating working directory
944 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
962 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
945
963
946 $ ls shareremote
964 $ ls shareremote
947 195bb1fcdb595c14a6c13e0269129ed78f6debde
965 195bb1fcdb595c14a6c13e0269129ed78f6debde
948
966
949 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1b share-remote1b
967 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1b share-remote1b
950 (sharing from new pooled repository c0d4f83847ca2a873741feb7048a45085fd47c46)
968 (sharing from new pooled repository c0d4f83847ca2a873741feb7048a45085fd47c46)
951 requesting all changes
969 requesting all changes
952 adding changesets
970 adding changesets
953 adding manifests
971 adding manifests
954 adding file changes
972 adding file changes
955 added 6 changesets with 6 changes to 1 files (+4 heads)
973 added 6 changesets with 6 changes to 1 files (+4 heads)
956 new changesets b5f04eac9d8f:6bacf4683960
974 new changesets b5f04eac9d8f:6bacf4683960
957 searching for changes
975 searching for changes
958 no changes found
976 no changes found
959 adding remote bookmark head1
977 adding remote bookmark head1
960 adding remote bookmark head2
978 adding remote bookmark head2
961 updating working directory
979 updating working directory
962 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
980 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
963
981
964 $ ls shareremote
982 $ ls shareremote
965 195bb1fcdb595c14a6c13e0269129ed78f6debde
983 195bb1fcdb595c14a6c13e0269129ed78f6debde
966 c0d4f83847ca2a873741feb7048a45085fd47c46
984 c0d4f83847ca2a873741feb7048a45085fd47c46
967
985
968 request to clone a single revision is respected in sharing mode
986 request to clone a single revision is respected in sharing mode
969
987
970 $ hg --config share.pool=sharerevs clone -r 4a8dc1ab4c13 source1b share-1arev
988 $ hg --config share.pool=sharerevs clone -r 4a8dc1ab4c13 source1b share-1arev
971 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
989 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
972 adding changesets
990 adding changesets
973 adding manifests
991 adding manifests
974 adding file changes
992 adding file changes
975 added 2 changesets with 2 changes to 1 files
993 added 2 changesets with 2 changes to 1 files
976 new changesets b5f04eac9d8f:4a8dc1ab4c13
994 new changesets b5f04eac9d8f:4a8dc1ab4c13
977 no changes found
995 no changes found
978 adding remote bookmark head1
996 adding remote bookmark head1
979 updating working directory
997 updating working directory
980 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
998 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
981
999
982 $ hg -R share-1arev log -G
1000 $ hg -R share-1arev log -G
983 @ changeset: 1:4a8dc1ab4c13
1001 @ changeset: 1:4a8dc1ab4c13
984 | bookmark: head1
1002 | bookmark: head1
985 | tag: tip
1003 | tag: tip
986 | user: test
1004 | user: test
987 | date: Thu Jan 01 00:00:00 1970 +0000
1005 | date: Thu Jan 01 00:00:00 1970 +0000
988 | summary: head1
1006 | summary: head1
989 |
1007 |
990 o changeset: 0:b5f04eac9d8f
1008 o changeset: 0:b5f04eac9d8f
991 user: test
1009 user: test
992 date: Thu Jan 01 00:00:00 1970 +0000
1010 date: Thu Jan 01 00:00:00 1970 +0000
993 summary: initial
1011 summary: initial
994
1012
995
1013
996 making another clone should only pull down requested rev
1014 making another clone should only pull down requested rev
997
1015
998 $ hg --config share.pool=sharerevs clone -r 99f71071f117 source1b share-1brev
1016 $ hg --config share.pool=sharerevs clone -r 99f71071f117 source1b share-1brev
999 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1017 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1000 searching for changes
1018 searching for changes
1001 adding changesets
1019 adding changesets
1002 adding manifests
1020 adding manifests
1003 adding file changes
1021 adding file changes
1004 adding remote bookmark head1
1022 adding remote bookmark head1
1005 adding remote bookmark head2
1023 adding remote bookmark head2
1006 added 1 changesets with 1 changes to 1 files (+1 heads)
1024 added 1 changesets with 1 changes to 1 files (+1 heads)
1007 new changesets 99f71071f117
1025 new changesets 99f71071f117
1008 updating working directory
1026 updating working directory
1009 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1027 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1010
1028
1011 $ hg -R share-1brev log -G
1029 $ hg -R share-1brev log -G
1012 @ changeset: 2:99f71071f117
1030 @ changeset: 2:99f71071f117
1013 | bookmark: head2
1031 | bookmark: head2
1014 | tag: tip
1032 | tag: tip
1015 | parent: 0:b5f04eac9d8f
1033 | parent: 0:b5f04eac9d8f
1016 | user: test
1034 | user: test
1017 | date: Thu Jan 01 00:00:00 1970 +0000
1035 | date: Thu Jan 01 00:00:00 1970 +0000
1018 | summary: head2
1036 | summary: head2
1019 |
1037 |
1020 | o changeset: 1:4a8dc1ab4c13
1038 | o changeset: 1:4a8dc1ab4c13
1021 |/ bookmark: head1
1039 |/ bookmark: head1
1022 | user: test
1040 | user: test
1023 | date: Thu Jan 01 00:00:00 1970 +0000
1041 | date: Thu Jan 01 00:00:00 1970 +0000
1024 | summary: head1
1042 | summary: head1
1025 |
1043 |
1026 o changeset: 0:b5f04eac9d8f
1044 o changeset: 0:b5f04eac9d8f
1027 user: test
1045 user: test
1028 date: Thu Jan 01 00:00:00 1970 +0000
1046 date: Thu Jan 01 00:00:00 1970 +0000
1029 summary: initial
1047 summary: initial
1030
1048
1031
1049
1032 Request to clone a single branch is respected in sharing mode
1050 Request to clone a single branch is respected in sharing mode
1033
1051
1034 $ hg --config share.pool=sharebranch clone -b branch1 source1b share-1bbranch1
1052 $ hg --config share.pool=sharebranch clone -b branch1 source1b share-1bbranch1
1035 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1053 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1036 adding changesets
1054 adding changesets
1037 adding manifests
1055 adding manifests
1038 adding file changes
1056 adding file changes
1039 added 2 changesets with 2 changes to 1 files
1057 added 2 changesets with 2 changes to 1 files
1040 new changesets b5f04eac9d8f:5f92a6c1a1b1
1058 new changesets b5f04eac9d8f:5f92a6c1a1b1
1041 no changes found
1059 no changes found
1042 updating working directory
1060 updating working directory
1043 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1061 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1044
1062
1045 $ hg -R share-1bbranch1 log -G
1063 $ hg -R share-1bbranch1 log -G
1046 o changeset: 1:5f92a6c1a1b1
1064 o changeset: 1:5f92a6c1a1b1
1047 | branch: branch1
1065 | branch: branch1
1048 | tag: tip
1066 | tag: tip
1049 | user: test
1067 | user: test
1050 | date: Thu Jan 01 00:00:00 1970 +0000
1068 | date: Thu Jan 01 00:00:00 1970 +0000
1051 | summary: branch1
1069 | summary: branch1
1052 |
1070 |
1053 @ changeset: 0:b5f04eac9d8f
1071 @ changeset: 0:b5f04eac9d8f
1054 user: test
1072 user: test
1055 date: Thu Jan 01 00:00:00 1970 +0000
1073 date: Thu Jan 01 00:00:00 1970 +0000
1056 summary: initial
1074 summary: initial
1057
1075
1058
1076
1059 $ hg --config share.pool=sharebranch clone -b branch2 source1b share-1bbranch2
1077 $ hg --config share.pool=sharebranch clone -b branch2 source1b share-1bbranch2
1060 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1078 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1061 searching for changes
1079 searching for changes
1062 adding changesets
1080 adding changesets
1063 adding manifests
1081 adding manifests
1064 adding file changes
1082 adding file changes
1065 added 1 changesets with 1 changes to 1 files (+1 heads)
1083 added 1 changesets with 1 changes to 1 files (+1 heads)
1066 new changesets 6bacf4683960
1084 new changesets 6bacf4683960
1067 updating working directory
1085 updating working directory
1068 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1086 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1069
1087
1070 $ hg -R share-1bbranch2 log -G
1088 $ hg -R share-1bbranch2 log -G
1071 o changeset: 2:6bacf4683960
1089 o changeset: 2:6bacf4683960
1072 | branch: branch2
1090 | branch: branch2
1073 | tag: tip
1091 | tag: tip
1074 | parent: 0:b5f04eac9d8f
1092 | parent: 0:b5f04eac9d8f
1075 | user: test
1093 | user: test
1076 | date: Thu Jan 01 00:00:00 1970 +0000
1094 | date: Thu Jan 01 00:00:00 1970 +0000
1077 | summary: branch2
1095 | summary: branch2
1078 |
1096 |
1079 | o changeset: 1:5f92a6c1a1b1
1097 | o changeset: 1:5f92a6c1a1b1
1080 |/ branch: branch1
1098 |/ branch: branch1
1081 | user: test
1099 | user: test
1082 | date: Thu Jan 01 00:00:00 1970 +0000
1100 | date: Thu Jan 01 00:00:00 1970 +0000
1083 | summary: branch1
1101 | summary: branch1
1084 |
1102 |
1085 @ changeset: 0:b5f04eac9d8f
1103 @ changeset: 0:b5f04eac9d8f
1086 user: test
1104 user: test
1087 date: Thu Jan 01 00:00:00 1970 +0000
1105 date: Thu Jan 01 00:00:00 1970 +0000
1088 summary: initial
1106 summary: initial
1089
1107
1090
1108
1091 -U is respected in share clone mode
1109 -U is respected in share clone mode
1092
1110
1093 $ hg --config share.pool=share clone -U source1a share-1anowc
1111 $ hg --config share.pool=share clone -U source1a share-1anowc
1094 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1112 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1095 searching for changes
1113 searching for changes
1096 no changes found
1114 no changes found
1097 adding remote bookmark bookA
1115 adding remote bookmark bookA
1098
1116
1099 $ ls -A share-1anowc
1117 $ ls -A share-1anowc
1100 .hg
1118 .hg
1101
1119
1102 Test that auto sharing doesn't cause failure of "hg clone local remote"
1120 Test that auto sharing doesn't cause failure of "hg clone local remote"
1103
1121
1104 $ cd $TESTTMP
1122 $ cd $TESTTMP
1105 $ hg -R a id -r 0
1123 $ hg -R a id -r 0
1106 acb14030fe0a
1124 acb14030fe0a
1107 $ hg id -R remote -r 0
1125 $ hg id -R remote -r 0
1108 abort: repository remote not found
1126 abort: repository remote not found
1109 [255]
1127 [255]
1110 $ hg --config share.pool=share -q clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" a ssh://user@dummy/remote
1128 $ hg --config share.pool=share -q clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" a ssh://user@dummy/remote
1111 $ hg -R remote id -r 0
1129 $ hg -R remote id -r 0
1112 acb14030fe0a
1130 acb14030fe0a
1113
1131
1114 Cloning into pooled storage doesn't race (issue5104)
1132 Cloning into pooled storage doesn't race (issue5104)
1115
1133
1116 $ HGPOSTLOCKDELAY=2.0 hg --config share.pool=racepool --config extensions.lockdelay=$TESTDIR/lockdelay.py clone source1a share-destrace1 > race1.log 2>&1 &
1134 $ HGPOSTLOCKDELAY=2.0 hg --config share.pool=racepool --config extensions.lockdelay=$TESTDIR/lockdelay.py clone source1a share-destrace1 > race1.log 2>&1 &
1117 $ HGPRELOCKDELAY=1.0 hg --config share.pool=racepool --config extensions.lockdelay=$TESTDIR/lockdelay.py clone source1a share-destrace2 > race2.log 2>&1
1135 $ HGPRELOCKDELAY=1.0 hg --config share.pool=racepool --config extensions.lockdelay=$TESTDIR/lockdelay.py clone source1a share-destrace2 > race2.log 2>&1
1118 $ wait
1136 $ wait
1119
1137
1120 $ hg -R share-destrace1 log -r tip
1138 $ hg -R share-destrace1 log -r tip
1121 changeset: 2:e5bfe23c0b47
1139 changeset: 2:e5bfe23c0b47
1122 bookmark: bookA
1140 bookmark: bookA
1123 tag: tip
1141 tag: tip
1124 user: test
1142 user: test
1125 date: Thu Jan 01 00:00:00 1970 +0000
1143 date: Thu Jan 01 00:00:00 1970 +0000
1126 summary: 1a
1144 summary: 1a
1127
1145
1128
1146
1129 $ hg -R share-destrace2 log -r tip
1147 $ hg -R share-destrace2 log -r tip
1130 changeset: 2:e5bfe23c0b47
1148 changeset: 2:e5bfe23c0b47
1131 bookmark: bookA
1149 bookmark: bookA
1132 tag: tip
1150 tag: tip
1133 user: test
1151 user: test
1134 date: Thu Jan 01 00:00:00 1970 +0000
1152 date: Thu Jan 01 00:00:00 1970 +0000
1135 summary: 1a
1153 summary: 1a
1136
1154
1137 One repo should be new, the other should be shared from the pool. We
1155 One repo should be new, the other should be shared from the pool. We
1138 don't care which is which, so we just make sure we always print the
1156 don't care which is which, so we just make sure we always print the
1139 one containing "new pooled" first, then one one containing "existing
1157 one containing "new pooled" first, then one one containing "existing
1140 pooled".
1158 pooled".
1141
1159
1142 $ (grep 'new pooled' race1.log > /dev/null && cat race1.log || cat race2.log) | grep -v lock
1160 $ (grep 'new pooled' race1.log > /dev/null && cat race1.log || cat race2.log) | grep -v lock
1143 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1161 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1144 requesting all changes
1162 requesting all changes
1145 adding changesets
1163 adding changesets
1146 adding manifests
1164 adding manifests
1147 adding file changes
1165 adding file changes
1148 added 3 changesets with 3 changes to 1 files
1166 added 3 changesets with 3 changes to 1 files
1149 new changesets b5f04eac9d8f:e5bfe23c0b47
1167 new changesets b5f04eac9d8f:e5bfe23c0b47
1150 searching for changes
1168 searching for changes
1151 no changes found
1169 no changes found
1152 adding remote bookmark bookA
1170 adding remote bookmark bookA
1153 updating working directory
1171 updating working directory
1154 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1172 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1155
1173
1156 $ (grep 'existing pooled' race1.log > /dev/null && cat race1.log || cat race2.log) | grep -v lock
1174 $ (grep 'existing pooled' race1.log > /dev/null && cat race1.log || cat race2.log) | grep -v lock
1157 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1175 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1158 searching for changes
1176 searching for changes
1159 no changes found
1177 no changes found
1160 adding remote bookmark bookA
1178 adding remote bookmark bookA
1161 updating working directory
1179 updating working directory
1162 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1180 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1163
1181
1164 SEC: check for unsafe ssh url
1182 SEC: check for unsafe ssh url
1165
1183
1166 $ cat >> $HGRCPATH << EOF
1184 $ cat >> $HGRCPATH << EOF
1167 > [ui]
1185 > [ui]
1168 > ssh = sh -c "read l; read l; read l"
1186 > ssh = sh -c "read l; read l; read l"
1169 > EOF
1187 > EOF
1170
1188
1171 $ hg clone 'ssh://-oProxyCommand=touch${IFS}owned/path'
1189 $ hg clone 'ssh://-oProxyCommand=touch${IFS}owned/path'
1172 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
1190 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
1173 [255]
1191 [255]
1174 $ hg clone 'ssh://%2DoProxyCommand=touch${IFS}owned/path'
1192 $ hg clone 'ssh://%2DoProxyCommand=touch${IFS}owned/path'
1175 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
1193 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
1176 [255]
1194 [255]
1177 $ hg clone 'ssh://fakehost|touch%20owned/path'
1195 $ hg clone 'ssh://fakehost|touch%20owned/path'
1178 abort: no suitable response from remote hg
1196 abort: no suitable response from remote hg
1179 [255]
1197 [255]
1180 $ hg clone 'ssh://fakehost%7Ctouch%20owned/path'
1198 $ hg clone 'ssh://fakehost%7Ctouch%20owned/path'
1181 abort: no suitable response from remote hg
1199 abort: no suitable response from remote hg
1182 [255]
1200 [255]
1183
1201
1184 $ hg clone 'ssh://-oProxyCommand=touch owned%20foo@example.com/nonexistent/path'
1202 $ hg clone 'ssh://-oProxyCommand=touch owned%20foo@example.com/nonexistent/path'
1185 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch owned foo@example.com/nonexistent/path'
1203 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch owned foo@example.com/nonexistent/path'
1186 [255]
1204 [255]
1187
1205
1188 #if windows
1206 #if windows
1189 $ hg clone "ssh://%26touch%20owned%20/" --debug
1207 $ hg clone "ssh://%26touch%20owned%20/" --debug
1190 running sh -c "read l; read l; read l" "&touch owned " "hg -R . serve --stdio"
1208 running sh -c "read l; read l; read l" "&touch owned " "hg -R . serve --stdio"
1191 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1209 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1192 sending hello command
1210 sending hello command
1193 sending between command
1211 sending between command
1194 abort: no suitable response from remote hg
1212 abort: no suitable response from remote hg
1195 [255]
1213 [255]
1196 $ hg clone "ssh://example.com:%26touch%20owned%20/" --debug
1214 $ hg clone "ssh://example.com:%26touch%20owned%20/" --debug
1197 running sh -c "read l; read l; read l" -p "&touch owned " example.com "hg -R . serve --stdio"
1215 running sh -c "read l; read l; read l" -p "&touch owned " example.com "hg -R . serve --stdio"
1198 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1216 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1199 sending hello command
1217 sending hello command
1200 sending between command
1218 sending between command
1201 abort: no suitable response from remote hg
1219 abort: no suitable response from remote hg
1202 [255]
1220 [255]
1203 #else
1221 #else
1204 $ hg clone "ssh://%3btouch%20owned%20/" --debug
1222 $ hg clone "ssh://%3btouch%20owned%20/" --debug
1205 running sh -c "read l; read l; read l" ';touch owned ' 'hg -R . serve --stdio'
1223 running sh -c "read l; read l; read l" ';touch owned ' 'hg -R . serve --stdio'
1206 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1224 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1207 sending hello command
1225 sending hello command
1208 sending between command
1226 sending between command
1209 abort: no suitable response from remote hg
1227 abort: no suitable response from remote hg
1210 [255]
1228 [255]
1211 $ hg clone "ssh://example.com:%3btouch%20owned%20/" --debug
1229 $ hg clone "ssh://example.com:%3btouch%20owned%20/" --debug
1212 running sh -c "read l; read l; read l" -p ';touch owned ' example.com 'hg -R . serve --stdio'
1230 running sh -c "read l; read l; read l" -p ';touch owned ' example.com 'hg -R . serve --stdio'
1213 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1231 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1214 sending hello command
1232 sending hello command
1215 sending between command
1233 sending between command
1216 abort: no suitable response from remote hg
1234 abort: no suitable response from remote hg
1217 [255]
1235 [255]
1218 #endif
1236 #endif
1219
1237
1220 $ hg clone "ssh://v-alid.example.com/" --debug
1238 $ hg clone "ssh://v-alid.example.com/" --debug
1221 running sh -c "read l; read l; read l" v-alid\.example\.com ['"]hg -R \. serve --stdio['"] (re)
1239 running sh -c "read l; read l; read l" v-alid\.example\.com ['"]hg -R \. serve --stdio['"] (re)
1222 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1240 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1223 sending hello command
1241 sending hello command
1224 sending between command
1242 sending between command
1225 abort: no suitable response from remote hg
1243 abort: no suitable response from remote hg
1226 [255]
1244 [255]
1227
1245
1228 We should not have created a file named owned - if it exists, the
1246 We should not have created a file named owned - if it exists, the
1229 attack succeeded.
1247 attack succeeded.
1230 $ if test -f owned; then echo 'you got owned'; fi
1248 $ if test -f owned; then echo 'you got owned'; fi
1231
1249
1232 Cloning without fsmonitor enabled does not print a warning for small repos
1250 Cloning without fsmonitor enabled does not print a warning for small repos
1233
1251
1234 $ hg clone a fsmonitor-default
1252 $ hg clone a fsmonitor-default
1235 updating to bookmark @ on branch stable
1253 updating to bookmark @ on branch stable
1236 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1254 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1237
1255
1238 Lower the warning threshold to simulate a large repo
1256 Lower the warning threshold to simulate a large repo
1239
1257
1240 $ cat >> $HGRCPATH << EOF
1258 $ cat >> $HGRCPATH << EOF
1241 > [fsmonitor]
1259 > [fsmonitor]
1242 > warn_update_file_count = 2
1260 > warn_update_file_count = 2
1243 > warn_update_file_count_rust = 2
1261 > warn_update_file_count_rust = 2
1244 > EOF
1262 > EOF
1245
1263
1246 We should see a warning about no fsmonitor on supported platforms
1264 We should see a warning about no fsmonitor on supported platforms
1247
1265
1248 #if linuxormacos no-fsmonitor
1266 #if linuxormacos no-fsmonitor
1249 $ hg clone a nofsmonitor
1267 $ hg clone a nofsmonitor
1250 updating to bookmark @ on branch stable
1268 updating to bookmark @ on branch stable
1251 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
1269 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
1252 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1270 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1253 #else
1271 #else
1254 $ hg clone a nofsmonitor
1272 $ hg clone a nofsmonitor
1255 updating to bookmark @ on branch stable
1273 updating to bookmark @ on branch stable
1256 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1274 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1257 #endif
1275 #endif
1258
1276
1259 We should not see warning about fsmonitor when it is enabled
1277 We should not see warning about fsmonitor when it is enabled
1260
1278
1261 #if fsmonitor
1279 #if fsmonitor
1262 $ hg clone a fsmonitor-enabled
1280 $ hg clone a fsmonitor-enabled
1263 updating to bookmark @ on branch stable
1281 updating to bookmark @ on branch stable
1264 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1282 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1265 #endif
1283 #endif
1266
1284
1267 We can disable the fsmonitor warning
1285 We can disable the fsmonitor warning
1268
1286
1269 $ hg --config fsmonitor.warn_when_unused=false clone a fsmonitor-disable-warning
1287 $ hg --config fsmonitor.warn_when_unused=false clone a fsmonitor-disable-warning
1270 updating to bookmark @ on branch stable
1288 updating to bookmark @ on branch stable
1271 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1289 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1272
1290
1273 Loaded fsmonitor but disabled in config should still print warning
1291 Loaded fsmonitor but disabled in config should still print warning
1274
1292
1275 #if linuxormacos fsmonitor
1293 #if linuxormacos fsmonitor
1276 $ hg --config fsmonitor.mode=off clone a fsmonitor-mode-off
1294 $ hg --config fsmonitor.mode=off clone a fsmonitor-mode-off
1277 updating to bookmark @ on branch stable
1295 updating to bookmark @ on branch stable
1278 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor") (fsmonitor !)
1296 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor") (fsmonitor !)
1279 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1297 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1280 #endif
1298 #endif
1281
1299
1282 Warning not printed if working directory isn't empty
1300 Warning not printed if working directory isn't empty
1283
1301
1284 $ hg -q clone a fsmonitor-update
1302 $ hg -q clone a fsmonitor-update
1285 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor") (?)
1303 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor") (?)
1286 $ cd fsmonitor-update
1304 $ cd fsmonitor-update
1287 $ hg up acb14030fe0a
1305 $ hg up acb14030fe0a
1288 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1306 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1289 (leaving bookmark @)
1307 (leaving bookmark @)
1290 $ hg up cf0fe1914066
1308 $ hg up cf0fe1914066
1291 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1309 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1292
1310
1293 `hg update` from null revision also prints
1311 `hg update` from null revision also prints
1294
1312
1295 $ hg up null
1313 $ hg up null
1296 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1314 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1297
1315
1298 #if linuxormacos no-fsmonitor
1316 #if linuxormacos no-fsmonitor
1299 $ hg up cf0fe1914066
1317 $ hg up cf0fe1914066
1300 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
1318 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
1301 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1319 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1302 #else
1320 #else
1303 $ hg up cf0fe1914066
1321 $ hg up cf0fe1914066
1304 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1322 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1305 #endif
1323 #endif
1306
1324
1307 $ cd ..
1325 $ cd ..
1308
1326
General Comments 0
You need to be logged in to leave comments. Login now