Show More
1 | NO CONTENT: new file 100644, binary diff hidden |
|
NO CONTENT: new file 100644, binary diff hidden |
@@ -0,0 +1,153 b'' | |||||
|
1 | ============================================ | |||
|
2 | Testing various race condition while pushing | |||
|
3 | ============================================ | |||
|
4 | ||||
|
5 | $ cat << EOF >> $HGRCPATH | |||
|
6 | > [command-templates] | |||
|
7 | > log={rev}:{node|short} {desc|firstline} {bookmarks} | |||
|
8 | > [ui] | |||
|
9 | > timeout = 20 | |||
|
10 | > [phases] | |||
|
11 | > publish=False | |||
|
12 | > EOF | |||
|
13 | ||||
|
14 | Initial Setup | |||
|
15 | ============= | |||
|
16 | ||||
|
17 | $ hg init dst | |||
|
18 | $ echo a > dst/a-file | |||
|
19 | $ hg --cwd dst add a-file | |||
|
20 | $ hg --cwd dst commit -m root | |||
|
21 | $ hg --cwd dst bookmark my-book | |||
|
22 | $ hg --cwd dst bookmarks | |||
|
23 | * my-book 0:a64e49638499 | |||
|
24 | $ hg --cwd dst log -G | |||
|
25 | @ 0:a64e49638499 root my-book | |||
|
26 | ||||
|
27 | ||||
|
28 | $ hg clone ssh://user@dummy/dst src | |||
|
29 | requesting all changes | |||
|
30 | adding changesets | |||
|
31 | adding manifests | |||
|
32 | adding file changes | |||
|
33 | added 1 changesets with 1 changes to 1 files | |||
|
34 | new changesets a64e49638499 (1 drafts) | |||
|
35 | updating to branch default | |||
|
36 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
37 | $ hg --cwd src update my-book | |||
|
38 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
39 | (activating bookmark my-book) | |||
|
40 | $ hg --cwd src log -G | |||
|
41 | @ 0:a64e49638499 root my-book | |||
|
42 | ||||
|
43 | ||||
|
44 | $ echo b > src/a-file | |||
|
45 | $ hg --cwd src commit -m cA0_ | |||
|
46 | $ hg --cwd src log -G | |||
|
47 | @ 1:e89d3a6ed79b cA0_ my-book | |||
|
48 | | | |||
|
49 | o 0:a64e49638499 root | |||
|
50 | ||||
|
51 | ||||
|
52 | Race condition while pushing a forward moving bookmarks | |||
|
53 | ======================================================= | |||
|
54 | ||||
|
55 | This is currently slightly broken as we eventually don't push the bookmark. | |||
|
56 | However at least we do not delete the remote one. | |||
|
57 | ||||
|
58 | $ echo c > src/a-file | |||
|
59 | $ hg --cwd src push -B my-book --config hooks.prelock="hg commit -m cA1_" | |||
|
60 | pushing to ssh://user@dummy/dst | |||
|
61 | searching for changes | |||
|
62 | remote: adding changesets | |||
|
63 | remote: adding manifests | |||
|
64 | remote: adding file changes | |||
|
65 | remote: added 1 changesets with 1 changes to 1 files | |||
|
66 | $ hg --cwd src log -G | |||
|
67 | @ 2:08d837bbfe8d cA1_ my-book | |||
|
68 | | | |||
|
69 | o 1:e89d3a6ed79b cA0_ | |||
|
70 | | | |||
|
71 | o 0:a64e49638499 root | |||
|
72 | ||||
|
73 | $ hg --cwd dst log -G | |||
|
74 | o 1:e89d3a6ed79b cA0_ | |||
|
75 | | | |||
|
76 | @ 0:a64e49638499 root my-book | |||
|
77 | ||||
|
78 | ||||
|
79 | create a side-moving bookmark | |||
|
80 | Race condition while pushing a side moving bookmarks | |||
|
81 | ======================================================= | |||
|
82 | ||||
|
83 | resynchronize the repo and setup test | |||
|
84 | ------------------------------------- | |||
|
85 | ||||
|
86 | $ hg --cwd src push -B my-book | |||
|
87 | pushing to ssh://user@dummy/dst | |||
|
88 | searching for changes | |||
|
89 | remote: adding changesets | |||
|
90 | remote: adding manifests | |||
|
91 | remote: adding file changes | |||
|
92 | remote: added 1 changesets with 1 changes to 1 files | |||
|
93 | updating bookmark my-book | |||
|
94 | $ hg --cwd dst log -G | |||
|
95 | o 2:08d837bbfe8d cA1_ my-book | |||
|
96 | | | |||
|
97 | o 1:e89d3a6ed79b cA0_ | |||
|
98 | | | |||
|
99 | @ 0:a64e49638499 root | |||
|
100 | ||||
|
101 | ||||
|
102 | $ hg --cwd src up 'desc("root")' | |||
|
103 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
104 | (leaving bookmark my-book) | |||
|
105 | $ echo d > src/a-file | |||
|
106 | $ hg --cwd src commit -m cB0_ | |||
|
107 | created new head | |||
|
108 | $ hg --cwd src bookmark --force my-book | |||
|
109 | $ echo e > src/a-file | |||
|
110 | $ hg --cwd src log -G | |||
|
111 | @ 3:726401661fe5 cB0_ my-book | |||
|
112 | | | |||
|
113 | | o 2:08d837bbfe8d cA1_ | |||
|
114 | | | | |||
|
115 | | o 1:e89d3a6ed79b cA0_ | |||
|
116 | |/ | |||
|
117 | o 0:a64e49638499 root | |||
|
118 | ||||
|
119 | ||||
|
120 | Push the bookmark while a commit is being made | |||
|
121 | ---------------------------------------------- | |||
|
122 | ||||
|
123 | This is currently slightly broken as we eventually don't push the bookmark. | |||
|
124 | However at least we do not delete the remote one. | |||
|
125 | ||||
|
126 | $ hg --cwd src push -f -r 'desc("cB0_")' -B my-book --config hooks.prelock="hg commit -m cB1_" | |||
|
127 | pushing to ssh://user@dummy/dst | |||
|
128 | searching for changes | |||
|
129 | remote: adding changesets | |||
|
130 | remote: adding manifests | |||
|
131 | remote: adding file changes | |||
|
132 | remote: added 1 changesets with 1 changes to 1 files (+1 heads) | |||
|
133 | $ hg --cwd src log -G | |||
|
134 | @ 4:a7f9cbf631a0 cB1_ my-book | |||
|
135 | | | |||
|
136 | o 3:726401661fe5 cB0_ | |||
|
137 | | | |||
|
138 | | o 2:08d837bbfe8d cA1_ | |||
|
139 | | | | |||
|
140 | | o 1:e89d3a6ed79b cA0_ | |||
|
141 | |/ | |||
|
142 | o 0:a64e49638499 root | |||
|
143 | ||||
|
144 | ||||
|
145 | $ hg --cwd dst log -G | |||
|
146 | o 3:726401661fe5 cB0_ | |||
|
147 | | | |||
|
148 | | o 2:08d837bbfe8d cA1_ my-book | |||
|
149 | | | | |||
|
150 | | o 1:e89d3a6ed79b cA0_ | |||
|
151 | |/ | |||
|
152 | @ 0:a64e49638499 root | |||
|
153 |
@@ -0,0 +1,303 b'' | |||||
|
1 | ====================================================== | |||
|
2 | Test operation on repository with an inlined changelog | |||
|
3 | ====================================================== | |||
|
4 | ||||
|
5 | Inlined revlog has been a bag of complexity for a long time and the combination | |||
|
6 | with special transaction logic on the changelog was a long source of bugs | |||
|
7 | poorly covered by the test suites. | |||
|
8 | ||||
|
9 | We stopped doing any usage of inlined-revlog for changelog in a93e52f0b6ff, | |||
|
10 | upgrading legacy inlined version as soon as possible when we see them. However | |||
|
11 | this Mercurial does not produce such inlined-changelog that case is very poorly | |||
|
12 | covered in the test suites. This test file aims at covering these cases. | |||
|
13 | ||||
|
14 | Double checking test data | |||
|
15 | ========================= | |||
|
16 | ||||
|
17 | We should have a repository around | |||
|
18 | ||||
|
19 | $ mkdir sanity-check | |||
|
20 | $ cd sanity-check | |||
|
21 | $ tar xf $TESTDIR/bundles/inlined-changelog.tar | |||
|
22 | $ cd inlined-changelog | |||
|
23 | $ hg root | |||
|
24 | $TESTTMP/sanity-check/inlined-changelog | |||
|
25 | ||||
|
26 | The repository should not be corrupted initially | |||
|
27 | ||||
|
28 | $ hg verify | |||
|
29 | checking changesets | |||
|
30 | checking manifests | |||
|
31 | crosschecking files in changesets and manifests | |||
|
32 | checking files | |||
|
33 | checking dirstate | |||
|
34 | checked 1 changesets with 1 changes to 1 files | |||
|
35 | ||||
|
36 | The changelog of that repository MUST be inlined | |||
|
37 | ||||
|
38 | $ hg debugrevlog -c | grep -E '^flags\b' | |||
|
39 | flags : inline | |||
|
40 | ||||
|
41 | Touching that repository MUST split that inlined changelog | |||
|
42 | ||||
|
43 | $ hg branch foo --quiet | |||
|
44 | $ hg commit -m foo --quiet | |||
|
45 | $ hg debugrevlog -c | grep -E '^flags\b' | |||
|
46 | flags : (none) | |||
|
47 | ||||
|
48 | $ cd ../.. | |||
|
49 | ||||
|
50 | Test doing a simple commit | |||
|
51 | ========================== | |||
|
52 | ||||
|
53 | Simple commit | |||
|
54 | ------------- | |||
|
55 | ||||
|
56 | $ mkdir simple-commit | |||
|
57 | $ cd simple-commit | |||
|
58 | $ tar xf $TESTDIR/bundles/inlined-changelog.tar | |||
|
59 | $ cd inlined-changelog | |||
|
60 | $ hg up --quiet | |||
|
61 | $ hg log -GT '[{rev}] {desc}\n' | |||
|
62 | @ [0] first commit | |||
|
63 | ||||
|
64 | $ echo b > b | |||
|
65 | $ hg add b | |||
|
66 | $ hg commit -m "second changeset" | |||
|
67 | $ hg verify | |||
|
68 | checking changesets | |||
|
69 | checking manifests | |||
|
70 | crosschecking files in changesets and manifests | |||
|
71 | checking files | |||
|
72 | checking dirstate | |||
|
73 | checked 2 changesets with 2 changes to 2 files | |||
|
74 | $ hg log -GT '[{rev}] {desc}\n' | |||
|
75 | @ [1] second changeset | |||
|
76 | | | |||
|
77 | o [0] first commit | |||
|
78 | ||||
|
79 | $ cd ../.. | |||
|
80 | ||||
|
81 | Simple commit with a pretxn hook configured | |||
|
82 | ------------------------------------------- | |||
|
83 | ||||
|
84 | Before 6.7.3 this used to delete the changelog index | |||
|
85 | ||||
|
86 | $ mkdir pretxnclose-commit | |||
|
87 | $ cd pretxnclose-commit | |||
|
88 | $ tar xf $TESTDIR/bundles/inlined-changelog.tar | |||
|
89 | $ cat >> inlined-changelog/.hg/hgrc <<EOF | |||
|
90 | > [hooks] | |||
|
91 | > pretxnclose=hg log -r tip -T "pre-txn tip rev: {rev}\n" | |||
|
92 | > EOF | |||
|
93 | $ cd inlined-changelog | |||
|
94 | $ hg up --quiet | |||
|
95 | $ hg log -GT '[{rev}] {desc}\n' | |||
|
96 | @ [0] first commit | |||
|
97 | ||||
|
98 | $ echo b > b | |||
|
99 | $ hg add b | |||
|
100 | $ hg commit -m "second changeset" | |||
|
101 | pre-txn tip rev: 1 | |||
|
102 | $ hg verify | |||
|
103 | checking changesets | |||
|
104 | checking manifests | |||
|
105 | crosschecking files in changesets and manifests | |||
|
106 | checking files | |||
|
107 | checking dirstate | |||
|
108 | checked 2 changesets with 2 changes to 2 files | |||
|
109 | $ hg log -GT '[{rev}] {desc}\n' | |||
|
110 | @ [1] second changeset | |||
|
111 | | | |||
|
112 | o [0] first commit | |||
|
113 | ||||
|
114 | $ cd ../.. | |||
|
115 | ||||
|
116 | Test pushing to a repository with a repository revlog | |||
|
117 | ===================================================== | |||
|
118 | ||||
|
119 | Simple local push | |||
|
120 | ----------------- | |||
|
121 | ||||
|
122 | $ mkdir simple-local-push | |||
|
123 | $ cd simple-local-push | |||
|
124 | $ tar xf $TESTDIR/bundles/inlined-changelog.tar | |||
|
125 | $ hg log -R inlined-changelog -T '[{rev}] {desc}\n' | |||
|
126 | [0] first commit | |||
|
127 | ||||
|
128 | $ hg clone --pull inlined-changelog client | |||
|
129 | requesting all changes | |||
|
130 | adding changesets | |||
|
131 | adding manifests | |||
|
132 | adding file changes | |||
|
133 | added 1 changesets with 1 changes to 1 files | |||
|
134 | new changesets 827f11bfd362 | |||
|
135 | updating to branch default | |||
|
136 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
137 | $ cd client | |||
|
138 | $ echo b > b | |||
|
139 | $ hg add b | |||
|
140 | $ hg commit -m "second changeset" | |||
|
141 | $ hg push | |||
|
142 | pushing to $TESTTMP/*/inlined-changelog (glob) | |||
|
143 | searching for changes | |||
|
144 | adding changesets | |||
|
145 | adding manifests | |||
|
146 | adding file changes | |||
|
147 | added 1 changesets with 1 changes to 1 files | |||
|
148 | $ cd .. | |||
|
149 | ||||
|
150 | $ hg verify -R inlined-changelog | |||
|
151 | checking changesets | |||
|
152 | checking manifests | |||
|
153 | crosschecking files in changesets and manifests | |||
|
154 | checking files | |||
|
155 | checking dirstate | |||
|
156 | checked 2 changesets with 2 changes to 2 files | |||
|
157 | $ hg log -R inlined-changelog -T '[{rev}] {desc}\n' | |||
|
158 | [1] second changeset | |||
|
159 | [0] first commit | |||
|
160 | $ cd .. | |||
|
161 | ||||
|
162 | Simple local push with a pretxnchangegroup hook | |||
|
163 | ----------------------------------------------- | |||
|
164 | ||||
|
165 | Before 6.7.3 this used to delete the server changelog | |||
|
166 | ||||
|
167 | $ mkdir pretxnchangegroup-local-push | |||
|
168 | $ cd pretxnchangegroup-local-push | |||
|
169 | $ tar xf $TESTDIR/bundles/inlined-changelog.tar | |||
|
170 | $ cat >> inlined-changelog/.hg/hgrc <<EOF | |||
|
171 | > [hooks] | |||
|
172 | > pretxnchangegroup=hg log -r tip -T "pre-txn tip rev: {rev}\n" | |||
|
173 | > EOF | |||
|
174 | $ hg log -R inlined-changelog -T '[{rev}] {desc}\n' | |||
|
175 | [0] first commit | |||
|
176 | ||||
|
177 | $ hg clone --pull inlined-changelog client | |||
|
178 | requesting all changes | |||
|
179 | adding changesets | |||
|
180 | adding manifests | |||
|
181 | adding file changes | |||
|
182 | added 1 changesets with 1 changes to 1 files | |||
|
183 | new changesets 827f11bfd362 | |||
|
184 | updating to branch default | |||
|
185 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
186 | $ cd client | |||
|
187 | $ echo b > b | |||
|
188 | $ hg add b | |||
|
189 | $ hg commit -m "second changeset" | |||
|
190 | $ hg push | |||
|
191 | pushing to $TESTTMP/*/inlined-changelog (glob) | |||
|
192 | searching for changes | |||
|
193 | adding changesets | |||
|
194 | adding manifests | |||
|
195 | adding file changes | |||
|
196 | pre-txn tip rev: 1 | |||
|
197 | added 1 changesets with 1 changes to 1 files | |||
|
198 | $ cd .. | |||
|
199 | ||||
|
200 | $ hg verify -R inlined-changelog | |||
|
201 | checking changesets | |||
|
202 | checking manifests | |||
|
203 | crosschecking files in changesets and manifests | |||
|
204 | checking files | |||
|
205 | checking dirstate | |||
|
206 | checked 2 changesets with 2 changes to 2 files | |||
|
207 | $ hg log -R inlined-changelog -T '[{rev}] {desc}\n' | |||
|
208 | [1] second changeset | |||
|
209 | [0] first commit | |||
|
210 | $ cd .. | |||
|
211 | ||||
|
212 | Simple ssh push | |||
|
213 | ----------------- | |||
|
214 | ||||
|
215 | $ mkdir simple-ssh-push | |||
|
216 | $ cd simple-ssh-push | |||
|
217 | $ tar xf $TESTDIR/bundles/inlined-changelog.tar | |||
|
218 | $ hg log -R inlined-changelog -T '[{rev}] {desc}\n' | |||
|
219 | [0] first commit | |||
|
220 | ||||
|
221 | $ hg clone ssh://user@dummy/"`pwd`"/inlined-changelog client | |||
|
222 | requesting all changes | |||
|
223 | adding changesets | |||
|
224 | adding manifests | |||
|
225 | adding file changes | |||
|
226 | added 1 changesets with 1 changes to 1 files | |||
|
227 | new changesets 827f11bfd362 | |||
|
228 | updating to branch default | |||
|
229 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
230 | $ cd client | |||
|
231 | $ echo b > b | |||
|
232 | $ hg add b | |||
|
233 | $ hg commit -m "second changeset" | |||
|
234 | $ hg push | |||
|
235 | pushing to ssh://user@dummy/$TESTTMP/simple-ssh-push/inlined-changelog | |||
|
236 | searching for changes | |||
|
237 | remote: adding changesets | |||
|
238 | remote: adding manifests | |||
|
239 | remote: adding file changes | |||
|
240 | remote: added 1 changesets with 1 changes to 1 files | |||
|
241 | $ cd .. | |||
|
242 | ||||
|
243 | $ hg verify -R inlined-changelog | |||
|
244 | checking changesets | |||
|
245 | checking manifests | |||
|
246 | crosschecking files in changesets and manifests | |||
|
247 | checking files | |||
|
248 | checking dirstate | |||
|
249 | checked 2 changesets with 2 changes to 2 files | |||
|
250 | $ hg log -R inlined-changelog -T '[{rev}] {desc}\n' | |||
|
251 | [1] second changeset | |||
|
252 | [0] first commit | |||
|
253 | $ cd .. | |||
|
254 | ||||
|
255 | Simple ssh push with a pretxnchangegroup hook | |||
|
256 | ----------------------------------------------- | |||
|
257 | ||||
|
258 | Before 6.7.3 this used to delete the server changelog | |||
|
259 | ||||
|
260 | $ mkdir pretxnchangegroup-ssh-push | |||
|
261 | $ cd pretxnchangegroup-ssh-push | |||
|
262 | $ tar xf $TESTDIR/bundles/inlined-changelog.tar | |||
|
263 | $ cat >> inlined-changelog/.hg/hgrc <<EOF | |||
|
264 | > [hooks] | |||
|
265 | > pretxnchangegroup=hg log -r tip -T "pre-txn tip rev: {rev}\n" | |||
|
266 | > EOF | |||
|
267 | $ hg log -R inlined-changelog -T '[{rev}] {desc}\n' | |||
|
268 | [0] first commit | |||
|
269 | ||||
|
270 | $ hg clone ssh://user@dummy/"`pwd`"/inlined-changelog client | |||
|
271 | requesting all changes | |||
|
272 | adding changesets | |||
|
273 | adding manifests | |||
|
274 | adding file changes | |||
|
275 | added 1 changesets with 1 changes to 1 files | |||
|
276 | new changesets 827f11bfd362 | |||
|
277 | updating to branch default | |||
|
278 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
279 | $ cd client | |||
|
280 | $ echo b > b | |||
|
281 | $ hg add b | |||
|
282 | $ hg commit -m "second changeset" | |||
|
283 | $ hg push | |||
|
284 | pushing to ssh://user@dummy/$TESTTMP/pretxnchangegroup-ssh-push/inlined-changelog | |||
|
285 | searching for changes | |||
|
286 | remote: adding changesets | |||
|
287 | remote: adding manifests | |||
|
288 | remote: adding file changes | |||
|
289 | remote: pre-txn tip rev: 1 | |||
|
290 | remote: added 1 changesets with 1 changes to 1 files | |||
|
291 | $ cd .. | |||
|
292 | ||||
|
293 | $ hg verify -R inlined-changelog | |||
|
294 | checking changesets | |||
|
295 | checking manifests | |||
|
296 | crosschecking files in changesets and manifests | |||
|
297 | checking files | |||
|
298 | checking dirstate | |||
|
299 | checked 2 changesets with 2 changes to 2 files | |||
|
300 | $ hg log -R inlined-changelog -T '[{rev}] {desc}\n' | |||
|
301 | [1] second changeset | |||
|
302 | [0] first commit | |||
|
303 | $ cd .. |
@@ -261,3 +261,4 b' c9ceb4f6025690167bdb245e530de6bac8baae95' | |||||
261 | 2e6fde2ed01e63f0de6a5966994fbb60b1f87057 0 iQHNBAABCgA3FiEEH2b4zfZU6QXBHaBhoR4BzQ4F2VYFAmX8GPUZHGFscGhhcmVAcmFwaGFlbGdvbWVzLmRldgAKCRChHgHNDgXZVpWgC/9SVyelSQOgPVhSWkIExRw5fW1pwDa3RfVWf050o1SGzRpiTwKdKSyiOslxVEv/N59Gro/lqhKg210naBgBiii+RUsADFPS8mHCGuZsYPcRlmpgGoSsN8LF6IxrPqyWnHie2KKPJ68PyAF/9ciUH6Cc+0/gVcd1p6xsHjTp7X/AhKJBImojg/23+3jDN8FVfJus7doRnWU1k10QUGhtWkdiabIdKir6iKroTgT6gEoZs6t0OkIcfGmXYXFzvF+0GHSSXiDUfRbzbizH8T2UhsvYVcAISTmaxfJka4/ZshbPA+lmUS68BkOOp6Qc6Flq+lp+wqnfim9hniAw52QZu6ts9yipdJvYGI7KiWGf7gxTwQsdBuhD01SArsPfCpcHLD9u0lfGSrmX6rt9tELZBqBDFD25Cq1IRU6fV/A2hd7Ohp+K4ypAWdwdR7Od1NGGT7R0r5WOf7itGkEyKu0GldQgLbvx9Drzex5KryQU3urqIHUCSE1rWc/4EZcnNuyedfI= |
|
261 | 2e6fde2ed01e63f0de6a5966994fbb60b1f87057 0 iQHNBAABCgA3FiEEH2b4zfZU6QXBHaBhoR4BzQ4F2VYFAmX8GPUZHGFscGhhcmVAcmFwaGFlbGdvbWVzLmRldgAKCRChHgHNDgXZVpWgC/9SVyelSQOgPVhSWkIExRw5fW1pwDa3RfVWf050o1SGzRpiTwKdKSyiOslxVEv/N59Gro/lqhKg210naBgBiii+RUsADFPS8mHCGuZsYPcRlmpgGoSsN8LF6IxrPqyWnHie2KKPJ68PyAF/9ciUH6Cc+0/gVcd1p6xsHjTp7X/AhKJBImojg/23+3jDN8FVfJus7doRnWU1k10QUGhtWkdiabIdKir6iKroTgT6gEoZs6t0OkIcfGmXYXFzvF+0GHSSXiDUfRbzbizH8T2UhsvYVcAISTmaxfJka4/ZshbPA+lmUS68BkOOp6Qc6Flq+lp+wqnfim9hniAw52QZu6ts9yipdJvYGI7KiWGf7gxTwQsdBuhD01SArsPfCpcHLD9u0lfGSrmX6rt9tELZBqBDFD25Cq1IRU6fV/A2hd7Ohp+K4ypAWdwdR7Od1NGGT7R0r5WOf7itGkEyKu0GldQgLbvx9Drzex5KryQU3urqIHUCSE1rWc/4EZcnNuyedfI= | |
262 | 803e61387e86f103483120df35619bdb175e3482 0 iQHNBAABCgA3FiEEH2b4zfZU6QXBHaBhoR4BzQ4F2VYFAmYHJnMZHGFscGhhcmVAcmFwaGFlbGdvbWVzLmRldgAKCRChHgHNDgXZVtjcC/9VT/P5JmTSuC/8ldmj04IoVB/rG3c7o0bC6mu9ggP9wsyr7g6cqQrK1bnDtrXEpFzSEYI8314uep6ZFrFQJR/LuDAntRL0b5aBgXXxeaR7jVRlrcICbHK0kjESOKYOw90EQdJ4d4NPliJ7QLCk0JCptKWJUM/eNkZGlCokXx4OK+xn4SZF4d+WlcyhN5GOGFDb3Tb4gUKSvXw20rs6wB9QRKHpxDLPL2aO8ziHpuw5YaNvjkLuPhQsLcM04wPzv2mA1F+hX+PIK+4FHSS7rQQy1gRVR5ihtjJJWD+3eZ+FoMvXwoNLE0xqg89BZBySsO20dQFPpHjcvwp7VyIzpWCE5a9RbNtL//sQ8YxLBUEMb4HS5CpQOBTcy7a/uMmwQXfE1C8nvAvuMBafe3aOL1hy3hTtG6UhICoGMqF3ntKWOJL6aCE+qRusnGE63m3MuJJFlqL5Zfqs3oUTriGeePraaU7g2FXI0RrEflmLlK0Sc0tfegpk597YnxjcOk4lcfo= |
|
262 | 803e61387e86f103483120df35619bdb175e3482 0 iQHNBAABCgA3FiEEH2b4zfZU6QXBHaBhoR4BzQ4F2VYFAmYHJnMZHGFscGhhcmVAcmFwaGFlbGdvbWVzLmRldgAKCRChHgHNDgXZVtjcC/9VT/P5JmTSuC/8ldmj04IoVB/rG3c7o0bC6mu9ggP9wsyr7g6cqQrK1bnDtrXEpFzSEYI8314uep6ZFrFQJR/LuDAntRL0b5aBgXXxeaR7jVRlrcICbHK0kjESOKYOw90EQdJ4d4NPliJ7QLCk0JCptKWJUM/eNkZGlCokXx4OK+xn4SZF4d+WlcyhN5GOGFDb3Tb4gUKSvXw20rs6wB9QRKHpxDLPL2aO8ziHpuw5YaNvjkLuPhQsLcM04wPzv2mA1F+hX+PIK+4FHSS7rQQy1gRVR5ihtjJJWD+3eZ+FoMvXwoNLE0xqg89BZBySsO20dQFPpHjcvwp7VyIzpWCE5a9RbNtL//sQ8YxLBUEMb4HS5CpQOBTcy7a/uMmwQXfE1C8nvAvuMBafe3aOL1hy3hTtG6UhICoGMqF3ntKWOJL6aCE+qRusnGE63m3MuJJFlqL5Zfqs3oUTriGeePraaU7g2FXI0RrEflmLlK0Sc0tfegpk597YnxjcOk4lcfo= | |
263 | 028dc3f92dbd0f93bb78f9848c94ba5eecd72e71 0 iQHNBAABCgA3FiEEH2b4zfZU6QXBHaBhoR4BzQ4F2VYFAmY5CeIZHGFscGhhcmVAcmFwaGFlbGdvbWVzLmRldgAKCRChHgHNDgXZVvLhDACbr7OFlk4NzOL00QS4P7+A47SXxbQnR6Zag3MXG48Kv0PzCy3YEfxJHcsAN/x4C67BO7rasLi6hinNaIysyLc0aDRqCow2fR/VRoMCnW8cJjKIzgpB134r6jRdxjkNXzPvydYxPazpGgz/B1tsBejYmSTShfvCO6MmgGhAzD78TwxgqbBKPKlrTDtv+A2sBi/Uyv4PCCOdfVHNlfBlcaRjhzBKH7l6ckXWO8L0LBcksH2TVUMgE/jMP1gx35FNQSV0BSqXsnq9+sHhscFoMjcb8RjEUOOeYqQNvqbp9ldQlGU1H/OD42zUjQU66XwhAtMzw57jGyb8DUiG0BtYhK4+N+oGi9wzTrvoZGzKbSiTRP76mzIudyghITh0rD8AEwj3ke/EXoFZDZcNk48xdMaJ1cmXnsbWUCA7thtfFoPpC8prf0BXY+MGjiYnqUEikUJIzP/1z6By7H28mR9I4XifXW15vL5gDFrBJsao6PVb19inya3Zj49dXouU9Zu/iUk= |
|
263 | 028dc3f92dbd0f93bb78f9848c94ba5eecd72e71 0 iQHNBAABCgA3FiEEH2b4zfZU6QXBHaBhoR4BzQ4F2VYFAmY5CeIZHGFscGhhcmVAcmFwaGFlbGdvbWVzLmRldgAKCRChHgHNDgXZVvLhDACbr7OFlk4NzOL00QS4P7+A47SXxbQnR6Zag3MXG48Kv0PzCy3YEfxJHcsAN/x4C67BO7rasLi6hinNaIysyLc0aDRqCow2fR/VRoMCnW8cJjKIzgpB134r6jRdxjkNXzPvydYxPazpGgz/B1tsBejYmSTShfvCO6MmgGhAzD78TwxgqbBKPKlrTDtv+A2sBi/Uyv4PCCOdfVHNlfBlcaRjhzBKH7l6ckXWO8L0LBcksH2TVUMgE/jMP1gx35FNQSV0BSqXsnq9+sHhscFoMjcb8RjEUOOeYqQNvqbp9ldQlGU1H/OD42zUjQU66XwhAtMzw57jGyb8DUiG0BtYhK4+N+oGi9wzTrvoZGzKbSiTRP76mzIudyghITh0rD8AEwj3ke/EXoFZDZcNk48xdMaJ1cmXnsbWUCA7thtfFoPpC8prf0BXY+MGjiYnqUEikUJIzP/1z6By7H28mR9I4XifXW15vL5gDFrBJsao6PVb19inya3Zj49dXouU9Zu/iUk= | |
|
264 | a1a011d4b148955975cb40d619d285fdd4ee8713 0 iQHNBAABCgA3FiEEH2b4zfZU6QXBHaBhoR4BzQ4F2VYFAmZpaeIZHGFscGhhcmVAcmFwaGFlbGdvbWVzLmRldgAKCRChHgHNDgXZVhrTDACQ9OcYqWavkmdvILr6NbosTIg4i502iG/3OaKiV9PJIyQx3MAIx72fbQJK4nFEKu4Y7Bk7uHX/wH0mXxSYQR4hqslqfR+x6U4P382BzCOdyXZO7nXZYQVgtIvYhkHMkBVJzXcU/ECYgRLHSHS2vU2eHx2l3kRUV4BRvXvgeVo6oszftmOrJfVcjNg+vUvalJ/NIWs8+v9mFVhyeF+8iFeDyHarwG0Eht0btNmZK7MIadqh5IsNipzoLhPFzFJYkdGXZ1uJfI1oA/I4aCwo3NcTNCZ6uUYZOQ8FLhsj5LsyYAsFnVSDl0YwCebeIRiUUu7C3iPpn345VZUVx+HGlQTn92Iroy3L8j4cWLpd4VpL2OX+eX0jS0nSEPUOBMIAVWKrLYAcBxANo3jDC22hZuKJYX4IycQ+MvS7v5vOuP69xchcZnDfrwq4PWq1NBJlJ5EIA396RgIQD+bNQ/WF41vEIPQOiM9V4EmMGKBt3cwZlGIEWHaV6dbsXk4PSwmbu1M= |
@@ -277,3 +277,4 b' c9ceb4f6025690167bdb245e530de6bac8baae95' | |||||
277 | 2e6fde2ed01e63f0de6a5966994fbb60b1f87057 6.7.1 |
|
277 | 2e6fde2ed01e63f0de6a5966994fbb60b1f87057 6.7.1 | |
278 | 803e61387e86f103483120df35619bdb175e3482 6.7.2 |
|
278 | 803e61387e86f103483120df35619bdb175e3482 6.7.2 | |
279 | 028dc3f92dbd0f93bb78f9848c94ba5eecd72e71 6.7.3 |
|
279 | 028dc3f92dbd0f93bb78f9848c94ba5eecd72e71 6.7.3 | |
|
280 | a1a011d4b148955975cb40d619d285fdd4ee8713 6.7.4 |
@@ -360,8 +360,10 b' class changelog(revlog.revlog):' | |||||
360 | if new_index is not None: |
|
360 | if new_index is not None: | |
361 | self._indexfile = new_index |
|
361 | self._indexfile = new_index | |
362 | tr.registertmp(new_index) |
|
362 | tr.registertmp(new_index) | |
363 | tr.addpending(b'cl-%i' % id(self), self._writepending) |
|
363 | # use "000" as prefix to make sure we run before the spliting of legacy | |
364 | tr.addfinalize(b'cl-%i' % id(self), self._finalize) |
|
364 | # inline changelog.. | |
|
365 | tr.addpending(b'000-cl-%i' % id(self), self._writepending) | |||
|
366 | tr.addfinalize(b'000-cl-%i' % id(self), self._finalize) | |||
365 |
|
367 | |||
366 | def _finalize(self, tr): |
|
368 | def _finalize(self, tr): | |
367 | """finalize index updates""" |
|
369 | """finalize index updates""" |
@@ -490,42 +490,46 b' def push(' | |||||
490 | # get lock as we might write phase data |
|
490 | # get lock as we might write phase data | |
491 | wlock = lock = None |
|
491 | wlock = lock = None | |
492 | try: |
|
492 | try: | |
493 | # bundle2 push may receive a reply bundle touching bookmarks |
|
493 | try: | |
494 | # requiring the wlock. Take it now to ensure proper ordering. |
|
494 | # bundle2 push may receive a reply bundle touching bookmarks | |
495 | maypushback = pushop.ui.configbool(b'experimental', b'bundle2.pushback') |
|
495 | # requiring the wlock. Take it now to ensure proper ordering. | |
496 | if ( |
|
496 | maypushback = pushop.ui.configbool( | |
497 | (not _forcebundle1(pushop)) |
|
497 | b'experimental', | |
498 |
|
|
498 | b'bundle2.pushback', | |
499 | and not bookmod.bookmarksinstore(repo) |
|
499 | ) | |
500 |
|
|
500 | if ( | |
501 | wlock = pushop.repo.wlock() |
|
501 | (not _forcebundle1(pushop)) | |
502 | lock = pushop.repo.lock() |
|
502 | and maypushback | |
503 | pushop.trmanager = transactionmanager( |
|
503 | and not bookmod.bookmarksinstore(repo) | |
504 | pushop.repo, b'push-response', pushop.remote.url() |
|
504 | ): | |
505 | ) |
|
505 | wlock = pushop.repo.wlock() | |
506 | except error.LockUnavailable as err: |
|
506 | lock = pushop.repo.lock() | |
507 | # source repo cannot be locked. |
|
507 | pushop.trmanager = transactionmanager( | |
508 | # We do not abort the push, but just disable the local phase |
|
508 | pushop.repo, b'push-response', pushop.remote.url() | |
509 | # synchronisation. |
|
509 | ) | |
510 | msg = b'cannot lock source repository: %s\n' % stringutil.forcebytestr( |
|
510 | except error.LockUnavailable as err: | |
511 | err |
|
511 | # source repo cannot be locked. | |
512 | ) |
|
512 | # We do not abort the push, but just disable the local phase | |
513 | pushop.ui.debug(msg) |
|
513 | # synchronisation. | |
514 |
|
514 | msg = b'cannot lock source repository: %s\n' | ||
515 | with wlock or util.nullcontextmanager(): |
|
515 | msg %= stringutil.forcebytestr(err) | |
516 | with lock or util.nullcontextmanager(): |
|
516 | pushop.ui.debug(msg) | |
517 | with pushop.trmanager or util.nullcontextmanager(): |
|
517 | ||
518 |
|
|
518 | pushop.repo.checkpush(pushop) | |
519 |
|
|
519 | _checkpublish(pushop) | |
520 |
|
|
520 | _pushdiscovery(pushop) | |
521 |
|
|
521 | if not pushop.force: | |
522 |
|
|
522 | _checksubrepostate(pushop) | |
523 |
|
|
523 | if not _forcebundle1(pushop): | |
524 |
|
|
524 | _pushbundle2(pushop) | |
525 |
|
|
525 | _pushchangeset(pushop) | |
526 |
|
|
526 | _pushsyncphase(pushop) | |
527 |
|
|
527 | _pushobsolete(pushop) | |
528 |
|
|
528 | _pushbookmark(pushop) | |
|
529 | if pushop.trmanager is not None: | |||
|
530 | pushop.trmanager.close() | |||
|
531 | finally: | |||
|
532 | lockmod.release(pushop.trmanager, lock, wlock) | |||
529 |
|
533 | |||
530 | if repo.ui.configbool(b'experimental', b'remotenames'): |
|
534 | if repo.ui.configbool(b'experimental', b'remotenames'): | |
531 | logexchange.pullremotenames(repo, remote) |
|
535 | logexchange.pullremotenames(repo, remote) | |
@@ -745,13 +749,19 b' def _processcompared(pushop, pushed, exp' | |||||
745 | if bookmod.isdivergent(b): |
|
749 | if bookmod.isdivergent(b): | |
746 | pushop.ui.warn(_(b'cannot push divergent bookmark %s!\n') % b) |
|
750 | pushop.ui.warn(_(b'cannot push divergent bookmark %s!\n') % b) | |
747 | pushop.bkresult = 2 |
|
751 | pushop.bkresult = 2 | |
|
752 | elif pushed and repo[scid].rev() not in pushed: | |||
|
753 | # in case of race or secret | |||
|
754 | msg = _(b'cannot push bookmark X without its revision: %s!\n') | |||
|
755 | pushop.ui.warn(msg % b) | |||
|
756 | pushop.bkresult = 2 | |||
748 | else: |
|
757 | else: | |
749 | pushop.outbookmarks.append((b, b'', scid)) |
|
758 | pushop.outbookmarks.append((b, b'', scid)) | |
750 | # search for overwritten bookmark |
|
759 | # search for overwritten bookmark | |
751 | for b, scid, dcid in list(advdst) + list(diverge) + list(differ): |
|
760 | for b, scid, dcid in list(advdst) + list(diverge) + list(differ): | |
752 | if b in explicit: |
|
761 | if b in explicit: | |
753 | explicit.remove(b) |
|
762 | explicit.remove(b) | |
754 | pushop.outbookmarks.append((b, dcid, scid)) |
|
763 | if not pushed or repo[scid].rev() in pushed: | |
|
764 | pushop.outbookmarks.append((b, dcid, scid)) | |||
755 | # search for bookmark to delete |
|
765 | # search for bookmark to delete | |
756 | for b, scid, dcid in adddst: |
|
766 | for b, scid, dcid in adddst: | |
757 | if b in explicit: |
|
767 | if b in explicit: | |
@@ -1739,10 +1749,10 b' def pull(' | |||||
1739 | ) |
|
1749 | ) | |
1740 |
|
1750 | |||
1741 | pullop.trmanager = transactionmanager(repo, b'pull', remote.url()) |
|
1751 | pullop.trmanager = transactionmanager(repo, b'pull', remote.url()) | |
1742 |
wlock = util.nullcontextmanager |
|
1752 | wlock = util.nullcontextmanager | |
1743 | if not bookmod.bookmarksinstore(repo): |
|
1753 | if not bookmod.bookmarksinstore(repo): | |
1744 |
wlock = repo.wlock |
|
1754 | wlock = repo.wlock | |
1745 | with wlock, repo.lock(), pullop.trmanager: |
|
1755 | with wlock(), repo.lock(), pullop.trmanager: | |
1746 | if confirm or ( |
|
1756 | if confirm or ( | |
1747 | repo.ui.configbool(b"pull", b"confirm") and not repo.ui.plain() |
|
1757 | repo.ui.configbool(b"pull", b"confirm") and not repo.ui.plain() | |
1748 | ): |
|
1758 | ): |
@@ -1438,6 +1438,12 b' be ``$HG_HOOKTYPE=incoming`` and ``$HG_H' | |||||
1438 | parent is in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the |
|
1438 | parent is in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the | |
1439 | update failed (e.g. because conflicts were not resolved), ``$HG_ERROR=1``. |
|
1439 | update failed (e.g. because conflicts were not resolved), ``$HG_ERROR=1``. | |
1440 |
|
1440 | |||
|
1441 | ``prelock`` | |||
|
1442 | run before the store lock is taken, mostly used for test and debug. | |||
|
1443 | ||||
|
1444 | ``prewlock`` | |||
|
1445 | run before the working copy lock is taken, mostly used for test and debug. | |||
|
1446 | ||||
1441 | .. note:: |
|
1447 | .. note:: | |
1442 |
|
1448 | |||
1443 | It is generally better to use standard hooks rather than the |
|
1449 | It is generally better to use standard hooks rather than the |
@@ -3122,6 +3122,7 b' class localrepository:' | |||||
3122 | l.lock() |
|
3122 | l.lock() | |
3123 | return l |
|
3123 | return l | |
3124 |
|
3124 | |||
|
3125 | self.hook(b'prelock', throw=True) | |||
3125 | l = self._lock( |
|
3126 | l = self._lock( | |
3126 | vfs=self.svfs, |
|
3127 | vfs=self.svfs, | |
3127 | lockname=b"lock", |
|
3128 | lockname=b"lock", | |
@@ -3146,6 +3147,7 b' class localrepository:' | |||||
3146 | l.lock() |
|
3147 | l.lock() | |
3147 | return l |
|
3148 | return l | |
3148 |
|
3149 | |||
|
3150 | self.hook(b'prewlock', throw=True) | |||
3149 | # We do not need to check for non-waiting lock acquisition. Such |
|
3151 | # We do not need to check for non-waiting lock acquisition. Such | |
3150 | # acquisition would not cause dead-lock as they would just fail. |
|
3152 | # acquisition would not cause dead-lock as they would just fail. | |
3151 | if wait and ( |
|
3153 | if wait and ( |
@@ -1148,7 +1148,14 b' class _InnerRevlog:' | |||||
1148 | ) |
|
1148 | ) | |
1149 |
|
1149 | |||
1150 | def _divert_index(self): |
|
1150 | def _divert_index(self): | |
1151 |
|
|
1151 | index_file = self.index_file | |
|
1152 | # when we encounter a legacy inline-changelog, split it. However it is | |||
|
1153 | # important to use the expected filename for pending content | |||
|
1154 | # (<radix>.a) otherwise hooks won't be seeing the content of the | |||
|
1155 | # pending transaction. | |||
|
1156 | if index_file.endswith(b'.s'): | |||
|
1157 | index_file = self.index_file[:-2] | |||
|
1158 | return index_file + b'.a' | |||
1152 |
|
1159 | |||
1153 | def delay(self): |
|
1160 | def delay(self): | |
1154 | assert not self.is_open |
|
1161 | assert not self.is_open | |
@@ -2895,10 +2902,13 b' class revlog:' | |||||
2895 | maybe_self._inner.index_file = old_index_file_path |
|
2902 | maybe_self._inner.index_file = old_index_file_path | |
2896 |
|
2903 | |||
2897 | tr.registertmp(new_index_file_path) |
|
2904 | tr.registertmp(new_index_file_path) | |
|
2905 | # we use 001 here to make this this happens after the finalisation of | |||
|
2906 | # pending changelog write (using 000). Otherwise the two finalizer | |||
|
2907 | # would step over each other and delete the changelog.i file. | |||
2898 | if self.target[1] is not None: |
|
2908 | if self.target[1] is not None: | |
2899 |
callback_id = b'00 |
|
2909 | callback_id = b'001-revlog-split-%d-%s' % self.target | |
2900 | else: |
|
2910 | else: | |
2901 |
callback_id = b'00 |
|
2911 | callback_id = b'001-revlog-split-%d' % self.target[0] | |
2902 | tr.addfinalize(callback_id, finalize_callback) |
|
2912 | tr.addfinalize(callback_id, finalize_callback) | |
2903 | tr.addabort(callback_id, abort_callback) |
|
2913 | tr.addabort(callback_id, abort_callback) | |
2904 |
|
2914 |
@@ -1,5 +1,23 b'' | |||||
|
1 | = Mercurial 6.7.4 = | |||
|
2 | ||||
|
3 | Exceptional release following a critical regression causing possible data loss | |||
|
4 | in certain conditions: | |||
|
5 | ||||
|
6 | * inline-changelog: fix a critical bug in write_pending that delete data (3cf9e52f5e27) | |||
|
7 | * inline-changelog: fix pending transaction visibility when splitting (1721d983dd6d) | |||
|
8 | ||||
|
9 | Other changes in this release: | |||
|
10 | ||||
|
11 | * exchange: fix locking to actually be scoped | |||
|
12 | * chistedit: change action for the correct item | |||
|
13 | * rust-status: sort the failed matches when printing them | |||
|
14 | * hooks: add a prewlock and a prelock hooks | |||
|
15 | * bookmark: fix remote bookmark deletion when the push is raced | |||
|
16 | ||||
1 | = Mercurial 6.7.3 = |
|
17 | = Mercurial 6.7.3 = | |
2 |
|
18 | |||
|
19 | /!\ This release contains a bug causing possible data loss, use 6.7.4 instead. | |||
|
20 | ||||
3 | * setup: display return code information about failed `hg` call |
|
21 | * setup: display return code information about failed `hg` call | |
4 | * bundle-spec: properly identify changegroup-less bundle |
|
22 | * bundle-spec: properly identify changegroup-less bundle | |
5 | * bundle-spec: properly parse boolean configuration as boolean |
|
23 | * bundle-spec: properly parse boolean configuration as boolean | |
@@ -17,6 +35,8 b'' | |||||
17 |
|
35 | |||
18 | = Mercurial 6.7.2 = |
|
36 | = Mercurial 6.7.2 = | |
19 |
|
37 | |||
|
38 | /!\ This release contains a bug causing possible data loss, use 6.7.4 instead. | |||
|
39 | ||||
20 | Exceptional release following a large performance regression when cloning. |
|
40 | Exceptional release following a large performance regression when cloning. | |
21 |
|
41 | |||
22 | We are setting up automated benchmarks to reduce the likelihood of regressions |
|
42 | We are setting up automated benchmarks to reduce the likelihood of regressions | |
@@ -28,6 +48,8 b' of the sort from happening in the future' | |||||
28 |
|
48 | |||
29 | = Mercurial 6.7.1 = |
|
49 | = Mercurial 6.7.1 = | |
30 |
|
50 | |||
|
51 | /!\ This release contains a bug causing possible data loss, use 6.7.4 instead. | |||
|
52 | ||||
31 | Exceptional release following a crash found in delta code that can be triggered |
|
53 | Exceptional release following a crash found in delta code that can be triggered | |
32 | with complex repository shapes. |
|
54 | with complex repository shapes. | |
33 |
|
55 | |||
@@ -37,6 +59,8 b' with complex repository shapes.' | |||||
37 |
|
59 | |||
38 | = Mercurial 6.7 = |
|
60 | = Mercurial 6.7 = | |
39 |
|
61 | |||
|
62 | /!\ This release contains a bug causing possible data loss, use 6.7.4 instead. | |||
|
63 | ||||
40 | As usual, a *lot* of patches don't make it to this list. |
|
64 | As usual, a *lot* of patches don't make it to this list. | |
41 |
|
65 | |||
42 | == New Features == |
|
66 | == New Features == |
@@ -1082,9 +1082,9 b' ensure changelog is written before bookm' | |||||
1082 | > time.sleep(0.5) |
|
1082 | > time.sleep(0.5) | |
1083 | > if os.path.exists(b"$TESTTMP/unpause"): |
|
1083 | > if os.path.exists(b"$TESTTMP/unpause"): | |
1084 | > os.remove(b"$TESTTMP/unpause") |
|
1084 | > os.remove(b"$TESTTMP/unpause") | |
1085 |
> # It is important that this finalizer start with 'a', so it runs |
|
1085 | > # It is important that this finalizer start with '000-a', so it runs | |
1086 | > # the changelog finalizer appends to the changelog. |
|
1086 | > # before the changelog finalizer appends to the changelog. | |
1087 | > tr.addfinalize(b'a-sleep', sleep) |
|
1087 | > tr.addfinalize(b'000-a-sleep', sleep) | |
1088 | > return tr |
|
1088 | > return tr | |
1089 | > |
|
1089 | > | |
1090 | > def extsetup(ui): |
|
1090 | > def extsetup(ui): |
General Comments 0
You need to be logged in to leave comments.
Login now