##// END OF EJS Templates
largefiles: opts appears to already be bytes in this instance...
Augie Fackler -
r37773:88675432 default
parent child Browse files
Show More
@@ -1,450 +1,451 b''
1 test-abort-checkin.t
1 test-abort-checkin.t
2 test-add.t
2 test-add.t
3 test-addremove-similar.t
3 test-addremove-similar.t
4 test-addremove.t
4 test-addremove.t
5 test-amend-subrepo.t
5 test-amend-subrepo.t
6 test-amend.t
6 test-amend.t
7 test-ancestor.py
7 test-ancestor.py
8 test-annotate.py
8 test-annotate.py
9 test-annotate.t
9 test-annotate.t
10 test-archive-symlinks.t
10 test-archive-symlinks.t
11 test-atomictempfile.py
11 test-atomictempfile.py
12 test-audit-path.t
12 test-audit-path.t
13 test-audit-subrepo.t
13 test-audit-subrepo.t
14 test-automv.t
14 test-automv.t
15 test-backout.t
15 test-backout.t
16 test-backwards-remove.t
16 test-backwards-remove.t
17 test-basic.t
17 test-basic.t
18 test-bheads.t
18 test-bheads.t
19 test-bisect.t
19 test-bisect.t
20 test-bisect2.t
20 test-bisect2.t
21 test-bisect3.t
21 test-bisect3.t
22 test-blackbox.t
22 test-blackbox.t
23 test-bookmarks-current.t
23 test-bookmarks-current.t
24 test-bookmarks-merge.t
24 test-bookmarks-merge.t
25 test-bookmarks-rebase.t
25 test-bookmarks-rebase.t
26 test-bookmarks-strip.t
26 test-bookmarks-strip.t
27 test-bookmarks.t
27 test-bookmarks.t
28 test-branch-change.t
28 test-branch-change.t
29 test-branch-option.t
29 test-branch-option.t
30 test-branch-tag-confict.t
30 test-branch-tag-confict.t
31 test-branches.t
31 test-branches.t
32 test-bundle-phases.t
32 test-bundle-phases.t
33 test-bundle-type.t
33 test-bundle-type.t
34 test-bundle-vs-outgoing.t
34 test-bundle-vs-outgoing.t
35 test-bundle2-multiple-changegroups.t
35 test-bundle2-multiple-changegroups.t
36 test-cappedreader.py
36 test-cappedreader.py
37 test-casecollision.t
37 test-casecollision.t
38 test-cat.t
38 test-cat.t
39 test-censor.t
39 test-censor.t
40 test-changelog-exec.t
40 test-changelog-exec.t
41 test-check-commit.t
41 test-check-commit.t
42 test-check-execute.t
42 test-check-execute.t
43 test-check-module-imports.t
43 test-check-module-imports.t
44 test-check-pyflakes.t
44 test-check-pyflakes.t
45 test-check-pylint.t
45 test-check-pylint.t
46 test-check-shbang.t
46 test-check-shbang.t
47 test-children.t
47 test-children.t
48 test-clone-cgi.t
48 test-clone-cgi.t
49 test-clone-pull-corruption.t
49 test-clone-pull-corruption.t
50 test-clone-r.t
50 test-clone-r.t
51 test-clone-update-order.t
51 test-clone-update-order.t
52 test-command-template.t
52 test-command-template.t
53 test-commit-amend.t
53 test-commit-amend.t
54 test-commit-interactive.t
54 test-commit-interactive.t
55 test-commit-multiple.t
55 test-commit-multiple.t
56 test-commit-unresolved.t
56 test-commit-unresolved.t
57 test-commit.t
57 test-commit.t
58 test-committer.t
58 test-committer.t
59 test-completion.t
59 test-completion.t
60 test-config-env.py
60 test-config-env.py
61 test-config.t
61 test-config.t
62 test-conflict.t
62 test-conflict.t
63 test-confused-revert.t
63 test-confused-revert.t
64 test-contrib-check-code.t
64 test-contrib-check-code.t
65 test-contrib-check-commit.t
65 test-contrib-check-commit.t
66 test-convert-authormap.t
66 test-convert-authormap.t
67 test-convert-clonebranches.t
67 test-convert-clonebranches.t
68 test-convert-datesort.t
68 test-convert-datesort.t
69 test-convert-filemap.t
69 test-convert-filemap.t
70 test-convert-hg-sink.t
70 test-convert-hg-sink.t
71 test-convert-hg-source.t
71 test-convert-hg-source.t
72 test-convert-hg-startrev.t
72 test-convert-hg-startrev.t
73 test-convert-splicemap.t
73 test-convert-splicemap.t
74 test-convert-tagsbranch-topology.t
74 test-convert-tagsbranch-topology.t
75 test-copy-move-merge.t
75 test-copy-move-merge.t
76 test-copy.t
76 test-copy.t
77 test-copytrace-heuristics.t
77 test-copytrace-heuristics.t
78 test-debugbuilddag.t
78 test-debugbuilddag.t
79 test-debugbundle.t
79 test-debugbundle.t
80 test-debugextensions.t
80 test-debugextensions.t
81 test-debugindexdot.t
81 test-debugindexdot.t
82 test-debugrename.t
82 test-debugrename.t
83 test-default-push.t
83 test-default-push.t
84 test-diff-binary-file.t
84 test-diff-binary-file.t
85 test-diff-change.t
85 test-diff-change.t
86 test-diff-copy-depth.t
86 test-diff-copy-depth.t
87 test-diff-hashes.t
87 test-diff-hashes.t
88 test-diff-ignore-whitespace.t
88 test-diff-ignore-whitespace.t
89 test-diff-indent-heuristic.t
89 test-diff-indent-heuristic.t
90 test-diff-issue2761.t
90 test-diff-issue2761.t
91 test-diff-newlines.t
91 test-diff-newlines.t
92 test-diff-reverse.t
92 test-diff-reverse.t
93 test-diff-subdir.t
93 test-diff-subdir.t
94 test-diff-unified.t
94 test-diff-unified.t
95 test-diff-upgrade.t
95 test-diff-upgrade.t
96 test-diffdir.t
96 test-diffdir.t
97 test-diffstat.t
97 test-diffstat.t
98 test-directaccess.t
98 test-directaccess.t
99 test-dirstate-backup.t
99 test-dirstate-backup.t
100 test-dirstate-nonnormalset.t
100 test-dirstate-nonnormalset.t
101 test-dirstate.t
101 test-dirstate.t
102 test-doctest.py
102 test-doctest.py
103 test-double-merge.t
103 test-double-merge.t
104 test-drawdag.t
104 test-drawdag.t
105 test-duplicateoptions.py
105 test-duplicateoptions.py
106 test-editor-filename.t
106 test-editor-filename.t
107 test-empty-dir.t
107 test-empty-dir.t
108 test-empty-file.t
108 test-empty-file.t
109 test-empty-group.t
109 test-empty-group.t
110 test-empty.t
110 test-empty.t
111 test-encode.t
111 test-encode.t
112 test-encoding-func.py
112 test-encoding-func.py
113 test-encoding.t
113 test-encoding.t
114 test-eol-add.t
114 test-eol-add.t
115 test-eol-clone.t
115 test-eol-clone.t
116 test-eol-hook.t
116 test-eol-hook.t
117 test-eol-tag.t
117 test-eol-tag.t
118 test-eol-update.t
118 test-eol-update.t
119 test-excessive-merge.t
119 test-excessive-merge.t
120 test-exchange-obsmarkers-case-A1.t
120 test-exchange-obsmarkers-case-A1.t
121 test-exchange-obsmarkers-case-A2.t
121 test-exchange-obsmarkers-case-A2.t
122 test-exchange-obsmarkers-case-A3.t
122 test-exchange-obsmarkers-case-A3.t
123 test-exchange-obsmarkers-case-A4.t
123 test-exchange-obsmarkers-case-A4.t
124 test-exchange-obsmarkers-case-A5.t
124 test-exchange-obsmarkers-case-A5.t
125 test-exchange-obsmarkers-case-A6.t
125 test-exchange-obsmarkers-case-A6.t
126 test-exchange-obsmarkers-case-A7.t
126 test-exchange-obsmarkers-case-A7.t
127 test-exchange-obsmarkers-case-B1.t
127 test-exchange-obsmarkers-case-B1.t
128 test-exchange-obsmarkers-case-B2.t
128 test-exchange-obsmarkers-case-B2.t
129 test-exchange-obsmarkers-case-B3.t
129 test-exchange-obsmarkers-case-B3.t
130 test-exchange-obsmarkers-case-B4.t
130 test-exchange-obsmarkers-case-B4.t
131 test-exchange-obsmarkers-case-B5.t
131 test-exchange-obsmarkers-case-B5.t
132 test-exchange-obsmarkers-case-B6.t
132 test-exchange-obsmarkers-case-B6.t
133 test-exchange-obsmarkers-case-B7.t
133 test-exchange-obsmarkers-case-B7.t
134 test-exchange-obsmarkers-case-C1.t
134 test-exchange-obsmarkers-case-C1.t
135 test-exchange-obsmarkers-case-C2.t
135 test-exchange-obsmarkers-case-C2.t
136 test-exchange-obsmarkers-case-C3.t
136 test-exchange-obsmarkers-case-C3.t
137 test-exchange-obsmarkers-case-C4.t
137 test-exchange-obsmarkers-case-C4.t
138 test-exchange-obsmarkers-case-D1.t
138 test-exchange-obsmarkers-case-D1.t
139 test-exchange-obsmarkers-case-D2.t
139 test-exchange-obsmarkers-case-D2.t
140 test-exchange-obsmarkers-case-D3.t
140 test-exchange-obsmarkers-case-D3.t
141 test-exchange-obsmarkers-case-D4.t
141 test-exchange-obsmarkers-case-D4.t
142 test-execute-bit.t
142 test-execute-bit.t
143 test-export.t
143 test-export.t
144 test-extdata.t
144 test-extdata.t
145 test-extdiff.t
145 test-extdiff.t
146 test-extra-filelog-entry.t
146 test-extra-filelog-entry.t
147 test-filebranch.t
147 test-filebranch.t
148 test-fileset-generated.t
148 test-fileset-generated.t
149 test-flags.t
149 test-flags.t
150 test-generaldelta.t
150 test-generaldelta.t
151 test-getbundle.t
151 test-getbundle.t
152 test-git-export.t
152 test-git-export.t
153 test-glog-topological.t
153 test-glog-topological.t
154 test-gpg.t
154 test-gpg.t
155 test-graft.t
155 test-graft.t
156 test-hg-parseurl.py
156 test-hg-parseurl.py
157 test-hghave.t
157 test-hghave.t
158 test-hgignore.t
158 test-hgignore.t
159 test-hgk.t
159 test-hgk.t
160 test-hgweb-bundle.t
160 test-hgweb-bundle.t
161 test-hgweb-descend-empties.t
161 test-hgweb-descend-empties.t
162 test-hgweb-empty.t
162 test-hgweb-empty.t
163 test-hgweb-removed.t
163 test-hgweb-removed.t
164 test-histedit-arguments.t
164 test-histedit-arguments.t
165 test-histedit-base.t
165 test-histedit-base.t
166 test-histedit-bookmark-motion.t
166 test-histedit-bookmark-motion.t
167 test-histedit-commute.t
167 test-histedit-commute.t
168 test-histedit-drop.t
168 test-histedit-drop.t
169 test-histedit-edit.t
169 test-histedit-edit.t
170 test-histedit-fold-non-commute.t
170 test-histedit-fold-non-commute.t
171 test-histedit-fold.t
171 test-histedit-fold.t
172 test-histedit-no-change.t
172 test-histedit-no-change.t
173 test-histedit-non-commute-abort.t
173 test-histedit-non-commute-abort.t
174 test-histedit-non-commute.t
174 test-histedit-non-commute.t
175 test-histedit-obsolete.t
175 test-histedit-obsolete.t
176 test-histedit-outgoing.t
176 test-histedit-outgoing.t
177 test-histedit-templates.t
177 test-histedit-templates.t
178 test-http-branchmap.t
178 test-http-branchmap.t
179 test-http-bundle1.t
179 test-http-bundle1.t
180 test-http-clone-r.t
180 test-http-clone-r.t
181 test-http.t
181 test-http.t
182 test-identify.t
182 test-identify.t
183 test-import-unknown.t
183 test-import-unknown.t
184 test-import.t
184 test-import.t
185 test-imports-checker.t
185 test-imports-checker.t
186 test-incoming-outgoing.t
186 test-incoming-outgoing.t
187 test-inherit-mode.t
187 test-inherit-mode.t
188 test-issue1089.t
188 test-issue1089.t
189 test-issue1102.t
189 test-issue1102.t
190 test-issue1175.t
190 test-issue1175.t
191 test-issue1306.t
191 test-issue1306.t
192 test-issue1438.t
192 test-issue1438.t
193 test-issue1502.t
193 test-issue1502.t
194 test-issue1802.t
194 test-issue1802.t
195 test-issue1877.t
195 test-issue1877.t
196 test-issue1993.t
196 test-issue1993.t
197 test-issue2137.t
197 test-issue2137.t
198 test-issue3084.t
198 test-issue3084.t
199 test-issue4074.t
199 test-issue4074.t
200 test-issue522.t
200 test-issue522.t
201 test-issue586.t
201 test-issue586.t
202 test-issue612.t
202 test-issue612.t
203 test-issue619.t
203 test-issue619.t
204 test-issue660.t
204 test-issue660.t
205 test-issue672.t
205 test-issue672.t
206 test-issue842.t
206 test-issue842.t
207 test-journal-exists.t
207 test-journal-exists.t
208 test-journal-share.t
208 test-journal-share.t
209 test-journal.t
209 test-journal.t
210 test-largefiles-cache.t
210 test-largefiles-cache.t
211 test-largefiles-misc.t
211 test-largefiles-misc.t
212 test-largefiles-small-disk.t
212 test-largefiles-small-disk.t
213 test-largefiles-update.t
213 test-largefiles-update.t
214 test-largefiles.t
214 test-lfs-largefiles.t
215 test-lfs-largefiles.t
215 test-linerange.py
216 test-linerange.py
216 test-locate.t
217 test-locate.t
217 test-lock-badness.t
218 test-lock-badness.t
218 test-log-linerange.t
219 test-log-linerange.t
219 test-log.t
220 test-log.t
220 test-logexchange.t
221 test-logexchange.t
221 test-lrucachedict.py
222 test-lrucachedict.py
222 test-mactext.t
223 test-mactext.t
223 test-mailmap.t
224 test-mailmap.t
224 test-manifest-merging.t
225 test-manifest-merging.t
225 test-manifest.py
226 test-manifest.py
226 test-manifest.t
227 test-manifest.t
227 test-match.py
228 test-match.py
228 test-mdiff.py
229 test-mdiff.py
229 test-merge-changedelete.t
230 test-merge-changedelete.t
230 test-merge-closedheads.t
231 test-merge-closedheads.t
231 test-merge-commit.t
232 test-merge-commit.t
232 test-merge-criss-cross.t
233 test-merge-criss-cross.t
233 test-merge-default.t
234 test-merge-default.t
234 test-merge-force.t
235 test-merge-force.t
235 test-merge-halt.t
236 test-merge-halt.t
236 test-merge-internal-tools-pattern.t
237 test-merge-internal-tools-pattern.t
237 test-merge-local.t
238 test-merge-local.t
238 test-merge-remove.t
239 test-merge-remove.t
239 test-merge-revert.t
240 test-merge-revert.t
240 test-merge-revert2.t
241 test-merge-revert2.t
241 test-merge-subrepos.t
242 test-merge-subrepos.t
242 test-merge-symlinks.t
243 test-merge-symlinks.t
243 test-merge-tools.t
244 test-merge-tools.t
244 test-merge-types.t
245 test-merge-types.t
245 test-merge1.t
246 test-merge1.t
246 test-merge10.t
247 test-merge10.t
247 test-merge2.t
248 test-merge2.t
248 test-merge4.t
249 test-merge4.t
249 test-merge5.t
250 test-merge5.t
250 test-merge6.t
251 test-merge6.t
251 test-merge7.t
252 test-merge7.t
252 test-merge8.t
253 test-merge8.t
253 test-merge9.t
254 test-merge9.t
254 test-mq-git.t
255 test-mq-git.t
255 test-mq-header-date.t
256 test-mq-header-date.t
256 test-mq-header-from.t
257 test-mq-header-from.t
257 test-mq-merge.t
258 test-mq-merge.t
258 test-mq-pull-from-bundle.t
259 test-mq-pull-from-bundle.t
259 test-mq-qdelete.t
260 test-mq-qdelete.t
260 test-mq-qdiff.t
261 test-mq-qdiff.t
261 test-mq-qfold.t
262 test-mq-qfold.t
262 test-mq-qgoto.t
263 test-mq-qgoto.t
263 test-mq-qimport-fail-cleanup.t
264 test-mq-qimport-fail-cleanup.t
264 test-mq-qnew.t
265 test-mq-qnew.t
265 test-mq-qpush-exact.t
266 test-mq-qpush-exact.t
266 test-mq-qqueue.t
267 test-mq-qqueue.t
267 test-mq-qrefresh-interactive.t
268 test-mq-qrefresh-interactive.t
268 test-mq-qrefresh-replace-log-message.t
269 test-mq-qrefresh-replace-log-message.t
269 test-mq-qrefresh.t
270 test-mq-qrefresh.t
270 test-mq-qrename.t
271 test-mq-qrename.t
271 test-mq-qsave.t
272 test-mq-qsave.t
272 test-mq-safety.t
273 test-mq-safety.t
273 test-mq-subrepo.t
274 test-mq-subrepo.t
274 test-mq-symlinks.t
275 test-mq-symlinks.t
275 test-mv-cp-st-diff.t
276 test-mv-cp-st-diff.t
276 test-narrow-archive.t
277 test-narrow-archive.t
277 test-narrow-clone-no-ellipsis.t
278 test-narrow-clone-no-ellipsis.t
278 test-narrow-clone-non-narrow-server.t
279 test-narrow-clone-non-narrow-server.t
279 test-narrow-clone-nonlinear.t
280 test-narrow-clone-nonlinear.t
280 test-narrow-clone.t
281 test-narrow-clone.t
281 test-narrow-commit.t
282 test-narrow-commit.t
282 test-narrow-copies.t
283 test-narrow-copies.t
283 test-narrow-debugcommands.t
284 test-narrow-debugcommands.t
284 test-narrow-debugrebuilddirstate.t
285 test-narrow-debugrebuilddirstate.t
285 test-narrow-exchange-merges.t
286 test-narrow-exchange-merges.t
286 test-narrow-exchange.t
287 test-narrow-exchange.t
287 test-narrow-expanddirstate.t
288 test-narrow-expanddirstate.t
288 test-narrow-merge.t
289 test-narrow-merge.t
289 test-narrow-patch.t
290 test-narrow-patch.t
290 test-narrow-patterns.t
291 test-narrow-patterns.t
291 test-narrow-pull.t
292 test-narrow-pull.t
292 test-narrow-rebase.t
293 test-narrow-rebase.t
293 test-narrow-shallow-merges.t
294 test-narrow-shallow-merges.t
294 test-narrow-shallow.t
295 test-narrow-shallow.t
295 test-narrow-strip.t
296 test-narrow-strip.t
296 test-narrow-update.t
297 test-narrow-update.t
297 test-nested-repo.t
298 test-nested-repo.t
298 test-newbranch.t
299 test-newbranch.t
299 test-obshistory.t
300 test-obshistory.t
300 test-obsmarker-template.t
301 test-obsmarker-template.t
301 test-obsmarkers-effectflag.t
302 test-obsmarkers-effectflag.t
302 test-obsolete-bundle-strip.t
303 test-obsolete-bundle-strip.t
303 test-obsolete-changeset-exchange.t
304 test-obsolete-changeset-exchange.t
304 test-obsolete-checkheads.t
305 test-obsolete-checkheads.t
305 test-obsolete-distributed.t
306 test-obsolete-distributed.t
306 test-obsolete-tag-cache.t
307 test-obsolete-tag-cache.t
307 test-parents.t
308 test-parents.t
308 test-pathconflicts-merge.t
309 test-pathconflicts-merge.t
309 test-pathconflicts-update.t
310 test-pathconflicts-update.t
310 test-pending.t
311 test-pending.t
311 test-permissions.t
312 test-permissions.t
312 test-phases.t
313 test-phases.t
313 test-pull-branch.t
314 test-pull-branch.t
314 test-pull-http.t
315 test-pull-http.t
315 test-pull-permission.t
316 test-pull-permission.t
316 test-pull-pull-corruption.t
317 test-pull-pull-corruption.t
317 test-pull-r.t
318 test-pull-r.t
318 test-pull-update.t
319 test-pull-update.t
319 test-purge.t
320 test-purge.t
320 test-push-checkheads-partial-C1.t
321 test-push-checkheads-partial-C1.t
321 test-push-checkheads-partial-C2.t
322 test-push-checkheads-partial-C2.t
322 test-push-checkheads-partial-C3.t
323 test-push-checkheads-partial-C3.t
323 test-push-checkheads-partial-C4.t
324 test-push-checkheads-partial-C4.t
324 test-push-checkheads-pruned-B1.t
325 test-push-checkheads-pruned-B1.t
325 test-push-checkheads-pruned-B2.t
326 test-push-checkheads-pruned-B2.t
326 test-push-checkheads-pruned-B3.t
327 test-push-checkheads-pruned-B3.t
327 test-push-checkheads-pruned-B4.t
328 test-push-checkheads-pruned-B4.t
328 test-push-checkheads-pruned-B5.t
329 test-push-checkheads-pruned-B5.t
329 test-push-checkheads-pruned-B6.t
330 test-push-checkheads-pruned-B6.t
330 test-push-checkheads-pruned-B7.t
331 test-push-checkheads-pruned-B7.t
331 test-push-checkheads-pruned-B8.t
332 test-push-checkheads-pruned-B8.t
332 test-push-checkheads-superceed-A1.t
333 test-push-checkheads-superceed-A1.t
333 test-push-checkheads-superceed-A2.t
334 test-push-checkheads-superceed-A2.t
334 test-push-checkheads-superceed-A3.t
335 test-push-checkheads-superceed-A3.t
335 test-push-checkheads-superceed-A4.t
336 test-push-checkheads-superceed-A4.t
336 test-push-checkheads-superceed-A5.t
337 test-push-checkheads-superceed-A5.t
337 test-push-checkheads-superceed-A6.t
338 test-push-checkheads-superceed-A6.t
338 test-push-checkheads-superceed-A7.t
339 test-push-checkheads-superceed-A7.t
339 test-push-checkheads-superceed-A8.t
340 test-push-checkheads-superceed-A8.t
340 test-push-checkheads-unpushed-D1.t
341 test-push-checkheads-unpushed-D1.t
341 test-push-checkheads-unpushed-D2.t
342 test-push-checkheads-unpushed-D2.t
342 test-push-checkheads-unpushed-D3.t
343 test-push-checkheads-unpushed-D3.t
343 test-push-checkheads-unpushed-D4.t
344 test-push-checkheads-unpushed-D4.t
344 test-push-checkheads-unpushed-D5.t
345 test-push-checkheads-unpushed-D5.t
345 test-push-checkheads-unpushed-D6.t
346 test-push-checkheads-unpushed-D6.t
346 test-push-checkheads-unpushed-D7.t
347 test-push-checkheads-unpushed-D7.t
347 test-push-http.t
348 test-push-http.t
348 test-push-warn.t
349 test-push-warn.t
349 test-pushvars.t
350 test-pushvars.t
350 test-rebase-abort.t
351 test-rebase-abort.t
351 test-rebase-base-flag.t
352 test-rebase-base-flag.t
352 test-rebase-bookmarks.t
353 test-rebase-bookmarks.t
353 test-rebase-brute-force.t
354 test-rebase-brute-force.t
354 test-rebase-cache.t
355 test-rebase-cache.t
355 test-rebase-check-restore.t
356 test-rebase-check-restore.t
356 test-rebase-collapse.t
357 test-rebase-collapse.t
357 test-rebase-conflicts.t
358 test-rebase-conflicts.t
358 test-rebase-dest.t
359 test-rebase-dest.t
359 test-rebase-detach.t
360 test-rebase-detach.t
360 test-rebase-emptycommit.t
361 test-rebase-emptycommit.t
361 test-rebase-inmemory.t
362 test-rebase-inmemory.t
362 test-rebase-interruptions.t
363 test-rebase-interruptions.t
363 test-rebase-issue-noparam-single-rev.t
364 test-rebase-issue-noparam-single-rev.t
364 test-rebase-legacy.t
365 test-rebase-legacy.t
365 test-rebase-mq-skip.t
366 test-rebase-mq-skip.t
366 test-rebase-mq.t
367 test-rebase-mq.t
367 test-rebase-named-branches.t
368 test-rebase-named-branches.t
368 test-rebase-newancestor.t
369 test-rebase-newancestor.t
369 test-rebase-obsolete.t
370 test-rebase-obsolete.t
370 test-rebase-parameters.t
371 test-rebase-parameters.t
371 test-rebase-partial.t
372 test-rebase-partial.t
372 test-rebase-pull.t
373 test-rebase-pull.t
373 test-rebase-rename.t
374 test-rebase-rename.t
374 test-rebase-scenario-global.t
375 test-rebase-scenario-global.t
375 test-rebase-templates.t
376 test-rebase-templates.t
376 test-rebase-transaction.t
377 test-rebase-transaction.t
377 test-record.t
378 test-record.t
378 test-relink.t
379 test-relink.t
379 test-remove.t
380 test-remove.t
380 test-rename-after-merge.t
381 test-rename-after-merge.t
381 test-rename-dir-merge.t
382 test-rename-dir-merge.t
382 test-rename-merge1.t
383 test-rename-merge1.t
383 test-rename.t
384 test-rename.t
384 test-repair-strip.t
385 test-repair-strip.t
385 test-repo-compengines.t
386 test-repo-compengines.t
386 test-resolve.t
387 test-resolve.t
387 test-revert-flags.t
388 test-revert-flags.t
388 test-revert-unknown.t
389 test-revert-unknown.t
389 test-revlog-ancestry.py
390 test-revlog-ancestry.py
390 test-revlog-group-emptyiter.t
391 test-revlog-group-emptyiter.t
391 test-revlog-mmapindex.t
392 test-revlog-mmapindex.t
392 test-revlog-packentry.t
393 test-revlog-packentry.t
393 test-revset-dirstate-parents.t
394 test-revset-dirstate-parents.t
394 test-revset-outgoing.t
395 test-revset-outgoing.t
395 test-rollback.t
396 test-rollback.t
396 test-run-tests.py
397 test-run-tests.py
397 test-run-tests.t
398 test-run-tests.t
398 test-schemes.t
399 test-schemes.t
399 test-serve.t
400 test-serve.t
400 test-setdiscovery.t
401 test-setdiscovery.t
401 test-share.t
402 test-share.t
402 test-shelve.t
403 test-shelve.t
403 test-show-stack.t
404 test-show-stack.t
404 test-show-work.t
405 test-show-work.t
405 test-show.t
406 test-show.t
406 test-simple-update.t
407 test-simple-update.t
407 test-single-head.t
408 test-single-head.t
408 test-sparse-clear.t
409 test-sparse-clear.t
409 test-sparse-import.t
410 test-sparse-import.t
410 test-sparse-merges.t
411 test-sparse-merges.t
411 test-sparse-profiles.t
412 test-sparse-profiles.t
412 test-sparse-requirement.t
413 test-sparse-requirement.t
413 test-sparse-verbose-json.t
414 test-sparse-verbose-json.t
414 test-ssh-clone-r.t
415 test-ssh-clone-r.t
415 test-ssh-proto.t
416 test-ssh-proto.t
416 test-sshserver.py
417 test-sshserver.py
417 test-stack.t
418 test-stack.t
418 test-status-rev.t
419 test-status-rev.t
419 test-status-terse.t
420 test-status-terse.t
420 test-strip-cross.t
421 test-strip-cross.t
421 test-strip.t
422 test-strip.t
422 test-subrepo-deep-nested-change.t
423 test-subrepo-deep-nested-change.t
423 test-subrepo-missing.t
424 test-subrepo-missing.t
424 test-subrepo.t
425 test-subrepo.t
425 test-symlinks.t
426 test-symlinks.t
426 test-tag.t
427 test-tag.t
427 test-tags.t
428 test-tags.t
428 test-template-engine.t
429 test-template-engine.t
429 test-treemanifest.t
430 test-treemanifest.t
430 test-unamend.t
431 test-unamend.t
431 test-uncommit.t
432 test-uncommit.t
432 test-unified-test.t
433 test-unified-test.t
433 test-unrelated-pull.t
434 test-unrelated-pull.t
434 test-up-local-change.t
435 test-up-local-change.t
435 test-update-branches.t
436 test-update-branches.t
436 test-update-dest.t
437 test-update-dest.t
437 test-update-issue1456.t
438 test-update-issue1456.t
438 test-update-names.t
439 test-update-names.t
439 test-update-reverse.t
440 test-update-reverse.t
440 test-upgrade-repo.t
441 test-upgrade-repo.t
441 test-url-download.t
442 test-url-download.t
442 test-url-rev.t
443 test-url-rev.t
443 test-username-newline.t
444 test-username-newline.t
444 test-verify.t
445 test-verify.t
445 test-websub.t
446 test-websub.t
446 test-win32text.t
447 test-win32text.t
447 test-wireproto-clientreactor.py
448 test-wireproto-clientreactor.py
448 test-wireproto-framing.py
449 test-wireproto-framing.py
449 test-wireproto-serverreactor.py
450 test-wireproto-serverreactor.py
450 test-xdg.t
451 test-xdg.t
@@ -1,1495 +1,1495 b''
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
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 '''Overridden Mercurial commands and functions for the largefiles extension'''
9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 import copy
12 import copy
13 import os
13 import os
14
14
15 from mercurial.i18n import _
15 from mercurial.i18n import _
16
16
17 from mercurial import (
17 from mercurial import (
18 archival,
18 archival,
19 cmdutil,
19 cmdutil,
20 error,
20 error,
21 hg,
21 hg,
22 logcmdutil,
22 logcmdutil,
23 match as matchmod,
23 match as matchmod,
24 pathutil,
24 pathutil,
25 pycompat,
25 pycompat,
26 registrar,
26 registrar,
27 scmutil,
27 scmutil,
28 smartset,
28 smartset,
29 util,
29 util,
30 )
30 )
31
31
32 from . import (
32 from . import (
33 lfcommands,
33 lfcommands,
34 lfutil,
34 lfutil,
35 storefactory,
35 storefactory,
36 )
36 )
37
37
38 # -- Utility functions: commonly/repeatedly needed functionality ---------------
38 # -- Utility functions: commonly/repeatedly needed functionality ---------------
39
39
40 def composelargefilematcher(match, manifest):
40 def composelargefilematcher(match, manifest):
41 '''create a matcher that matches only the largefiles in the original
41 '''create a matcher that matches only the largefiles in the original
42 matcher'''
42 matcher'''
43 m = copy.copy(match)
43 m = copy.copy(match)
44 lfile = lambda f: lfutil.standin(f) in manifest
44 lfile = lambda f: lfutil.standin(f) in manifest
45 m._files = [lf for lf in m._files if lfile(lf)]
45 m._files = [lf for lf in m._files if lfile(lf)]
46 m._fileset = set(m._files)
46 m._fileset = set(m._files)
47 m.always = lambda: False
47 m.always = lambda: False
48 origmatchfn = m.matchfn
48 origmatchfn = m.matchfn
49 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
49 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
50 return m
50 return m
51
51
52 def composenormalfilematcher(match, manifest, exclude=None):
52 def composenormalfilematcher(match, manifest, exclude=None):
53 excluded = set()
53 excluded = set()
54 if exclude is not None:
54 if exclude is not None:
55 excluded.update(exclude)
55 excluded.update(exclude)
56
56
57 m = copy.copy(match)
57 m = copy.copy(match)
58 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
58 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
59 manifest or f in excluded)
59 manifest or f in excluded)
60 m._files = [lf for lf in m._files if notlfile(lf)]
60 m._files = [lf for lf in m._files if notlfile(lf)]
61 m._fileset = set(m._files)
61 m._fileset = set(m._files)
62 m.always = lambda: False
62 m.always = lambda: False
63 origmatchfn = m.matchfn
63 origmatchfn = m.matchfn
64 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
64 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
65 return m
65 return m
66
66
67 def installnormalfilesmatchfn(manifest):
67 def installnormalfilesmatchfn(manifest):
68 '''installmatchfn with a matchfn that ignores all largefiles'''
68 '''installmatchfn with a matchfn that ignores all largefiles'''
69 def overridematch(ctx, pats=(), opts=None, globbed=False,
69 def overridematch(ctx, pats=(), opts=None, globbed=False,
70 default='relpath', badfn=None):
70 default='relpath', badfn=None):
71 if opts is None:
71 if opts is None:
72 opts = {}
72 opts = {}
73 match = oldmatch(ctx, pats, opts, globbed, default, badfn=badfn)
73 match = oldmatch(ctx, pats, opts, globbed, default, badfn=badfn)
74 return composenormalfilematcher(match, manifest)
74 return composenormalfilematcher(match, manifest)
75 oldmatch = installmatchfn(overridematch)
75 oldmatch = installmatchfn(overridematch)
76
76
77 def installmatchfn(f):
77 def installmatchfn(f):
78 '''monkey patch the scmutil module with a custom match function.
78 '''monkey patch the scmutil module with a custom match function.
79 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
79 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
80 oldmatch = scmutil.match
80 oldmatch = scmutil.match
81 setattr(f, 'oldmatch', oldmatch)
81 setattr(f, 'oldmatch', oldmatch)
82 scmutil.match = f
82 scmutil.match = f
83 return oldmatch
83 return oldmatch
84
84
85 def restorematchfn():
85 def restorematchfn():
86 '''restores scmutil.match to what it was before installmatchfn
86 '''restores scmutil.match to what it was before installmatchfn
87 was called. no-op if scmutil.match is its original function.
87 was called. no-op if scmutil.match is its original function.
88
88
89 Note that n calls to installmatchfn will require n calls to
89 Note that n calls to installmatchfn will require n calls to
90 restore the original matchfn.'''
90 restore the original matchfn.'''
91 scmutil.match = getattr(scmutil.match, 'oldmatch')
91 scmutil.match = getattr(scmutil.match, 'oldmatch')
92
92
93 def installmatchandpatsfn(f):
93 def installmatchandpatsfn(f):
94 oldmatchandpats = scmutil.matchandpats
94 oldmatchandpats = scmutil.matchandpats
95 setattr(f, 'oldmatchandpats', oldmatchandpats)
95 setattr(f, 'oldmatchandpats', oldmatchandpats)
96 scmutil.matchandpats = f
96 scmutil.matchandpats = f
97 return oldmatchandpats
97 return oldmatchandpats
98
98
99 def restorematchandpatsfn():
99 def restorematchandpatsfn():
100 '''restores scmutil.matchandpats to what it was before
100 '''restores scmutil.matchandpats to what it was before
101 installmatchandpatsfn was called. No-op if scmutil.matchandpats
101 installmatchandpatsfn was called. No-op if scmutil.matchandpats
102 is its original function.
102 is its original function.
103
103
104 Note that n calls to installmatchandpatsfn will require n calls
104 Note that n calls to installmatchandpatsfn will require n calls
105 to restore the original matchfn.'''
105 to restore the original matchfn.'''
106 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
106 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
107 scmutil.matchandpats)
107 scmutil.matchandpats)
108
108
109 def addlargefiles(ui, repo, isaddremove, matcher, **opts):
109 def addlargefiles(ui, repo, isaddremove, matcher, **opts):
110 large = opts.get(r'large')
110 large = opts.get(r'large')
111 lfsize = lfutil.getminsize(
111 lfsize = lfutil.getminsize(
112 ui, lfutil.islfilesrepo(repo), opts.get(r'lfsize'))
112 ui, lfutil.islfilesrepo(repo), opts.get(r'lfsize'))
113
113
114 lfmatcher = None
114 lfmatcher = None
115 if lfutil.islfilesrepo(repo):
115 if lfutil.islfilesrepo(repo):
116 lfpats = ui.configlist(lfutil.longname, 'patterns')
116 lfpats = ui.configlist(lfutil.longname, 'patterns')
117 if lfpats:
117 if lfpats:
118 lfmatcher = matchmod.match(repo.root, '', list(lfpats))
118 lfmatcher = matchmod.match(repo.root, '', list(lfpats))
119
119
120 lfnames = []
120 lfnames = []
121 m = matcher
121 m = matcher
122
122
123 wctx = repo[None]
123 wctx = repo[None]
124 for f in wctx.walk(matchmod.badmatch(m, lambda x, y: None)):
124 for f in wctx.walk(matchmod.badmatch(m, lambda x, y: None)):
125 exact = m.exact(f)
125 exact = m.exact(f)
126 lfile = lfutil.standin(f) in wctx
126 lfile = lfutil.standin(f) in wctx
127 nfile = f in wctx
127 nfile = f in wctx
128 exists = lfile or nfile
128 exists = lfile or nfile
129
129
130 # addremove in core gets fancy with the name, add doesn't
130 # addremove in core gets fancy with the name, add doesn't
131 if isaddremove:
131 if isaddremove:
132 name = m.uipath(f)
132 name = m.uipath(f)
133 else:
133 else:
134 name = m.rel(f)
134 name = m.rel(f)
135
135
136 # Don't warn the user when they attempt to add a normal tracked file.
136 # Don't warn the user when they attempt to add a normal tracked file.
137 # The normal add code will do that for us.
137 # The normal add code will do that for us.
138 if exact and exists:
138 if exact and exists:
139 if lfile:
139 if lfile:
140 ui.warn(_('%s already a largefile\n') % name)
140 ui.warn(_('%s already a largefile\n') % name)
141 continue
141 continue
142
142
143 if (exact or not exists) and not lfutil.isstandin(f):
143 if (exact or not exists) and not lfutil.isstandin(f):
144 # In case the file was removed previously, but not committed
144 # In case the file was removed previously, but not committed
145 # (issue3507)
145 # (issue3507)
146 if not repo.wvfs.exists(f):
146 if not repo.wvfs.exists(f):
147 continue
147 continue
148
148
149 abovemin = (lfsize and
149 abovemin = (lfsize and
150 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
150 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
151 if large or abovemin or (lfmatcher and lfmatcher(f)):
151 if large or abovemin or (lfmatcher and lfmatcher(f)):
152 lfnames.append(f)
152 lfnames.append(f)
153 if ui.verbose or not exact:
153 if ui.verbose or not exact:
154 ui.status(_('adding %s as a largefile\n') % name)
154 ui.status(_('adding %s as a largefile\n') % name)
155
155
156 bad = []
156 bad = []
157
157
158 # Need to lock, otherwise there could be a race condition between
158 # Need to lock, otherwise there could be a race condition between
159 # when standins are created and added to the repo.
159 # when standins are created and added to the repo.
160 with repo.wlock():
160 with repo.wlock():
161 if not opts.get(r'dry_run'):
161 if not opts.get(r'dry_run'):
162 standins = []
162 standins = []
163 lfdirstate = lfutil.openlfdirstate(ui, repo)
163 lfdirstate = lfutil.openlfdirstate(ui, repo)
164 for f in lfnames:
164 for f in lfnames:
165 standinname = lfutil.standin(f)
165 standinname = lfutil.standin(f)
166 lfutil.writestandin(repo, standinname, hash='',
166 lfutil.writestandin(repo, standinname, hash='',
167 executable=lfutil.getexecutable(repo.wjoin(f)))
167 executable=lfutil.getexecutable(repo.wjoin(f)))
168 standins.append(standinname)
168 standins.append(standinname)
169 if lfdirstate[f] == 'r':
169 if lfdirstate[f] == 'r':
170 lfdirstate.normallookup(f)
170 lfdirstate.normallookup(f)
171 else:
171 else:
172 lfdirstate.add(f)
172 lfdirstate.add(f)
173 lfdirstate.write()
173 lfdirstate.write()
174 bad += [lfutil.splitstandin(f)
174 bad += [lfutil.splitstandin(f)
175 for f in repo[None].add(standins)
175 for f in repo[None].add(standins)
176 if f in m.files()]
176 if f in m.files()]
177
177
178 added = [f for f in lfnames if f not in bad]
178 added = [f for f in lfnames if f not in bad]
179 return added, bad
179 return added, bad
180
180
181 def removelargefiles(ui, repo, isaddremove, matcher, dryrun, **opts):
181 def removelargefiles(ui, repo, isaddremove, matcher, dryrun, **opts):
182 after = opts.get(r'after')
182 after = opts.get(r'after')
183 m = composelargefilematcher(matcher, repo[None].manifest())
183 m = composelargefilematcher(matcher, repo[None].manifest())
184 try:
184 try:
185 repo.lfstatus = True
185 repo.lfstatus = True
186 s = repo.status(match=m, clean=not isaddremove)
186 s = repo.status(match=m, clean=not isaddremove)
187 finally:
187 finally:
188 repo.lfstatus = False
188 repo.lfstatus = False
189 manifest = repo[None].manifest()
189 manifest = repo[None].manifest()
190 modified, added, deleted, clean = [[f for f in list
190 modified, added, deleted, clean = [[f for f in list
191 if lfutil.standin(f) in manifest]
191 if lfutil.standin(f) in manifest]
192 for list in (s.modified, s.added,
192 for list in (s.modified, s.added,
193 s.deleted, s.clean)]
193 s.deleted, s.clean)]
194
194
195 def warn(files, msg):
195 def warn(files, msg):
196 for f in files:
196 for f in files:
197 ui.warn(msg % m.rel(f))
197 ui.warn(msg % m.rel(f))
198 return int(len(files) > 0)
198 return int(len(files) > 0)
199
199
200 result = 0
200 result = 0
201
201
202 if after:
202 if after:
203 remove = deleted
203 remove = deleted
204 result = warn(modified + added + clean,
204 result = warn(modified + added + clean,
205 _('not removing %s: file still exists\n'))
205 _('not removing %s: file still exists\n'))
206 else:
206 else:
207 remove = deleted + clean
207 remove = deleted + clean
208 result = warn(modified, _('not removing %s: file is modified (use -f'
208 result = warn(modified, _('not removing %s: file is modified (use -f'
209 ' to force removal)\n'))
209 ' to force removal)\n'))
210 result = warn(added, _('not removing %s: file has been marked for add'
210 result = warn(added, _('not removing %s: file has been marked for add'
211 ' (use forget to undo)\n')) or result
211 ' (use forget to undo)\n')) or result
212
212
213 # Need to lock because standin files are deleted then removed from the
213 # Need to lock because standin files are deleted then removed from the
214 # repository and we could race in-between.
214 # repository and we could race in-between.
215 with repo.wlock():
215 with repo.wlock():
216 lfdirstate = lfutil.openlfdirstate(ui, repo)
216 lfdirstate = lfutil.openlfdirstate(ui, repo)
217 for f in sorted(remove):
217 for f in sorted(remove):
218 if ui.verbose or not m.exact(f):
218 if ui.verbose or not m.exact(f):
219 # addremove in core gets fancy with the name, remove doesn't
219 # addremove in core gets fancy with the name, remove doesn't
220 if isaddremove:
220 if isaddremove:
221 name = m.uipath(f)
221 name = m.uipath(f)
222 else:
222 else:
223 name = m.rel(f)
223 name = m.rel(f)
224 ui.status(_('removing %s\n') % name)
224 ui.status(_('removing %s\n') % name)
225
225
226 if not dryrun:
226 if not dryrun:
227 if not after:
227 if not after:
228 repo.wvfs.unlinkpath(f, ignoremissing=True)
228 repo.wvfs.unlinkpath(f, ignoremissing=True)
229
229
230 if dryrun:
230 if dryrun:
231 return result
231 return result
232
232
233 remove = [lfutil.standin(f) for f in remove]
233 remove = [lfutil.standin(f) for f in remove]
234 # If this is being called by addremove, let the original addremove
234 # If this is being called by addremove, let the original addremove
235 # function handle this.
235 # function handle this.
236 if not isaddremove:
236 if not isaddremove:
237 for f in remove:
237 for f in remove:
238 repo.wvfs.unlinkpath(f, ignoremissing=True)
238 repo.wvfs.unlinkpath(f, ignoremissing=True)
239 repo[None].forget(remove)
239 repo[None].forget(remove)
240
240
241 for f in remove:
241 for f in remove:
242 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
242 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
243 False)
243 False)
244
244
245 lfdirstate.write()
245 lfdirstate.write()
246
246
247 return result
247 return result
248
248
249 # For overriding mercurial.hgweb.webcommands so that largefiles will
249 # For overriding mercurial.hgweb.webcommands so that largefiles will
250 # appear at their right place in the manifests.
250 # appear at their right place in the manifests.
251 def decodepath(orig, path):
251 def decodepath(orig, path):
252 return lfutil.splitstandin(path) or path
252 return lfutil.splitstandin(path) or path
253
253
254 # -- Wrappers: modify existing commands --------------------------------
254 # -- Wrappers: modify existing commands --------------------------------
255
255
256 def overrideadd(orig, ui, repo, *pats, **opts):
256 def overrideadd(orig, ui, repo, *pats, **opts):
257 if opts.get(r'normal') and opts.get(r'large'):
257 if opts.get(r'normal') and opts.get(r'large'):
258 raise error.Abort(_('--normal cannot be used with --large'))
258 raise error.Abort(_('--normal cannot be used with --large'))
259 return orig(ui, repo, *pats, **opts)
259 return orig(ui, repo, *pats, **opts)
260
260
261 def cmdutiladd(orig, ui, repo, matcher, prefix, explicitonly, **opts):
261 def cmdutiladd(orig, ui, repo, matcher, prefix, explicitonly, **opts):
262 # The --normal flag short circuits this override
262 # The --normal flag short circuits this override
263 if opts.get(r'normal'):
263 if opts.get(r'normal'):
264 return orig(ui, repo, matcher, prefix, explicitonly, **opts)
264 return orig(ui, repo, matcher, prefix, explicitonly, **opts)
265
265
266 ladded, lbad = addlargefiles(ui, repo, False, matcher, **opts)
266 ladded, lbad = addlargefiles(ui, repo, False, matcher, **opts)
267 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(),
267 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(),
268 ladded)
268 ladded)
269 bad = orig(ui, repo, normalmatcher, prefix, explicitonly, **opts)
269 bad = orig(ui, repo, normalmatcher, prefix, explicitonly, **opts)
270
270
271 bad.extend(f for f in lbad)
271 bad.extend(f for f in lbad)
272 return bad
272 return bad
273
273
274 def cmdutilremove(orig, ui, repo, matcher, prefix, after, force, subrepos,
274 def cmdutilremove(orig, ui, repo, matcher, prefix, after, force, subrepos,
275 dryrun):
275 dryrun):
276 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
276 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
277 result = orig(ui, repo, normalmatcher, prefix, after, force, subrepos,
277 result = orig(ui, repo, normalmatcher, prefix, after, force, subrepos,
278 dryrun)
278 dryrun)
279 return removelargefiles(ui, repo, False, matcher, dryrun, after=after,
279 return removelargefiles(ui, repo, False, matcher, dryrun, after=after,
280 force=force) or result
280 force=force) or result
281
281
282 def overridestatusfn(orig, repo, rev2, **opts):
282 def overridestatusfn(orig, repo, rev2, **opts):
283 try:
283 try:
284 repo._repo.lfstatus = True
284 repo._repo.lfstatus = True
285 return orig(repo, rev2, **opts)
285 return orig(repo, rev2, **opts)
286 finally:
286 finally:
287 repo._repo.lfstatus = False
287 repo._repo.lfstatus = False
288
288
289 def overridestatus(orig, ui, repo, *pats, **opts):
289 def overridestatus(orig, ui, repo, *pats, **opts):
290 try:
290 try:
291 repo.lfstatus = True
291 repo.lfstatus = True
292 return orig(ui, repo, *pats, **opts)
292 return orig(ui, repo, *pats, **opts)
293 finally:
293 finally:
294 repo.lfstatus = False
294 repo.lfstatus = False
295
295
296 def overridedirty(orig, repo, ignoreupdate=False, missing=False):
296 def overridedirty(orig, repo, ignoreupdate=False, missing=False):
297 try:
297 try:
298 repo._repo.lfstatus = True
298 repo._repo.lfstatus = True
299 return orig(repo, ignoreupdate=ignoreupdate, missing=missing)
299 return orig(repo, ignoreupdate=ignoreupdate, missing=missing)
300 finally:
300 finally:
301 repo._repo.lfstatus = False
301 repo._repo.lfstatus = False
302
302
303 def overridelog(orig, ui, repo, *pats, **opts):
303 def overridelog(orig, ui, repo, *pats, **opts):
304 def overridematchandpats(ctx, pats=(), opts=None, globbed=False,
304 def overridematchandpats(ctx, pats=(), opts=None, globbed=False,
305 default='relpath', badfn=None):
305 default='relpath', badfn=None):
306 """Matcher that merges root directory with .hglf, suitable for log.
306 """Matcher that merges root directory with .hglf, suitable for log.
307 It is still possible to match .hglf directly.
307 It is still possible to match .hglf directly.
308 For any listed files run log on the standin too.
308 For any listed files run log on the standin too.
309 matchfn tries both the given filename and with .hglf stripped.
309 matchfn tries both the given filename and with .hglf stripped.
310 """
310 """
311 if opts is None:
311 if opts is None:
312 opts = {}
312 opts = {}
313 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default,
313 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default,
314 badfn=badfn)
314 badfn=badfn)
315 m, p = copy.copy(matchandpats)
315 m, p = copy.copy(matchandpats)
316
316
317 if m.always():
317 if m.always():
318 # We want to match everything anyway, so there's no benefit trying
318 # We want to match everything anyway, so there's no benefit trying
319 # to add standins.
319 # to add standins.
320 return matchandpats
320 return matchandpats
321
321
322 pats = set(p)
322 pats = set(p)
323
323
324 def fixpats(pat, tostandin=lfutil.standin):
324 def fixpats(pat, tostandin=lfutil.standin):
325 if pat.startswith('set:'):
325 if pat.startswith('set:'):
326 return pat
326 return pat
327
327
328 kindpat = matchmod._patsplit(pat, None)
328 kindpat = matchmod._patsplit(pat, None)
329
329
330 if kindpat[0] is not None:
330 if kindpat[0] is not None:
331 return kindpat[0] + ':' + tostandin(kindpat[1])
331 return kindpat[0] + ':' + tostandin(kindpat[1])
332 return tostandin(kindpat[1])
332 return tostandin(kindpat[1])
333
333
334 if m._cwd:
334 if m._cwd:
335 hglf = lfutil.shortname
335 hglf = lfutil.shortname
336 back = util.pconvert(m.rel(hglf)[:-len(hglf)])
336 back = util.pconvert(m.rel(hglf)[:-len(hglf)])
337
337
338 def tostandin(f):
338 def tostandin(f):
339 # The file may already be a standin, so truncate the back
339 # The file may already be a standin, so truncate the back
340 # prefix and test before mangling it. This avoids turning
340 # prefix and test before mangling it. This avoids turning
341 # 'glob:../.hglf/foo*' into 'glob:../.hglf/../.hglf/foo*'.
341 # 'glob:../.hglf/foo*' into 'glob:../.hglf/../.hglf/foo*'.
342 if f.startswith(back) and lfutil.splitstandin(f[len(back):]):
342 if f.startswith(back) and lfutil.splitstandin(f[len(back):]):
343 return f
343 return f
344
344
345 # An absolute path is from outside the repo, so truncate the
345 # An absolute path is from outside the repo, so truncate the
346 # path to the root before building the standin. Otherwise cwd
346 # path to the root before building the standin. Otherwise cwd
347 # is somewhere in the repo, relative to root, and needs to be
347 # is somewhere in the repo, relative to root, and needs to be
348 # prepended before building the standin.
348 # prepended before building the standin.
349 if os.path.isabs(m._cwd):
349 if os.path.isabs(m._cwd):
350 f = f[len(back):]
350 f = f[len(back):]
351 else:
351 else:
352 f = m._cwd + '/' + f
352 f = m._cwd + '/' + f
353 return back + lfutil.standin(f)
353 return back + lfutil.standin(f)
354 else:
354 else:
355 def tostandin(f):
355 def tostandin(f):
356 if lfutil.isstandin(f):
356 if lfutil.isstandin(f):
357 return f
357 return f
358 return lfutil.standin(f)
358 return lfutil.standin(f)
359 pats.update(fixpats(f, tostandin) for f in p)
359 pats.update(fixpats(f, tostandin) for f in p)
360
360
361 for i in range(0, len(m._files)):
361 for i in range(0, len(m._files)):
362 # Don't add '.hglf' to m.files, since that is already covered by '.'
362 # Don't add '.hglf' to m.files, since that is already covered by '.'
363 if m._files[i] == '.':
363 if m._files[i] == '.':
364 continue
364 continue
365 standin = lfutil.standin(m._files[i])
365 standin = lfutil.standin(m._files[i])
366 # If the "standin" is a directory, append instead of replace to
366 # If the "standin" is a directory, append instead of replace to
367 # support naming a directory on the command line with only
367 # support naming a directory on the command line with only
368 # largefiles. The original directory is kept to support normal
368 # largefiles. The original directory is kept to support normal
369 # files.
369 # files.
370 if standin in ctx:
370 if standin in ctx:
371 m._files[i] = standin
371 m._files[i] = standin
372 elif m._files[i] not in ctx and repo.wvfs.isdir(standin):
372 elif m._files[i] not in ctx and repo.wvfs.isdir(standin):
373 m._files.append(standin)
373 m._files.append(standin)
374
374
375 m._fileset = set(m._files)
375 m._fileset = set(m._files)
376 m.always = lambda: False
376 m.always = lambda: False
377 origmatchfn = m.matchfn
377 origmatchfn = m.matchfn
378 def lfmatchfn(f):
378 def lfmatchfn(f):
379 lf = lfutil.splitstandin(f)
379 lf = lfutil.splitstandin(f)
380 if lf is not None and origmatchfn(lf):
380 if lf is not None and origmatchfn(lf):
381 return True
381 return True
382 r = origmatchfn(f)
382 r = origmatchfn(f)
383 return r
383 return r
384 m.matchfn = lfmatchfn
384 m.matchfn = lfmatchfn
385
385
386 ui.debug('updated patterns: %s\n' % ', '.join(sorted(pats)))
386 ui.debug('updated patterns: %s\n' % ', '.join(sorted(pats)))
387 return m, pats
387 return m, pats
388
388
389 # For hg log --patch, the match object is used in two different senses:
389 # For hg log --patch, the match object is used in two different senses:
390 # (1) to determine what revisions should be printed out, and
390 # (1) to determine what revisions should be printed out, and
391 # (2) to determine what files to print out diffs for.
391 # (2) to determine what files to print out diffs for.
392 # The magic matchandpats override should be used for case (1) but not for
392 # The magic matchandpats override should be used for case (1) but not for
393 # case (2).
393 # case (2).
394 def overridemakefilematcher(repo, pats, opts, badfn=None):
394 def overridemakefilematcher(repo, pats, opts, badfn=None):
395 wctx = repo[None]
395 wctx = repo[None]
396 match, pats = oldmatchandpats(wctx, pats, opts, badfn=badfn)
396 match, pats = oldmatchandpats(wctx, pats, opts, badfn=badfn)
397 return lambda ctx: match
397 return lambda ctx: match
398
398
399 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
399 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
400 oldmakefilematcher = logcmdutil._makenofollowfilematcher
400 oldmakefilematcher = logcmdutil._makenofollowfilematcher
401 setattr(logcmdutil, '_makenofollowfilematcher', overridemakefilematcher)
401 setattr(logcmdutil, '_makenofollowfilematcher', overridemakefilematcher)
402
402
403 try:
403 try:
404 return orig(ui, repo, *pats, **opts)
404 return orig(ui, repo, *pats, **opts)
405 finally:
405 finally:
406 restorematchandpatsfn()
406 restorematchandpatsfn()
407 setattr(logcmdutil, '_makenofollowfilematcher', oldmakefilematcher)
407 setattr(logcmdutil, '_makenofollowfilematcher', oldmakefilematcher)
408
408
409 def overrideverify(orig, ui, repo, *pats, **opts):
409 def overrideverify(orig, ui, repo, *pats, **opts):
410 large = opts.pop(r'large', False)
410 large = opts.pop(r'large', False)
411 all = opts.pop(r'lfa', False)
411 all = opts.pop(r'lfa', False)
412 contents = opts.pop(r'lfc', False)
412 contents = opts.pop(r'lfc', False)
413
413
414 result = orig(ui, repo, *pats, **opts)
414 result = orig(ui, repo, *pats, **opts)
415 if large or all or contents:
415 if large or all or contents:
416 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
416 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
417 return result
417 return result
418
418
419 def overridedebugstate(orig, ui, repo, *pats, **opts):
419 def overridedebugstate(orig, ui, repo, *pats, **opts):
420 large = opts.pop(r'large', False)
420 large = opts.pop(r'large', False)
421 if large:
421 if large:
422 class fakerepo(object):
422 class fakerepo(object):
423 dirstate = lfutil.openlfdirstate(ui, repo)
423 dirstate = lfutil.openlfdirstate(ui, repo)
424 orig(ui, fakerepo, *pats, **opts)
424 orig(ui, fakerepo, *pats, **opts)
425 else:
425 else:
426 orig(ui, repo, *pats, **opts)
426 orig(ui, repo, *pats, **opts)
427
427
428 # Before starting the manifest merge, merge.updates will call
428 # Before starting the manifest merge, merge.updates will call
429 # _checkunknownfile to check if there are any files in the merged-in
429 # _checkunknownfile to check if there are any files in the merged-in
430 # changeset that collide with unknown files in the working copy.
430 # changeset that collide with unknown files in the working copy.
431 #
431 #
432 # The largefiles are seen as unknown, so this prevents us from merging
432 # The largefiles are seen as unknown, so this prevents us from merging
433 # in a file 'foo' if we already have a largefile with the same name.
433 # in a file 'foo' if we already have a largefile with the same name.
434 #
434 #
435 # The overridden function filters the unknown files by removing any
435 # The overridden function filters the unknown files by removing any
436 # largefiles. This makes the merge proceed and we can then handle this
436 # largefiles. This makes the merge proceed and we can then handle this
437 # case further in the overridden calculateupdates function below.
437 # case further in the overridden calculateupdates function below.
438 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
438 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
439 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
439 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
440 return False
440 return False
441 return origfn(repo, wctx, mctx, f, f2)
441 return origfn(repo, wctx, mctx, f, f2)
442
442
443 # The manifest merge handles conflicts on the manifest level. We want
443 # The manifest merge handles conflicts on the manifest level. We want
444 # to handle changes in largefile-ness of files at this level too.
444 # to handle changes in largefile-ness of files at this level too.
445 #
445 #
446 # The strategy is to run the original calculateupdates and then process
446 # The strategy is to run the original calculateupdates and then process
447 # the action list it outputs. There are two cases we need to deal with:
447 # the action list it outputs. There are two cases we need to deal with:
448 #
448 #
449 # 1. Normal file in p1, largefile in p2. Here the largefile is
449 # 1. Normal file in p1, largefile in p2. Here the largefile is
450 # detected via its standin file, which will enter the working copy
450 # detected via its standin file, which will enter the working copy
451 # with a "get" action. It is not "merge" since the standin is all
451 # with a "get" action. It is not "merge" since the standin is all
452 # Mercurial is concerned with at this level -- the link to the
452 # Mercurial is concerned with at this level -- the link to the
453 # existing normal file is not relevant here.
453 # existing normal file is not relevant here.
454 #
454 #
455 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
455 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
456 # since the largefile will be present in the working copy and
456 # since the largefile will be present in the working copy and
457 # different from the normal file in p2. Mercurial therefore
457 # different from the normal file in p2. Mercurial therefore
458 # triggers a merge action.
458 # triggers a merge action.
459 #
459 #
460 # In both cases, we prompt the user and emit new actions to either
460 # In both cases, we prompt the user and emit new actions to either
461 # remove the standin (if the normal file was kept) or to remove the
461 # remove the standin (if the normal file was kept) or to remove the
462 # normal file and get the standin (if the largefile was kept). The
462 # normal file and get the standin (if the largefile was kept). The
463 # default prompt answer is to use the largefile version since it was
463 # default prompt answer is to use the largefile version since it was
464 # presumably changed on purpose.
464 # presumably changed on purpose.
465 #
465 #
466 # Finally, the merge.applyupdates function will then take care of
466 # Finally, the merge.applyupdates function will then take care of
467 # writing the files into the working copy and lfcommands.updatelfiles
467 # writing the files into the working copy and lfcommands.updatelfiles
468 # will update the largefiles.
468 # will update the largefiles.
469 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
469 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
470 acceptremote, *args, **kwargs):
470 acceptremote, *args, **kwargs):
471 overwrite = force and not branchmerge
471 overwrite = force and not branchmerge
472 actions, diverge, renamedelete = origfn(
472 actions, diverge, renamedelete = origfn(
473 repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs)
473 repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs)
474
474
475 if overwrite:
475 if overwrite:
476 return actions, diverge, renamedelete
476 return actions, diverge, renamedelete
477
477
478 # Convert to dictionary with filename as key and action as value.
478 # Convert to dictionary with filename as key and action as value.
479 lfiles = set()
479 lfiles = set()
480 for f in actions:
480 for f in actions:
481 splitstandin = lfutil.splitstandin(f)
481 splitstandin = lfutil.splitstandin(f)
482 if splitstandin in p1:
482 if splitstandin in p1:
483 lfiles.add(splitstandin)
483 lfiles.add(splitstandin)
484 elif lfutil.standin(f) in p1:
484 elif lfutil.standin(f) in p1:
485 lfiles.add(f)
485 lfiles.add(f)
486
486
487 for lfile in sorted(lfiles):
487 for lfile in sorted(lfiles):
488 standin = lfutil.standin(lfile)
488 standin = lfutil.standin(lfile)
489 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
489 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
490 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
490 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
491 if sm in ('g', 'dc') and lm != 'r':
491 if sm in ('g', 'dc') and lm != 'r':
492 if sm == 'dc':
492 if sm == 'dc':
493 f1, f2, fa, move, anc = sargs
493 f1, f2, fa, move, anc = sargs
494 sargs = (p2[f2].flags(), False)
494 sargs = (p2[f2].flags(), False)
495 # Case 1: normal file in the working copy, largefile in
495 # Case 1: normal file in the working copy, largefile in
496 # the second parent
496 # the second parent
497 usermsg = _('remote turned local normal file %s into a largefile\n'
497 usermsg = _('remote turned local normal file %s into a largefile\n'
498 'use (l)argefile or keep (n)ormal file?'
498 'use (l)argefile or keep (n)ormal file?'
499 '$$ &Largefile $$ &Normal file') % lfile
499 '$$ &Largefile $$ &Normal file') % lfile
500 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
500 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
501 actions[lfile] = ('r', None, 'replaced by standin')
501 actions[lfile] = ('r', None, 'replaced by standin')
502 actions[standin] = ('g', sargs, 'replaces standin')
502 actions[standin] = ('g', sargs, 'replaces standin')
503 else: # keep local normal file
503 else: # keep local normal file
504 actions[lfile] = ('k', None, 'replaces standin')
504 actions[lfile] = ('k', None, 'replaces standin')
505 if branchmerge:
505 if branchmerge:
506 actions[standin] = ('k', None, 'replaced by non-standin')
506 actions[standin] = ('k', None, 'replaced by non-standin')
507 else:
507 else:
508 actions[standin] = ('r', None, 'replaced by non-standin')
508 actions[standin] = ('r', None, 'replaced by non-standin')
509 elif lm in ('g', 'dc') and sm != 'r':
509 elif lm in ('g', 'dc') and sm != 'r':
510 if lm == 'dc':
510 if lm == 'dc':
511 f1, f2, fa, move, anc = largs
511 f1, f2, fa, move, anc = largs
512 largs = (p2[f2].flags(), False)
512 largs = (p2[f2].flags(), False)
513 # Case 2: largefile in the working copy, normal file in
513 # Case 2: largefile in the working copy, normal file in
514 # the second parent
514 # the second parent
515 usermsg = _('remote turned local largefile %s into a normal file\n'
515 usermsg = _('remote turned local largefile %s into a normal file\n'
516 'keep (l)argefile or use (n)ormal file?'
516 'keep (l)argefile or use (n)ormal file?'
517 '$$ &Largefile $$ &Normal file') % lfile
517 '$$ &Largefile $$ &Normal file') % lfile
518 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
518 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
519 if branchmerge:
519 if branchmerge:
520 # largefile can be restored from standin safely
520 # largefile can be restored from standin safely
521 actions[lfile] = ('k', None, 'replaced by standin')
521 actions[lfile] = ('k', None, 'replaced by standin')
522 actions[standin] = ('k', None, 'replaces standin')
522 actions[standin] = ('k', None, 'replaces standin')
523 else:
523 else:
524 # "lfile" should be marked as "removed" without
524 # "lfile" should be marked as "removed" without
525 # removal of itself
525 # removal of itself
526 actions[lfile] = ('lfmr', None,
526 actions[lfile] = ('lfmr', None,
527 'forget non-standin largefile')
527 'forget non-standin largefile')
528
528
529 # linear-merge should treat this largefile as 're-added'
529 # linear-merge should treat this largefile as 're-added'
530 actions[standin] = ('a', None, 'keep standin')
530 actions[standin] = ('a', None, 'keep standin')
531 else: # pick remote normal file
531 else: # pick remote normal file
532 actions[lfile] = ('g', largs, 'replaces standin')
532 actions[lfile] = ('g', largs, 'replaces standin')
533 actions[standin] = ('r', None, 'replaced by non-standin')
533 actions[standin] = ('r', None, 'replaced by non-standin')
534
534
535 return actions, diverge, renamedelete
535 return actions, diverge, renamedelete
536
536
537 def mergerecordupdates(orig, repo, actions, branchmerge):
537 def mergerecordupdates(orig, repo, actions, branchmerge):
538 if 'lfmr' in actions:
538 if 'lfmr' in actions:
539 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
539 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
540 for lfile, args, msg in actions['lfmr']:
540 for lfile, args, msg in actions['lfmr']:
541 # this should be executed before 'orig', to execute 'remove'
541 # this should be executed before 'orig', to execute 'remove'
542 # before all other actions
542 # before all other actions
543 repo.dirstate.remove(lfile)
543 repo.dirstate.remove(lfile)
544 # make sure lfile doesn't get synclfdirstate'd as normal
544 # make sure lfile doesn't get synclfdirstate'd as normal
545 lfdirstate.add(lfile)
545 lfdirstate.add(lfile)
546 lfdirstate.write()
546 lfdirstate.write()
547
547
548 return orig(repo, actions, branchmerge)
548 return orig(repo, actions, branchmerge)
549
549
550 # Override filemerge to prompt the user about how they wish to merge
550 # Override filemerge to prompt the user about how they wish to merge
551 # largefiles. This will handle identical edits without prompting the user.
551 # largefiles. This will handle identical edits without prompting the user.
552 def overridefilemerge(origfn, premerge, repo, wctx, mynode, orig, fcd, fco, fca,
552 def overridefilemerge(origfn, premerge, repo, wctx, mynode, orig, fcd, fco, fca,
553 labels=None):
553 labels=None):
554 if not lfutil.isstandin(orig) or fcd.isabsent() or fco.isabsent():
554 if not lfutil.isstandin(orig) or fcd.isabsent() or fco.isabsent():
555 return origfn(premerge, repo, wctx, mynode, orig, fcd, fco, fca,
555 return origfn(premerge, repo, wctx, mynode, orig, fcd, fco, fca,
556 labels=labels)
556 labels=labels)
557
557
558 ahash = lfutil.readasstandin(fca).lower()
558 ahash = lfutil.readasstandin(fca).lower()
559 dhash = lfutil.readasstandin(fcd).lower()
559 dhash = lfutil.readasstandin(fcd).lower()
560 ohash = lfutil.readasstandin(fco).lower()
560 ohash = lfutil.readasstandin(fco).lower()
561 if (ohash != ahash and
561 if (ohash != ahash and
562 ohash != dhash and
562 ohash != dhash and
563 (dhash == ahash or
563 (dhash == ahash or
564 repo.ui.promptchoice(
564 repo.ui.promptchoice(
565 _('largefile %s has a merge conflict\nancestor was %s\n'
565 _('largefile %s has a merge conflict\nancestor was %s\n'
566 'keep (l)ocal %s or\ntake (o)ther %s?'
566 'keep (l)ocal %s or\ntake (o)ther %s?'
567 '$$ &Local $$ &Other') %
567 '$$ &Local $$ &Other') %
568 (lfutil.splitstandin(orig), ahash, dhash, ohash),
568 (lfutil.splitstandin(orig), ahash, dhash, ohash),
569 0) == 1)):
569 0) == 1)):
570 repo.wwrite(fcd.path(), fco.data(), fco.flags())
570 repo.wwrite(fcd.path(), fco.data(), fco.flags())
571 return True, 0, False
571 return True, 0, False
572
572
573 def copiespathcopies(orig, ctx1, ctx2, match=None):
573 def copiespathcopies(orig, ctx1, ctx2, match=None):
574 copies = orig(ctx1, ctx2, match=match)
574 copies = orig(ctx1, ctx2, match=match)
575 updated = {}
575 updated = {}
576
576
577 for k, v in copies.iteritems():
577 for k, v in copies.iteritems():
578 updated[lfutil.splitstandin(k) or k] = lfutil.splitstandin(v) or v
578 updated[lfutil.splitstandin(k) or k] = lfutil.splitstandin(v) or v
579
579
580 return updated
580 return updated
581
581
582 # Copy first changes the matchers to match standins instead of
582 # Copy first changes the matchers to match standins instead of
583 # largefiles. Then it overrides util.copyfile in that function it
583 # largefiles. Then it overrides util.copyfile in that function it
584 # checks if the destination largefile already exists. It also keeps a
584 # checks if the destination largefile already exists. It also keeps a
585 # list of copied files so that the largefiles can be copied and the
585 # list of copied files so that the largefiles can be copied and the
586 # dirstate updated.
586 # dirstate updated.
587 def overridecopy(orig, ui, repo, pats, opts, rename=False):
587 def overridecopy(orig, ui, repo, pats, opts, rename=False):
588 # doesn't remove largefile on rename
588 # doesn't remove largefile on rename
589 if len(pats) < 2:
589 if len(pats) < 2:
590 # this isn't legal, let the original function deal with it
590 # this isn't legal, let the original function deal with it
591 return orig(ui, repo, pats, opts, rename)
591 return orig(ui, repo, pats, opts, rename)
592
592
593 # This could copy both lfiles and normal files in one command,
593 # This could copy both lfiles and normal files in one command,
594 # but we don't want to do that. First replace their matcher to
594 # but we don't want to do that. First replace their matcher to
595 # only match normal files and run it, then replace it to just
595 # only match normal files and run it, then replace it to just
596 # match largefiles and run it again.
596 # match largefiles and run it again.
597 nonormalfiles = False
597 nonormalfiles = False
598 nolfiles = False
598 nolfiles = False
599 installnormalfilesmatchfn(repo[None].manifest())
599 installnormalfilesmatchfn(repo[None].manifest())
600 try:
600 try:
601 result = orig(ui, repo, pats, opts, rename)
601 result = orig(ui, repo, pats, opts, rename)
602 except error.Abort as e:
602 except error.Abort as e:
603 if pycompat.bytestr(e) != _('no files to copy'):
603 if pycompat.bytestr(e) != _('no files to copy'):
604 raise e
604 raise e
605 else:
605 else:
606 nonormalfiles = True
606 nonormalfiles = True
607 result = 0
607 result = 0
608 finally:
608 finally:
609 restorematchfn()
609 restorematchfn()
610
610
611 # The first rename can cause our current working directory to be removed.
611 # The first rename can cause our current working directory to be removed.
612 # In that case there is nothing left to copy/rename so just quit.
612 # In that case there is nothing left to copy/rename so just quit.
613 try:
613 try:
614 repo.getcwd()
614 repo.getcwd()
615 except OSError:
615 except OSError:
616 return result
616 return result
617
617
618 def makestandin(relpath):
618 def makestandin(relpath):
619 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
619 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
620 return repo.wvfs.join(lfutil.standin(path))
620 return repo.wvfs.join(lfutil.standin(path))
621
621
622 fullpats = scmutil.expandpats(pats)
622 fullpats = scmutil.expandpats(pats)
623 dest = fullpats[-1]
623 dest = fullpats[-1]
624
624
625 if os.path.isdir(dest):
625 if os.path.isdir(dest):
626 if not os.path.isdir(makestandin(dest)):
626 if not os.path.isdir(makestandin(dest)):
627 os.makedirs(makestandin(dest))
627 os.makedirs(makestandin(dest))
628
628
629 try:
629 try:
630 # When we call orig below it creates the standins but we don't add
630 # When we call orig below it creates the standins but we don't add
631 # them to the dir state until later so lock during that time.
631 # them to the dir state until later so lock during that time.
632 wlock = repo.wlock()
632 wlock = repo.wlock()
633
633
634 manifest = repo[None].manifest()
634 manifest = repo[None].manifest()
635 def overridematch(ctx, pats=(), opts=None, globbed=False,
635 def overridematch(ctx, pats=(), opts=None, globbed=False,
636 default='relpath', badfn=None):
636 default='relpath', badfn=None):
637 if opts is None:
637 if opts is None:
638 opts = {}
638 opts = {}
639 newpats = []
639 newpats = []
640 # The patterns were previously mangled to add the standin
640 # The patterns were previously mangled to add the standin
641 # directory; we need to remove that now
641 # directory; we need to remove that now
642 for pat in pats:
642 for pat in pats:
643 if matchmod.patkind(pat) is None and lfutil.shortname in pat:
643 if matchmod.patkind(pat) is None and lfutil.shortname in pat:
644 newpats.append(pat.replace(lfutil.shortname, ''))
644 newpats.append(pat.replace(lfutil.shortname, ''))
645 else:
645 else:
646 newpats.append(pat)
646 newpats.append(pat)
647 match = oldmatch(ctx, newpats, opts, globbed, default, badfn=badfn)
647 match = oldmatch(ctx, newpats, opts, globbed, default, badfn=badfn)
648 m = copy.copy(match)
648 m = copy.copy(match)
649 lfile = lambda f: lfutil.standin(f) in manifest
649 lfile = lambda f: lfutil.standin(f) in manifest
650 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
650 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
651 m._fileset = set(m._files)
651 m._fileset = set(m._files)
652 origmatchfn = m.matchfn
652 origmatchfn = m.matchfn
653 def matchfn(f):
653 def matchfn(f):
654 lfile = lfutil.splitstandin(f)
654 lfile = lfutil.splitstandin(f)
655 return (lfile is not None and
655 return (lfile is not None and
656 (f in manifest) and
656 (f in manifest) and
657 origmatchfn(lfile) or
657 origmatchfn(lfile) or
658 None)
658 None)
659 m.matchfn = matchfn
659 m.matchfn = matchfn
660 return m
660 return m
661 oldmatch = installmatchfn(overridematch)
661 oldmatch = installmatchfn(overridematch)
662 listpats = []
662 listpats = []
663 for pat in pats:
663 for pat in pats:
664 if matchmod.patkind(pat) is not None:
664 if matchmod.patkind(pat) is not None:
665 listpats.append(pat)
665 listpats.append(pat)
666 else:
666 else:
667 listpats.append(makestandin(pat))
667 listpats.append(makestandin(pat))
668
668
669 try:
669 try:
670 origcopyfile = util.copyfile
670 origcopyfile = util.copyfile
671 copiedfiles = []
671 copiedfiles = []
672 def overridecopyfile(src, dest, *args, **kwargs):
672 def overridecopyfile(src, dest, *args, **kwargs):
673 if (lfutil.shortname in src and
673 if (lfutil.shortname in src and
674 dest.startswith(repo.wjoin(lfutil.shortname))):
674 dest.startswith(repo.wjoin(lfutil.shortname))):
675 destlfile = dest.replace(lfutil.shortname, '')
675 destlfile = dest.replace(lfutil.shortname, '')
676 if not opts['force'] and os.path.exists(destlfile):
676 if not opts['force'] and os.path.exists(destlfile):
677 raise IOError('',
677 raise IOError('',
678 _('destination largefile already exists'))
678 _('destination largefile already exists'))
679 copiedfiles.append((src, dest))
679 copiedfiles.append((src, dest))
680 origcopyfile(src, dest, *args, **kwargs)
680 origcopyfile(src, dest, *args, **kwargs)
681
681
682 util.copyfile = overridecopyfile
682 util.copyfile = overridecopyfile
683 result += orig(ui, repo, listpats, opts, rename)
683 result += orig(ui, repo, listpats, opts, rename)
684 finally:
684 finally:
685 util.copyfile = origcopyfile
685 util.copyfile = origcopyfile
686
686
687 lfdirstate = lfutil.openlfdirstate(ui, repo)
687 lfdirstate = lfutil.openlfdirstate(ui, repo)
688 for (src, dest) in copiedfiles:
688 for (src, dest) in copiedfiles:
689 if (lfutil.shortname in src and
689 if (lfutil.shortname in src and
690 dest.startswith(repo.wjoin(lfutil.shortname))):
690 dest.startswith(repo.wjoin(lfutil.shortname))):
691 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
691 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
692 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
692 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
693 destlfiledir = repo.wvfs.dirname(repo.wjoin(destlfile)) or '.'
693 destlfiledir = repo.wvfs.dirname(repo.wjoin(destlfile)) or '.'
694 if not os.path.isdir(destlfiledir):
694 if not os.path.isdir(destlfiledir):
695 os.makedirs(destlfiledir)
695 os.makedirs(destlfiledir)
696 if rename:
696 if rename:
697 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
697 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
698
698
699 # The file is gone, but this deletes any empty parent
699 # The file is gone, but this deletes any empty parent
700 # directories as a side-effect.
700 # directories as a side-effect.
701 repo.wvfs.unlinkpath(srclfile, ignoremissing=True)
701 repo.wvfs.unlinkpath(srclfile, ignoremissing=True)
702 lfdirstate.remove(srclfile)
702 lfdirstate.remove(srclfile)
703 else:
703 else:
704 util.copyfile(repo.wjoin(srclfile),
704 util.copyfile(repo.wjoin(srclfile),
705 repo.wjoin(destlfile))
705 repo.wjoin(destlfile))
706
706
707 lfdirstate.add(destlfile)
707 lfdirstate.add(destlfile)
708 lfdirstate.write()
708 lfdirstate.write()
709 except error.Abort as e:
709 except error.Abort as e:
710 if pycompat.bytestr(e) != _('no files to copy'):
710 if pycompat.bytestr(e) != _('no files to copy'):
711 raise e
711 raise e
712 else:
712 else:
713 nolfiles = True
713 nolfiles = True
714 finally:
714 finally:
715 restorematchfn()
715 restorematchfn()
716 wlock.release()
716 wlock.release()
717
717
718 if nolfiles and nonormalfiles:
718 if nolfiles and nonormalfiles:
719 raise error.Abort(_('no files to copy'))
719 raise error.Abort(_('no files to copy'))
720
720
721 return result
721 return result
722
722
723 # When the user calls revert, we have to be careful to not revert any
723 # When the user calls revert, we have to be careful to not revert any
724 # changes to other largefiles accidentally. This means we have to keep
724 # changes to other largefiles accidentally. This means we have to keep
725 # track of the largefiles that are being reverted so we only pull down
725 # track of the largefiles that are being reverted so we only pull down
726 # the necessary largefiles.
726 # the necessary largefiles.
727 #
727 #
728 # Standins are only updated (to match the hash of largefiles) before
728 # Standins are only updated (to match the hash of largefiles) before
729 # commits. Update the standins then run the original revert, changing
729 # commits. Update the standins then run the original revert, changing
730 # the matcher to hit standins instead of largefiles. Based on the
730 # the matcher to hit standins instead of largefiles. Based on the
731 # resulting standins update the largefiles.
731 # resulting standins update the largefiles.
732 def overriderevert(orig, ui, repo, ctx, parents, *pats, **opts):
732 def overriderevert(orig, ui, repo, ctx, parents, *pats, **opts):
733 # Because we put the standins in a bad state (by updating them)
733 # Because we put the standins in a bad state (by updating them)
734 # and then return them to a correct state we need to lock to
734 # and then return them to a correct state we need to lock to
735 # prevent others from changing them in their incorrect state.
735 # prevent others from changing them in their incorrect state.
736 with repo.wlock():
736 with repo.wlock():
737 lfdirstate = lfutil.openlfdirstate(ui, repo)
737 lfdirstate = lfutil.openlfdirstate(ui, repo)
738 s = lfutil.lfdirstatestatus(lfdirstate, repo)
738 s = lfutil.lfdirstatestatus(lfdirstate, repo)
739 lfdirstate.write()
739 lfdirstate.write()
740 for lfile in s.modified:
740 for lfile in s.modified:
741 lfutil.updatestandin(repo, lfile, lfutil.standin(lfile))
741 lfutil.updatestandin(repo, lfile, lfutil.standin(lfile))
742 for lfile in s.deleted:
742 for lfile in s.deleted:
743 fstandin = lfutil.standin(lfile)
743 fstandin = lfutil.standin(lfile)
744 if (repo.wvfs.exists(fstandin)):
744 if (repo.wvfs.exists(fstandin)):
745 repo.wvfs.unlink(fstandin)
745 repo.wvfs.unlink(fstandin)
746
746
747 oldstandins = lfutil.getstandinsstate(repo)
747 oldstandins = lfutil.getstandinsstate(repo)
748
748
749 def overridematch(mctx, pats=(), opts=None, globbed=False,
749 def overridematch(mctx, pats=(), opts=None, globbed=False,
750 default='relpath', badfn=None):
750 default='relpath', badfn=None):
751 if opts is None:
751 if opts is None:
752 opts = {}
752 opts = {}
753 match = oldmatch(mctx, pats, opts, globbed, default, badfn=badfn)
753 match = oldmatch(mctx, pats, opts, globbed, default, badfn=badfn)
754 m = copy.copy(match)
754 m = copy.copy(match)
755
755
756 # revert supports recursing into subrepos, and though largefiles
756 # revert supports recursing into subrepos, and though largefiles
757 # currently doesn't work correctly in that case, this match is
757 # currently doesn't work correctly in that case, this match is
758 # called, so the lfdirstate above may not be the correct one for
758 # called, so the lfdirstate above may not be the correct one for
759 # this invocation of match.
759 # this invocation of match.
760 lfdirstate = lfutil.openlfdirstate(mctx.repo().ui, mctx.repo(),
760 lfdirstate = lfutil.openlfdirstate(mctx.repo().ui, mctx.repo(),
761 False)
761 False)
762
762
763 wctx = repo[None]
763 wctx = repo[None]
764 matchfiles = []
764 matchfiles = []
765 for f in m._files:
765 for f in m._files:
766 standin = lfutil.standin(f)
766 standin = lfutil.standin(f)
767 if standin in ctx or standin in mctx:
767 if standin in ctx or standin in mctx:
768 matchfiles.append(standin)
768 matchfiles.append(standin)
769 elif standin in wctx or lfdirstate[f] == 'r':
769 elif standin in wctx or lfdirstate[f] == 'r':
770 continue
770 continue
771 else:
771 else:
772 matchfiles.append(f)
772 matchfiles.append(f)
773 m._files = matchfiles
773 m._files = matchfiles
774 m._fileset = set(m._files)
774 m._fileset = set(m._files)
775 origmatchfn = m.matchfn
775 origmatchfn = m.matchfn
776 def matchfn(f):
776 def matchfn(f):
777 lfile = lfutil.splitstandin(f)
777 lfile = lfutil.splitstandin(f)
778 if lfile is not None:
778 if lfile is not None:
779 return (origmatchfn(lfile) and
779 return (origmatchfn(lfile) and
780 (f in ctx or f in mctx))
780 (f in ctx or f in mctx))
781 return origmatchfn(f)
781 return origmatchfn(f)
782 m.matchfn = matchfn
782 m.matchfn = matchfn
783 return m
783 return m
784 oldmatch = installmatchfn(overridematch)
784 oldmatch = installmatchfn(overridematch)
785 try:
785 try:
786 orig(ui, repo, ctx, parents, *pats, **opts)
786 orig(ui, repo, ctx, parents, *pats, **opts)
787 finally:
787 finally:
788 restorematchfn()
788 restorematchfn()
789
789
790 newstandins = lfutil.getstandinsstate(repo)
790 newstandins = lfutil.getstandinsstate(repo)
791 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
791 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
792 # lfdirstate should be 'normallookup'-ed for updated files,
792 # lfdirstate should be 'normallookup'-ed for updated files,
793 # because reverting doesn't touch dirstate for 'normal' files
793 # because reverting doesn't touch dirstate for 'normal' files
794 # when target revision is explicitly specified: in such case,
794 # when target revision is explicitly specified: in such case,
795 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
795 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
796 # of target (standin) file.
796 # of target (standin) file.
797 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
797 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
798 normallookup=True)
798 normallookup=True)
799
799
800 # after pulling changesets, we need to take some extra care to get
800 # after pulling changesets, we need to take some extra care to get
801 # largefiles updated remotely
801 # largefiles updated remotely
802 def overridepull(orig, ui, repo, source=None, **opts):
802 def overridepull(orig, ui, repo, source=None, **opts):
803 revsprepull = len(repo)
803 revsprepull = len(repo)
804 if not source:
804 if not source:
805 source = 'default'
805 source = 'default'
806 repo.lfpullsource = source
806 repo.lfpullsource = source
807 result = orig(ui, repo, source, **opts)
807 result = orig(ui, repo, source, **opts)
808 revspostpull = len(repo)
808 revspostpull = len(repo)
809 lfrevs = opts.get(r'lfrev', [])
809 lfrevs = opts.get(r'lfrev', [])
810 if opts.get(r'all_largefiles'):
810 if opts.get(r'all_largefiles'):
811 lfrevs.append('pulled()')
811 lfrevs.append('pulled()')
812 if lfrevs and revspostpull > revsprepull:
812 if lfrevs and revspostpull > revsprepull:
813 numcached = 0
813 numcached = 0
814 repo.firstpulled = revsprepull # for pulled() revset expression
814 repo.firstpulled = revsprepull # for pulled() revset expression
815 try:
815 try:
816 for rev in scmutil.revrange(repo, lfrevs):
816 for rev in scmutil.revrange(repo, lfrevs):
817 ui.note(_('pulling largefiles for revision %d\n') % rev)
817 ui.note(_('pulling largefiles for revision %d\n') % rev)
818 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
818 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
819 numcached += len(cached)
819 numcached += len(cached)
820 finally:
820 finally:
821 del repo.firstpulled
821 del repo.firstpulled
822 ui.status(_("%d largefiles cached\n") % numcached)
822 ui.status(_("%d largefiles cached\n") % numcached)
823 return result
823 return result
824
824
825 def overridepush(orig, ui, repo, *args, **kwargs):
825 def overridepush(orig, ui, repo, *args, **kwargs):
826 """Override push command and store --lfrev parameters in opargs"""
826 """Override push command and store --lfrev parameters in opargs"""
827 lfrevs = kwargs.pop(r'lfrev', None)
827 lfrevs = kwargs.pop(r'lfrev', None)
828 if lfrevs:
828 if lfrevs:
829 opargs = kwargs.setdefault(r'opargs', {})
829 opargs = kwargs.setdefault(r'opargs', {})
830 opargs['lfrevs'] = scmutil.revrange(repo, lfrevs)
830 opargs['lfrevs'] = scmutil.revrange(repo, lfrevs)
831 return orig(ui, repo, *args, **kwargs)
831 return orig(ui, repo, *args, **kwargs)
832
832
833 def exchangepushoperation(orig, *args, **kwargs):
833 def exchangepushoperation(orig, *args, **kwargs):
834 """Override pushoperation constructor and store lfrevs parameter"""
834 """Override pushoperation constructor and store lfrevs parameter"""
835 lfrevs = kwargs.pop(r'lfrevs', None)
835 lfrevs = kwargs.pop(r'lfrevs', None)
836 pushop = orig(*args, **kwargs)
836 pushop = orig(*args, **kwargs)
837 pushop.lfrevs = lfrevs
837 pushop.lfrevs = lfrevs
838 return pushop
838 return pushop
839
839
840 revsetpredicate = registrar.revsetpredicate()
840 revsetpredicate = registrar.revsetpredicate()
841
841
842 @revsetpredicate('pulled()')
842 @revsetpredicate('pulled()')
843 def pulledrevsetsymbol(repo, subset, x):
843 def pulledrevsetsymbol(repo, subset, x):
844 """Changesets that just has been pulled.
844 """Changesets that just has been pulled.
845
845
846 Only available with largefiles from pull --lfrev expressions.
846 Only available with largefiles from pull --lfrev expressions.
847
847
848 .. container:: verbose
848 .. container:: verbose
849
849
850 Some examples:
850 Some examples:
851
851
852 - pull largefiles for all new changesets::
852 - pull largefiles for all new changesets::
853
853
854 hg pull -lfrev "pulled()"
854 hg pull -lfrev "pulled()"
855
855
856 - pull largefiles for all new branch heads::
856 - pull largefiles for all new branch heads::
857
857
858 hg pull -lfrev "head(pulled()) and not closed()"
858 hg pull -lfrev "head(pulled()) and not closed()"
859
859
860 """
860 """
861
861
862 try:
862 try:
863 firstpulled = repo.firstpulled
863 firstpulled = repo.firstpulled
864 except AttributeError:
864 except AttributeError:
865 raise error.Abort(_("pulled() only available in --lfrev"))
865 raise error.Abort(_("pulled() only available in --lfrev"))
866 return smartset.baseset([r for r in subset if r >= firstpulled])
866 return smartset.baseset([r for r in subset if r >= firstpulled])
867
867
868 def overrideclone(orig, ui, source, dest=None, **opts):
868 def overrideclone(orig, ui, source, dest=None, **opts):
869 d = dest
869 d = dest
870 if d is None:
870 if d is None:
871 d = hg.defaultdest(source)
871 d = hg.defaultdest(source)
872 if opts.get(r'all_largefiles') and not hg.islocal(d):
872 if opts.get(r'all_largefiles') and not hg.islocal(d):
873 raise error.Abort(_(
873 raise error.Abort(_(
874 '--all-largefiles is incompatible with non-local destination %s') %
874 '--all-largefiles is incompatible with non-local destination %s') %
875 d)
875 d)
876
876
877 return orig(ui, source, dest, **opts)
877 return orig(ui, source, dest, **opts)
878
878
879 def hgclone(orig, ui, opts, *args, **kwargs):
879 def hgclone(orig, ui, opts, *args, **kwargs):
880 result = orig(ui, opts, *args, **kwargs)
880 result = orig(ui, opts, *args, **kwargs)
881
881
882 if result is not None:
882 if result is not None:
883 sourcerepo, destrepo = result
883 sourcerepo, destrepo = result
884 repo = destrepo.local()
884 repo = destrepo.local()
885
885
886 # When cloning to a remote repo (like through SSH), no repo is available
886 # When cloning to a remote repo (like through SSH), no repo is available
887 # from the peer. Therefore the largefiles can't be downloaded and the
887 # from the peer. Therefore the largefiles can't be downloaded and the
888 # hgrc can't be updated.
888 # hgrc can't be updated.
889 if not repo:
889 if not repo:
890 return result
890 return result
891
891
892 # If largefiles is required for this repo, permanently enable it locally
892 # If largefiles is required for this repo, permanently enable it locally
893 if 'largefiles' in repo.requirements:
893 if 'largefiles' in repo.requirements:
894 repo.vfs.append('hgrc',
894 repo.vfs.append('hgrc',
895 util.tonativeeol('\n[extensions]\nlargefiles=\n'))
895 util.tonativeeol('\n[extensions]\nlargefiles=\n'))
896
896
897 # Caching is implicitly limited to 'rev' option, since the dest repo was
897 # Caching is implicitly limited to 'rev' option, since the dest repo was
898 # truncated at that point. The user may expect a download count with
898 # truncated at that point. The user may expect a download count with
899 # this option, so attempt whether or not this is a largefile repo.
899 # this option, so attempt whether or not this is a largefile repo.
900 if opts.get(r'all_largefiles'):
900 if opts.get('all_largefiles'):
901 success, missing = lfcommands.downloadlfiles(ui, repo, None)
901 success, missing = lfcommands.downloadlfiles(ui, repo, None)
902
902
903 if missing != 0:
903 if missing != 0:
904 return None
904 return None
905
905
906 return result
906 return result
907
907
908 def hgpostshare(orig, sourcerepo, destrepo, bookmarks=True, defaultpath=None):
908 def hgpostshare(orig, sourcerepo, destrepo, bookmarks=True, defaultpath=None):
909 orig(sourcerepo, destrepo, bookmarks, defaultpath)
909 orig(sourcerepo, destrepo, bookmarks, defaultpath)
910
910
911 # If largefiles is required for this repo, permanently enable it locally
911 # If largefiles is required for this repo, permanently enable it locally
912 if 'largefiles' in destrepo.requirements:
912 if 'largefiles' in destrepo.requirements:
913 destrepo.vfs.append('hgrc',
913 destrepo.vfs.append('hgrc',
914 util.tonativeeol('\n[extensions]\nlargefiles=\n'))
914 util.tonativeeol('\n[extensions]\nlargefiles=\n'))
915
915
916 def overriderebase(orig, ui, repo, **opts):
916 def overriderebase(orig, ui, repo, **opts):
917 if not util.safehasattr(repo, '_largefilesenabled'):
917 if not util.safehasattr(repo, '_largefilesenabled'):
918 return orig(ui, repo, **opts)
918 return orig(ui, repo, **opts)
919
919
920 resuming = opts.get(r'continue')
920 resuming = opts.get(r'continue')
921 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
921 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
922 repo._lfstatuswriters.append(lambda *msg, **opts: None)
922 repo._lfstatuswriters.append(lambda *msg, **opts: None)
923 try:
923 try:
924 return orig(ui, repo, **opts)
924 return orig(ui, repo, **opts)
925 finally:
925 finally:
926 repo._lfstatuswriters.pop()
926 repo._lfstatuswriters.pop()
927 repo._lfcommithooks.pop()
927 repo._lfcommithooks.pop()
928
928
929 def overridearchivecmd(orig, ui, repo, dest, **opts):
929 def overridearchivecmd(orig, ui, repo, dest, **opts):
930 repo.unfiltered().lfstatus = True
930 repo.unfiltered().lfstatus = True
931
931
932 try:
932 try:
933 return orig(ui, repo.unfiltered(), dest, **opts)
933 return orig(ui, repo.unfiltered(), dest, **opts)
934 finally:
934 finally:
935 repo.unfiltered().lfstatus = False
935 repo.unfiltered().lfstatus = False
936
936
937 def hgwebarchive(orig, web):
937 def hgwebarchive(orig, web):
938 web.repo.lfstatus = True
938 web.repo.lfstatus = True
939
939
940 try:
940 try:
941 return orig(web)
941 return orig(web)
942 finally:
942 finally:
943 web.repo.lfstatus = False
943 web.repo.lfstatus = False
944
944
945 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
945 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
946 prefix='', mtime=None, subrepos=None):
946 prefix='', mtime=None, subrepos=None):
947 # For some reason setting repo.lfstatus in hgwebarchive only changes the
947 # For some reason setting repo.lfstatus in hgwebarchive only changes the
948 # unfiltered repo's attr, so check that as well.
948 # unfiltered repo's attr, so check that as well.
949 if not repo.lfstatus and not repo.unfiltered().lfstatus:
949 if not repo.lfstatus and not repo.unfiltered().lfstatus:
950 return orig(repo, dest, node, kind, decode, matchfn, prefix, mtime,
950 return orig(repo, dest, node, kind, decode, matchfn, prefix, mtime,
951 subrepos)
951 subrepos)
952
952
953 # No need to lock because we are only reading history and
953 # No need to lock because we are only reading history and
954 # largefile caches, neither of which are modified.
954 # largefile caches, neither of which are modified.
955 if node is not None:
955 if node is not None:
956 lfcommands.cachelfiles(repo.ui, repo, node)
956 lfcommands.cachelfiles(repo.ui, repo, node)
957
957
958 if kind not in archival.archivers:
958 if kind not in archival.archivers:
959 raise error.Abort(_("unknown archive type '%s'") % kind)
959 raise error.Abort(_("unknown archive type '%s'") % kind)
960
960
961 ctx = repo[node]
961 ctx = repo[node]
962
962
963 if kind == 'files':
963 if kind == 'files':
964 if prefix:
964 if prefix:
965 raise error.Abort(
965 raise error.Abort(
966 _('cannot give prefix when archiving to files'))
966 _('cannot give prefix when archiving to files'))
967 else:
967 else:
968 prefix = archival.tidyprefix(dest, kind, prefix)
968 prefix = archival.tidyprefix(dest, kind, prefix)
969
969
970 def write(name, mode, islink, getdata):
970 def write(name, mode, islink, getdata):
971 if matchfn and not matchfn(name):
971 if matchfn and not matchfn(name):
972 return
972 return
973 data = getdata()
973 data = getdata()
974 if decode:
974 if decode:
975 data = repo.wwritedata(name, data)
975 data = repo.wwritedata(name, data)
976 archiver.addfile(prefix + name, mode, islink, data)
976 archiver.addfile(prefix + name, mode, islink, data)
977
977
978 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
978 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
979
979
980 if repo.ui.configbool("ui", "archivemeta"):
980 if repo.ui.configbool("ui", "archivemeta"):
981 write('.hg_archival.txt', 0o644, False,
981 write('.hg_archival.txt', 0o644, False,
982 lambda: archival.buildmetadata(ctx))
982 lambda: archival.buildmetadata(ctx))
983
983
984 for f in ctx:
984 for f in ctx:
985 ff = ctx.flags(f)
985 ff = ctx.flags(f)
986 getdata = ctx[f].data
986 getdata = ctx[f].data
987 lfile = lfutil.splitstandin(f)
987 lfile = lfutil.splitstandin(f)
988 if lfile is not None:
988 if lfile is not None:
989 if node is not None:
989 if node is not None:
990 path = lfutil.findfile(repo, getdata().strip())
990 path = lfutil.findfile(repo, getdata().strip())
991
991
992 if path is None:
992 if path is None:
993 raise error.Abort(
993 raise error.Abort(
994 _('largefile %s not found in repo store or system cache')
994 _('largefile %s not found in repo store or system cache')
995 % lfile)
995 % lfile)
996 else:
996 else:
997 path = lfile
997 path = lfile
998
998
999 f = lfile
999 f = lfile
1000
1000
1001 getdata = lambda: util.readfile(path)
1001 getdata = lambda: util.readfile(path)
1002 write(f, 'x' in ff and 0o755 or 0o644, 'l' in ff, getdata)
1002 write(f, 'x' in ff and 0o755 or 0o644, 'l' in ff, getdata)
1003
1003
1004 if subrepos:
1004 if subrepos:
1005 for subpath in sorted(ctx.substate):
1005 for subpath in sorted(ctx.substate):
1006 sub = ctx.workingsub(subpath)
1006 sub = ctx.workingsub(subpath)
1007 submatch = matchmod.subdirmatcher(subpath, matchfn)
1007 submatch = matchmod.subdirmatcher(subpath, matchfn)
1008 sub._repo.lfstatus = True
1008 sub._repo.lfstatus = True
1009 sub.archive(archiver, prefix, submatch)
1009 sub.archive(archiver, prefix, submatch)
1010
1010
1011 archiver.done()
1011 archiver.done()
1012
1012
1013 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None, decode=True):
1013 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None, decode=True):
1014 lfenabled = util.safehasattr(repo._repo, '_largefilesenabled')
1014 lfenabled = util.safehasattr(repo._repo, '_largefilesenabled')
1015 if not lfenabled or not repo._repo.lfstatus:
1015 if not lfenabled or not repo._repo.lfstatus:
1016 return orig(repo, archiver, prefix, match, decode)
1016 return orig(repo, archiver, prefix, match, decode)
1017
1017
1018 repo._get(repo._state + ('hg',))
1018 repo._get(repo._state + ('hg',))
1019 rev = repo._state[1]
1019 rev = repo._state[1]
1020 ctx = repo._repo[rev]
1020 ctx = repo._repo[rev]
1021
1021
1022 if ctx.node() is not None:
1022 if ctx.node() is not None:
1023 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
1023 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
1024
1024
1025 def write(name, mode, islink, getdata):
1025 def write(name, mode, islink, getdata):
1026 # At this point, the standin has been replaced with the largefile name,
1026 # At this point, the standin has been replaced with the largefile name,
1027 # so the normal matcher works here without the lfutil variants.
1027 # so the normal matcher works here without the lfutil variants.
1028 if match and not match(f):
1028 if match and not match(f):
1029 return
1029 return
1030 data = getdata()
1030 data = getdata()
1031 if decode:
1031 if decode:
1032 data = repo._repo.wwritedata(name, data)
1032 data = repo._repo.wwritedata(name, data)
1033
1033
1034 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
1034 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
1035
1035
1036 for f in ctx:
1036 for f in ctx:
1037 ff = ctx.flags(f)
1037 ff = ctx.flags(f)
1038 getdata = ctx[f].data
1038 getdata = ctx[f].data
1039 lfile = lfutil.splitstandin(f)
1039 lfile = lfutil.splitstandin(f)
1040 if lfile is not None:
1040 if lfile is not None:
1041 if ctx.node() is not None:
1041 if ctx.node() is not None:
1042 path = lfutil.findfile(repo._repo, getdata().strip())
1042 path = lfutil.findfile(repo._repo, getdata().strip())
1043
1043
1044 if path is None:
1044 if path is None:
1045 raise error.Abort(
1045 raise error.Abort(
1046 _('largefile %s not found in repo store or system cache')
1046 _('largefile %s not found in repo store or system cache')
1047 % lfile)
1047 % lfile)
1048 else:
1048 else:
1049 path = lfile
1049 path = lfile
1050
1050
1051 f = lfile
1051 f = lfile
1052
1052
1053 getdata = lambda: util.readfile(os.path.join(prefix, path))
1053 getdata = lambda: util.readfile(os.path.join(prefix, path))
1054
1054
1055 write(f, 'x' in ff and 0o755 or 0o644, 'l' in ff, getdata)
1055 write(f, 'x' in ff and 0o755 or 0o644, 'l' in ff, getdata)
1056
1056
1057 for subpath in sorted(ctx.substate):
1057 for subpath in sorted(ctx.substate):
1058 sub = ctx.workingsub(subpath)
1058 sub = ctx.workingsub(subpath)
1059 submatch = matchmod.subdirmatcher(subpath, match)
1059 submatch = matchmod.subdirmatcher(subpath, match)
1060 sub._repo.lfstatus = True
1060 sub._repo.lfstatus = True
1061 sub.archive(archiver, prefix + repo._path + '/', submatch, decode)
1061 sub.archive(archiver, prefix + repo._path + '/', submatch, decode)
1062
1062
1063 # If a largefile is modified, the change is not reflected in its
1063 # If a largefile is modified, the change is not reflected in its
1064 # standin until a commit. cmdutil.bailifchanged() raises an exception
1064 # standin until a commit. cmdutil.bailifchanged() raises an exception
1065 # if the repo has uncommitted changes. Wrap it to also check if
1065 # if the repo has uncommitted changes. Wrap it to also check if
1066 # largefiles were changed. This is used by bisect, backout and fetch.
1066 # largefiles were changed. This is used by bisect, backout and fetch.
1067 def overridebailifchanged(orig, repo, *args, **kwargs):
1067 def overridebailifchanged(orig, repo, *args, **kwargs):
1068 orig(repo, *args, **kwargs)
1068 orig(repo, *args, **kwargs)
1069 repo.lfstatus = True
1069 repo.lfstatus = True
1070 s = repo.status()
1070 s = repo.status()
1071 repo.lfstatus = False
1071 repo.lfstatus = False
1072 if s.modified or s.added or s.removed or s.deleted:
1072 if s.modified or s.added or s.removed or s.deleted:
1073 raise error.Abort(_('uncommitted changes'))
1073 raise error.Abort(_('uncommitted changes'))
1074
1074
1075 def postcommitstatus(orig, repo, *args, **kwargs):
1075 def postcommitstatus(orig, repo, *args, **kwargs):
1076 repo.lfstatus = True
1076 repo.lfstatus = True
1077 try:
1077 try:
1078 return orig(repo, *args, **kwargs)
1078 return orig(repo, *args, **kwargs)
1079 finally:
1079 finally:
1080 repo.lfstatus = False
1080 repo.lfstatus = False
1081
1081
1082 def cmdutilforget(orig, ui, repo, match, prefix, explicitonly, dryrun):
1082 def cmdutilforget(orig, ui, repo, match, prefix, explicitonly, dryrun):
1083 normalmatcher = composenormalfilematcher(match, repo[None].manifest())
1083 normalmatcher = composenormalfilematcher(match, repo[None].manifest())
1084 bad, forgot = orig(ui, repo, normalmatcher, prefix, explicitonly, dryrun)
1084 bad, forgot = orig(ui, repo, normalmatcher, prefix, explicitonly, dryrun)
1085 m = composelargefilematcher(match, repo[None].manifest())
1085 m = composelargefilematcher(match, repo[None].manifest())
1086
1086
1087 try:
1087 try:
1088 repo.lfstatus = True
1088 repo.lfstatus = True
1089 s = repo.status(match=m, clean=True)
1089 s = repo.status(match=m, clean=True)
1090 finally:
1090 finally:
1091 repo.lfstatus = False
1091 repo.lfstatus = False
1092 manifest = repo[None].manifest()
1092 manifest = repo[None].manifest()
1093 forget = sorted(s.modified + s.added + s.deleted + s.clean)
1093 forget = sorted(s.modified + s.added + s.deleted + s.clean)
1094 forget = [f for f in forget if lfutil.standin(f) in manifest]
1094 forget = [f for f in forget if lfutil.standin(f) in manifest]
1095
1095
1096 for f in forget:
1096 for f in forget:
1097 fstandin = lfutil.standin(f)
1097 fstandin = lfutil.standin(f)
1098 if fstandin not in repo.dirstate and not repo.wvfs.isdir(fstandin):
1098 if fstandin not in repo.dirstate and not repo.wvfs.isdir(fstandin):
1099 ui.warn(_('not removing %s: file is already untracked\n')
1099 ui.warn(_('not removing %s: file is already untracked\n')
1100 % m.rel(f))
1100 % m.rel(f))
1101 bad.append(f)
1101 bad.append(f)
1102
1102
1103 for f in forget:
1103 for f in forget:
1104 if ui.verbose or not m.exact(f):
1104 if ui.verbose or not m.exact(f):
1105 ui.status(_('removing %s\n') % m.rel(f))
1105 ui.status(_('removing %s\n') % m.rel(f))
1106
1106
1107 # Need to lock because standin files are deleted then removed from the
1107 # Need to lock because standin files are deleted then removed from the
1108 # repository and we could race in-between.
1108 # repository and we could race in-between.
1109 with repo.wlock():
1109 with repo.wlock():
1110 lfdirstate = lfutil.openlfdirstate(ui, repo)
1110 lfdirstate = lfutil.openlfdirstate(ui, repo)
1111 for f in forget:
1111 for f in forget:
1112 if lfdirstate[f] == 'a':
1112 if lfdirstate[f] == 'a':
1113 lfdirstate.drop(f)
1113 lfdirstate.drop(f)
1114 else:
1114 else:
1115 lfdirstate.remove(f)
1115 lfdirstate.remove(f)
1116 lfdirstate.write()
1116 lfdirstate.write()
1117 standins = [lfutil.standin(f) for f in forget]
1117 standins = [lfutil.standin(f) for f in forget]
1118 for f in standins:
1118 for f in standins:
1119 repo.wvfs.unlinkpath(f, ignoremissing=True)
1119 repo.wvfs.unlinkpath(f, ignoremissing=True)
1120 rejected = repo[None].forget(standins)
1120 rejected = repo[None].forget(standins)
1121
1121
1122 bad.extend(f for f in rejected if f in m.files())
1122 bad.extend(f for f in rejected if f in m.files())
1123 forgot.extend(f for f in forget if f not in rejected)
1123 forgot.extend(f for f in forget if f not in rejected)
1124 return bad, forgot
1124 return bad, forgot
1125
1125
1126 def _getoutgoings(repo, other, missing, addfunc):
1126 def _getoutgoings(repo, other, missing, addfunc):
1127 """get pairs of filename and largefile hash in outgoing revisions
1127 """get pairs of filename and largefile hash in outgoing revisions
1128 in 'missing'.
1128 in 'missing'.
1129
1129
1130 largefiles already existing on 'other' repository are ignored.
1130 largefiles already existing on 'other' repository are ignored.
1131
1131
1132 'addfunc' is invoked with each unique pairs of filename and
1132 'addfunc' is invoked with each unique pairs of filename and
1133 largefile hash value.
1133 largefile hash value.
1134 """
1134 """
1135 knowns = set()
1135 knowns = set()
1136 lfhashes = set()
1136 lfhashes = set()
1137 def dedup(fn, lfhash):
1137 def dedup(fn, lfhash):
1138 k = (fn, lfhash)
1138 k = (fn, lfhash)
1139 if k not in knowns:
1139 if k not in knowns:
1140 knowns.add(k)
1140 knowns.add(k)
1141 lfhashes.add(lfhash)
1141 lfhashes.add(lfhash)
1142 lfutil.getlfilestoupload(repo, missing, dedup)
1142 lfutil.getlfilestoupload(repo, missing, dedup)
1143 if lfhashes:
1143 if lfhashes:
1144 lfexists = storefactory.openstore(repo, other).exists(lfhashes)
1144 lfexists = storefactory.openstore(repo, other).exists(lfhashes)
1145 for fn, lfhash in knowns:
1145 for fn, lfhash in knowns:
1146 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1146 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1147 addfunc(fn, lfhash)
1147 addfunc(fn, lfhash)
1148
1148
1149 def outgoinghook(ui, repo, other, opts, missing):
1149 def outgoinghook(ui, repo, other, opts, missing):
1150 if opts.pop('large', None):
1150 if opts.pop('large', None):
1151 lfhashes = set()
1151 lfhashes = set()
1152 if ui.debugflag:
1152 if ui.debugflag:
1153 toupload = {}
1153 toupload = {}
1154 def addfunc(fn, lfhash):
1154 def addfunc(fn, lfhash):
1155 if fn not in toupload:
1155 if fn not in toupload:
1156 toupload[fn] = []
1156 toupload[fn] = []
1157 toupload[fn].append(lfhash)
1157 toupload[fn].append(lfhash)
1158 lfhashes.add(lfhash)
1158 lfhashes.add(lfhash)
1159 def showhashes(fn):
1159 def showhashes(fn):
1160 for lfhash in sorted(toupload[fn]):
1160 for lfhash in sorted(toupload[fn]):
1161 ui.debug(' %s\n' % (lfhash))
1161 ui.debug(' %s\n' % (lfhash))
1162 else:
1162 else:
1163 toupload = set()
1163 toupload = set()
1164 def addfunc(fn, lfhash):
1164 def addfunc(fn, lfhash):
1165 toupload.add(fn)
1165 toupload.add(fn)
1166 lfhashes.add(lfhash)
1166 lfhashes.add(lfhash)
1167 def showhashes(fn):
1167 def showhashes(fn):
1168 pass
1168 pass
1169 _getoutgoings(repo, other, missing, addfunc)
1169 _getoutgoings(repo, other, missing, addfunc)
1170
1170
1171 if not toupload:
1171 if not toupload:
1172 ui.status(_('largefiles: no files to upload\n'))
1172 ui.status(_('largefiles: no files to upload\n'))
1173 else:
1173 else:
1174 ui.status(_('largefiles to upload (%d entities):\n')
1174 ui.status(_('largefiles to upload (%d entities):\n')
1175 % (len(lfhashes)))
1175 % (len(lfhashes)))
1176 for file in sorted(toupload):
1176 for file in sorted(toupload):
1177 ui.status(lfutil.splitstandin(file) + '\n')
1177 ui.status(lfutil.splitstandin(file) + '\n')
1178 showhashes(file)
1178 showhashes(file)
1179 ui.status('\n')
1179 ui.status('\n')
1180
1180
1181 def summaryremotehook(ui, repo, opts, changes):
1181 def summaryremotehook(ui, repo, opts, changes):
1182 largeopt = opts.get('large', False)
1182 largeopt = opts.get('large', False)
1183 if changes is None:
1183 if changes is None:
1184 if largeopt:
1184 if largeopt:
1185 return (False, True) # only outgoing check is needed
1185 return (False, True) # only outgoing check is needed
1186 else:
1186 else:
1187 return (False, False)
1187 return (False, False)
1188 elif largeopt:
1188 elif largeopt:
1189 url, branch, peer, outgoing = changes[1]
1189 url, branch, peer, outgoing = changes[1]
1190 if peer is None:
1190 if peer is None:
1191 # i18n: column positioning for "hg summary"
1191 # i18n: column positioning for "hg summary"
1192 ui.status(_('largefiles: (no remote repo)\n'))
1192 ui.status(_('largefiles: (no remote repo)\n'))
1193 return
1193 return
1194
1194
1195 toupload = set()
1195 toupload = set()
1196 lfhashes = set()
1196 lfhashes = set()
1197 def addfunc(fn, lfhash):
1197 def addfunc(fn, lfhash):
1198 toupload.add(fn)
1198 toupload.add(fn)
1199 lfhashes.add(lfhash)
1199 lfhashes.add(lfhash)
1200 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1200 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1201
1201
1202 if not toupload:
1202 if not toupload:
1203 # i18n: column positioning for "hg summary"
1203 # i18n: column positioning for "hg summary"
1204 ui.status(_('largefiles: (no files to upload)\n'))
1204 ui.status(_('largefiles: (no files to upload)\n'))
1205 else:
1205 else:
1206 # i18n: column positioning for "hg summary"
1206 # i18n: column positioning for "hg summary"
1207 ui.status(_('largefiles: %d entities for %d files to upload\n')
1207 ui.status(_('largefiles: %d entities for %d files to upload\n')
1208 % (len(lfhashes), len(toupload)))
1208 % (len(lfhashes), len(toupload)))
1209
1209
1210 def overridesummary(orig, ui, repo, *pats, **opts):
1210 def overridesummary(orig, ui, repo, *pats, **opts):
1211 try:
1211 try:
1212 repo.lfstatus = True
1212 repo.lfstatus = True
1213 orig(ui, repo, *pats, **opts)
1213 orig(ui, repo, *pats, **opts)
1214 finally:
1214 finally:
1215 repo.lfstatus = False
1215 repo.lfstatus = False
1216
1216
1217 def scmutiladdremove(orig, repo, matcher, prefix, opts=None):
1217 def scmutiladdremove(orig, repo, matcher, prefix, opts=None):
1218 if opts is None:
1218 if opts is None:
1219 opts = {}
1219 opts = {}
1220 if not lfutil.islfilesrepo(repo):
1220 if not lfutil.islfilesrepo(repo):
1221 return orig(repo, matcher, prefix, opts)
1221 return orig(repo, matcher, prefix, opts)
1222 # Get the list of missing largefiles so we can remove them
1222 # Get the list of missing largefiles so we can remove them
1223 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1223 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1224 unsure, s = lfdirstate.status(matchmod.always(repo.root, repo.getcwd()),
1224 unsure, s = lfdirstate.status(matchmod.always(repo.root, repo.getcwd()),
1225 subrepos=[], ignored=False, clean=False,
1225 subrepos=[], ignored=False, clean=False,
1226 unknown=False)
1226 unknown=False)
1227
1227
1228 # Call into the normal remove code, but the removing of the standin, we want
1228 # Call into the normal remove code, but the removing of the standin, we want
1229 # to have handled by original addremove. Monkey patching here makes sure
1229 # to have handled by original addremove. Monkey patching here makes sure
1230 # we don't remove the standin in the largefiles code, preventing a very
1230 # we don't remove the standin in the largefiles code, preventing a very
1231 # confused state later.
1231 # confused state later.
1232 if s.deleted:
1232 if s.deleted:
1233 m = copy.copy(matcher)
1233 m = copy.copy(matcher)
1234
1234
1235 # The m._files and m._map attributes are not changed to the deleted list
1235 # The m._files and m._map attributes are not changed to the deleted list
1236 # because that affects the m.exact() test, which in turn governs whether
1236 # because that affects the m.exact() test, which in turn governs whether
1237 # or not the file name is printed, and how. Simply limit the original
1237 # or not the file name is printed, and how. Simply limit the original
1238 # matches to those in the deleted status list.
1238 # matches to those in the deleted status list.
1239 matchfn = m.matchfn
1239 matchfn = m.matchfn
1240 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1240 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1241
1241
1242 removelargefiles(repo.ui, repo, True, m, opts.get('dry_run'),
1242 removelargefiles(repo.ui, repo, True, m, opts.get('dry_run'),
1243 **pycompat.strkwargs(opts))
1243 **pycompat.strkwargs(opts))
1244 # Call into the normal add code, and any files that *should* be added as
1244 # Call into the normal add code, and any files that *should* be added as
1245 # largefiles will be
1245 # largefiles will be
1246 added, bad = addlargefiles(repo.ui, repo, True, matcher,
1246 added, bad = addlargefiles(repo.ui, repo, True, matcher,
1247 **pycompat.strkwargs(opts))
1247 **pycompat.strkwargs(opts))
1248 # Now that we've handled largefiles, hand off to the original addremove
1248 # Now that we've handled largefiles, hand off to the original addremove
1249 # function to take care of the rest. Make sure it doesn't do anything with
1249 # function to take care of the rest. Make sure it doesn't do anything with
1250 # largefiles by passing a matcher that will ignore them.
1250 # largefiles by passing a matcher that will ignore them.
1251 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1251 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1252 return orig(repo, matcher, prefix, opts)
1252 return orig(repo, matcher, prefix, opts)
1253
1253
1254 # Calling purge with --all will cause the largefiles to be deleted.
1254 # Calling purge with --all will cause the largefiles to be deleted.
1255 # Override repo.status to prevent this from happening.
1255 # Override repo.status to prevent this from happening.
1256 def overridepurge(orig, ui, repo, *dirs, **opts):
1256 def overridepurge(orig, ui, repo, *dirs, **opts):
1257 # XXX Monkey patching a repoview will not work. The assigned attribute will
1257 # XXX Monkey patching a repoview will not work. The assigned attribute will
1258 # be set on the unfiltered repo, but we will only lookup attributes in the
1258 # be set on the unfiltered repo, but we will only lookup attributes in the
1259 # unfiltered repo if the lookup in the repoview object itself fails. As the
1259 # unfiltered repo if the lookup in the repoview object itself fails. As the
1260 # monkey patched method exists on the repoview class the lookup will not
1260 # monkey patched method exists on the repoview class the lookup will not
1261 # fail. As a result, the original version will shadow the monkey patched
1261 # fail. As a result, the original version will shadow the monkey patched
1262 # one, defeating the monkey patch.
1262 # one, defeating the monkey patch.
1263 #
1263 #
1264 # As a work around we use an unfiltered repo here. We should do something
1264 # As a work around we use an unfiltered repo here. We should do something
1265 # cleaner instead.
1265 # cleaner instead.
1266 repo = repo.unfiltered()
1266 repo = repo.unfiltered()
1267 oldstatus = repo.status
1267 oldstatus = repo.status
1268 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1268 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1269 clean=False, unknown=False, listsubrepos=False):
1269 clean=False, unknown=False, listsubrepos=False):
1270 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1270 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1271 listsubrepos)
1271 listsubrepos)
1272 lfdirstate = lfutil.openlfdirstate(ui, repo)
1272 lfdirstate = lfutil.openlfdirstate(ui, repo)
1273 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1273 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1274 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1274 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1275 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1275 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1276 unknown, ignored, r.clean)
1276 unknown, ignored, r.clean)
1277 repo.status = overridestatus
1277 repo.status = overridestatus
1278 orig(ui, repo, *dirs, **opts)
1278 orig(ui, repo, *dirs, **opts)
1279 repo.status = oldstatus
1279 repo.status = oldstatus
1280
1280
1281 def overriderollback(orig, ui, repo, **opts):
1281 def overriderollback(orig, ui, repo, **opts):
1282 with repo.wlock():
1282 with repo.wlock():
1283 before = repo.dirstate.parents()
1283 before = repo.dirstate.parents()
1284 orphans = set(f for f in repo.dirstate
1284 orphans = set(f for f in repo.dirstate
1285 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1285 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1286 result = orig(ui, repo, **opts)
1286 result = orig(ui, repo, **opts)
1287 after = repo.dirstate.parents()
1287 after = repo.dirstate.parents()
1288 if before == after:
1288 if before == after:
1289 return result # no need to restore standins
1289 return result # no need to restore standins
1290
1290
1291 pctx = repo['.']
1291 pctx = repo['.']
1292 for f in repo.dirstate:
1292 for f in repo.dirstate:
1293 if lfutil.isstandin(f):
1293 if lfutil.isstandin(f):
1294 orphans.discard(f)
1294 orphans.discard(f)
1295 if repo.dirstate[f] == 'r':
1295 if repo.dirstate[f] == 'r':
1296 repo.wvfs.unlinkpath(f, ignoremissing=True)
1296 repo.wvfs.unlinkpath(f, ignoremissing=True)
1297 elif f in pctx:
1297 elif f in pctx:
1298 fctx = pctx[f]
1298 fctx = pctx[f]
1299 repo.wwrite(f, fctx.data(), fctx.flags())
1299 repo.wwrite(f, fctx.data(), fctx.flags())
1300 else:
1300 else:
1301 # content of standin is not so important in 'a',
1301 # content of standin is not so important in 'a',
1302 # 'm' or 'n' (coming from the 2nd parent) cases
1302 # 'm' or 'n' (coming from the 2nd parent) cases
1303 lfutil.writestandin(repo, f, '', False)
1303 lfutil.writestandin(repo, f, '', False)
1304 for standin in orphans:
1304 for standin in orphans:
1305 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1305 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1306
1306
1307 lfdirstate = lfutil.openlfdirstate(ui, repo)
1307 lfdirstate = lfutil.openlfdirstate(ui, repo)
1308 orphans = set(lfdirstate)
1308 orphans = set(lfdirstate)
1309 lfiles = lfutil.listlfiles(repo)
1309 lfiles = lfutil.listlfiles(repo)
1310 for file in lfiles:
1310 for file in lfiles:
1311 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1311 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1312 orphans.discard(file)
1312 orphans.discard(file)
1313 for lfile in orphans:
1313 for lfile in orphans:
1314 lfdirstate.drop(lfile)
1314 lfdirstate.drop(lfile)
1315 lfdirstate.write()
1315 lfdirstate.write()
1316 return result
1316 return result
1317
1317
1318 def overridetransplant(orig, ui, repo, *revs, **opts):
1318 def overridetransplant(orig, ui, repo, *revs, **opts):
1319 resuming = opts.get(r'continue')
1319 resuming = opts.get(r'continue')
1320 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1320 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1321 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1321 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1322 try:
1322 try:
1323 result = orig(ui, repo, *revs, **opts)
1323 result = orig(ui, repo, *revs, **opts)
1324 finally:
1324 finally:
1325 repo._lfstatuswriters.pop()
1325 repo._lfstatuswriters.pop()
1326 repo._lfcommithooks.pop()
1326 repo._lfcommithooks.pop()
1327 return result
1327 return result
1328
1328
1329 def overridecat(orig, ui, repo, file1, *pats, **opts):
1329 def overridecat(orig, ui, repo, file1, *pats, **opts):
1330 opts = pycompat.byteskwargs(opts)
1330 opts = pycompat.byteskwargs(opts)
1331 ctx = scmutil.revsingle(repo, opts.get('rev'))
1331 ctx = scmutil.revsingle(repo, opts.get('rev'))
1332 err = 1
1332 err = 1
1333 notbad = set()
1333 notbad = set()
1334 m = scmutil.match(ctx, (file1,) + pats, opts)
1334 m = scmutil.match(ctx, (file1,) + pats, opts)
1335 origmatchfn = m.matchfn
1335 origmatchfn = m.matchfn
1336 def lfmatchfn(f):
1336 def lfmatchfn(f):
1337 if origmatchfn(f):
1337 if origmatchfn(f):
1338 return True
1338 return True
1339 lf = lfutil.splitstandin(f)
1339 lf = lfutil.splitstandin(f)
1340 if lf is None:
1340 if lf is None:
1341 return False
1341 return False
1342 notbad.add(lf)
1342 notbad.add(lf)
1343 return origmatchfn(lf)
1343 return origmatchfn(lf)
1344 m.matchfn = lfmatchfn
1344 m.matchfn = lfmatchfn
1345 origbadfn = m.bad
1345 origbadfn = m.bad
1346 def lfbadfn(f, msg):
1346 def lfbadfn(f, msg):
1347 if not f in notbad:
1347 if not f in notbad:
1348 origbadfn(f, msg)
1348 origbadfn(f, msg)
1349 m.bad = lfbadfn
1349 m.bad = lfbadfn
1350
1350
1351 origvisitdirfn = m.visitdir
1351 origvisitdirfn = m.visitdir
1352 def lfvisitdirfn(dir):
1352 def lfvisitdirfn(dir):
1353 if dir == lfutil.shortname:
1353 if dir == lfutil.shortname:
1354 return True
1354 return True
1355 ret = origvisitdirfn(dir)
1355 ret = origvisitdirfn(dir)
1356 if ret:
1356 if ret:
1357 return ret
1357 return ret
1358 lf = lfutil.splitstandin(dir)
1358 lf = lfutil.splitstandin(dir)
1359 if lf is None:
1359 if lf is None:
1360 return False
1360 return False
1361 return origvisitdirfn(lf)
1361 return origvisitdirfn(lf)
1362 m.visitdir = lfvisitdirfn
1362 m.visitdir = lfvisitdirfn
1363
1363
1364 for f in ctx.walk(m):
1364 for f in ctx.walk(m):
1365 with cmdutil.makefileobj(ctx, opts.get('output'), pathname=f) as fp:
1365 with cmdutil.makefileobj(ctx, opts.get('output'), pathname=f) as fp:
1366 lf = lfutil.splitstandin(f)
1366 lf = lfutil.splitstandin(f)
1367 if lf is None or origmatchfn(f):
1367 if lf is None or origmatchfn(f):
1368 # duplicating unreachable code from commands.cat
1368 # duplicating unreachable code from commands.cat
1369 data = ctx[f].data()
1369 data = ctx[f].data()
1370 if opts.get('decode'):
1370 if opts.get('decode'):
1371 data = repo.wwritedata(f, data)
1371 data = repo.wwritedata(f, data)
1372 fp.write(data)
1372 fp.write(data)
1373 else:
1373 else:
1374 hash = lfutil.readasstandin(ctx[f])
1374 hash = lfutil.readasstandin(ctx[f])
1375 if not lfutil.inusercache(repo.ui, hash):
1375 if not lfutil.inusercache(repo.ui, hash):
1376 store = storefactory.openstore(repo)
1376 store = storefactory.openstore(repo)
1377 success, missing = store.get([(lf, hash)])
1377 success, missing = store.get([(lf, hash)])
1378 if len(success) != 1:
1378 if len(success) != 1:
1379 raise error.Abort(
1379 raise error.Abort(
1380 _('largefile %s is not in cache and could not be '
1380 _('largefile %s is not in cache and could not be '
1381 'downloaded') % lf)
1381 'downloaded') % lf)
1382 path = lfutil.usercachepath(repo.ui, hash)
1382 path = lfutil.usercachepath(repo.ui, hash)
1383 with open(path, "rb") as fpin:
1383 with open(path, "rb") as fpin:
1384 for chunk in util.filechunkiter(fpin):
1384 for chunk in util.filechunkiter(fpin):
1385 fp.write(chunk)
1385 fp.write(chunk)
1386 err = 0
1386 err = 0
1387 return err
1387 return err
1388
1388
1389 def mergeupdate(orig, repo, node, branchmerge, force,
1389 def mergeupdate(orig, repo, node, branchmerge, force,
1390 *args, **kwargs):
1390 *args, **kwargs):
1391 matcher = kwargs.get(r'matcher', None)
1391 matcher = kwargs.get(r'matcher', None)
1392 # note if this is a partial update
1392 # note if this is a partial update
1393 partial = matcher and not matcher.always()
1393 partial = matcher and not matcher.always()
1394 with repo.wlock():
1394 with repo.wlock():
1395 # branch | | |
1395 # branch | | |
1396 # merge | force | partial | action
1396 # merge | force | partial | action
1397 # -------+-------+---------+--------------
1397 # -------+-------+---------+--------------
1398 # x | x | x | linear-merge
1398 # x | x | x | linear-merge
1399 # o | x | x | branch-merge
1399 # o | x | x | branch-merge
1400 # x | o | x | overwrite (as clean update)
1400 # x | o | x | overwrite (as clean update)
1401 # o | o | x | force-branch-merge (*1)
1401 # o | o | x | force-branch-merge (*1)
1402 # x | x | o | (*)
1402 # x | x | o | (*)
1403 # o | x | o | (*)
1403 # o | x | o | (*)
1404 # x | o | o | overwrite (as revert)
1404 # x | o | o | overwrite (as revert)
1405 # o | o | o | (*)
1405 # o | o | o | (*)
1406 #
1406 #
1407 # (*) don't care
1407 # (*) don't care
1408 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1408 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1409
1409
1410 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1410 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1411 unsure, s = lfdirstate.status(matchmod.always(repo.root,
1411 unsure, s = lfdirstate.status(matchmod.always(repo.root,
1412 repo.getcwd()),
1412 repo.getcwd()),
1413 subrepos=[], ignored=False,
1413 subrepos=[], ignored=False,
1414 clean=True, unknown=False)
1414 clean=True, unknown=False)
1415 oldclean = set(s.clean)
1415 oldclean = set(s.clean)
1416 pctx = repo['.']
1416 pctx = repo['.']
1417 dctx = repo[node]
1417 dctx = repo[node]
1418 for lfile in unsure + s.modified:
1418 for lfile in unsure + s.modified:
1419 lfileabs = repo.wvfs.join(lfile)
1419 lfileabs = repo.wvfs.join(lfile)
1420 if not repo.wvfs.exists(lfileabs):
1420 if not repo.wvfs.exists(lfileabs):
1421 continue
1421 continue
1422 lfhash = lfutil.hashfile(lfileabs)
1422 lfhash = lfutil.hashfile(lfileabs)
1423 standin = lfutil.standin(lfile)
1423 standin = lfutil.standin(lfile)
1424 lfutil.writestandin(repo, standin, lfhash,
1424 lfutil.writestandin(repo, standin, lfhash,
1425 lfutil.getexecutable(lfileabs))
1425 lfutil.getexecutable(lfileabs))
1426 if (standin in pctx and
1426 if (standin in pctx and
1427 lfhash == lfutil.readasstandin(pctx[standin])):
1427 lfhash == lfutil.readasstandin(pctx[standin])):
1428 oldclean.add(lfile)
1428 oldclean.add(lfile)
1429 for lfile in s.added:
1429 for lfile in s.added:
1430 fstandin = lfutil.standin(lfile)
1430 fstandin = lfutil.standin(lfile)
1431 if fstandin not in dctx:
1431 if fstandin not in dctx:
1432 # in this case, content of standin file is meaningless
1432 # in this case, content of standin file is meaningless
1433 # (in dctx, lfile is unknown, or normal file)
1433 # (in dctx, lfile is unknown, or normal file)
1434 continue
1434 continue
1435 lfutil.updatestandin(repo, lfile, fstandin)
1435 lfutil.updatestandin(repo, lfile, fstandin)
1436 # mark all clean largefiles as dirty, just in case the update gets
1436 # mark all clean largefiles as dirty, just in case the update gets
1437 # interrupted before largefiles and lfdirstate are synchronized
1437 # interrupted before largefiles and lfdirstate are synchronized
1438 for lfile in oldclean:
1438 for lfile in oldclean:
1439 lfdirstate.normallookup(lfile)
1439 lfdirstate.normallookup(lfile)
1440 lfdirstate.write()
1440 lfdirstate.write()
1441
1441
1442 oldstandins = lfutil.getstandinsstate(repo)
1442 oldstandins = lfutil.getstandinsstate(repo)
1443 # Make sure the merge runs on disk, not in-memory. largefiles is not a
1443 # Make sure the merge runs on disk, not in-memory. largefiles is not a
1444 # good candidate for in-memory merge (large files, custom dirstate,
1444 # good candidate for in-memory merge (large files, custom dirstate,
1445 # matcher usage).
1445 # matcher usage).
1446 kwargs[r'wc'] = repo[None]
1446 kwargs[r'wc'] = repo[None]
1447 result = orig(repo, node, branchmerge, force, *args, **kwargs)
1447 result = orig(repo, node, branchmerge, force, *args, **kwargs)
1448
1448
1449 newstandins = lfutil.getstandinsstate(repo)
1449 newstandins = lfutil.getstandinsstate(repo)
1450 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1450 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1451
1451
1452 # to avoid leaving all largefiles as dirty and thus rehash them, mark
1452 # to avoid leaving all largefiles as dirty and thus rehash them, mark
1453 # all the ones that didn't change as clean
1453 # all the ones that didn't change as clean
1454 for lfile in oldclean.difference(filelist):
1454 for lfile in oldclean.difference(filelist):
1455 lfdirstate.normal(lfile)
1455 lfdirstate.normal(lfile)
1456 lfdirstate.write()
1456 lfdirstate.write()
1457
1457
1458 if branchmerge or force or partial:
1458 if branchmerge or force or partial:
1459 filelist.extend(s.deleted + s.removed)
1459 filelist.extend(s.deleted + s.removed)
1460
1460
1461 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1461 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1462 normallookup=partial)
1462 normallookup=partial)
1463
1463
1464 return result
1464 return result
1465
1465
1466 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1466 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1467 result = orig(repo, files, *args, **kwargs)
1467 result = orig(repo, files, *args, **kwargs)
1468
1468
1469 filelist = []
1469 filelist = []
1470 for f in files:
1470 for f in files:
1471 lf = lfutil.splitstandin(f)
1471 lf = lfutil.splitstandin(f)
1472 if lf is not None:
1472 if lf is not None:
1473 filelist.append(lf)
1473 filelist.append(lf)
1474 if filelist:
1474 if filelist:
1475 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1475 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1476 printmessage=False, normallookup=True)
1476 printmessage=False, normallookup=True)
1477
1477
1478 return result
1478 return result
1479
1479
1480 def upgraderequirements(orig, repo):
1480 def upgraderequirements(orig, repo):
1481 reqs = orig(repo)
1481 reqs = orig(repo)
1482 if 'largefiles' in repo.requirements:
1482 if 'largefiles' in repo.requirements:
1483 reqs.add('largefiles')
1483 reqs.add('largefiles')
1484 return reqs
1484 return reqs
1485
1485
1486 _lfscheme = 'largefile://'
1486 _lfscheme = 'largefile://'
1487 def openlargefile(orig, ui, url_, data=None):
1487 def openlargefile(orig, ui, url_, data=None):
1488 if url_.startswith(_lfscheme):
1488 if url_.startswith(_lfscheme):
1489 if data:
1489 if data:
1490 msg = "cannot use data on a 'largefile://' url"
1490 msg = "cannot use data on a 'largefile://' url"
1491 raise error.ProgrammingError(msg)
1491 raise error.ProgrammingError(msg)
1492 lfid = url_[len(_lfscheme):]
1492 lfid = url_[len(_lfscheme):]
1493 return storefactory.getlfile(ui, lfid)
1493 return storefactory.getlfile(ui, lfid)
1494 else:
1494 else:
1495 return orig(ui, url_, data=data)
1495 return orig(ui, url_, data=data)
General Comments 0
You need to be logged in to leave comments. Login now