Show More
@@ -0,0 +1,278 b'' | |||||
|
1 | ||||
|
2 | Set up repo | |||
|
3 | ||||
|
4 | $ hg --config experimental.treemanifest=True init repo | |||
|
5 | $ cd repo | |||
|
6 | ||||
|
7 | Requirements get set on init | |||
|
8 | ||||
|
9 | $ grep treemanifest .hg/requires | |||
|
10 | treemanifest | |||
|
11 | ||||
|
12 | Without directories, looks like any other repo | |||
|
13 | ||||
|
14 | $ echo 0 > a | |||
|
15 | $ echo 0 > b | |||
|
16 | $ hg ci -Aqm initial | |||
|
17 | $ hg debugdata -m 0 | |||
|
18 | a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc) | |||
|
19 | b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc) | |||
|
20 | ||||
|
21 | Submanifest is stored in separate revlog | |||
|
22 | ||||
|
23 | $ mkdir dir1 | |||
|
24 | $ echo 1 > dir1/a | |||
|
25 | $ echo 1 > dir1/b | |||
|
26 | $ echo 1 > e | |||
|
27 | $ hg ci -Aqm 'add dir1' | |||
|
28 | $ hg debugdata -m 1 | |||
|
29 | a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc) | |||
|
30 | b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc) | |||
|
31 | dir1\x008b3ffd73f901e83304c83d33132c8e774ceac44ed (esc) | |||
|
32 | e\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc) | |||
|
33 | $ hg debugdata .hg/store/meta/dir1/00manifest.i 0 | |||
|
34 | a\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc) | |||
|
35 | b\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc) | |||
|
36 | ||||
|
37 | Can add nested directories | |||
|
38 | ||||
|
39 | $ mkdir dir1/dir1 | |||
|
40 | $ echo 2 > dir1/dir1/a | |||
|
41 | $ echo 2 > dir1/dir1/b | |||
|
42 | $ mkdir dir1/dir2 | |||
|
43 | $ echo 2 > dir1/dir2/a | |||
|
44 | $ echo 2 > dir1/dir2/b | |||
|
45 | $ hg ci -Aqm 'add dir1/dir1' | |||
|
46 | $ hg files -r . | |||
|
47 | a | |||
|
48 | b | |||
|
49 | dir1/a | |||
|
50 | dir1/b | |||
|
51 | dir1/dir1/a | |||
|
52 | dir1/dir1/b | |||
|
53 | dir1/dir2/a | |||
|
54 | dir1/dir2/b | |||
|
55 | e | |||
|
56 | ||||
|
57 | Revision is not created for unchanged directory | |||
|
58 | ||||
|
59 | $ mkdir dir2 | |||
|
60 | $ echo 3 > dir2/a | |||
|
61 | $ hg add dir2 | |||
|
62 | adding dir2/a | |||
|
63 | $ hg debugindex .hg/store/meta/dir1/00manifest.i > before | |||
|
64 | $ hg ci -qm 'add dir2' | |||
|
65 | $ hg debugindex .hg/store/meta/dir1/00manifest.i > after | |||
|
66 | $ diff before after | |||
|
67 | $ rm before after | |||
|
68 | ||||
|
69 | Removing directory does not create an revlog entry | |||
|
70 | ||||
|
71 | $ hg rm dir1/dir1 | |||
|
72 | removing dir1/dir1/a | |||
|
73 | removing dir1/dir1/b | |||
|
74 | $ hg debugindex .hg/store/meta/dir1/dir1/00manifest.i > before | |||
|
75 | $ hg ci -qm 'remove dir1/dir1' | |||
|
76 | $ hg debugindex .hg/store/meta/dir1/dir1/00manifest.i > after | |||
|
77 | $ diff before after | |||
|
78 | $ rm before after | |||
|
79 | ||||
|
80 | Check that hg files (calls treemanifest.walk()) works | |||
|
81 | ||||
|
82 | $ hg co 'desc("add dir2")' | |||
|
83 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
84 | $ hg files -r . dir1 | |||
|
85 | dir1/a | |||
|
86 | dir1/b | |||
|
87 | dir1/dir1/a | |||
|
88 | dir1/dir1/b | |||
|
89 | dir1/dir2/a | |||
|
90 | dir1/dir2/b | |||
|
91 | ||||
|
92 | Check that status between revisions works (calls treemanifest.matches()) | |||
|
93 | ||||
|
94 | $ hg status --rev 'desc("add dir1")' --rev . dir1 | |||
|
95 | A dir1/dir1/a | |||
|
96 | A dir1/dir1/b | |||
|
97 | A dir1/dir2/a | |||
|
98 | A dir1/dir2/b | |||
|
99 | ||||
|
100 | Merge creates 2-parent revision of directory revlog | |||
|
101 | ||||
|
102 | $ echo 5 > dir1/a | |||
|
103 | $ hg ci -Aqm 'modify dir1/a' | |||
|
104 | $ hg co '.^' | |||
|
105 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
106 | $ echo 6 > dir1/b | |||
|
107 | $ hg ci -Aqm 'modify dir1/b' | |||
|
108 | $ hg merge 'desc("modify dir1/a")' | |||
|
109 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
110 | (branch merge, don't forget to commit) | |||
|
111 | $ hg ci -m 'conflict-free merge involving dir1/' | |||
|
112 | $ cat dir1/a | |||
|
113 | 5 | |||
|
114 | $ cat dir1/b | |||
|
115 | 6 | |||
|
116 | $ hg debugindex .hg/store/meta/dir1/00manifest.i | |||
|
117 | rev offset length base linkrev nodeid p1 p2 | |||
|
118 | 0 0 54 0 1 8b3ffd73f901 000000000000 000000000000 | |||
|
119 | 1 54 68 0 2 b66d046c644f 8b3ffd73f901 000000000000 | |||
|
120 | 2 122 12 0 4 b87265673c8a b66d046c644f 000000000000 | |||
|
121 | 3 134 95 0 5 aa5d3adcec72 b66d046c644f 000000000000 | |||
|
122 | 4 229 81 0 6 e29b066b91ad b66d046c644f 000000000000 | |||
|
123 | 5 310 107 5 7 a120ce2b83f5 e29b066b91ad aa5d3adcec72 | |||
|
124 | ||||
|
125 | Merge keeping directory from parent 1 does not create revlog entry. (Note that | |||
|
126 | dir1's manifest does change, but only because dir1/a's filelog changes.) | |||
|
127 | ||||
|
128 | $ hg co 'desc("add dir2")' | |||
|
129 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
130 | $ echo 8 > dir2/a | |||
|
131 | $ hg ci -m 'modify dir2/a' | |||
|
132 | created new head | |||
|
133 | ||||
|
134 | $ hg debugindex .hg/store/meta/dir2/00manifest.i > before | |||
|
135 | $ hg merge 'desc("modify dir1/a")' | |||
|
136 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
137 | (branch merge, don't forget to commit) | |||
|
138 | $ hg revert -r 'desc("modify dir2/a")' . | |||
|
139 | reverting dir1/a (glob) | |||
|
140 | $ hg ci -m 'merge, keeping parent 1' | |||
|
141 | $ hg debugindex .hg/store/meta/dir2/00manifest.i > after | |||
|
142 | $ diff before after | |||
|
143 | $ rm before after | |||
|
144 | ||||
|
145 | Merge keeping directory from parent 2 does not create revlog entry. (Note that | |||
|
146 | dir2's manifest does change, but only because dir2/a's filelog changes.) | |||
|
147 | ||||
|
148 | $ hg co 'desc("modify dir2/a")' | |||
|
149 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
150 | $ hg debugindex .hg/store/meta/dir1/00manifest.i > before | |||
|
151 | $ hg merge 'desc("modify dir1/a")' | |||
|
152 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
153 | (branch merge, don't forget to commit) | |||
|
154 | $ hg revert -r 'desc("modify dir1/a")' . | |||
|
155 | reverting dir2/a (glob) | |||
|
156 | $ hg ci -m 'merge, keeping parent 2' | |||
|
157 | created new head | |||
|
158 | $ hg debugindex .hg/store/meta/dir1/00manifest.i > after | |||
|
159 | $ diff before after | |||
|
160 | $ rm before after | |||
|
161 | ||||
|
162 | Create flat source repo for tests with mixed flat/tree manifests | |||
|
163 | ||||
|
164 | $ cd .. | |||
|
165 | $ hg init repo-flat | |||
|
166 | $ cd repo-flat | |||
|
167 | ||||
|
168 | Create a few commits with flat manifest | |||
|
169 | ||||
|
170 | $ echo 0 > a | |||
|
171 | $ echo 0 > b | |||
|
172 | $ echo 0 > e | |||
|
173 | $ for d in dir1 dir1/dir1 dir1/dir2 dir2 | |||
|
174 | > do | |||
|
175 | > mkdir $d | |||
|
176 | > echo 0 > $d/a | |||
|
177 | > echo 0 > $d/b | |||
|
178 | > done | |||
|
179 | $ hg ci -Aqm initial | |||
|
180 | ||||
|
181 | $ echo 1 > a | |||
|
182 | $ echo 1 > dir1/a | |||
|
183 | $ echo 1 > dir1/dir1/a | |||
|
184 | $ hg ci -Aqm 'modify on branch 1' | |||
|
185 | ||||
|
186 | $ hg co 0 | |||
|
187 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
188 | $ echo 2 > b | |||
|
189 | $ echo 2 > dir1/b | |||
|
190 | $ echo 2 > dir1/dir1/b | |||
|
191 | $ hg ci -Aqm 'modify on branch 2' | |||
|
192 | ||||
|
193 | $ hg merge 1 | |||
|
194 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
195 | (branch merge, don't forget to commit) | |||
|
196 | $ hg ci -m 'merge of flat manifests to new flat manifest' | |||
|
197 | ||||
|
198 | Create clone with tree manifests enabled | |||
|
199 | ||||
|
200 | $ cd .. | |||
|
201 | $ hg clone --pull --config experimental.treemanifest=1 repo-flat repo-mixed | |||
|
202 | requesting all changes | |||
|
203 | adding changesets | |||
|
204 | adding manifests | |||
|
205 | adding file changes | |||
|
206 | added 4 changesets with 17 changes to 11 files | |||
|
207 | updating to branch default | |||
|
208 | 11 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
209 | $ cd repo-mixed | |||
|
210 | $ test -f .hg/store/meta | |||
|
211 | [1] | |||
|
212 | $ grep treemanifest .hg/requires | |||
|
213 | treemanifest | |||
|
214 | ||||
|
215 | Commit should store revlog per directory | |||
|
216 | ||||
|
217 | $ hg co 1 | |||
|
218 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
219 | $ echo 3 > a | |||
|
220 | $ echo 3 > dir1/a | |||
|
221 | $ echo 3 > dir1/dir1/a | |||
|
222 | $ hg ci -m 'first tree' | |||
|
223 | created new head | |||
|
224 | $ find .hg/store/meta | sort | |||
|
225 | .hg/store/meta | |||
|
226 | .hg/store/meta/dir1 | |||
|
227 | .hg/store/meta/dir1/00manifest.i | |||
|
228 | .hg/store/meta/dir1/dir1 | |||
|
229 | .hg/store/meta/dir1/dir1/00manifest.i | |||
|
230 | .hg/store/meta/dir1/dir2 | |||
|
231 | .hg/store/meta/dir1/dir2/00manifest.i | |||
|
232 | .hg/store/meta/dir2 | |||
|
233 | .hg/store/meta/dir2/00manifest.i | |||
|
234 | ||||
|
235 | Merge of two trees | |||
|
236 | ||||
|
237 | $ hg co 2 | |||
|
238 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
239 | $ hg merge 1 | |||
|
240 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
241 | (branch merge, don't forget to commit) | |||
|
242 | $ hg ci -m 'merge of flat manifests to new tree manifest' | |||
|
243 | created new head | |||
|
244 | $ hg diff -r 3 | |||
|
245 | ||||
|
246 | Parent of tree root manifest should be flat manifest, and two for merge | |||
|
247 | ||||
|
248 | $ hg debugindex -m | |||
|
249 | rev offset length base linkrev nodeid p1 p2 | |||
|
250 | 0 0 80 0 0 40536115ed9e 000000000000 000000000000 | |||
|
251 | 1 80 83 0 1 f3376063c255 40536115ed9e 000000000000 | |||
|
252 | 2 163 103 0 2 5d9b9da231a2 40536115ed9e 000000000000 | |||
|
253 | 3 266 83 0 3 d17d663cbd8a 5d9b9da231a2 f3376063c255 | |||
|
254 | 4 349 132 4 4 c05a51345f86 f3376063c255 000000000000 | |||
|
255 | 5 481 110 4 5 82594b1f557d 5d9b9da231a2 f3376063c255 | |||
|
256 | ||||
|
257 | ||||
|
258 | Status across flat/tree boundary should work | |||
|
259 | ||||
|
260 | $ hg status --rev '.^' --rev . | |||
|
261 | M a | |||
|
262 | M dir1/a | |||
|
263 | M dir1/dir1/a | |||
|
264 | ||||
|
265 | ||||
|
266 | Turning off treemanifest config has no effect | |||
|
267 | ||||
|
268 | $ hg debugindex .hg/store/meta/dir1/00manifest.i | |||
|
269 | rev offset length base linkrev nodeid p1 p2 | |||
|
270 | 0 0 125 0 4 63c9c0557d24 000000000000 000000000000 | |||
|
271 | 1 125 109 0 5 23d12a1f6e0e 000000000000 000000000000 | |||
|
272 | $ echo 2 > dir1/a | |||
|
273 | $ hg --config experimental.treemanifest=False ci -qm 'modify dir1/a' | |||
|
274 | $ hg debugindex .hg/store/meta/dir1/00manifest.i | |||
|
275 | rev offset length base linkrev nodeid p1 p2 | |||
|
276 | 0 0 125 0 4 63c9c0557d24 000000000000 000000000000 | |||
|
277 | 1 125 109 0 5 23d12a1f6e0e 000000000000 000000000000 | |||
|
278 | 2 234 55 0 6 3cb2d87b4250 23d12a1f6e0e 000000000000 |
@@ -444,11 +444,15 b' def _splittopdir(f):' | |||||
444 | class treemanifest(object): |
|
444 | class treemanifest(object): | |
445 | def __init__(self, dir='', text=''): |
|
445 | def __init__(self, dir='', text=''): | |
446 | self._dir = dir |
|
446 | self._dir = dir | |
|
447 | self._node = revlog.nullid | |||
447 | self._dirs = {} |
|
448 | self._dirs = {} | |
448 | # Using _lazymanifest here is a little slower than plain old dicts |
|
449 | # Using _lazymanifest here is a little slower than plain old dicts | |
449 | self._files = {} |
|
450 | self._files = {} | |
450 | self._flags = {} |
|
451 | self._flags = {} | |
451 | self.parse(text) |
|
452 | def readsubtree(subdir, subm): | |
|
453 | raise AssertionError('treemanifest constructor only accepts ' | |||
|
454 | 'flat manifests') | |||
|
455 | self.parse(text, readsubtree) | |||
452 |
|
456 | |||
453 | def _subpath(self, path): |
|
457 | def _subpath(self, path): | |
454 | return self._dir + path |
|
458 | return self._dir + path | |
@@ -464,7 +468,22 b' class treemanifest(object):' | |||||
464 | util.all(m._isempty() for m in self._dirs.values()))) |
|
468 | util.all(m._isempty() for m in self._dirs.values()))) | |
465 |
|
469 | |||
466 | def __str__(self): |
|
470 | def __str__(self): | |
467 |
return '<treemanifest dir=%s>' % |
|
471 | return ('<treemanifest dir=%s, node=%s>' % | |
|
472 | (self._dir, revlog.hex(self._node))) | |||
|
473 | ||||
|
474 | def dir(self): | |||
|
475 | '''The directory that this tree manifest represents, including a | |||
|
476 | trailing '/'. Empty string for the repo root directory.''' | |||
|
477 | return self._dir | |||
|
478 | ||||
|
479 | def node(self): | |||
|
480 | '''This node of this instance. nullid for unsaved instances. Should | |||
|
481 | be updated when the instance is read or written from a revlog. | |||
|
482 | ''' | |||
|
483 | return self._node | |||
|
484 | ||||
|
485 | def setnode(self, node): | |||
|
486 | self._node = node | |||
468 |
|
487 | |||
469 | def iteritems(self): |
|
488 | def iteritems(self): | |
470 | for p, n in sorted(self._dirs.items() + self._files.items()): |
|
489 | for p, n in sorted(self._dirs.items() + self._files.items()): | |
@@ -557,6 +576,7 b' class treemanifest(object):' | |||||
557 |
|
576 | |||
558 | def setflag(self, f, flags): |
|
577 | def setflag(self, f, flags): | |
559 | """Set the flags (symlink, executable) for path f.""" |
|
578 | """Set the flags (symlink, executable) for path f.""" | |
|
579 | assert 'd' not in flags | |||
560 | dir, subpath = _splittopdir(f) |
|
580 | dir, subpath = _splittopdir(f) | |
561 | if dir: |
|
581 | if dir: | |
562 | if dir not in self._dirs: |
|
582 | if dir not in self._dirs: | |
@@ -567,6 +587,7 b' class treemanifest(object):' | |||||
567 |
|
587 | |||
568 | def copy(self): |
|
588 | def copy(self): | |
569 | copy = treemanifest(self._dir) |
|
589 | copy = treemanifest(self._dir) | |
|
590 | copy._node = self._node | |||
570 | for d in self._dirs: |
|
591 | for d in self._dirs: | |
571 | copy._dirs[d] = self._dirs[d].copy() |
|
592 | copy._dirs[d] = self._dirs[d].copy() | |
572 | copy._files = dict.copy(self._files) |
|
593 | copy._files = dict.copy(self._files) | |
@@ -737,8 +758,15 b' class treemanifest(object):' | |||||
737 | _diff(self, m2) |
|
758 | _diff(self, m2) | |
738 | return result |
|
759 | return result | |
739 |
|
760 | |||
740 | def parse(self, text): |
|
761 | def parse(self, text, readsubtree): | |
741 | for f, n, fl in _parse(text): |
|
762 | for f, n, fl in _parse(text): | |
|
763 | if fl == 'd': | |||
|
764 | f = f + '/' | |||
|
765 | self._dirs[f] = readsubtree(self._subpath(f), n) | |||
|
766 | else: | |||
|
767 | # Use __setitem__ and setflag rather than assigning directly | |||
|
768 | # to _files and _flags, thereby letting us parse flat manifests | |||
|
769 | # as well as tree manifests. | |||
742 | self[f] = n |
|
770 | self[f] = n | |
743 | if fl: |
|
771 | if fl: | |
744 | self.setflag(f, fl) |
|
772 | self.setflag(f, fl) | |
@@ -749,8 +777,26 b' class treemanifest(object):' | |||||
749 | return _text(((f, self[f], flags(f)) for f in self.keys()), |
|
777 | return _text(((f, self[f], flags(f)) for f in self.keys()), | |
750 | usemanifestv2) |
|
778 | usemanifestv2) | |
751 |
|
779 | |||
|
780 | def dirtext(self, usemanifestv2=False): | |||
|
781 | """Get the full data of this directory as a bytestring. Make sure that | |||
|
782 | any submanifests have been written first, so their nodeids are correct. | |||
|
783 | """ | |||
|
784 | flags = self.flags | |||
|
785 | dirs = [(d[:-1], self._dirs[d]._node, 'd') for d in self._dirs] | |||
|
786 | files = [(f, self._files[f], flags(f)) for f in self._files] | |||
|
787 | return _text(sorted(dirs + files), usemanifestv2) | |||
|
788 | ||||
|
789 | def writesubtrees(self, m1, m2, writesubtree): | |||
|
790 | emptytree = treemanifest() | |||
|
791 | for d, subm in self._dirs.iteritems(): | |||
|
792 | subp1 = m1._dirs.get(d, emptytree)._node | |||
|
793 | subp2 = m2._dirs.get(d, emptytree)._node | |||
|
794 | if subp1 == revlog.nullid: | |||
|
795 | subp1, subp2 = subp2, subp1 | |||
|
796 | writesubtree(subm, subp1, subp2) | |||
|
797 | ||||
752 | class manifest(revlog.revlog): |
|
798 | class manifest(revlog.revlog): | |
753 | def __init__(self, opener): |
|
799 | def __init__(self, opener, dir=''): | |
754 | # During normal operations, we expect to deal with not more than four |
|
800 | # During normal operations, we expect to deal with not more than four | |
755 | # revs at a time (such as during commit --amend). When rebasing large |
|
801 | # revs at a time (such as during commit --amend). When rebasing large | |
756 | # stacks of commits, the number can go up, hence the config knob below. |
|
802 | # stacks of commits, the number can go up, hence the config knob below. | |
@@ -763,14 +809,19 b' class manifest(revlog.revlog):' | |||||
763 | usetreemanifest = opts.get('treemanifest', usetreemanifest) |
|
809 | usetreemanifest = opts.get('treemanifest', usetreemanifest) | |
764 | usemanifestv2 = opts.get('manifestv2', usemanifestv2) |
|
810 | usemanifestv2 = opts.get('manifestv2', usemanifestv2) | |
765 | self._mancache = util.lrucachedict(cachesize) |
|
811 | self._mancache = util.lrucachedict(cachesize) | |
766 | revlog.revlog.__init__(self, opener, "00manifest.i") |
|
|||
767 | self._treeinmem = usetreemanifest |
|
812 | self._treeinmem = usetreemanifest | |
768 | self._treeondisk = usetreemanifest |
|
813 | self._treeondisk = usetreemanifest | |
769 | self._usemanifestv2 = usemanifestv2 |
|
814 | self._usemanifestv2 = usemanifestv2 | |
|
815 | indexfile = "00manifest.i" | |||
|
816 | if dir: | |||
|
817 | assert self._treeondisk | |||
|
818 | indexfile = "meta/" + dir + "00manifest.i" | |||
|
819 | revlog.revlog.__init__(self, opener, indexfile) | |||
|
820 | self._dir = dir | |||
770 |
|
821 | |||
771 | def _newmanifest(self, data=''): |
|
822 | def _newmanifest(self, data=''): | |
772 | if self._treeinmem: |
|
823 | if self._treeinmem: | |
773 |
return treemanifest( |
|
824 | return treemanifest(self._dir, data) | |
774 | return manifestdict(data) |
|
825 | return manifestdict(data) | |
775 |
|
826 | |||
776 | def _slowreaddelta(self, node): |
|
827 | def _slowreaddelta(self, node): | |
@@ -812,8 +863,17 b' class manifest(revlog.revlog):' | |||||
812 | if node in self._mancache: |
|
863 | if node in self._mancache: | |
813 | return self._mancache[node][0] |
|
864 | return self._mancache[node][0] | |
814 | text = self.revision(node) |
|
865 | text = self.revision(node) | |
|
866 | if self._treeondisk: | |||
|
867 | def readsubtree(dir, subm): | |||
|
868 | sublog = manifest(self.opener, dir) | |||
|
869 | return sublog.read(subm) | |||
|
870 | m = self._newmanifest() | |||
|
871 | m.parse(text, readsubtree) | |||
|
872 | m.setnode(node) | |||
|
873 | arraytext = None | |||
|
874 | else: | |||
|
875 | m = self._newmanifest(text) | |||
815 | arraytext = array.array('c', text) |
|
876 | arraytext = array.array('c', text) | |
816 | m = self._newmanifest(text) |
|
|||
817 | self._mancache[node] = (m, arraytext) |
|
877 | self._mancache[node] = (m, arraytext) | |
818 | return m |
|
878 | return m | |
819 |
|
879 | |||
@@ -851,10 +911,34 b' class manifest(revlog.revlog):' | |||||
851 | # just encode a fulltext of the manifest and pass that |
|
911 | # just encode a fulltext of the manifest and pass that | |
852 | # through to the revlog layer, and let it handle the delta |
|
912 | # through to the revlog layer, and let it handle the delta | |
853 | # process. |
|
913 | # process. | |
|
914 | if self._treeondisk: | |||
|
915 | m1 = self.read(p1) | |||
|
916 | m2 = self.read(p2) | |||
|
917 | n = self._addtree(m, transaction, link, m1, m2) | |||
|
918 | arraytext = None | |||
|
919 | else: | |||
854 | text = m.text(self._usemanifestv2) |
|
920 | text = m.text(self._usemanifestv2) | |
|
921 | n = self.addrevision(text, transaction, link, p1, p2) | |||
855 | arraytext = array.array('c', text) |
|
922 | arraytext = array.array('c', text) | |
856 | n = self.addrevision(text, transaction, link, p1, p2) |
|
|||
857 |
|
923 | |||
858 | self._mancache[n] = (m, arraytext) |
|
924 | self._mancache[n] = (m, arraytext) | |
859 |
|
925 | |||
860 | return n |
|
926 | return n | |
|
927 | ||||
|
928 | def _addtree(self, m, transaction, link, m1, m2): | |||
|
929 | def writesubtree(subm, subp1, subp2): | |||
|
930 | sublog = manifest(self.opener, subm.dir()) | |||
|
931 | sublog.add(subm, transaction, link, subp1, subp2, None, None) | |||
|
932 | m.writesubtrees(m1, m2, writesubtree) | |||
|
933 | text = m.dirtext(self._usemanifestv2) | |||
|
934 | # If the manifest is unchanged compared to one parent, | |||
|
935 | # don't write a new revision | |||
|
936 | if text == m1.dirtext(self._usemanifestv2): | |||
|
937 | n = m1.node() | |||
|
938 | elif text == m2.dirtext(self._usemanifestv2): | |||
|
939 | n = m2.node() | |||
|
940 | else: | |||
|
941 | n = self.addrevision(text, transaction, link, m1.node(), m2.node()) | |||
|
942 | # Save nodeid so parent manifest can calculate its nodeid | |||
|
943 | m.setnode(n) | |||
|
944 | return n |
@@ -187,7 +187,7 b' def _auxencode(path, dotencode):' | |||||
187 |
|
187 | |||
188 | def _hashencode(path, dotencode): |
|
188 | def _hashencode(path, dotencode): | |
189 | digest = _sha(path).hexdigest() |
|
189 | digest = _sha(path).hexdigest() | |
190 | le = lowerencode(path[5:]).split('/') # skips prefix 'data/' |
|
190 | le = lowerencode(path[5:]).split('/') # skips prefix 'data/' or 'meta/' | |
191 | parts = _auxencode(le, dotencode) |
|
191 | parts = _auxencode(le, dotencode) | |
192 | basename = parts[-1] |
|
192 | basename = parts[-1] | |
193 | _root, ext = os.path.splitext(basename) |
|
193 | _root, ext = os.path.splitext(basename) |
General Comments 0
You need to be logged in to leave comments.
Login now