##// END OF EJS Templates
merge: use constants for merge state record types...
Gregory Szorc -
r37127:a532b2f5 default
parent child Browse files
Show More
@@ -47,6 +47,20 b' def _droponode(data):'
47 bits = bits[:-2] + bits[-1:]
47 bits = bits[:-2] + bits[-1:]
48 return '\0'.join(bits)
48 return '\0'.join(bits)
49
49
50 # Merge state record types. See ``mergestate`` docs for more.
51 RECORD_LOCAL = b'L'
52 RECORD_OTHER = b'O'
53 RECORD_MERGED = b'F'
54 RECORD_CHANGEDELETE_CONFLICT = b'C'
55 RECORD_MERGE_DRIVER_MERGE = b'D'
56 RECORD_PATH_CONFLICT = b'P'
57 RECORD_MERGE_DRIVER_STATE = b'm'
58 RECORD_FILE_VALUES = b'f'
59 RECORD_LABELS = b'l'
60 RECORD_OVERRIDE = b't'
61 RECORD_UNSUPPORTED_MANDATORY = b'X'
62 RECORD_UNSUPPORTED_ADVISORY = b'x'
63
50 class mergestate(object):
64 class mergestate(object):
51 '''track 3-way merge state of individual files
65 '''track 3-way merge state of individual files
52
66
@@ -158,11 +172,11 b' class mergestate(object):'
158 unsupported = set()
172 unsupported = set()
159 records = self._readrecords()
173 records = self._readrecords()
160 for rtype, record in records:
174 for rtype, record in records:
161 if rtype == 'L':
175 if rtype == RECORD_LOCAL:
162 self._local = bin(record)
176 self._local = bin(record)
163 elif rtype == 'O':
177 elif rtype == RECORD_OTHER:
164 self._other = bin(record)
178 self._other = bin(record)
165 elif rtype == 'm':
179 elif rtype == RECORD_MERGE_DRIVER_STATE:
166 bits = record.split('\0', 1)
180 bits = record.split('\0', 1)
167 mdstate = bits[1]
181 mdstate = bits[1]
168 if len(mdstate) != 1 or mdstate not in 'ums':
182 if len(mdstate) != 1 or mdstate not in 'ums':
@@ -171,10 +185,11 b' class mergestate(object):'
171
185
172 self._readmergedriver = bits[0]
186 self._readmergedriver = bits[0]
173 self._mdstate = mdstate
187 self._mdstate = mdstate
174 elif rtype in 'FDCP':
188 elif rtype in (RECORD_MERGED, RECORD_CHANGEDELETE_CONFLICT,
189 RECORD_PATH_CONFLICT, RECORD_MERGE_DRIVER_MERGE):
175 bits = record.split('\0')
190 bits = record.split('\0')
176 self._state[bits[0]] = bits[1:]
191 self._state[bits[0]] = bits[1:]
177 elif rtype == 'f':
192 elif rtype == RECORD_FILE_VALUES:
178 filename, rawextras = record.split('\0', 1)
193 filename, rawextras = record.split('\0', 1)
179 extraparts = rawextras.split('\0')
194 extraparts = rawextras.split('\0')
180 extras = {}
195 extras = {}
@@ -184,7 +199,7 b' class mergestate(object):'
184 i += 2
199 i += 2
185
200
186 self._stateextras[filename] = extras
201 self._stateextras[filename] = extras
187 elif rtype == 'l':
202 elif rtype == RECORD_LABELS:
188 labels = record.split('\0', 2)
203 labels = record.split('\0', 2)
189 self._labels = [l for l in labels if len(l) > 0]
204 self._labels = [l for l in labels if len(l) > 0]
190 elif not rtype.islower():
205 elif not rtype.islower():
@@ -218,12 +233,12 b' class mergestate(object):'
218 # we have to infer the "other" changeset of the merge
233 # we have to infer the "other" changeset of the merge
219 # we cannot do better than that with v1 of the format
234 # we cannot do better than that with v1 of the format
220 mctx = self._repo[None].parents()[-1]
235 mctx = self._repo[None].parents()[-1]
221 v1records.append(('O', mctx.hex()))
236 v1records.append((RECORD_OTHER, mctx.hex()))
222 # add place holder "other" file node information
237 # add place holder "other" file node information
223 # nobody is using it yet so we do no need to fetch the data
238 # nobody is using it yet so we do no need to fetch the data
224 # if mctx was wrong `mctx[bits[-2]]` may fails.
239 # if mctx was wrong `mctx[bits[-2]]` may fails.
225 for idx, r in enumerate(v1records):
240 for idx, r in enumerate(v1records):
226 if r[0] == 'F':
241 if r[0] == RECORD_MERGED:
227 bits = r[1].split('\0')
242 bits = r[1].split('\0')
228 bits.insert(-2, '')
243 bits.insert(-2, '')
229 v1records[idx] = (r[0], '\0'.join(bits))
244 v1records[idx] = (r[0], '\0'.join(bits))
@@ -232,11 +247,11 b' class mergestate(object):'
232 def _v1v2match(self, v1records, v2records):
247 def _v1v2match(self, v1records, v2records):
233 oldv2 = set() # old format version of v2 record
248 oldv2 = set() # old format version of v2 record
234 for rec in v2records:
249 for rec in v2records:
235 if rec[0] == 'L':
250 if rec[0] == RECORD_LOCAL:
236 oldv2.add(rec)
251 oldv2.add(rec)
237 elif rec[0] == 'F':
252 elif rec[0] == RECORD_MERGED:
238 # drop the onode data (not contained in v1)
253 # drop the onode data (not contained in v1)
239 oldv2.add(('F', _droponode(rec[1])))
254 oldv2.add((RECORD_MERGED, _droponode(rec[1])))
240 for rec in v1records:
255 for rec in v1records:
241 if rec not in oldv2:
256 if rec not in oldv2:
242 return False
257 return False
@@ -256,9 +271,9 b' class mergestate(object):'
256 f = self._repo.vfs(self.statepathv1)
271 f = self._repo.vfs(self.statepathv1)
257 for i, l in enumerate(f):
272 for i, l in enumerate(f):
258 if i == 0:
273 if i == 0:
259 records.append(('L', l[:-1]))
274 records.append((RECORD_LOCAL, l[:-1]))
260 else:
275 else:
261 records.append(('F', l[:-1]))
276 records.append((RECORD_MERGED, l[:-1]))
262 f.close()
277 f.close()
263 except IOError as err:
278 except IOError as err:
264 if err.errno != errno.ENOENT:
279 if err.errno != errno.ENOENT:
@@ -296,7 +311,7 b' class mergestate(object):'
296 off += 4
311 off += 4
297 record = data[off:(off + length)]
312 record = data[off:(off + length)]
298 off += length
313 off += length
299 if rtype == 't':
314 if rtype == RECORD_OVERRIDE:
300 rtype, record = record[0:1], record[1:]
315 rtype, record = record[0:1], record[1:]
301 records.append((rtype, record))
316 records.append((rtype, record))
302 f.close()
317 f.close()
@@ -359,10 +374,10 b' class mergestate(object):'
359
374
360 def _makerecords(self):
375 def _makerecords(self):
361 records = []
376 records = []
362 records.append(('L', hex(self._local)))
377 records.append((RECORD_LOCAL, hex(self._local)))
363 records.append(('O', hex(self._other)))
378 records.append((RECORD_OTHER, hex(self._other)))
364 if self.mergedriver:
379 if self.mergedriver:
365 records.append(('m', '\0'.join([
380 records.append((RECORD_MERGE_DRIVER_STATE, '\0'.join([
366 self.mergedriver, self._mdstate])))
381 self.mergedriver, self._mdstate])))
367 # Write out state items. In all cases, the value of the state map entry
382 # Write out state items. In all cases, the value of the state map entry
368 # is written as the contents of the record. The record type depends on
383 # is written as the contents of the record. The record type depends on
@@ -372,27 +387,32 b' class mergestate(object):'
372 for filename, v in self._state.iteritems():
387 for filename, v in self._state.iteritems():
373 if v[0] == 'd':
388 if v[0] == 'd':
374 # Driver-resolved merge. These are stored in 'D' records.
389 # Driver-resolved merge. These are stored in 'D' records.
375 records.append(('D', '\0'.join([filename] + v)))
390 records.append((RECORD_MERGE_DRIVER_MERGE,
391 '\0'.join([filename] + v)))
376 elif v[0] in ('pu', 'pr'):
392 elif v[0] in ('pu', 'pr'):
377 # Path conflicts. These are stored in 'P' records. The current
393 # Path conflicts. These are stored in 'P' records. The current
378 # resolution state ('pu' or 'pr') is stored within the record.
394 # resolution state ('pu' or 'pr') is stored within the record.
379 records.append(('P', '\0'.join([filename] + v)))
395 records.append((RECORD_PATH_CONFLICT,
396 '\0'.join([filename] + v)))
380 elif v[1] == nullhex or v[6] == nullhex:
397 elif v[1] == nullhex or v[6] == nullhex:
381 # Change/Delete or Delete/Change conflicts. These are stored in
398 # Change/Delete or Delete/Change conflicts. These are stored in
382 # 'C' records. v[1] is the local file, and is nullhex when the
399 # 'C' records. v[1] is the local file, and is nullhex when the
383 # file is deleted locally ('dc'). v[6] is the remote file, and
400 # file is deleted locally ('dc'). v[6] is the remote file, and
384 # is nullhex when the file is deleted remotely ('cd').
401 # is nullhex when the file is deleted remotely ('cd').
385 records.append(('C', '\0'.join([filename] + v)))
402 records.append((RECORD_CHANGEDELETE_CONFLICT,
403 '\0'.join([filename] + v)))
386 else:
404 else:
387 # Normal files. These are stored in 'F' records.
405 # Normal files. These are stored in 'F' records.
388 records.append(('F', '\0'.join([filename] + v)))
406 records.append((RECORD_MERGED,
407 '\0'.join([filename] + v)))
389 for filename, extras in sorted(self._stateextras.iteritems()):
408 for filename, extras in sorted(self._stateextras.iteritems()):
390 rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in
409 rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in
391 extras.iteritems())
410 extras.iteritems())
392 records.append(('f', '%s\0%s' % (filename, rawextras)))
411 records.append((RECORD_FILE_VALUES,
412 '%s\0%s' % (filename, rawextras)))
393 if self._labels is not None:
413 if self._labels is not None:
394 labels = '\0'.join(self._labels)
414 labels = '\0'.join(self._labels)
395 records.append(('l', labels))
415 records.append((RECORD_LABELS, labels))
396 return records
416 return records
397
417
398 def _writerecords(self, records):
418 def _writerecords(self, records):
@@ -405,10 +425,10 b' class mergestate(object):'
405 f = self._repo.vfs(self.statepathv1, 'wb')
425 f = self._repo.vfs(self.statepathv1, 'wb')
406 irecords = iter(records)
426 irecords = iter(records)
407 lrecords = next(irecords)
427 lrecords = next(irecords)
408 assert lrecords[0] == 'L'
428 assert lrecords[0] == RECORD_LOCAL
409 f.write(hex(self._local) + '\n')
429 f.write(hex(self._local) + '\n')
410 for rtype, data in irecords:
430 for rtype, data in irecords:
411 if rtype == 'F':
431 if rtype == RECORD_MERGED:
412 f.write('%s\n' % _droponode(data))
432 f.write('%s\n' % _droponode(data))
413 f.close()
433 f.close()
414
434
@@ -417,12 +437,12 b' class mergestate(object):'
417
437
418 See the docstring for _readrecordsv2 for why we use 't'."""
438 See the docstring for _readrecordsv2 for why we use 't'."""
419 # these are the records that all version 2 clients can read
439 # these are the records that all version 2 clients can read
420 whitelist = 'LOF'
440 allowlist = (RECORD_LOCAL, RECORD_OTHER, RECORD_MERGED)
421 f = self._repo.vfs(self.statepathv2, 'wb')
441 f = self._repo.vfs(self.statepathv2, 'wb')
422 for key, data in records:
442 for key, data in records:
423 assert len(key) == 1
443 assert len(key) == 1
424 if key not in whitelist:
444 if key not in allowlist:
425 key, data = 't', '%s%s' % (key, data)
445 key, data = RECORD_OVERRIDE, '%s%s' % (key, data)
426 format = '>sI%is' % len(data)
446 format = '>sI%is' % len(data)
427 f.write(_pack(format, key, len(data), data))
447 f.write(_pack(format, key, len(data), data))
428 f.close()
448 f.close()
General Comments 0
You need to be logged in to leave comments. Login now