78 _string_escape('%s:%s' % (k, pycompat.bytestr(d[k]))) |
78 _string_escape('%s:%s' % (k, pycompat.bytestr(d[k]))) |
79 for k in sorted(d) |
79 for k in sorted(d) |
80 ] |
80 ] |
81 return "\0".join(items) |
81 return "\0".join(items) |
82 |
82 |
83 def encodecopies(copies): |
83 def encodecopies(files, copies): |
84 items = [ |
84 items = [] |
85 '%s\0%s' % (k, copies[k]) |
85 for i, dst in enumerate(files): |
86 for k in sorted(copies) |
86 if dst in copies: |
87 ] |
87 items.append('%d\0%s' % (i, copies[dst])) |
|
88 if len(items) != len(copies): |
|
89 raise error.ProgrammingError('some copy targets missing from file list') |
88 return "\n".join(items) |
90 return "\n".join(items) |
89 |
91 |
90 def decodecopies(data): |
92 def decodecopies(files, data): |
91 try: |
93 try: |
92 copies = {} |
94 copies = {} |
93 for l in data.split('\n'): |
95 for l in data.split('\n'): |
94 k, v = l.split('\0') |
96 strindex, src = l.split('\0') |
95 copies[k] = v |
97 i = int(strindex) |
|
98 dst = files[i] |
|
99 copies[dst] = src |
96 return copies |
100 return copies |
97 except ValueError: |
101 except (ValueError, IndexError): |
98 # Perhaps someone had chosen the same key name (e.g. "p1copies") and |
102 # Perhaps someone had chosen the same key name (e.g. "p1copies") and |
99 # used different syntax for the value. |
103 # used different syntax for the value. |
100 return None |
104 return None |
101 |
105 |
102 def encodefileindices(files, subset): |
106 def encodefileindices(files, subset): |
334 return rawindices and decodefileindices(self.files, rawindices) |
338 return rawindices and decodefileindices(self.files, rawindices) |
335 |
339 |
336 @property |
340 @property |
337 def p1copies(self): |
341 def p1copies(self): |
338 rawcopies = self.extra.get('p1copies') |
342 rawcopies = self.extra.get('p1copies') |
339 return rawcopies and decodecopies(rawcopies) |
343 return rawcopies and decodecopies(self.files, rawcopies) |
340 |
344 |
341 @property |
345 @property |
342 def p2copies(self): |
346 def p2copies(self): |
343 rawcopies = self.extra.get('p2copies') |
347 rawcopies = self.extra.get('p2copies') |
344 return rawcopies and decodecopies(rawcopies) |
348 return rawcopies and decodecopies(self.files, rawcopies) |
345 |
349 |
346 @property |
350 @property |
347 def description(self): |
351 def description(self): |
348 return encoding.tolocal(self._text[self._offsets[3] + 2:]) |
352 return encoding.tolocal(self._text[self._offsets[3] + 2:]) |
349 |
353 |
629 raise error.StorageError(_('the name \'%s\' is reserved') |
633 raise error.StorageError(_('the name \'%s\' is reserved') |
630 % branch) |
634 % branch) |
631 extrasentries = p1copies, p2copies, filesadded, filesremoved |
635 extrasentries = p1copies, p2copies, filesadded, filesremoved |
632 if extra is None and any(x is not None for x in extrasentries): |
636 if extra is None and any(x is not None for x in extrasentries): |
633 extra = {} |
637 extra = {} |
|
638 sortedfiles = sorted(files) |
634 if p1copies is not None: |
639 if p1copies is not None: |
635 extra['p1copies'] = encodecopies(p1copies) |
640 extra['p1copies'] = encodecopies(sortedfiles, p1copies) |
636 if p2copies is not None: |
641 if p2copies is not None: |
637 extra['p2copies'] = encodecopies(p2copies) |
642 extra['p2copies'] = encodecopies(sortedfiles, p2copies) |
638 sortedfiles = sorted(files) |
|
639 if filesadded is not None: |
643 if filesadded is not None: |
640 extra['filesadded'] = encodefileindices(sortedfiles, filesadded) |
644 extra['filesadded'] = encodefileindices(sortedfiles, filesadded) |
641 if filesremoved is not None: |
645 if filesremoved is not None: |
642 extra['filesremoved'] = encodefileindices(sortedfiles, filesremoved) |
646 extra['filesremoved'] = encodefileindices(sortedfiles, filesremoved) |
643 |
647 |