##// END OF EJS Templates
i18n: fix "% inside _()" problem
FUJIWARA Katsunori -
r21096:a45ed365 default
parent child Browse files
Show More
@@ -1,1136 +1,1136 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
10
11 import os
11 import os
12 import copy
12 import copy
13
13
14 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
14 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
15 archival, merge, pathutil, revset
15 archival, merge, pathutil, revset
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial.node import hex
17 from mercurial.node import hex
18 from hgext import rebase
18 from hgext import rebase
19
19
20 import lfutil
20 import lfutil
21 import lfcommands
21 import lfcommands
22 import basestore
22 import basestore
23
23
24 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24 # -- Utility functions: commonly/repeatedly needed functionality ---------------
25
25
26 def installnormalfilesmatchfn(manifest):
26 def installnormalfilesmatchfn(manifest):
27 '''installmatchfn with a matchfn that ignores all largefiles'''
27 '''installmatchfn with a matchfn that ignores all largefiles'''
28 def overridematch(ctx, pats=[], opts={}, globbed=False,
28 def overridematch(ctx, pats=[], opts={}, globbed=False,
29 default='relpath'):
29 default='relpath'):
30 match = oldmatch(ctx, pats, opts, globbed, default)
30 match = oldmatch(ctx, pats, opts, globbed, default)
31 m = copy.copy(match)
31 m = copy.copy(match)
32 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
32 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
33 manifest)
33 manifest)
34 m._files = filter(notlfile, m._files)
34 m._files = filter(notlfile, m._files)
35 m._fmap = set(m._files)
35 m._fmap = set(m._files)
36 m._always = False
36 m._always = False
37 origmatchfn = m.matchfn
37 origmatchfn = m.matchfn
38 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
38 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
39 return m
39 return m
40 oldmatch = installmatchfn(overridematch)
40 oldmatch = installmatchfn(overridematch)
41
41
42 def installmatchfn(f):
42 def installmatchfn(f):
43 '''monkey patch the scmutil module with a custom match function.
43 '''monkey patch the scmutil module with a custom match function.
44 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
44 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
45 oldmatch = scmutil.match
45 oldmatch = scmutil.match
46 setattr(f, 'oldmatch', oldmatch)
46 setattr(f, 'oldmatch', oldmatch)
47 scmutil.match = f
47 scmutil.match = f
48 return oldmatch
48 return oldmatch
49
49
50 def restorematchfn():
50 def restorematchfn():
51 '''restores scmutil.match to what it was before installmatchfn
51 '''restores scmutil.match to what it was before installmatchfn
52 was called. no-op if scmutil.match is its original function.
52 was called. no-op if scmutil.match is its original function.
53
53
54 Note that n calls to installmatchfn will require n calls to
54 Note that n calls to installmatchfn will require n calls to
55 restore matchfn to reverse'''
55 restore matchfn to reverse'''
56 scmutil.match = getattr(scmutil.match, 'oldmatch')
56 scmutil.match = getattr(scmutil.match, 'oldmatch')
57
57
58 def addlargefiles(ui, repo, *pats, **opts):
58 def addlargefiles(ui, repo, *pats, **opts):
59 large = opts.pop('large', None)
59 large = opts.pop('large', None)
60 lfsize = lfutil.getminsize(
60 lfsize = lfutil.getminsize(
61 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
61 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
62
62
63 lfmatcher = None
63 lfmatcher = None
64 if lfutil.islfilesrepo(repo):
64 if lfutil.islfilesrepo(repo):
65 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
65 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
66 if lfpats:
66 if lfpats:
67 lfmatcher = match_.match(repo.root, '', list(lfpats))
67 lfmatcher = match_.match(repo.root, '', list(lfpats))
68
68
69 lfnames = []
69 lfnames = []
70 m = scmutil.match(repo[None], pats, opts)
70 m = scmutil.match(repo[None], pats, opts)
71 m.bad = lambda x, y: None
71 m.bad = lambda x, y: None
72 wctx = repo[None]
72 wctx = repo[None]
73 for f in repo.walk(m):
73 for f in repo.walk(m):
74 exact = m.exact(f)
74 exact = m.exact(f)
75 lfile = lfutil.standin(f) in wctx
75 lfile = lfutil.standin(f) in wctx
76 nfile = f in wctx
76 nfile = f in wctx
77 exists = lfile or nfile
77 exists = lfile or nfile
78
78
79 # Don't warn the user when they attempt to add a normal tracked file.
79 # Don't warn the user when they attempt to add a normal tracked file.
80 # The normal add code will do that for us.
80 # The normal add code will do that for us.
81 if exact and exists:
81 if exact and exists:
82 if lfile:
82 if lfile:
83 ui.warn(_('%s already a largefile\n') % f)
83 ui.warn(_('%s already a largefile\n') % f)
84 continue
84 continue
85
85
86 if (exact or not exists) and not lfutil.isstandin(f):
86 if (exact or not exists) and not lfutil.isstandin(f):
87 wfile = repo.wjoin(f)
87 wfile = repo.wjoin(f)
88
88
89 # In case the file was removed previously, but not committed
89 # In case the file was removed previously, but not committed
90 # (issue3507)
90 # (issue3507)
91 if not os.path.exists(wfile):
91 if not os.path.exists(wfile):
92 continue
92 continue
93
93
94 abovemin = (lfsize and
94 abovemin = (lfsize and
95 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
95 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
96 if large or abovemin or (lfmatcher and lfmatcher(f)):
96 if large or abovemin or (lfmatcher and lfmatcher(f)):
97 lfnames.append(f)
97 lfnames.append(f)
98 if ui.verbose or not exact:
98 if ui.verbose or not exact:
99 ui.status(_('adding %s as a largefile\n') % m.rel(f))
99 ui.status(_('adding %s as a largefile\n') % m.rel(f))
100
100
101 bad = []
101 bad = []
102 standins = []
102 standins = []
103
103
104 # Need to lock, otherwise there could be a race condition between
104 # Need to lock, otherwise there could be a race condition between
105 # when standins are created and added to the repo.
105 # when standins are created and added to the repo.
106 wlock = repo.wlock()
106 wlock = repo.wlock()
107 try:
107 try:
108 if not opts.get('dry_run'):
108 if not opts.get('dry_run'):
109 lfdirstate = lfutil.openlfdirstate(ui, repo)
109 lfdirstate = lfutil.openlfdirstate(ui, repo)
110 for f in lfnames:
110 for f in lfnames:
111 standinname = lfutil.standin(f)
111 standinname = lfutil.standin(f)
112 lfutil.writestandin(repo, standinname, hash='',
112 lfutil.writestandin(repo, standinname, hash='',
113 executable=lfutil.getexecutable(repo.wjoin(f)))
113 executable=lfutil.getexecutable(repo.wjoin(f)))
114 standins.append(standinname)
114 standins.append(standinname)
115 if lfdirstate[f] == 'r':
115 if lfdirstate[f] == 'r':
116 lfdirstate.normallookup(f)
116 lfdirstate.normallookup(f)
117 else:
117 else:
118 lfdirstate.add(f)
118 lfdirstate.add(f)
119 lfdirstate.write()
119 lfdirstate.write()
120 bad += [lfutil.splitstandin(f)
120 bad += [lfutil.splitstandin(f)
121 for f in repo[None].add(standins)
121 for f in repo[None].add(standins)
122 if f in m.files()]
122 if f in m.files()]
123 finally:
123 finally:
124 wlock.release()
124 wlock.release()
125 return bad
125 return bad
126
126
127 def removelargefiles(ui, repo, *pats, **opts):
127 def removelargefiles(ui, repo, *pats, **opts):
128 after = opts.get('after')
128 after = opts.get('after')
129 if not pats and not after:
129 if not pats and not after:
130 raise util.Abort(_('no files specified'))
130 raise util.Abort(_('no files specified'))
131 m = scmutil.match(repo[None], pats, opts)
131 m = scmutil.match(repo[None], pats, opts)
132 try:
132 try:
133 repo.lfstatus = True
133 repo.lfstatus = True
134 s = repo.status(match=m, clean=True)
134 s = repo.status(match=m, clean=True)
135 finally:
135 finally:
136 repo.lfstatus = False
136 repo.lfstatus = False
137 manifest = repo[None].manifest()
137 manifest = repo[None].manifest()
138 modified, added, deleted, clean = [[f for f in list
138 modified, added, deleted, clean = [[f for f in list
139 if lfutil.standin(f) in manifest]
139 if lfutil.standin(f) in manifest]
140 for list in [s[0], s[1], s[3], s[6]]]
140 for list in [s[0], s[1], s[3], s[6]]]
141
141
142 def warn(files, msg):
142 def warn(files, msg):
143 for f in files:
143 for f in files:
144 ui.warn(msg % m.rel(f))
144 ui.warn(msg % m.rel(f))
145 return int(len(files) > 0)
145 return int(len(files) > 0)
146
146
147 result = 0
147 result = 0
148
148
149 if after:
149 if after:
150 remove, forget = deleted, []
150 remove, forget = deleted, []
151 result = warn(modified + added + clean,
151 result = warn(modified + added + clean,
152 _('not removing %s: file still exists\n'))
152 _('not removing %s: file still exists\n'))
153 else:
153 else:
154 remove, forget = deleted + clean, []
154 remove, forget = deleted + clean, []
155 result = warn(modified, _('not removing %s: file is modified (use -f'
155 result = warn(modified, _('not removing %s: file is modified (use -f'
156 ' to force removal)\n'))
156 ' to force removal)\n'))
157 result = warn(added, _('not removing %s: file has been marked for add'
157 result = warn(added, _('not removing %s: file has been marked for add'
158 ' (use forget to undo)\n')) or result
158 ' (use forget to undo)\n')) or result
159
159
160 for f in sorted(remove + forget):
160 for f in sorted(remove + forget):
161 if ui.verbose or not m.exact(f):
161 if ui.verbose or not m.exact(f):
162 ui.status(_('removing %s\n') % m.rel(f))
162 ui.status(_('removing %s\n') % m.rel(f))
163
163
164 # Need to lock because standin files are deleted then removed from the
164 # Need to lock because standin files are deleted then removed from the
165 # repository and we could race in-between.
165 # repository and we could race in-between.
166 wlock = repo.wlock()
166 wlock = repo.wlock()
167 try:
167 try:
168 lfdirstate = lfutil.openlfdirstate(ui, repo)
168 lfdirstate = lfutil.openlfdirstate(ui, repo)
169 for f in remove:
169 for f in remove:
170 if not after:
170 if not after:
171 # If this is being called by addremove, notify the user that we
171 # If this is being called by addremove, notify the user that we
172 # are removing the file.
172 # are removing the file.
173 if getattr(repo, "_isaddremove", False):
173 if getattr(repo, "_isaddremove", False):
174 ui.status(_('removing %s\n') % f)
174 ui.status(_('removing %s\n') % f)
175 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
175 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
176 lfdirstate.remove(f)
176 lfdirstate.remove(f)
177 lfdirstate.write()
177 lfdirstate.write()
178 forget = [lfutil.standin(f) for f in forget]
178 forget = [lfutil.standin(f) for f in forget]
179 remove = [lfutil.standin(f) for f in remove]
179 remove = [lfutil.standin(f) for f in remove]
180 repo[None].forget(forget)
180 repo[None].forget(forget)
181 # If this is being called by addremove, let the original addremove
181 # If this is being called by addremove, let the original addremove
182 # function handle this.
182 # function handle this.
183 if not getattr(repo, "_isaddremove", False):
183 if not getattr(repo, "_isaddremove", False):
184 for f in remove:
184 for f in remove:
185 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
185 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
186 repo[None].forget(remove)
186 repo[None].forget(remove)
187 finally:
187 finally:
188 wlock.release()
188 wlock.release()
189
189
190 return result
190 return result
191
191
192 # For overriding mercurial.hgweb.webcommands so that largefiles will
192 # For overriding mercurial.hgweb.webcommands so that largefiles will
193 # appear at their right place in the manifests.
193 # appear at their right place in the manifests.
194 def decodepath(orig, path):
194 def decodepath(orig, path):
195 return lfutil.splitstandin(path) or path
195 return lfutil.splitstandin(path) or path
196
196
197 # -- Wrappers: modify existing commands --------------------------------
197 # -- Wrappers: modify existing commands --------------------------------
198
198
199 # Add works by going through the files that the user wanted to add and
199 # Add works by going through the files that the user wanted to add and
200 # checking if they should be added as largefiles. Then it makes a new
200 # checking if they should be added as largefiles. Then it makes a new
201 # matcher which matches only the normal files and runs the original
201 # matcher which matches only the normal files and runs the original
202 # version of add.
202 # version of add.
203 def overrideadd(orig, ui, repo, *pats, **opts):
203 def overrideadd(orig, ui, repo, *pats, **opts):
204 normal = opts.pop('normal')
204 normal = opts.pop('normal')
205 if normal:
205 if normal:
206 if opts.get('large'):
206 if opts.get('large'):
207 raise util.Abort(_('--normal cannot be used with --large'))
207 raise util.Abort(_('--normal cannot be used with --large'))
208 return orig(ui, repo, *pats, **opts)
208 return orig(ui, repo, *pats, **opts)
209 bad = addlargefiles(ui, repo, *pats, **opts)
209 bad = addlargefiles(ui, repo, *pats, **opts)
210 installnormalfilesmatchfn(repo[None].manifest())
210 installnormalfilesmatchfn(repo[None].manifest())
211 result = orig(ui, repo, *pats, **opts)
211 result = orig(ui, repo, *pats, **opts)
212 restorematchfn()
212 restorematchfn()
213
213
214 return (result == 1 or bad) and 1 or 0
214 return (result == 1 or bad) and 1 or 0
215
215
216 def overrideremove(orig, ui, repo, *pats, **opts):
216 def overrideremove(orig, ui, repo, *pats, **opts):
217 installnormalfilesmatchfn(repo[None].manifest())
217 installnormalfilesmatchfn(repo[None].manifest())
218 result = orig(ui, repo, *pats, **opts)
218 result = orig(ui, repo, *pats, **opts)
219 restorematchfn()
219 restorematchfn()
220 return removelargefiles(ui, repo, *pats, **opts) or result
220 return removelargefiles(ui, repo, *pats, **opts) or result
221
221
222 def overridestatusfn(orig, repo, rev2, **opts):
222 def overridestatusfn(orig, repo, rev2, **opts):
223 try:
223 try:
224 repo._repo.lfstatus = True
224 repo._repo.lfstatus = True
225 return orig(repo, rev2, **opts)
225 return orig(repo, rev2, **opts)
226 finally:
226 finally:
227 repo._repo.lfstatus = False
227 repo._repo.lfstatus = False
228
228
229 def overridestatus(orig, ui, repo, *pats, **opts):
229 def overridestatus(orig, ui, repo, *pats, **opts):
230 try:
230 try:
231 repo.lfstatus = True
231 repo.lfstatus = True
232 return orig(ui, repo, *pats, **opts)
232 return orig(ui, repo, *pats, **opts)
233 finally:
233 finally:
234 repo.lfstatus = False
234 repo.lfstatus = False
235
235
236 def overridedirty(orig, repo, ignoreupdate=False):
236 def overridedirty(orig, repo, ignoreupdate=False):
237 try:
237 try:
238 repo._repo.lfstatus = True
238 repo._repo.lfstatus = True
239 return orig(repo, ignoreupdate)
239 return orig(repo, ignoreupdate)
240 finally:
240 finally:
241 repo._repo.lfstatus = False
241 repo._repo.lfstatus = False
242
242
243 def overridelog(orig, ui, repo, *pats, **opts):
243 def overridelog(orig, ui, repo, *pats, **opts):
244 def overridematch(ctx, pats=[], opts={}, globbed=False,
244 def overridematch(ctx, pats=[], opts={}, globbed=False,
245 default='relpath'):
245 default='relpath'):
246 """Matcher that merges root directory with .hglf, suitable for log.
246 """Matcher that merges root directory with .hglf, suitable for log.
247 It is still possible to match .hglf directly.
247 It is still possible to match .hglf directly.
248 For any listed files run log on the standin too.
248 For any listed files run log on the standin too.
249 matchfn tries both the given filename and with .hglf stripped.
249 matchfn tries both the given filename and with .hglf stripped.
250 """
250 """
251 match = oldmatch(ctx, pats, opts, globbed, default)
251 match = oldmatch(ctx, pats, opts, globbed, default)
252 m = copy.copy(match)
252 m = copy.copy(match)
253 for i in range(0, len(m._files)):
253 for i in range(0, len(m._files)):
254 standin = lfutil.standin(m._files[i])
254 standin = lfutil.standin(m._files[i])
255 if standin in repo[ctx.node()]:
255 if standin in repo[ctx.node()]:
256 m._files[i] = standin
256 m._files[i] = standin
257 m._fmap = set(m._files)
257 m._fmap = set(m._files)
258 m._always = False
258 m._always = False
259 origmatchfn = m.matchfn
259 origmatchfn = m.matchfn
260 def lfmatchfn(f):
260 def lfmatchfn(f):
261 lf = lfutil.splitstandin(f)
261 lf = lfutil.splitstandin(f)
262 if lf is not None and origmatchfn(lf):
262 if lf is not None and origmatchfn(lf):
263 return True
263 return True
264 r = origmatchfn(f)
264 r = origmatchfn(f)
265 return r
265 return r
266 m.matchfn = lfmatchfn
266 m.matchfn = lfmatchfn
267 return m
267 return m
268 oldmatch = installmatchfn(overridematch)
268 oldmatch = installmatchfn(overridematch)
269 try:
269 try:
270 repo.lfstatus = True
270 repo.lfstatus = True
271 return orig(ui, repo, *pats, **opts)
271 return orig(ui, repo, *pats, **opts)
272 finally:
272 finally:
273 repo.lfstatus = False
273 repo.lfstatus = False
274 restorematchfn()
274 restorematchfn()
275
275
276 def overrideverify(orig, ui, repo, *pats, **opts):
276 def overrideverify(orig, ui, repo, *pats, **opts):
277 large = opts.pop('large', False)
277 large = opts.pop('large', False)
278 all = opts.pop('lfa', False)
278 all = opts.pop('lfa', False)
279 contents = opts.pop('lfc', False)
279 contents = opts.pop('lfc', False)
280
280
281 result = orig(ui, repo, *pats, **opts)
281 result = orig(ui, repo, *pats, **opts)
282 if large or all or contents:
282 if large or all or contents:
283 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
283 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
284 return result
284 return result
285
285
286 def overridedebugstate(orig, ui, repo, *pats, **opts):
286 def overridedebugstate(orig, ui, repo, *pats, **opts):
287 large = opts.pop('large', False)
287 large = opts.pop('large', False)
288 if large:
288 if large:
289 class fakerepo(object):
289 class fakerepo(object):
290 dirstate = lfutil.openlfdirstate(ui, repo)
290 dirstate = lfutil.openlfdirstate(ui, repo)
291 orig(ui, fakerepo, *pats, **opts)
291 orig(ui, fakerepo, *pats, **opts)
292 else:
292 else:
293 orig(ui, repo, *pats, **opts)
293 orig(ui, repo, *pats, **opts)
294
294
295 # Override needs to refresh standins so that update's normal merge
295 # Override needs to refresh standins so that update's normal merge
296 # will go through properly. Then the other update hook (overriding repo.update)
296 # will go through properly. Then the other update hook (overriding repo.update)
297 # will get the new files. Filemerge is also overridden so that the merge
297 # will get the new files. Filemerge is also overridden so that the merge
298 # will merge standins correctly.
298 # will merge standins correctly.
299 def overrideupdate(orig, ui, repo, *pats, **opts):
299 def overrideupdate(orig, ui, repo, *pats, **opts):
300 # Need to lock between the standins getting updated and their
300 # Need to lock between the standins getting updated and their
301 # largefiles getting updated
301 # largefiles getting updated
302 wlock = repo.wlock()
302 wlock = repo.wlock()
303 try:
303 try:
304 lfdirstate = lfutil.openlfdirstate(ui, repo)
304 lfdirstate = lfutil.openlfdirstate(ui, repo)
305 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()),
305 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()),
306 [], False, False, False)
306 [], False, False, False)
307 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
307 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
308
308
309 if opts['check']:
309 if opts['check']:
310 mod = len(modified) > 0
310 mod = len(modified) > 0
311 for lfile in unsure:
311 for lfile in unsure:
312 standin = lfutil.standin(lfile)
312 standin = lfutil.standin(lfile)
313 if repo['.'][standin].data().strip() != \
313 if repo['.'][standin].data().strip() != \
314 lfutil.hashfile(repo.wjoin(lfile)):
314 lfutil.hashfile(repo.wjoin(lfile)):
315 mod = True
315 mod = True
316 else:
316 else:
317 lfdirstate.normal(lfile)
317 lfdirstate.normal(lfile)
318 lfdirstate.write()
318 lfdirstate.write()
319 if mod:
319 if mod:
320 raise util.Abort(_('uncommitted changes'))
320 raise util.Abort(_('uncommitted changes'))
321 # XXX handle removed differently
321 # XXX handle removed differently
322 if not opts['clean']:
322 if not opts['clean']:
323 for lfile in unsure + modified + added:
323 for lfile in unsure + modified + added:
324 lfutil.updatestandin(repo, lfutil.standin(lfile))
324 lfutil.updatestandin(repo, lfutil.standin(lfile))
325 return orig(ui, repo, *pats, **opts)
325 return orig(ui, repo, *pats, **opts)
326 finally:
326 finally:
327 wlock.release()
327 wlock.release()
328
328
329 # Before starting the manifest merge, merge.updates will call
329 # Before starting the manifest merge, merge.updates will call
330 # _checkunknown to check if there are any files in the merged-in
330 # _checkunknown to check if there are any files in the merged-in
331 # changeset that collide with unknown files in the working copy.
331 # changeset that collide with unknown files in the working copy.
332 #
332 #
333 # The largefiles are seen as unknown, so this prevents us from merging
333 # The largefiles are seen as unknown, so this prevents us from merging
334 # in a file 'foo' if we already have a largefile with the same name.
334 # in a file 'foo' if we already have a largefile with the same name.
335 #
335 #
336 # The overridden function filters the unknown files by removing any
336 # The overridden function filters the unknown files by removing any
337 # largefiles. This makes the merge proceed and we can then handle this
337 # largefiles. This makes the merge proceed and we can then handle this
338 # case further in the overridden manifestmerge function below.
338 # case further in the overridden manifestmerge function below.
339 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
339 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
340 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
340 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
341 return False
341 return False
342 return origfn(repo, wctx, mctx, f)
342 return origfn(repo, wctx, mctx, f)
343
343
344 # The manifest merge handles conflicts on the manifest level. We want
344 # The manifest merge handles conflicts on the manifest level. We want
345 # to handle changes in largefile-ness of files at this level too.
345 # to handle changes in largefile-ness of files at this level too.
346 #
346 #
347 # The strategy is to run the original manifestmerge and then process
347 # The strategy is to run the original manifestmerge and then process
348 # the action list it outputs. There are two cases we need to deal with:
348 # the action list it outputs. There are two cases we need to deal with:
349 #
349 #
350 # 1. Normal file in p1, largefile in p2. Here the largefile is
350 # 1. Normal file in p1, largefile in p2. Here the largefile is
351 # detected via its standin file, which will enter the working copy
351 # detected via its standin file, which will enter the working copy
352 # with a "get" action. It is not "merge" since the standin is all
352 # with a "get" action. It is not "merge" since the standin is all
353 # Mercurial is concerned with at this level -- the link to the
353 # Mercurial is concerned with at this level -- the link to the
354 # existing normal file is not relevant here.
354 # existing normal file is not relevant here.
355 #
355 #
356 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
356 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
357 # since the largefile will be present in the working copy and
357 # since the largefile will be present in the working copy and
358 # different from the normal file in p2. Mercurial therefore
358 # different from the normal file in p2. Mercurial therefore
359 # triggers a merge action.
359 # triggers a merge action.
360 #
360 #
361 # In both cases, we prompt the user and emit new actions to either
361 # In both cases, we prompt the user and emit new actions to either
362 # remove the standin (if the normal file was kept) or to remove the
362 # remove the standin (if the normal file was kept) or to remove the
363 # normal file and get the standin (if the largefile was kept). The
363 # normal file and get the standin (if the largefile was kept). The
364 # default prompt answer is to use the largefile version since it was
364 # default prompt answer is to use the largefile version since it was
365 # presumably changed on purpose.
365 # presumably changed on purpose.
366 #
366 #
367 # Finally, the merge.applyupdates function will then take care of
367 # Finally, the merge.applyupdates function will then take care of
368 # writing the files into the working copy and lfcommands.updatelfiles
368 # writing the files into the working copy and lfcommands.updatelfiles
369 # will update the largefiles.
369 # will update the largefiles.
370 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
370 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
371 partial, acceptremote, followcopies):
371 partial, acceptremote, followcopies):
372 overwrite = force and not branchmerge
372 overwrite = force and not branchmerge
373 actions = origfn(repo, p1, p2, pas, branchmerge, force, partial,
373 actions = origfn(repo, p1, p2, pas, branchmerge, force, partial,
374 acceptremote, followcopies)
374 acceptremote, followcopies)
375
375
376 if overwrite:
376 if overwrite:
377 return actions
377 return actions
378
378
379 removes = set(a[0] for a in actions if a[1] == 'r')
379 removes = set(a[0] for a in actions if a[1] == 'r')
380 processed = []
380 processed = []
381
381
382 for action in actions:
382 for action in actions:
383 f, m, args, msg = action
383 f, m, args, msg = action
384
384
385 splitstandin = f and lfutil.splitstandin(f)
385 splitstandin = f and lfutil.splitstandin(f)
386 if (m == "g" and splitstandin is not None and
386 if (m == "g" and splitstandin is not None and
387 splitstandin in p1 and splitstandin not in removes):
387 splitstandin in p1 and splitstandin not in removes):
388 # Case 1: normal file in the working copy, largefile in
388 # Case 1: normal file in the working copy, largefile in
389 # the second parent
389 # the second parent
390 lfile = splitstandin
390 lfile = splitstandin
391 standin = f
391 standin = f
392 msg = _('remote turned local normal file %s into a largefile\n'
392 msg = _('remote turned local normal file %s into a largefile\n'
393 'use (l)argefile or keep (n)ormal file?'
393 'use (l)argefile or keep (n)ormal file?'
394 '$$ &Largefile $$ &Normal file') % lfile
394 '$$ &Largefile $$ &Normal file') % lfile
395 if repo.ui.promptchoice(msg, 0) == 0:
395 if repo.ui.promptchoice(msg, 0) == 0:
396 processed.append((lfile, "r", None, msg))
396 processed.append((lfile, "r", None, msg))
397 processed.append((standin, "g", (p2.flags(standin),), msg))
397 processed.append((standin, "g", (p2.flags(standin),), msg))
398 else:
398 else:
399 processed.append((standin, "r", None, msg))
399 processed.append((standin, "r", None, msg))
400 elif (m == "g" and
400 elif (m == "g" and
401 lfutil.standin(f) in p1 and lfutil.standin(f) not in removes):
401 lfutil.standin(f) in p1 and lfutil.standin(f) not in removes):
402 # Case 2: largefile in the working copy, normal file in
402 # Case 2: largefile in the working copy, normal file in
403 # the second parent
403 # the second parent
404 standin = lfutil.standin(f)
404 standin = lfutil.standin(f)
405 lfile = f
405 lfile = f
406 msg = _('remote turned local largefile %s into a normal file\n'
406 msg = _('remote turned local largefile %s into a normal file\n'
407 'keep (l)argefile or use (n)ormal file?'
407 'keep (l)argefile or use (n)ormal file?'
408 '$$ &Largefile $$ &Normal file') % lfile
408 '$$ &Largefile $$ &Normal file') % lfile
409 if repo.ui.promptchoice(msg, 0) == 0:
409 if repo.ui.promptchoice(msg, 0) == 0:
410 processed.append((lfile, "r", None, msg))
410 processed.append((lfile, "r", None, msg))
411 else:
411 else:
412 processed.append((standin, "r", None, msg))
412 processed.append((standin, "r", None, msg))
413 processed.append((lfile, "g", (p2.flags(lfile),), msg))
413 processed.append((lfile, "g", (p2.flags(lfile),), msg))
414 else:
414 else:
415 processed.append(action)
415 processed.append(action)
416
416
417 return processed
417 return processed
418
418
419 # Override filemerge to prompt the user about how they wish to merge
419 # Override filemerge to prompt the user about how they wish to merge
420 # largefiles. This will handle identical edits without prompting the user.
420 # largefiles. This will handle identical edits without prompting the user.
421 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
421 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
422 if not lfutil.isstandin(orig):
422 if not lfutil.isstandin(orig):
423 return origfn(repo, mynode, orig, fcd, fco, fca)
423 return origfn(repo, mynode, orig, fcd, fco, fca)
424
424
425 ahash = fca.data().strip().lower()
425 ahash = fca.data().strip().lower()
426 dhash = fcd.data().strip().lower()
426 dhash = fcd.data().strip().lower()
427 ohash = fco.data().strip().lower()
427 ohash = fco.data().strip().lower()
428 if (ohash != ahash and
428 if (ohash != ahash and
429 ohash != dhash and
429 ohash != dhash and
430 (dhash == ahash or
430 (dhash == ahash or
431 repo.ui.promptchoice(
431 repo.ui.promptchoice(
432 _('largefile %s has a merge conflict\nancestor was %s\n'
432 _('largefile %s has a merge conflict\nancestor was %s\n'
433 'keep (l)ocal %s or\ntake (o)ther %s?'
433 'keep (l)ocal %s or\ntake (o)ther %s?'
434 '$$ &Local $$ &Other') %
434 '$$ &Local $$ &Other') %
435 (lfutil.splitstandin(orig), ahash, dhash, ohash),
435 (lfutil.splitstandin(orig), ahash, dhash, ohash),
436 0) == 1)):
436 0) == 1)):
437 repo.wwrite(fcd.path(), fco.data(), fco.flags())
437 repo.wwrite(fcd.path(), fco.data(), fco.flags())
438 return 0
438 return 0
439
439
440 # Copy first changes the matchers to match standins instead of
440 # Copy first changes the matchers to match standins instead of
441 # largefiles. Then it overrides util.copyfile in that function it
441 # largefiles. Then it overrides util.copyfile in that function it
442 # checks if the destination largefile already exists. It also keeps a
442 # checks if the destination largefile already exists. It also keeps a
443 # list of copied files so that the largefiles can be copied and the
443 # list of copied files so that the largefiles can be copied and the
444 # dirstate updated.
444 # dirstate updated.
445 def overridecopy(orig, ui, repo, pats, opts, rename=False):
445 def overridecopy(orig, ui, repo, pats, opts, rename=False):
446 # doesn't remove largefile on rename
446 # doesn't remove largefile on rename
447 if len(pats) < 2:
447 if len(pats) < 2:
448 # this isn't legal, let the original function deal with it
448 # this isn't legal, let the original function deal with it
449 return orig(ui, repo, pats, opts, rename)
449 return orig(ui, repo, pats, opts, rename)
450
450
451 def makestandin(relpath):
451 def makestandin(relpath):
452 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
452 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
453 return os.path.join(repo.wjoin(lfutil.standin(path)))
453 return os.path.join(repo.wjoin(lfutil.standin(path)))
454
454
455 fullpats = scmutil.expandpats(pats)
455 fullpats = scmutil.expandpats(pats)
456 dest = fullpats[-1]
456 dest = fullpats[-1]
457
457
458 if os.path.isdir(dest):
458 if os.path.isdir(dest):
459 if not os.path.isdir(makestandin(dest)):
459 if not os.path.isdir(makestandin(dest)):
460 os.makedirs(makestandin(dest))
460 os.makedirs(makestandin(dest))
461 # This could copy both lfiles and normal files in one command,
461 # This could copy both lfiles and normal files in one command,
462 # but we don't want to do that. First replace their matcher to
462 # but we don't want to do that. First replace their matcher to
463 # only match normal files and run it, then replace it to just
463 # only match normal files and run it, then replace it to just
464 # match largefiles and run it again.
464 # match largefiles and run it again.
465 nonormalfiles = False
465 nonormalfiles = False
466 nolfiles = False
466 nolfiles = False
467 installnormalfilesmatchfn(repo[None].manifest())
467 installnormalfilesmatchfn(repo[None].manifest())
468 try:
468 try:
469 try:
469 try:
470 result = orig(ui, repo, pats, opts, rename)
470 result = orig(ui, repo, pats, opts, rename)
471 except util.Abort, e:
471 except util.Abort, e:
472 if str(e) != _('no files to copy'):
472 if str(e) != _('no files to copy'):
473 raise e
473 raise e
474 else:
474 else:
475 nonormalfiles = True
475 nonormalfiles = True
476 result = 0
476 result = 0
477 finally:
477 finally:
478 restorematchfn()
478 restorematchfn()
479
479
480 # The first rename can cause our current working directory to be removed.
480 # The first rename can cause our current working directory to be removed.
481 # In that case there is nothing left to copy/rename so just quit.
481 # In that case there is nothing left to copy/rename so just quit.
482 try:
482 try:
483 repo.getcwd()
483 repo.getcwd()
484 except OSError:
484 except OSError:
485 return result
485 return result
486
486
487 try:
487 try:
488 try:
488 try:
489 # When we call orig below it creates the standins but we don't add
489 # When we call orig below it creates the standins but we don't add
490 # them to the dir state until later so lock during that time.
490 # them to the dir state until later so lock during that time.
491 wlock = repo.wlock()
491 wlock = repo.wlock()
492
492
493 manifest = repo[None].manifest()
493 manifest = repo[None].manifest()
494 def overridematch(ctx, pats=[], opts={}, globbed=False,
494 def overridematch(ctx, pats=[], opts={}, globbed=False,
495 default='relpath'):
495 default='relpath'):
496 newpats = []
496 newpats = []
497 # The patterns were previously mangled to add the standin
497 # The patterns were previously mangled to add the standin
498 # directory; we need to remove that now
498 # directory; we need to remove that now
499 for pat in pats:
499 for pat in pats:
500 if match_.patkind(pat) is None and lfutil.shortname in pat:
500 if match_.patkind(pat) is None and lfutil.shortname in pat:
501 newpats.append(pat.replace(lfutil.shortname, ''))
501 newpats.append(pat.replace(lfutil.shortname, ''))
502 else:
502 else:
503 newpats.append(pat)
503 newpats.append(pat)
504 match = oldmatch(ctx, newpats, opts, globbed, default)
504 match = oldmatch(ctx, newpats, opts, globbed, default)
505 m = copy.copy(match)
505 m = copy.copy(match)
506 lfile = lambda f: lfutil.standin(f) in manifest
506 lfile = lambda f: lfutil.standin(f) in manifest
507 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
507 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
508 m._fmap = set(m._files)
508 m._fmap = set(m._files)
509 m._always = False
509 m._always = False
510 origmatchfn = m.matchfn
510 origmatchfn = m.matchfn
511 m.matchfn = lambda f: (lfutil.isstandin(f) and
511 m.matchfn = lambda f: (lfutil.isstandin(f) and
512 (f in manifest) and
512 (f in manifest) and
513 origmatchfn(lfutil.splitstandin(f)) or
513 origmatchfn(lfutil.splitstandin(f)) or
514 None)
514 None)
515 return m
515 return m
516 oldmatch = installmatchfn(overridematch)
516 oldmatch = installmatchfn(overridematch)
517 listpats = []
517 listpats = []
518 for pat in pats:
518 for pat in pats:
519 if match_.patkind(pat) is not None:
519 if match_.patkind(pat) is not None:
520 listpats.append(pat)
520 listpats.append(pat)
521 else:
521 else:
522 listpats.append(makestandin(pat))
522 listpats.append(makestandin(pat))
523
523
524 try:
524 try:
525 origcopyfile = util.copyfile
525 origcopyfile = util.copyfile
526 copiedfiles = []
526 copiedfiles = []
527 def overridecopyfile(src, dest):
527 def overridecopyfile(src, dest):
528 if (lfutil.shortname in src and
528 if (lfutil.shortname in src and
529 dest.startswith(repo.wjoin(lfutil.shortname))):
529 dest.startswith(repo.wjoin(lfutil.shortname))):
530 destlfile = dest.replace(lfutil.shortname, '')
530 destlfile = dest.replace(lfutil.shortname, '')
531 if not opts['force'] and os.path.exists(destlfile):
531 if not opts['force'] and os.path.exists(destlfile):
532 raise IOError('',
532 raise IOError('',
533 _('destination largefile already exists'))
533 _('destination largefile already exists'))
534 copiedfiles.append((src, dest))
534 copiedfiles.append((src, dest))
535 origcopyfile(src, dest)
535 origcopyfile(src, dest)
536
536
537 util.copyfile = overridecopyfile
537 util.copyfile = overridecopyfile
538 result += orig(ui, repo, listpats, opts, rename)
538 result += orig(ui, repo, listpats, opts, rename)
539 finally:
539 finally:
540 util.copyfile = origcopyfile
540 util.copyfile = origcopyfile
541
541
542 lfdirstate = lfutil.openlfdirstate(ui, repo)
542 lfdirstate = lfutil.openlfdirstate(ui, repo)
543 for (src, dest) in copiedfiles:
543 for (src, dest) in copiedfiles:
544 if (lfutil.shortname in src and
544 if (lfutil.shortname in src and
545 dest.startswith(repo.wjoin(lfutil.shortname))):
545 dest.startswith(repo.wjoin(lfutil.shortname))):
546 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
546 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
547 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
547 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
548 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
548 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
549 if not os.path.isdir(destlfiledir):
549 if not os.path.isdir(destlfiledir):
550 os.makedirs(destlfiledir)
550 os.makedirs(destlfiledir)
551 if rename:
551 if rename:
552 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
552 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
553 lfdirstate.remove(srclfile)
553 lfdirstate.remove(srclfile)
554 else:
554 else:
555 util.copyfile(repo.wjoin(srclfile),
555 util.copyfile(repo.wjoin(srclfile),
556 repo.wjoin(destlfile))
556 repo.wjoin(destlfile))
557
557
558 lfdirstate.add(destlfile)
558 lfdirstate.add(destlfile)
559 lfdirstate.write()
559 lfdirstate.write()
560 except util.Abort, e:
560 except util.Abort, e:
561 if str(e) != _('no files to copy'):
561 if str(e) != _('no files to copy'):
562 raise e
562 raise e
563 else:
563 else:
564 nolfiles = True
564 nolfiles = True
565 finally:
565 finally:
566 restorematchfn()
566 restorematchfn()
567 wlock.release()
567 wlock.release()
568
568
569 if nolfiles and nonormalfiles:
569 if nolfiles and nonormalfiles:
570 raise util.Abort(_('no files to copy'))
570 raise util.Abort(_('no files to copy'))
571
571
572 return result
572 return result
573
573
574 # When the user calls revert, we have to be careful to not revert any
574 # When the user calls revert, we have to be careful to not revert any
575 # changes to other largefiles accidentally. This means we have to keep
575 # changes to other largefiles accidentally. This means we have to keep
576 # track of the largefiles that are being reverted so we only pull down
576 # track of the largefiles that are being reverted so we only pull down
577 # the necessary largefiles.
577 # the necessary largefiles.
578 #
578 #
579 # Standins are only updated (to match the hash of largefiles) before
579 # Standins are only updated (to match the hash of largefiles) before
580 # commits. Update the standins then run the original revert, changing
580 # commits. Update the standins then run the original revert, changing
581 # the matcher to hit standins instead of largefiles. Based on the
581 # the matcher to hit standins instead of largefiles. Based on the
582 # resulting standins update the largefiles.
582 # resulting standins update the largefiles.
583 def overriderevert(orig, ui, repo, *pats, **opts):
583 def overriderevert(orig, ui, repo, *pats, **opts):
584 # Because we put the standins in a bad state (by updating them)
584 # Because we put the standins in a bad state (by updating them)
585 # and then return them to a correct state we need to lock to
585 # and then return them to a correct state we need to lock to
586 # prevent others from changing them in their incorrect state.
586 # prevent others from changing them in their incorrect state.
587 wlock = repo.wlock()
587 wlock = repo.wlock()
588 try:
588 try:
589 lfdirstate = lfutil.openlfdirstate(ui, repo)
589 lfdirstate = lfutil.openlfdirstate(ui, repo)
590 (modified, added, removed, missing, unknown, ignored, clean) = \
590 (modified, added, removed, missing, unknown, ignored, clean) = \
591 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
591 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
592 lfdirstate.write()
592 lfdirstate.write()
593 for lfile in modified:
593 for lfile in modified:
594 lfutil.updatestandin(repo, lfutil.standin(lfile))
594 lfutil.updatestandin(repo, lfutil.standin(lfile))
595 for lfile in missing:
595 for lfile in missing:
596 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
596 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
597 os.unlink(repo.wjoin(lfutil.standin(lfile)))
597 os.unlink(repo.wjoin(lfutil.standin(lfile)))
598
598
599 oldstandins = lfutil.getstandinsstate(repo)
599 oldstandins = lfutil.getstandinsstate(repo)
600
600
601 def overridematch(ctx, pats=[], opts={}, globbed=False,
601 def overridematch(ctx, pats=[], opts={}, globbed=False,
602 default='relpath'):
602 default='relpath'):
603 match = oldmatch(ctx, pats, opts, globbed, default)
603 match = oldmatch(ctx, pats, opts, globbed, default)
604 m = copy.copy(match)
604 m = copy.copy(match)
605 def tostandin(f):
605 def tostandin(f):
606 if lfutil.standin(f) in ctx:
606 if lfutil.standin(f) in ctx:
607 return lfutil.standin(f)
607 return lfutil.standin(f)
608 elif lfutil.standin(f) in repo[None]:
608 elif lfutil.standin(f) in repo[None]:
609 return None
609 return None
610 return f
610 return f
611 m._files = [tostandin(f) for f in m._files]
611 m._files = [tostandin(f) for f in m._files]
612 m._files = [f for f in m._files if f is not None]
612 m._files = [f for f in m._files if f is not None]
613 m._fmap = set(m._files)
613 m._fmap = set(m._files)
614 m._always = False
614 m._always = False
615 origmatchfn = m.matchfn
615 origmatchfn = m.matchfn
616 def matchfn(f):
616 def matchfn(f):
617 if lfutil.isstandin(f):
617 if lfutil.isstandin(f):
618 return (origmatchfn(lfutil.splitstandin(f)) and
618 return (origmatchfn(lfutil.splitstandin(f)) and
619 (f in repo[None] or f in ctx))
619 (f in repo[None] or f in ctx))
620 return origmatchfn(f)
620 return origmatchfn(f)
621 m.matchfn = matchfn
621 m.matchfn = matchfn
622 return m
622 return m
623 oldmatch = installmatchfn(overridematch)
623 oldmatch = installmatchfn(overridematch)
624 try:
624 try:
625 orig(ui, repo, *pats, **opts)
625 orig(ui, repo, *pats, **opts)
626 finally:
626 finally:
627 restorematchfn()
627 restorematchfn()
628
628
629 newstandins = lfutil.getstandinsstate(repo)
629 newstandins = lfutil.getstandinsstate(repo)
630 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
630 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
631 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False)
631 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False)
632
632
633 finally:
633 finally:
634 wlock.release()
634 wlock.release()
635
635
636 def hgupdaterepo(orig, repo, node, overwrite):
636 def hgupdaterepo(orig, repo, node, overwrite):
637 if not overwrite:
637 if not overwrite:
638 # Only call updatelfiles on the standins that have changed to save time
638 # Only call updatelfiles on the standins that have changed to save time
639 oldstandins = lfutil.getstandinsstate(repo)
639 oldstandins = lfutil.getstandinsstate(repo)
640
640
641 result = orig(repo, node, overwrite)
641 result = orig(repo, node, overwrite)
642
642
643 filelist = None
643 filelist = None
644 if not overwrite:
644 if not overwrite:
645 newstandins = lfutil.getstandinsstate(repo)
645 newstandins = lfutil.getstandinsstate(repo)
646 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
646 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
647 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
647 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
648 return result
648 return result
649
649
650 def hgmerge(orig, repo, node, force=None, remind=True):
650 def hgmerge(orig, repo, node, force=None, remind=True):
651 result = orig(repo, node, force, remind)
651 result = orig(repo, node, force, remind)
652 lfcommands.updatelfiles(repo.ui, repo)
652 lfcommands.updatelfiles(repo.ui, repo)
653 return result
653 return result
654
654
655 # When we rebase a repository with remotely changed largefiles, we need to
655 # When we rebase a repository with remotely changed largefiles, we need to
656 # take some extra care so that the largefiles are correctly updated in the
656 # take some extra care so that the largefiles are correctly updated in the
657 # working copy
657 # working copy
658 def overridepull(orig, ui, repo, source=None, **opts):
658 def overridepull(orig, ui, repo, source=None, **opts):
659 revsprepull = len(repo)
659 revsprepull = len(repo)
660 if not source:
660 if not source:
661 source = 'default'
661 source = 'default'
662 repo.lfpullsource = source
662 repo.lfpullsource = source
663 if opts.get('rebase', False):
663 if opts.get('rebase', False):
664 repo._isrebasing = True
664 repo._isrebasing = True
665 try:
665 try:
666 if opts.get('update'):
666 if opts.get('update'):
667 del opts['update']
667 del opts['update']
668 ui.debug('--update and --rebase are not compatible, ignoring '
668 ui.debug('--update and --rebase are not compatible, ignoring '
669 'the update flag\n')
669 'the update flag\n')
670 del opts['rebase']
670 del opts['rebase']
671 origpostincoming = commands.postincoming
671 origpostincoming = commands.postincoming
672 def _dummy(*args, **kwargs):
672 def _dummy(*args, **kwargs):
673 pass
673 pass
674 commands.postincoming = _dummy
674 commands.postincoming = _dummy
675 try:
675 try:
676 result = commands.pull(ui, repo, source, **opts)
676 result = commands.pull(ui, repo, source, **opts)
677 finally:
677 finally:
678 commands.postincoming = origpostincoming
678 commands.postincoming = origpostincoming
679 revspostpull = len(repo)
679 revspostpull = len(repo)
680 if revspostpull > revsprepull:
680 if revspostpull > revsprepull:
681 result = result or rebase.rebase(ui, repo)
681 result = result or rebase.rebase(ui, repo)
682 finally:
682 finally:
683 repo._isrebasing = False
683 repo._isrebasing = False
684 else:
684 else:
685 result = orig(ui, repo, source, **opts)
685 result = orig(ui, repo, source, **opts)
686 revspostpull = len(repo)
686 revspostpull = len(repo)
687 lfrevs = opts.get('lfrev', [])
687 lfrevs = opts.get('lfrev', [])
688 if opts.get('all_largefiles'):
688 if opts.get('all_largefiles'):
689 lfrevs.append('pulled()')
689 lfrevs.append('pulled()')
690 if lfrevs and revspostpull > revsprepull:
690 if lfrevs and revspostpull > revsprepull:
691 numcached = 0
691 numcached = 0
692 repo.firstpulled = revsprepull # for pulled() revset expression
692 repo.firstpulled = revsprepull # for pulled() revset expression
693 try:
693 try:
694 for rev in scmutil.revrange(repo, lfrevs):
694 for rev in scmutil.revrange(repo, lfrevs):
695 ui.note(_('pulling largefiles for revision %s\n') % rev)
695 ui.note(_('pulling largefiles for revision %s\n') % rev)
696 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
696 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
697 numcached += len(cached)
697 numcached += len(cached)
698 finally:
698 finally:
699 del repo.firstpulled
699 del repo.firstpulled
700 ui.status(_("%d largefiles cached\n") % numcached)
700 ui.status(_("%d largefiles cached\n") % numcached)
701 return result
701 return result
702
702
703 def pulledrevsetsymbol(repo, subset, x):
703 def pulledrevsetsymbol(repo, subset, x):
704 """``pulled()``
704 """``pulled()``
705 Changesets that just has been pulled.
705 Changesets that just has been pulled.
706
706
707 Only available with largefiles from pull --lfrev expressions.
707 Only available with largefiles from pull --lfrev expressions.
708
708
709 .. container:: verbose
709 .. container:: verbose
710
710
711 Some examples:
711 Some examples:
712
712
713 - pull largefiles for all new changesets::
713 - pull largefiles for all new changesets::
714
714
715 hg pull -lfrev "pulled()"
715 hg pull -lfrev "pulled()"
716
716
717 - pull largefiles for all new branch heads::
717 - pull largefiles for all new branch heads::
718
718
719 hg pull -lfrev "head(pulled()) and not closed()"
719 hg pull -lfrev "head(pulled()) and not closed()"
720
720
721 """
721 """
722
722
723 try:
723 try:
724 firstpulled = repo.firstpulled
724 firstpulled = repo.firstpulled
725 except AttributeError:
725 except AttributeError:
726 raise util.Abort(_("pulled() only available in --lfrev"))
726 raise util.Abort(_("pulled() only available in --lfrev"))
727 return revset.baseset([r for r in subset if r >= firstpulled])
727 return revset.baseset([r for r in subset if r >= firstpulled])
728
728
729 def overrideclone(orig, ui, source, dest=None, **opts):
729 def overrideclone(orig, ui, source, dest=None, **opts):
730 d = dest
730 d = dest
731 if d is None:
731 if d is None:
732 d = hg.defaultdest(source)
732 d = hg.defaultdest(source)
733 if opts.get('all_largefiles') and not hg.islocal(d):
733 if opts.get('all_largefiles') and not hg.islocal(d):
734 raise util.Abort(_(
734 raise util.Abort(_(
735 '--all-largefiles is incompatible with non-local destination %s' %
735 '--all-largefiles is incompatible with non-local destination %s') %
736 d))
736 d)
737
737
738 return orig(ui, source, dest, **opts)
738 return orig(ui, source, dest, **opts)
739
739
740 def hgclone(orig, ui, opts, *args, **kwargs):
740 def hgclone(orig, ui, opts, *args, **kwargs):
741 result = orig(ui, opts, *args, **kwargs)
741 result = orig(ui, opts, *args, **kwargs)
742
742
743 if result is not None:
743 if result is not None:
744 sourcerepo, destrepo = result
744 sourcerepo, destrepo = result
745 repo = destrepo.local()
745 repo = destrepo.local()
746
746
747 # Caching is implicitly limited to 'rev' option, since the dest repo was
747 # Caching is implicitly limited to 'rev' option, since the dest repo was
748 # truncated at that point. The user may expect a download count with
748 # truncated at that point. The user may expect a download count with
749 # this option, so attempt whether or not this is a largefile repo.
749 # this option, so attempt whether or not this is a largefile repo.
750 if opts.get('all_largefiles'):
750 if opts.get('all_largefiles'):
751 success, missing = lfcommands.downloadlfiles(ui, repo, None)
751 success, missing = lfcommands.downloadlfiles(ui, repo, None)
752
752
753 if missing != 0:
753 if missing != 0:
754 return None
754 return None
755
755
756 return result
756 return result
757
757
758 def overriderebase(orig, ui, repo, **opts):
758 def overriderebase(orig, ui, repo, **opts):
759 repo._isrebasing = True
759 repo._isrebasing = True
760 try:
760 try:
761 return orig(ui, repo, **opts)
761 return orig(ui, repo, **opts)
762 finally:
762 finally:
763 repo._isrebasing = False
763 repo._isrebasing = False
764
764
765 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
765 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
766 prefix=None, mtime=None, subrepos=None):
766 prefix=None, mtime=None, subrepos=None):
767 # No need to lock because we are only reading history and
767 # No need to lock because we are only reading history and
768 # largefile caches, neither of which are modified.
768 # largefile caches, neither of which are modified.
769 lfcommands.cachelfiles(repo.ui, repo, node)
769 lfcommands.cachelfiles(repo.ui, repo, node)
770
770
771 if kind not in archival.archivers:
771 if kind not in archival.archivers:
772 raise util.Abort(_("unknown archive type '%s'") % kind)
772 raise util.Abort(_("unknown archive type '%s'") % kind)
773
773
774 ctx = repo[node]
774 ctx = repo[node]
775
775
776 if kind == 'files':
776 if kind == 'files':
777 if prefix:
777 if prefix:
778 raise util.Abort(
778 raise util.Abort(
779 _('cannot give prefix when archiving to files'))
779 _('cannot give prefix when archiving to files'))
780 else:
780 else:
781 prefix = archival.tidyprefix(dest, kind, prefix)
781 prefix = archival.tidyprefix(dest, kind, prefix)
782
782
783 def write(name, mode, islink, getdata):
783 def write(name, mode, islink, getdata):
784 if matchfn and not matchfn(name):
784 if matchfn and not matchfn(name):
785 return
785 return
786 data = getdata()
786 data = getdata()
787 if decode:
787 if decode:
788 data = repo.wwritedata(name, data)
788 data = repo.wwritedata(name, data)
789 archiver.addfile(prefix + name, mode, islink, data)
789 archiver.addfile(prefix + name, mode, islink, data)
790
790
791 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
791 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
792
792
793 if repo.ui.configbool("ui", "archivemeta", True):
793 if repo.ui.configbool("ui", "archivemeta", True):
794 def metadata():
794 def metadata():
795 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
795 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
796 hex(repo.changelog.node(0)), hex(node), ctx.branch())
796 hex(repo.changelog.node(0)), hex(node), ctx.branch())
797
797
798 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
798 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
799 if repo.tagtype(t) == 'global')
799 if repo.tagtype(t) == 'global')
800 if not tags:
800 if not tags:
801 repo.ui.pushbuffer()
801 repo.ui.pushbuffer()
802 opts = {'template': '{latesttag}\n{latesttagdistance}',
802 opts = {'template': '{latesttag}\n{latesttagdistance}',
803 'style': '', 'patch': None, 'git': None}
803 'style': '', 'patch': None, 'git': None}
804 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
804 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
805 ltags, dist = repo.ui.popbuffer().split('\n')
805 ltags, dist = repo.ui.popbuffer().split('\n')
806 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
806 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
807 tags += 'latesttagdistance: %s\n' % dist
807 tags += 'latesttagdistance: %s\n' % dist
808
808
809 return base + tags
809 return base + tags
810
810
811 write('.hg_archival.txt', 0644, False, metadata)
811 write('.hg_archival.txt', 0644, False, metadata)
812
812
813 for f in ctx:
813 for f in ctx:
814 ff = ctx.flags(f)
814 ff = ctx.flags(f)
815 getdata = ctx[f].data
815 getdata = ctx[f].data
816 if lfutil.isstandin(f):
816 if lfutil.isstandin(f):
817 path = lfutil.findfile(repo, getdata().strip())
817 path = lfutil.findfile(repo, getdata().strip())
818 if path is None:
818 if path is None:
819 raise util.Abort(
819 raise util.Abort(
820 _('largefile %s not found in repo store or system cache')
820 _('largefile %s not found in repo store or system cache')
821 % lfutil.splitstandin(f))
821 % lfutil.splitstandin(f))
822 f = lfutil.splitstandin(f)
822 f = lfutil.splitstandin(f)
823
823
824 def getdatafn():
824 def getdatafn():
825 fd = None
825 fd = None
826 try:
826 try:
827 fd = open(path, 'rb')
827 fd = open(path, 'rb')
828 return fd.read()
828 return fd.read()
829 finally:
829 finally:
830 if fd:
830 if fd:
831 fd.close()
831 fd.close()
832
832
833 getdata = getdatafn
833 getdata = getdatafn
834 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
834 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
835
835
836 if subrepos:
836 if subrepos:
837 for subpath in sorted(ctx.substate):
837 for subpath in sorted(ctx.substate):
838 sub = ctx.sub(subpath)
838 sub = ctx.sub(subpath)
839 submatch = match_.narrowmatcher(subpath, matchfn)
839 submatch = match_.narrowmatcher(subpath, matchfn)
840 sub.archive(repo.ui, archiver, prefix, submatch)
840 sub.archive(repo.ui, archiver, prefix, submatch)
841
841
842 archiver.done()
842 archiver.done()
843
843
844 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
844 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
845 repo._get(repo._state + ('hg',))
845 repo._get(repo._state + ('hg',))
846 rev = repo._state[1]
846 rev = repo._state[1]
847 ctx = repo._repo[rev]
847 ctx = repo._repo[rev]
848
848
849 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
849 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
850
850
851 def write(name, mode, islink, getdata):
851 def write(name, mode, islink, getdata):
852 # At this point, the standin has been replaced with the largefile name,
852 # At this point, the standin has been replaced with the largefile name,
853 # so the normal matcher works here without the lfutil variants.
853 # so the normal matcher works here without the lfutil variants.
854 if match and not match(f):
854 if match and not match(f):
855 return
855 return
856 data = getdata()
856 data = getdata()
857
857
858 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
858 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
859
859
860 for f in ctx:
860 for f in ctx:
861 ff = ctx.flags(f)
861 ff = ctx.flags(f)
862 getdata = ctx[f].data
862 getdata = ctx[f].data
863 if lfutil.isstandin(f):
863 if lfutil.isstandin(f):
864 path = lfutil.findfile(repo._repo, getdata().strip())
864 path = lfutil.findfile(repo._repo, getdata().strip())
865 if path is None:
865 if path is None:
866 raise util.Abort(
866 raise util.Abort(
867 _('largefile %s not found in repo store or system cache')
867 _('largefile %s not found in repo store or system cache')
868 % lfutil.splitstandin(f))
868 % lfutil.splitstandin(f))
869 f = lfutil.splitstandin(f)
869 f = lfutil.splitstandin(f)
870
870
871 def getdatafn():
871 def getdatafn():
872 fd = None
872 fd = None
873 try:
873 try:
874 fd = open(os.path.join(prefix, path), 'rb')
874 fd = open(os.path.join(prefix, path), 'rb')
875 return fd.read()
875 return fd.read()
876 finally:
876 finally:
877 if fd:
877 if fd:
878 fd.close()
878 fd.close()
879
879
880 getdata = getdatafn
880 getdata = getdatafn
881
881
882 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
882 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
883
883
884 for subpath in sorted(ctx.substate):
884 for subpath in sorted(ctx.substate):
885 sub = ctx.sub(subpath)
885 sub = ctx.sub(subpath)
886 submatch = match_.narrowmatcher(subpath, match)
886 submatch = match_.narrowmatcher(subpath, match)
887 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
887 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
888 submatch)
888 submatch)
889
889
890 # If a largefile is modified, the change is not reflected in its
890 # If a largefile is modified, the change is not reflected in its
891 # standin until a commit. cmdutil.bailifchanged() raises an exception
891 # standin until a commit. cmdutil.bailifchanged() raises an exception
892 # if the repo has uncommitted changes. Wrap it to also check if
892 # if the repo has uncommitted changes. Wrap it to also check if
893 # largefiles were changed. This is used by bisect and backout.
893 # largefiles were changed. This is used by bisect and backout.
894 def overridebailifchanged(orig, repo):
894 def overridebailifchanged(orig, repo):
895 orig(repo)
895 orig(repo)
896 repo.lfstatus = True
896 repo.lfstatus = True
897 modified, added, removed, deleted = repo.status()[:4]
897 modified, added, removed, deleted = repo.status()[:4]
898 repo.lfstatus = False
898 repo.lfstatus = False
899 if modified or added or removed or deleted:
899 if modified or added or removed or deleted:
900 raise util.Abort(_('uncommitted changes'))
900 raise util.Abort(_('uncommitted changes'))
901
901
902 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
902 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
903 def overridefetch(orig, ui, repo, *pats, **opts):
903 def overridefetch(orig, ui, repo, *pats, **opts):
904 repo.lfstatus = True
904 repo.lfstatus = True
905 modified, added, removed, deleted = repo.status()[:4]
905 modified, added, removed, deleted = repo.status()[:4]
906 repo.lfstatus = False
906 repo.lfstatus = False
907 if modified or added or removed or deleted:
907 if modified or added or removed or deleted:
908 raise util.Abort(_('uncommitted changes'))
908 raise util.Abort(_('uncommitted changes'))
909 return orig(ui, repo, *pats, **opts)
909 return orig(ui, repo, *pats, **opts)
910
910
911 def overrideforget(orig, ui, repo, *pats, **opts):
911 def overrideforget(orig, ui, repo, *pats, **opts):
912 installnormalfilesmatchfn(repo[None].manifest())
912 installnormalfilesmatchfn(repo[None].manifest())
913 result = orig(ui, repo, *pats, **opts)
913 result = orig(ui, repo, *pats, **opts)
914 restorematchfn()
914 restorematchfn()
915 m = scmutil.match(repo[None], pats, opts)
915 m = scmutil.match(repo[None], pats, opts)
916
916
917 try:
917 try:
918 repo.lfstatus = True
918 repo.lfstatus = True
919 s = repo.status(match=m, clean=True)
919 s = repo.status(match=m, clean=True)
920 finally:
920 finally:
921 repo.lfstatus = False
921 repo.lfstatus = False
922 forget = sorted(s[0] + s[1] + s[3] + s[6])
922 forget = sorted(s[0] + s[1] + s[3] + s[6])
923 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
923 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
924
924
925 for f in forget:
925 for f in forget:
926 if lfutil.standin(f) not in repo.dirstate and not \
926 if lfutil.standin(f) not in repo.dirstate and not \
927 os.path.isdir(m.rel(lfutil.standin(f))):
927 os.path.isdir(m.rel(lfutil.standin(f))):
928 ui.warn(_('not removing %s: file is already untracked\n')
928 ui.warn(_('not removing %s: file is already untracked\n')
929 % m.rel(f))
929 % m.rel(f))
930 result = 1
930 result = 1
931
931
932 for f in forget:
932 for f in forget:
933 if ui.verbose or not m.exact(f):
933 if ui.verbose or not m.exact(f):
934 ui.status(_('removing %s\n') % m.rel(f))
934 ui.status(_('removing %s\n') % m.rel(f))
935
935
936 # Need to lock because standin files are deleted then removed from the
936 # Need to lock because standin files are deleted then removed from the
937 # repository and we could race in-between.
937 # repository and we could race in-between.
938 wlock = repo.wlock()
938 wlock = repo.wlock()
939 try:
939 try:
940 lfdirstate = lfutil.openlfdirstate(ui, repo)
940 lfdirstate = lfutil.openlfdirstate(ui, repo)
941 for f in forget:
941 for f in forget:
942 if lfdirstate[f] == 'a':
942 if lfdirstate[f] == 'a':
943 lfdirstate.drop(f)
943 lfdirstate.drop(f)
944 else:
944 else:
945 lfdirstate.remove(f)
945 lfdirstate.remove(f)
946 lfdirstate.write()
946 lfdirstate.write()
947 standins = [lfutil.standin(f) for f in forget]
947 standins = [lfutil.standin(f) for f in forget]
948 for f in standins:
948 for f in standins:
949 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
949 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
950 repo[None].forget(standins)
950 repo[None].forget(standins)
951 finally:
951 finally:
952 wlock.release()
952 wlock.release()
953
953
954 return result
954 return result
955
955
956 def outgoinghook(ui, repo, other, opts, missing):
956 def outgoinghook(ui, repo, other, opts, missing):
957 if opts.pop('large', None):
957 if opts.pop('large', None):
958 toupload = set()
958 toupload = set()
959 lfutil.getlfilestoupload(repo, missing,
959 lfutil.getlfilestoupload(repo, missing,
960 lambda fn, lfhash: toupload.add(fn))
960 lambda fn, lfhash: toupload.add(fn))
961 if not toupload:
961 if not toupload:
962 ui.status(_('largefiles: no files to upload\n'))
962 ui.status(_('largefiles: no files to upload\n'))
963 else:
963 else:
964 ui.status(_('largefiles to upload:\n'))
964 ui.status(_('largefiles to upload:\n'))
965 for file in sorted(toupload):
965 for file in sorted(toupload):
966 ui.status(lfutil.splitstandin(file) + '\n')
966 ui.status(lfutil.splitstandin(file) + '\n')
967 ui.status('\n')
967 ui.status('\n')
968
968
969 def summaryremotehook(ui, repo, opts, changes):
969 def summaryremotehook(ui, repo, opts, changes):
970 largeopt = opts.get('large', False)
970 largeopt = opts.get('large', False)
971 if changes is None:
971 if changes is None:
972 if largeopt:
972 if largeopt:
973 return (False, True) # only outgoing check is needed
973 return (False, True) # only outgoing check is needed
974 else:
974 else:
975 return (False, False)
975 return (False, False)
976 elif largeopt:
976 elif largeopt:
977 url, branch, peer, outgoing = changes[1]
977 url, branch, peer, outgoing = changes[1]
978 if peer is None:
978 if peer is None:
979 # i18n: column positioning for "hg summary"
979 # i18n: column positioning for "hg summary"
980 ui.status(_('largefiles: (no remote repo)\n'))
980 ui.status(_('largefiles: (no remote repo)\n'))
981 return
981 return
982
982
983 toupload = set()
983 toupload = set()
984 lfutil.getlfilestoupload(repo, outgoing.missing,
984 lfutil.getlfilestoupload(repo, outgoing.missing,
985 lambda fn, lfhash: toupload.add(fn))
985 lambda fn, lfhash: toupload.add(fn))
986 if not toupload:
986 if not toupload:
987 # i18n: column positioning for "hg summary"
987 # i18n: column positioning for "hg summary"
988 ui.status(_('largefiles: (no files to upload)\n'))
988 ui.status(_('largefiles: (no files to upload)\n'))
989 else:
989 else:
990 # i18n: column positioning for "hg summary"
990 # i18n: column positioning for "hg summary"
991 ui.status(_('largefiles: %d to upload\n') % len(toupload))
991 ui.status(_('largefiles: %d to upload\n') % len(toupload))
992
992
993 def overridesummary(orig, ui, repo, *pats, **opts):
993 def overridesummary(orig, ui, repo, *pats, **opts):
994 try:
994 try:
995 repo.lfstatus = True
995 repo.lfstatus = True
996 orig(ui, repo, *pats, **opts)
996 orig(ui, repo, *pats, **opts)
997 finally:
997 finally:
998 repo.lfstatus = False
998 repo.lfstatus = False
999
999
1000 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1000 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1001 similarity=None):
1001 similarity=None):
1002 if not lfutil.islfilesrepo(repo):
1002 if not lfutil.islfilesrepo(repo):
1003 return orig(repo, pats, opts, dry_run, similarity)
1003 return orig(repo, pats, opts, dry_run, similarity)
1004 # Get the list of missing largefiles so we can remove them
1004 # Get the list of missing largefiles so we can remove them
1005 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1005 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1006 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1006 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1007 False, False)
1007 False, False)
1008 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1008 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1009
1009
1010 # Call into the normal remove code, but the removing of the standin, we want
1010 # Call into the normal remove code, but the removing of the standin, we want
1011 # to have handled by original addremove. Monkey patching here makes sure
1011 # to have handled by original addremove. Monkey patching here makes sure
1012 # we don't remove the standin in the largefiles code, preventing a very
1012 # we don't remove the standin in the largefiles code, preventing a very
1013 # confused state later.
1013 # confused state later.
1014 if missing:
1014 if missing:
1015 m = [repo.wjoin(f) for f in missing]
1015 m = [repo.wjoin(f) for f in missing]
1016 repo._isaddremove = True
1016 repo._isaddremove = True
1017 removelargefiles(repo.ui, repo, *m, **opts)
1017 removelargefiles(repo.ui, repo, *m, **opts)
1018 repo._isaddremove = False
1018 repo._isaddremove = False
1019 # Call into the normal add code, and any files that *should* be added as
1019 # Call into the normal add code, and any files that *should* be added as
1020 # largefiles will be
1020 # largefiles will be
1021 addlargefiles(repo.ui, repo, *pats, **opts)
1021 addlargefiles(repo.ui, repo, *pats, **opts)
1022 # Now that we've handled largefiles, hand off to the original addremove
1022 # Now that we've handled largefiles, hand off to the original addremove
1023 # function to take care of the rest. Make sure it doesn't do anything with
1023 # function to take care of the rest. Make sure it doesn't do anything with
1024 # largefiles by installing a matcher that will ignore them.
1024 # largefiles by installing a matcher that will ignore them.
1025 installnormalfilesmatchfn(repo[None].manifest())
1025 installnormalfilesmatchfn(repo[None].manifest())
1026 result = orig(repo, pats, opts, dry_run, similarity)
1026 result = orig(repo, pats, opts, dry_run, similarity)
1027 restorematchfn()
1027 restorematchfn()
1028 return result
1028 return result
1029
1029
1030 # Calling purge with --all will cause the largefiles to be deleted.
1030 # Calling purge with --all will cause the largefiles to be deleted.
1031 # Override repo.status to prevent this from happening.
1031 # Override repo.status to prevent this from happening.
1032 def overridepurge(orig, ui, repo, *dirs, **opts):
1032 def overridepurge(orig, ui, repo, *dirs, **opts):
1033 # XXX large file status is buggy when used on repo proxy.
1033 # XXX large file status is buggy when used on repo proxy.
1034 # XXX this needs to be investigate.
1034 # XXX this needs to be investigate.
1035 repo = repo.unfiltered()
1035 repo = repo.unfiltered()
1036 oldstatus = repo.status
1036 oldstatus = repo.status
1037 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1037 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1038 clean=False, unknown=False, listsubrepos=False):
1038 clean=False, unknown=False, listsubrepos=False):
1039 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1039 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1040 listsubrepos)
1040 listsubrepos)
1041 lfdirstate = lfutil.openlfdirstate(ui, repo)
1041 lfdirstate = lfutil.openlfdirstate(ui, repo)
1042 modified, added, removed, deleted, unknown, ignored, clean = r
1042 modified, added, removed, deleted, unknown, ignored, clean = r
1043 unknown = [f for f in unknown if lfdirstate[f] == '?']
1043 unknown = [f for f in unknown if lfdirstate[f] == '?']
1044 ignored = [f for f in ignored if lfdirstate[f] == '?']
1044 ignored = [f for f in ignored if lfdirstate[f] == '?']
1045 return modified, added, removed, deleted, unknown, ignored, clean
1045 return modified, added, removed, deleted, unknown, ignored, clean
1046 repo.status = overridestatus
1046 repo.status = overridestatus
1047 orig(ui, repo, *dirs, **opts)
1047 orig(ui, repo, *dirs, **opts)
1048 repo.status = oldstatus
1048 repo.status = oldstatus
1049
1049
1050 def overriderollback(orig, ui, repo, **opts):
1050 def overriderollback(orig, ui, repo, **opts):
1051 result = orig(ui, repo, **opts)
1051 result = orig(ui, repo, **opts)
1052 merge.update(repo, node=None, branchmerge=False, force=True,
1052 merge.update(repo, node=None, branchmerge=False, force=True,
1053 partial=lfutil.isstandin)
1053 partial=lfutil.isstandin)
1054 wlock = repo.wlock()
1054 wlock = repo.wlock()
1055 try:
1055 try:
1056 lfdirstate = lfutil.openlfdirstate(ui, repo)
1056 lfdirstate = lfutil.openlfdirstate(ui, repo)
1057 lfiles = lfutil.listlfiles(repo)
1057 lfiles = lfutil.listlfiles(repo)
1058 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1058 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1059 for file in lfiles:
1059 for file in lfiles:
1060 if file in oldlfiles:
1060 if file in oldlfiles:
1061 lfdirstate.normallookup(file)
1061 lfdirstate.normallookup(file)
1062 else:
1062 else:
1063 lfdirstate.add(file)
1063 lfdirstate.add(file)
1064 lfdirstate.write()
1064 lfdirstate.write()
1065 finally:
1065 finally:
1066 wlock.release()
1066 wlock.release()
1067 return result
1067 return result
1068
1068
1069 def overridetransplant(orig, ui, repo, *revs, **opts):
1069 def overridetransplant(orig, ui, repo, *revs, **opts):
1070 try:
1070 try:
1071 oldstandins = lfutil.getstandinsstate(repo)
1071 oldstandins = lfutil.getstandinsstate(repo)
1072 repo._istransplanting = True
1072 repo._istransplanting = True
1073 result = orig(ui, repo, *revs, **opts)
1073 result = orig(ui, repo, *revs, **opts)
1074 newstandins = lfutil.getstandinsstate(repo)
1074 newstandins = lfutil.getstandinsstate(repo)
1075 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1075 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1076 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1076 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1077 printmessage=True)
1077 printmessage=True)
1078 finally:
1078 finally:
1079 repo._istransplanting = False
1079 repo._istransplanting = False
1080 return result
1080 return result
1081
1081
1082 def overridecat(orig, ui, repo, file1, *pats, **opts):
1082 def overridecat(orig, ui, repo, file1, *pats, **opts):
1083 ctx = scmutil.revsingle(repo, opts.get('rev'))
1083 ctx = scmutil.revsingle(repo, opts.get('rev'))
1084 err = 1
1084 err = 1
1085 notbad = set()
1085 notbad = set()
1086 m = scmutil.match(ctx, (file1,) + pats, opts)
1086 m = scmutil.match(ctx, (file1,) + pats, opts)
1087 origmatchfn = m.matchfn
1087 origmatchfn = m.matchfn
1088 def lfmatchfn(f):
1088 def lfmatchfn(f):
1089 if origmatchfn(f):
1089 if origmatchfn(f):
1090 return True
1090 return True
1091 lf = lfutil.splitstandin(f)
1091 lf = lfutil.splitstandin(f)
1092 if lf is None:
1092 if lf is None:
1093 return False
1093 return False
1094 notbad.add(lf)
1094 notbad.add(lf)
1095 return origmatchfn(lf)
1095 return origmatchfn(lf)
1096 m.matchfn = lfmatchfn
1096 m.matchfn = lfmatchfn
1097 origbadfn = m.bad
1097 origbadfn = m.bad
1098 def lfbadfn(f, msg):
1098 def lfbadfn(f, msg):
1099 if not f in notbad:
1099 if not f in notbad:
1100 origbadfn(f, msg)
1100 origbadfn(f, msg)
1101 m.bad = lfbadfn
1101 m.bad = lfbadfn
1102 for f in ctx.walk(m):
1102 for f in ctx.walk(m):
1103 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1103 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1104 pathname=f)
1104 pathname=f)
1105 lf = lfutil.splitstandin(f)
1105 lf = lfutil.splitstandin(f)
1106 if lf is None or origmatchfn(f):
1106 if lf is None or origmatchfn(f):
1107 # duplicating unreachable code from commands.cat
1107 # duplicating unreachable code from commands.cat
1108 data = ctx[f].data()
1108 data = ctx[f].data()
1109 if opts.get('decode'):
1109 if opts.get('decode'):
1110 data = repo.wwritedata(f, data)
1110 data = repo.wwritedata(f, data)
1111 fp.write(data)
1111 fp.write(data)
1112 else:
1112 else:
1113 hash = lfutil.readstandin(repo, lf, ctx.rev())
1113 hash = lfutil.readstandin(repo, lf, ctx.rev())
1114 if not lfutil.inusercache(repo.ui, hash):
1114 if not lfutil.inusercache(repo.ui, hash):
1115 store = basestore._openstore(repo)
1115 store = basestore._openstore(repo)
1116 success, missing = store.get([(lf, hash)])
1116 success, missing = store.get([(lf, hash)])
1117 if len(success) != 1:
1117 if len(success) != 1:
1118 raise util.Abort(
1118 raise util.Abort(
1119 _('largefile %s is not in cache and could not be '
1119 _('largefile %s is not in cache and could not be '
1120 'downloaded') % lf)
1120 'downloaded') % lf)
1121 path = lfutil.usercachepath(repo.ui, hash)
1121 path = lfutil.usercachepath(repo.ui, hash)
1122 fpin = open(path, "rb")
1122 fpin = open(path, "rb")
1123 for chunk in util.filechunkiter(fpin, 128 * 1024):
1123 for chunk in util.filechunkiter(fpin, 128 * 1024):
1124 fp.write(chunk)
1124 fp.write(chunk)
1125 fpin.close()
1125 fpin.close()
1126 fp.close()
1126 fp.close()
1127 err = 0
1127 err = 0
1128 return err
1128 return err
1129
1129
1130 def mercurialsinkbefore(orig, sink):
1130 def mercurialsinkbefore(orig, sink):
1131 sink.repo._isconverting = True
1131 sink.repo._isconverting = True
1132 orig(sink)
1132 orig(sink)
1133
1133
1134 def mercurialsinkafter(orig, sink):
1134 def mercurialsinkafter(orig, sink):
1135 sink.repo._isconverting = False
1135 sink.repo._isconverting = False
1136 orig(sink)
1136 orig(sink)
General Comments 0
You need to be logged in to leave comments. Login now