##// END OF EJS Templates
largefiles: remove confusing handling of .bad return value - it is void
Mads Kiilerich -
r21086:718f56c4 default
parent child Browse files
Show More
@@ -1,1164 +1,1164 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 '''overrides scmutil.match so that the matcher it returns will ignore all
27 '''overrides scmutil.match so that the matcher it returns will ignore all
28 largefiles'''
28 largefiles'''
29 oldmatch = None # for the closure
29 oldmatch = None # for the closure
30 def overridematch(ctx, pats=[], opts={}, globbed=False,
30 def overridematch(ctx, pats=[], opts={}, globbed=False,
31 default='relpath'):
31 default='relpath'):
32 match = oldmatch(ctx, pats, opts, globbed, default)
32 match = oldmatch(ctx, pats, opts, globbed, default)
33 m = copy.copy(match)
33 m = copy.copy(match)
34 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
34 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
35 manifest)
35 manifest)
36 m._files = filter(notlfile, m._files)
36 m._files = filter(notlfile, m._files)
37 m._fmap = set(m._files)
37 m._fmap = set(m._files)
38 m._always = False
38 m._always = False
39 origmatchfn = m.matchfn
39 origmatchfn = m.matchfn
40 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
40 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
41 return m
41 return m
42 oldmatch = installmatchfn(overridematch)
42 oldmatch = installmatchfn(overridematch)
43
43
44 def installmatchfn(f):
44 def installmatchfn(f):
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 installnormalfilesmatchfn
51 '''restores scmutil.match to what it was before installnormalfilesmatchfn
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 installnormalfilesmatchfn will require n calls to
54 Note that n calls to installnormalfilesmatchfn will require n calls to
55 restore matchfn to reverse'''
55 restore matchfn to reverse'''
56 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
56 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
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 lfcommands.debugdirstate(ui, repo)
289 lfcommands.debugdirstate(ui, repo)
290 else:
290 else:
291 orig(ui, repo, *pats, **opts)
291 orig(ui, repo, *pats, **opts)
292
292
293 # Override needs to refresh standins so that update's normal merge
293 # Override needs to refresh standins so that update's normal merge
294 # will go through properly. Then the other update hook (overriding repo.update)
294 # will go through properly. Then the other update hook (overriding repo.update)
295 # will get the new files. Filemerge is also overridden so that the merge
295 # will get the new files. Filemerge is also overridden so that the merge
296 # will merge standins correctly.
296 # will merge standins correctly.
297 def overrideupdate(orig, ui, repo, *pats, **opts):
297 def overrideupdate(orig, ui, repo, *pats, **opts):
298 lfdirstate = lfutil.openlfdirstate(ui, repo)
298 lfdirstate = lfutil.openlfdirstate(ui, repo)
299 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
299 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
300 False, False)
300 False, False)
301 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
301 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
302
302
303 # Need to lock between the standins getting updated and their
303 # Need to lock between the standins getting updated and their
304 # largefiles getting updated
304 # largefiles getting updated
305 wlock = repo.wlock()
305 wlock = repo.wlock()
306 try:
306 try:
307 if opts['check']:
307 if opts['check']:
308 mod = len(modified) > 0
308 mod = len(modified) > 0
309 for lfile in unsure:
309 for lfile in unsure:
310 standin = lfutil.standin(lfile)
310 standin = lfutil.standin(lfile)
311 if repo['.'][standin].data().strip() != \
311 if repo['.'][standin].data().strip() != \
312 lfutil.hashfile(repo.wjoin(lfile)):
312 lfutil.hashfile(repo.wjoin(lfile)):
313 mod = True
313 mod = True
314 else:
314 else:
315 lfdirstate.normal(lfile)
315 lfdirstate.normal(lfile)
316 lfdirstate.write()
316 lfdirstate.write()
317 if mod:
317 if mod:
318 raise util.Abort(_('uncommitted changes'))
318 raise util.Abort(_('uncommitted changes'))
319 # XXX handle removed differently
319 # XXX handle removed differently
320 if not opts['clean']:
320 if not opts['clean']:
321 for lfile in unsure + modified + added:
321 for lfile in unsure + modified + added:
322 lfutil.updatestandin(repo, lfutil.standin(lfile))
322 lfutil.updatestandin(repo, lfutil.standin(lfile))
323 finally:
323 finally:
324 wlock.release()
324 wlock.release()
325 return orig(ui, repo, *pats, **opts)
325 return orig(ui, repo, *pats, **opts)
326
326
327 # Before starting the manifest merge, merge.updates will call
327 # Before starting the manifest merge, merge.updates will call
328 # _checkunknown to check if there are any files in the merged-in
328 # _checkunknown to check if there are any files in the merged-in
329 # changeset that collide with unknown files in the working copy.
329 # changeset that collide with unknown files in the working copy.
330 #
330 #
331 # The largefiles are seen as unknown, so this prevents us from merging
331 # The largefiles are seen as unknown, so this prevents us from merging
332 # in a file 'foo' if we already have a largefile with the same name.
332 # in a file 'foo' if we already have a largefile with the same name.
333 #
333 #
334 # The overridden function filters the unknown files by removing any
334 # The overridden function filters the unknown files by removing any
335 # largefiles. This makes the merge proceed and we can then handle this
335 # largefiles. This makes the merge proceed and we can then handle this
336 # case further in the overridden manifestmerge function below.
336 # case further in the overridden manifestmerge function below.
337 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
337 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
338 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
338 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
339 return False
339 return False
340 return origfn(repo, wctx, mctx, f)
340 return origfn(repo, wctx, mctx, f)
341
341
342 # The manifest merge handles conflicts on the manifest level. We want
342 # The manifest merge handles conflicts on the manifest level. We want
343 # to handle changes in largefile-ness of files at this level too.
343 # to handle changes in largefile-ness of files at this level too.
344 #
344 #
345 # The strategy is to run the original manifestmerge and then process
345 # The strategy is to run the original manifestmerge and then process
346 # the action list it outputs. There are two cases we need to deal with:
346 # the action list it outputs. There are two cases we need to deal with:
347 #
347 #
348 # 1. Normal file in p1, largefile in p2. Here the largefile is
348 # 1. Normal file in p1, largefile in p2. Here the largefile is
349 # detected via its standin file, which will enter the working copy
349 # detected via its standin file, which will enter the working copy
350 # with a "get" action. It is not "merge" since the standin is all
350 # with a "get" action. It is not "merge" since the standin is all
351 # Mercurial is concerned with at this level -- the link to the
351 # Mercurial is concerned with at this level -- the link to the
352 # existing normal file is not relevant here.
352 # existing normal file is not relevant here.
353 #
353 #
354 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
354 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
355 # since the largefile will be present in the working copy and
355 # since the largefile will be present in the working copy and
356 # different from the normal file in p2. Mercurial therefore
356 # different from the normal file in p2. Mercurial therefore
357 # triggers a merge action.
357 # triggers a merge action.
358 #
358 #
359 # In both cases, we prompt the user and emit new actions to either
359 # In both cases, we prompt the user and emit new actions to either
360 # remove the standin (if the normal file was kept) or to remove the
360 # remove the standin (if the normal file was kept) or to remove the
361 # normal file and get the standin (if the largefile was kept). The
361 # normal file and get the standin (if the largefile was kept). The
362 # default prompt answer is to use the largefile version since it was
362 # default prompt answer is to use the largefile version since it was
363 # presumably changed on purpose.
363 # presumably changed on purpose.
364 #
364 #
365 # Finally, the merge.applyupdates function will then take care of
365 # Finally, the merge.applyupdates function will then take care of
366 # writing the files into the working copy and lfcommands.updatelfiles
366 # writing the files into the working copy and lfcommands.updatelfiles
367 # will update the largefiles.
367 # will update the largefiles.
368 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
368 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
369 partial, acceptremote, followcopies):
369 partial, acceptremote, followcopies):
370 overwrite = force and not branchmerge
370 overwrite = force and not branchmerge
371 actions = origfn(repo, p1, p2, pas, branchmerge, force, partial,
371 actions = origfn(repo, p1, p2, pas, branchmerge, force, partial,
372 acceptremote, followcopies)
372 acceptremote, followcopies)
373
373
374 if overwrite:
374 if overwrite:
375 return actions
375 return actions
376
376
377 removes = set(a[0] for a in actions if a[1] == 'r')
377 removes = set(a[0] for a in actions if a[1] == 'r')
378 processed = []
378 processed = []
379
379
380 for action in actions:
380 for action in actions:
381 f, m, args, msg = action
381 f, m, args, msg = action
382
382
383 splitstandin = f and lfutil.splitstandin(f)
383 splitstandin = f and lfutil.splitstandin(f)
384 if (m == "g" and splitstandin is not None and
384 if (m == "g" and splitstandin is not None and
385 splitstandin in p1 and splitstandin not in removes):
385 splitstandin in p1 and splitstandin not in removes):
386 # Case 1: normal file in the working copy, largefile in
386 # Case 1: normal file in the working copy, largefile in
387 # the second parent
387 # the second parent
388 lfile = splitstandin
388 lfile = splitstandin
389 standin = f
389 standin = f
390 msg = _('remote turned local normal file %s into a largefile\n'
390 msg = _('remote turned local normal file %s into a largefile\n'
391 'use (l)argefile or keep (n)ormal file?'
391 'use (l)argefile or keep (n)ormal file?'
392 '$$ &Largefile $$ &Normal file') % lfile
392 '$$ &Largefile $$ &Normal file') % lfile
393 if repo.ui.promptchoice(msg, 0) == 0:
393 if repo.ui.promptchoice(msg, 0) == 0:
394 processed.append((lfile, "r", None, msg))
394 processed.append((lfile, "r", None, msg))
395 processed.append((standin, "g", (p2.flags(standin),), msg))
395 processed.append((standin, "g", (p2.flags(standin),), msg))
396 else:
396 else:
397 processed.append((standin, "r", None, msg))
397 processed.append((standin, "r", None, msg))
398 elif (m == "g" and
398 elif (m == "g" and
399 lfutil.standin(f) in p1 and lfutil.standin(f) not in removes):
399 lfutil.standin(f) in p1 and lfutil.standin(f) not in removes):
400 # Case 2: largefile in the working copy, normal file in
400 # Case 2: largefile in the working copy, normal file in
401 # the second parent
401 # the second parent
402 standin = lfutil.standin(f)
402 standin = lfutil.standin(f)
403 lfile = f
403 lfile = f
404 msg = _('remote turned local largefile %s into a normal file\n'
404 msg = _('remote turned local largefile %s into a normal file\n'
405 'keep (l)argefile or use (n)ormal file?'
405 'keep (l)argefile or use (n)ormal file?'
406 '$$ &Largefile $$ &Normal file') % lfile
406 '$$ &Largefile $$ &Normal file') % lfile
407 if repo.ui.promptchoice(msg, 0) == 0:
407 if repo.ui.promptchoice(msg, 0) == 0:
408 processed.append((lfile, "r", None, msg))
408 processed.append((lfile, "r", None, msg))
409 else:
409 else:
410 processed.append((standin, "r", None, msg))
410 processed.append((standin, "r", None, msg))
411 processed.append((lfile, "g", (p2.flags(lfile),), msg))
411 processed.append((lfile, "g", (p2.flags(lfile),), msg))
412 else:
412 else:
413 processed.append(action)
413 processed.append(action)
414
414
415 return processed
415 return processed
416
416
417 # Override filemerge to prompt the user about how they wish to merge
417 # Override filemerge to prompt the user about how they wish to merge
418 # largefiles. This will handle identical edits without prompting the user.
418 # largefiles. This will handle identical edits without prompting the user.
419 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
419 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
420 if not lfutil.isstandin(orig):
420 if not lfutil.isstandin(orig):
421 return origfn(repo, mynode, orig, fcd, fco, fca)
421 return origfn(repo, mynode, orig, fcd, fco, fca)
422
422
423 ahash = fca.data().strip().lower()
423 ahash = fca.data().strip().lower()
424 dhash = fcd.data().strip().lower()
424 dhash = fcd.data().strip().lower()
425 ohash = fco.data().strip().lower()
425 ohash = fco.data().strip().lower()
426 if (ohash != ahash and
426 if (ohash != ahash and
427 ohash != dhash and
427 ohash != dhash and
428 (dhash == ahash or
428 (dhash == ahash or
429 repo.ui.promptchoice(
429 repo.ui.promptchoice(
430 _('largefile %s has a merge conflict\nancestor was %s\n'
430 _('largefile %s has a merge conflict\nancestor was %s\n'
431 'keep (l)ocal %s or\ntake (o)ther %s?'
431 'keep (l)ocal %s or\ntake (o)ther %s?'
432 '$$ &Local $$ &Other') %
432 '$$ &Local $$ &Other') %
433 (lfutil.splitstandin(orig), ahash, dhash, ohash),
433 (lfutil.splitstandin(orig), ahash, dhash, ohash),
434 0) == 1)):
434 0) == 1)):
435 repo.wwrite(fcd.path(), fco.data(), fco.flags())
435 repo.wwrite(fcd.path(), fco.data(), fco.flags())
436 return 0
436 return 0
437
437
438 # Copy first changes the matchers to match standins instead of
438 # Copy first changes the matchers to match standins instead of
439 # largefiles. Then it overrides util.copyfile in that function it
439 # largefiles. Then it overrides util.copyfile in that function it
440 # checks if the destination largefile already exists. It also keeps a
440 # checks if the destination largefile already exists. It also keeps a
441 # list of copied files so that the largefiles can be copied and the
441 # list of copied files so that the largefiles can be copied and the
442 # dirstate updated.
442 # dirstate updated.
443 def overridecopy(orig, ui, repo, pats, opts, rename=False):
443 def overridecopy(orig, ui, repo, pats, opts, rename=False):
444 # doesn't remove largefile on rename
444 # doesn't remove largefile on rename
445 if len(pats) < 2:
445 if len(pats) < 2:
446 # this isn't legal, let the original function deal with it
446 # this isn't legal, let the original function deal with it
447 return orig(ui, repo, pats, opts, rename)
447 return orig(ui, repo, pats, opts, rename)
448
448
449 def makestandin(relpath):
449 def makestandin(relpath):
450 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
450 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
451 return os.path.join(repo.wjoin(lfutil.standin(path)))
451 return os.path.join(repo.wjoin(lfutil.standin(path)))
452
452
453 fullpats = scmutil.expandpats(pats)
453 fullpats = scmutil.expandpats(pats)
454 dest = fullpats[-1]
454 dest = fullpats[-1]
455
455
456 if os.path.isdir(dest):
456 if os.path.isdir(dest):
457 if not os.path.isdir(makestandin(dest)):
457 if not os.path.isdir(makestandin(dest)):
458 os.makedirs(makestandin(dest))
458 os.makedirs(makestandin(dest))
459 # This could copy both lfiles and normal files in one command,
459 # This could copy both lfiles and normal files in one command,
460 # but we don't want to do that. First replace their matcher to
460 # but we don't want to do that. First replace their matcher to
461 # only match normal files and run it, then replace it to just
461 # only match normal files and run it, then replace it to just
462 # match largefiles and run it again.
462 # match largefiles and run it again.
463 nonormalfiles = False
463 nonormalfiles = False
464 nolfiles = False
464 nolfiles = False
465 try:
465 try:
466 try:
466 try:
467 installnormalfilesmatchfn(repo[None].manifest())
467 installnormalfilesmatchfn(repo[None].manifest())
468 result = orig(ui, repo, pats, opts, rename)
468 result = orig(ui, repo, pats, opts, rename)
469 except util.Abort, e:
469 except util.Abort, e:
470 if str(e) != _('no files to copy'):
470 if str(e) != _('no files to copy'):
471 raise e
471 raise e
472 else:
472 else:
473 nonormalfiles = True
473 nonormalfiles = True
474 result = 0
474 result = 0
475 finally:
475 finally:
476 restorematchfn()
476 restorematchfn()
477
477
478 # The first rename can cause our current working directory to be removed.
478 # The first rename can cause our current working directory to be removed.
479 # In that case there is nothing left to copy/rename so just quit.
479 # In that case there is nothing left to copy/rename so just quit.
480 try:
480 try:
481 repo.getcwd()
481 repo.getcwd()
482 except OSError:
482 except OSError:
483 return result
483 return result
484
484
485 try:
485 try:
486 try:
486 try:
487 # When we call orig below it creates the standins but we don't add
487 # When we call orig below it creates the standins but we don't add
488 # them to the dir state until later so lock during that time.
488 # them to the dir state until later so lock during that time.
489 wlock = repo.wlock()
489 wlock = repo.wlock()
490
490
491 manifest = repo[None].manifest()
491 manifest = repo[None].manifest()
492 oldmatch = None # for the closure
492 oldmatch = None # for the closure
493 def overridematch(ctx, pats=[], opts={}, globbed=False,
493 def overridematch(ctx, pats=[], opts={}, globbed=False,
494 default='relpath'):
494 default='relpath'):
495 newpats = []
495 newpats = []
496 # The patterns were previously mangled to add the standin
496 # The patterns were previously mangled to add the standin
497 # directory; we need to remove that now
497 # directory; we need to remove that now
498 for pat in pats:
498 for pat in pats:
499 if match_.patkind(pat) is None and lfutil.shortname in pat:
499 if match_.patkind(pat) is None and lfutil.shortname in pat:
500 newpats.append(pat.replace(lfutil.shortname, ''))
500 newpats.append(pat.replace(lfutil.shortname, ''))
501 else:
501 else:
502 newpats.append(pat)
502 newpats.append(pat)
503 match = oldmatch(ctx, newpats, opts, globbed, default)
503 match = oldmatch(ctx, newpats, opts, globbed, default)
504 m = copy.copy(match)
504 m = copy.copy(match)
505 lfile = lambda f: lfutil.standin(f) in manifest
505 lfile = lambda f: lfutil.standin(f) in manifest
506 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
506 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
507 m._fmap = set(m._files)
507 m._fmap = set(m._files)
508 m._always = False
508 m._always = False
509 origmatchfn = m.matchfn
509 origmatchfn = m.matchfn
510 m.matchfn = lambda f: (lfutil.isstandin(f) and
510 m.matchfn = lambda f: (lfutil.isstandin(f) and
511 (f in manifest) and
511 (f in manifest) and
512 origmatchfn(lfutil.splitstandin(f)) or
512 origmatchfn(lfutil.splitstandin(f)) or
513 None)
513 None)
514 return m
514 return m
515 oldmatch = installmatchfn(overridematch)
515 oldmatch = installmatchfn(overridematch)
516 listpats = []
516 listpats = []
517 for pat in pats:
517 for pat in pats:
518 if match_.patkind(pat) is not None:
518 if match_.patkind(pat) is not None:
519 listpats.append(pat)
519 listpats.append(pat)
520 else:
520 else:
521 listpats.append(makestandin(pat))
521 listpats.append(makestandin(pat))
522
522
523 try:
523 try:
524 origcopyfile = util.copyfile
524 origcopyfile = util.copyfile
525 copiedfiles = []
525 copiedfiles = []
526 def overridecopyfile(src, dest):
526 def overridecopyfile(src, dest):
527 if (lfutil.shortname in src and
527 if (lfutil.shortname in src and
528 dest.startswith(repo.wjoin(lfutil.shortname))):
528 dest.startswith(repo.wjoin(lfutil.shortname))):
529 destlfile = dest.replace(lfutil.shortname, '')
529 destlfile = dest.replace(lfutil.shortname, '')
530 if not opts['force'] and os.path.exists(destlfile):
530 if not opts['force'] and os.path.exists(destlfile):
531 raise IOError('',
531 raise IOError('',
532 _('destination largefile already exists'))
532 _('destination largefile already exists'))
533 copiedfiles.append((src, dest))
533 copiedfiles.append((src, dest))
534 origcopyfile(src, dest)
534 origcopyfile(src, dest)
535
535
536 util.copyfile = overridecopyfile
536 util.copyfile = overridecopyfile
537 result += orig(ui, repo, listpats, opts, rename)
537 result += orig(ui, repo, listpats, opts, rename)
538 finally:
538 finally:
539 util.copyfile = origcopyfile
539 util.copyfile = origcopyfile
540
540
541 lfdirstate = lfutil.openlfdirstate(ui, repo)
541 lfdirstate = lfutil.openlfdirstate(ui, repo)
542 for (src, dest) in copiedfiles:
542 for (src, dest) in copiedfiles:
543 if (lfutil.shortname in src and
543 if (lfutil.shortname in src and
544 dest.startswith(repo.wjoin(lfutil.shortname))):
544 dest.startswith(repo.wjoin(lfutil.shortname))):
545 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
545 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
546 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
546 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
547 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
547 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
548 if not os.path.isdir(destlfiledir):
548 if not os.path.isdir(destlfiledir):
549 os.makedirs(destlfiledir)
549 os.makedirs(destlfiledir)
550 if rename:
550 if rename:
551 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
551 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
552 lfdirstate.remove(srclfile)
552 lfdirstate.remove(srclfile)
553 else:
553 else:
554 util.copyfile(repo.wjoin(srclfile),
554 util.copyfile(repo.wjoin(srclfile),
555 repo.wjoin(destlfile))
555 repo.wjoin(destlfile))
556
556
557 lfdirstate.add(destlfile)
557 lfdirstate.add(destlfile)
558 lfdirstate.write()
558 lfdirstate.write()
559 except util.Abort, e:
559 except util.Abort, e:
560 if str(e) != _('no files to copy'):
560 if str(e) != _('no files to copy'):
561 raise e
561 raise e
562 else:
562 else:
563 nolfiles = True
563 nolfiles = True
564 finally:
564 finally:
565 restorematchfn()
565 restorematchfn()
566 wlock.release()
566 wlock.release()
567
567
568 if nolfiles and nonormalfiles:
568 if nolfiles and nonormalfiles:
569 raise util.Abort(_('no files to copy'))
569 raise util.Abort(_('no files to copy'))
570
570
571 return result
571 return result
572
572
573 # When the user calls revert, we have to be careful to not revert any
573 # When the user calls revert, we have to be careful to not revert any
574 # changes to other largefiles accidentally. This means we have to keep
574 # changes to other largefiles accidentally. This means we have to keep
575 # track of the largefiles that are being reverted so we only pull down
575 # track of the largefiles that are being reverted so we only pull down
576 # the necessary largefiles.
576 # the necessary largefiles.
577 #
577 #
578 # Standins are only updated (to match the hash of largefiles) before
578 # Standins are only updated (to match the hash of largefiles) before
579 # commits. Update the standins then run the original revert, changing
579 # commits. Update the standins then run the original revert, changing
580 # the matcher to hit standins instead of largefiles. Based on the
580 # the matcher to hit standins instead of largefiles. Based on the
581 # resulting standins update the largefiles. Then return the standins
581 # resulting standins update the largefiles. Then return the standins
582 # to their proper state
582 # to their proper state
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 try:
599 try:
600 ctx = scmutil.revsingle(repo, opts.get('rev'))
600 ctx = scmutil.revsingle(repo, opts.get('rev'))
601 oldmatch = None # for the closure
601 oldmatch = None # for the closure
602 def overridematch(ctx, pats=[], opts={}, globbed=False,
602 def overridematch(ctx, pats=[], opts={}, globbed=False,
603 default='relpath'):
603 default='relpath'):
604 match = oldmatch(ctx, pats, opts, globbed, default)
604 match = oldmatch(ctx, pats, opts, globbed, default)
605 m = copy.copy(match)
605 m = copy.copy(match)
606 def tostandin(f):
606 def tostandin(f):
607 if lfutil.standin(f) in ctx:
607 if lfutil.standin(f) in ctx:
608 return lfutil.standin(f)
608 return lfutil.standin(f)
609 elif lfutil.standin(f) in repo[None]:
609 elif lfutil.standin(f) in repo[None]:
610 return None
610 return None
611 return f
611 return f
612 m._files = [tostandin(f) for f in m._files]
612 m._files = [tostandin(f) for f in m._files]
613 m._files = [f for f in m._files if f is not None]
613 m._files = [f for f in m._files if f is not None]
614 m._fmap = set(m._files)
614 m._fmap = set(m._files)
615 m._always = False
615 m._always = False
616 origmatchfn = m.matchfn
616 origmatchfn = m.matchfn
617 def matchfn(f):
617 def matchfn(f):
618 if lfutil.isstandin(f):
618 if lfutil.isstandin(f):
619 # We need to keep track of what largefiles are being
619 # We need to keep track of what largefiles are being
620 # matched so we know which ones to update later --
620 # matched so we know which ones to update later --
621 # otherwise we accidentally revert changes to other
621 # otherwise we accidentally revert changes to other
622 # largefiles. This is repo-specific, so duckpunch the
622 # largefiles. This is repo-specific, so duckpunch the
623 # repo object to keep the list of largefiles for us
623 # repo object to keep the list of largefiles for us
624 # later.
624 # later.
625 if origmatchfn(lfutil.splitstandin(f)) and \
625 if origmatchfn(lfutil.splitstandin(f)) and \
626 (f in repo[None] or f in ctx):
626 (f in repo[None] or f in ctx):
627 lfileslist = getattr(repo, '_lfilestoupdate', [])
627 lfileslist = getattr(repo, '_lfilestoupdate', [])
628 lfileslist.append(lfutil.splitstandin(f))
628 lfileslist.append(lfutil.splitstandin(f))
629 repo._lfilestoupdate = lfileslist
629 repo._lfilestoupdate = lfileslist
630 return True
630 return True
631 else:
631 else:
632 return False
632 return False
633 return origmatchfn(f)
633 return origmatchfn(f)
634 m.matchfn = matchfn
634 m.matchfn = matchfn
635 return m
635 return m
636 oldmatch = installmatchfn(overridematch)
636 oldmatch = installmatchfn(overridematch)
637 scmutil.match
637 scmutil.match
638 matches = overridematch(repo[None], pats, opts)
638 matches = overridematch(repo[None], pats, opts)
639 orig(ui, repo, *pats, **opts)
639 orig(ui, repo, *pats, **opts)
640 finally:
640 finally:
641 restorematchfn()
641 restorematchfn()
642 lfileslist = getattr(repo, '_lfilestoupdate', [])
642 lfileslist = getattr(repo, '_lfilestoupdate', [])
643 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
643 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
644 printmessage=False)
644 printmessage=False)
645
645
646 # empty out the largefiles list so we start fresh next time
646 # empty out the largefiles list so we start fresh next time
647 repo._lfilestoupdate = []
647 repo._lfilestoupdate = []
648 for lfile in modified:
648 for lfile in modified:
649 if lfile in lfileslist:
649 if lfile in lfileslist:
650 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
650 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
651 in repo['.']:
651 in repo['.']:
652 lfutil.writestandin(repo, lfutil.standin(lfile),
652 lfutil.writestandin(repo, lfutil.standin(lfile),
653 repo['.'][lfile].data().strip(),
653 repo['.'][lfile].data().strip(),
654 'x' in repo['.'][lfile].flags())
654 'x' in repo['.'][lfile].flags())
655 lfdirstate = lfutil.openlfdirstate(ui, repo)
655 lfdirstate = lfutil.openlfdirstate(ui, repo)
656 for lfile in added:
656 for lfile in added:
657 standin = lfutil.standin(lfile)
657 standin = lfutil.standin(lfile)
658 if standin not in ctx and (standin in matches or opts.get('all')):
658 if standin not in ctx and (standin in matches or opts.get('all')):
659 if lfile in lfdirstate:
659 if lfile in lfdirstate:
660 lfdirstate.drop(lfile)
660 lfdirstate.drop(lfile)
661 util.unlinkpath(repo.wjoin(standin))
661 util.unlinkpath(repo.wjoin(standin))
662 lfdirstate.write()
662 lfdirstate.write()
663 finally:
663 finally:
664 wlock.release()
664 wlock.release()
665
665
666 def hgupdaterepo(orig, repo, node, overwrite):
666 def hgupdaterepo(orig, repo, node, overwrite):
667 if not overwrite:
667 if not overwrite:
668 # Only call updatelfiles on the standins that have changed to save time
668 # Only call updatelfiles on the standins that have changed to save time
669 oldstandins = lfutil.getstandinsstate(repo)
669 oldstandins = lfutil.getstandinsstate(repo)
670
670
671 result = orig(repo, node, overwrite)
671 result = orig(repo, node, overwrite)
672
672
673 filelist = None
673 filelist = None
674 if not overwrite:
674 if not overwrite:
675 newstandins = lfutil.getstandinsstate(repo)
675 newstandins = lfutil.getstandinsstate(repo)
676 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
676 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
677 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
677 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
678 return result
678 return result
679
679
680 def hgmerge(orig, repo, node, force=None, remind=True):
680 def hgmerge(orig, repo, node, force=None, remind=True):
681 result = orig(repo, node, force, remind)
681 result = orig(repo, node, force, remind)
682 lfcommands.updatelfiles(repo.ui, repo)
682 lfcommands.updatelfiles(repo.ui, repo)
683 return result
683 return result
684
684
685 # When we rebase a repository with remotely changed largefiles, we need to
685 # When we rebase a repository with remotely changed largefiles, we need to
686 # take some extra care so that the largefiles are correctly updated in the
686 # take some extra care so that the largefiles are correctly updated in the
687 # working copy
687 # working copy
688 def overridepull(orig, ui, repo, source=None, **opts):
688 def overridepull(orig, ui, repo, source=None, **opts):
689 revsprepull = len(repo)
689 revsprepull = len(repo)
690 if not source:
690 if not source:
691 source = 'default'
691 source = 'default'
692 repo.lfpullsource = source
692 repo.lfpullsource = source
693 if opts.get('rebase', False):
693 if opts.get('rebase', False):
694 repo._isrebasing = True
694 repo._isrebasing = True
695 try:
695 try:
696 if opts.get('update'):
696 if opts.get('update'):
697 del opts['update']
697 del opts['update']
698 ui.debug('--update and --rebase are not compatible, ignoring '
698 ui.debug('--update and --rebase are not compatible, ignoring '
699 'the update flag\n')
699 'the update flag\n')
700 del opts['rebase']
700 del opts['rebase']
701 origpostincoming = commands.postincoming
701 origpostincoming = commands.postincoming
702 def _dummy(*args, **kwargs):
702 def _dummy(*args, **kwargs):
703 pass
703 pass
704 commands.postincoming = _dummy
704 commands.postincoming = _dummy
705 try:
705 try:
706 result = commands.pull(ui, repo, source, **opts)
706 result = commands.pull(ui, repo, source, **opts)
707 finally:
707 finally:
708 commands.postincoming = origpostincoming
708 commands.postincoming = origpostincoming
709 revspostpull = len(repo)
709 revspostpull = len(repo)
710 if revspostpull > revsprepull:
710 if revspostpull > revsprepull:
711 result = result or rebase.rebase(ui, repo)
711 result = result or rebase.rebase(ui, repo)
712 finally:
712 finally:
713 repo._isrebasing = False
713 repo._isrebasing = False
714 else:
714 else:
715 result = orig(ui, repo, source, **opts)
715 result = orig(ui, repo, source, **opts)
716 revspostpull = len(repo)
716 revspostpull = len(repo)
717 lfrevs = opts.get('lfrev', [])
717 lfrevs = opts.get('lfrev', [])
718 if opts.get('all_largefiles'):
718 if opts.get('all_largefiles'):
719 lfrevs.append('pulled()')
719 lfrevs.append('pulled()')
720 if lfrevs and revspostpull > revsprepull:
720 if lfrevs and revspostpull > revsprepull:
721 numcached = 0
721 numcached = 0
722 repo.firstpulled = revsprepull # for pulled() revset expression
722 repo.firstpulled = revsprepull # for pulled() revset expression
723 try:
723 try:
724 for rev in scmutil.revrange(repo, lfrevs):
724 for rev in scmutil.revrange(repo, lfrevs):
725 ui.note(_('pulling largefiles for revision %s\n') % rev)
725 ui.note(_('pulling largefiles for revision %s\n') % rev)
726 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
726 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
727 numcached += len(cached)
727 numcached += len(cached)
728 finally:
728 finally:
729 del repo.firstpulled
729 del repo.firstpulled
730 ui.status(_("%d largefiles cached\n") % numcached)
730 ui.status(_("%d largefiles cached\n") % numcached)
731 return result
731 return result
732
732
733 def pulledrevsetsymbol(repo, subset, x):
733 def pulledrevsetsymbol(repo, subset, x):
734 """``pulled()``
734 """``pulled()``
735 Changesets that just has been pulled.
735 Changesets that just has been pulled.
736
736
737 Only available with largefiles from pull --lfrev expressions.
737 Only available with largefiles from pull --lfrev expressions.
738
738
739 .. container:: verbose
739 .. container:: verbose
740
740
741 Some examples:
741 Some examples:
742
742
743 - pull largefiles for all new changesets::
743 - pull largefiles for all new changesets::
744
744
745 hg pull -lfrev "pulled()"
745 hg pull -lfrev "pulled()"
746
746
747 - pull largefiles for all new branch heads::
747 - pull largefiles for all new branch heads::
748
748
749 hg pull -lfrev "head(pulled()) and not closed()"
749 hg pull -lfrev "head(pulled()) and not closed()"
750
750
751 """
751 """
752
752
753 try:
753 try:
754 firstpulled = repo.firstpulled
754 firstpulled = repo.firstpulled
755 except AttributeError:
755 except AttributeError:
756 raise util.Abort(_("pulled() only available in --lfrev"))
756 raise util.Abort(_("pulled() only available in --lfrev"))
757 return revset.baseset([r for r in subset if r >= firstpulled])
757 return revset.baseset([r for r in subset if r >= firstpulled])
758
758
759 def overrideclone(orig, ui, source, dest=None, **opts):
759 def overrideclone(orig, ui, source, dest=None, **opts):
760 d = dest
760 d = dest
761 if d is None:
761 if d is None:
762 d = hg.defaultdest(source)
762 d = hg.defaultdest(source)
763 if opts.get('all_largefiles') and not hg.islocal(d):
763 if opts.get('all_largefiles') and not hg.islocal(d):
764 raise util.Abort(_(
764 raise util.Abort(_(
765 '--all-largefiles is incompatible with non-local destination %s' %
765 '--all-largefiles is incompatible with non-local destination %s' %
766 d))
766 d))
767
767
768 return orig(ui, source, dest, **opts)
768 return orig(ui, source, dest, **opts)
769
769
770 def hgclone(orig, ui, opts, *args, **kwargs):
770 def hgclone(orig, ui, opts, *args, **kwargs):
771 result = orig(ui, opts, *args, **kwargs)
771 result = orig(ui, opts, *args, **kwargs)
772
772
773 if result is not None:
773 if result is not None:
774 sourcerepo, destrepo = result
774 sourcerepo, destrepo = result
775 repo = destrepo.local()
775 repo = destrepo.local()
776
776
777 # Caching is implicitly limited to 'rev' option, since the dest repo was
777 # Caching is implicitly limited to 'rev' option, since the dest repo was
778 # truncated at that point. The user may expect a download count with
778 # truncated at that point. The user may expect a download count with
779 # this option, so attempt whether or not this is a largefile repo.
779 # this option, so attempt whether or not this is a largefile repo.
780 if opts.get('all_largefiles'):
780 if opts.get('all_largefiles'):
781 success, missing = lfcommands.downloadlfiles(ui, repo, None)
781 success, missing = lfcommands.downloadlfiles(ui, repo, None)
782
782
783 if missing != 0:
783 if missing != 0:
784 return None
784 return None
785
785
786 return result
786 return result
787
787
788 def overriderebase(orig, ui, repo, **opts):
788 def overriderebase(orig, ui, repo, **opts):
789 repo._isrebasing = True
789 repo._isrebasing = True
790 try:
790 try:
791 return orig(ui, repo, **opts)
791 return orig(ui, repo, **opts)
792 finally:
792 finally:
793 repo._isrebasing = False
793 repo._isrebasing = False
794
794
795 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
795 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
796 prefix=None, mtime=None, subrepos=None):
796 prefix=None, mtime=None, subrepos=None):
797 # No need to lock because we are only reading history and
797 # No need to lock because we are only reading history and
798 # largefile caches, neither of which are modified.
798 # largefile caches, neither of which are modified.
799 lfcommands.cachelfiles(repo.ui, repo, node)
799 lfcommands.cachelfiles(repo.ui, repo, node)
800
800
801 if kind not in archival.archivers:
801 if kind not in archival.archivers:
802 raise util.Abort(_("unknown archive type '%s'") % kind)
802 raise util.Abort(_("unknown archive type '%s'") % kind)
803
803
804 ctx = repo[node]
804 ctx = repo[node]
805
805
806 if kind == 'files':
806 if kind == 'files':
807 if prefix:
807 if prefix:
808 raise util.Abort(
808 raise util.Abort(
809 _('cannot give prefix when archiving to files'))
809 _('cannot give prefix when archiving to files'))
810 else:
810 else:
811 prefix = archival.tidyprefix(dest, kind, prefix)
811 prefix = archival.tidyprefix(dest, kind, prefix)
812
812
813 def write(name, mode, islink, getdata):
813 def write(name, mode, islink, getdata):
814 if matchfn and not matchfn(name):
814 if matchfn and not matchfn(name):
815 return
815 return
816 data = getdata()
816 data = getdata()
817 if decode:
817 if decode:
818 data = repo.wwritedata(name, data)
818 data = repo.wwritedata(name, data)
819 archiver.addfile(prefix + name, mode, islink, data)
819 archiver.addfile(prefix + name, mode, islink, data)
820
820
821 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
821 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
822
822
823 if repo.ui.configbool("ui", "archivemeta", True):
823 if repo.ui.configbool("ui", "archivemeta", True):
824 def metadata():
824 def metadata():
825 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
825 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
826 hex(repo.changelog.node(0)), hex(node), ctx.branch())
826 hex(repo.changelog.node(0)), hex(node), ctx.branch())
827
827
828 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
828 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
829 if repo.tagtype(t) == 'global')
829 if repo.tagtype(t) == 'global')
830 if not tags:
830 if not tags:
831 repo.ui.pushbuffer()
831 repo.ui.pushbuffer()
832 opts = {'template': '{latesttag}\n{latesttagdistance}',
832 opts = {'template': '{latesttag}\n{latesttagdistance}',
833 'style': '', 'patch': None, 'git': None}
833 'style': '', 'patch': None, 'git': None}
834 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
834 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
835 ltags, dist = repo.ui.popbuffer().split('\n')
835 ltags, dist = repo.ui.popbuffer().split('\n')
836 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
836 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
837 tags += 'latesttagdistance: %s\n' % dist
837 tags += 'latesttagdistance: %s\n' % dist
838
838
839 return base + tags
839 return base + tags
840
840
841 write('.hg_archival.txt', 0644, False, metadata)
841 write('.hg_archival.txt', 0644, False, metadata)
842
842
843 for f in ctx:
843 for f in ctx:
844 ff = ctx.flags(f)
844 ff = ctx.flags(f)
845 getdata = ctx[f].data
845 getdata = ctx[f].data
846 if lfutil.isstandin(f):
846 if lfutil.isstandin(f):
847 path = lfutil.findfile(repo, getdata().strip())
847 path = lfutil.findfile(repo, getdata().strip())
848 if path is None:
848 if path is None:
849 raise util.Abort(
849 raise util.Abort(
850 _('largefile %s not found in repo store or system cache')
850 _('largefile %s not found in repo store or system cache')
851 % lfutil.splitstandin(f))
851 % lfutil.splitstandin(f))
852 f = lfutil.splitstandin(f)
852 f = lfutil.splitstandin(f)
853
853
854 def getdatafn():
854 def getdatafn():
855 fd = None
855 fd = None
856 try:
856 try:
857 fd = open(path, 'rb')
857 fd = open(path, 'rb')
858 return fd.read()
858 return fd.read()
859 finally:
859 finally:
860 if fd:
860 if fd:
861 fd.close()
861 fd.close()
862
862
863 getdata = getdatafn
863 getdata = getdatafn
864 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
864 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
865
865
866 if subrepos:
866 if subrepos:
867 for subpath in sorted(ctx.substate):
867 for subpath in sorted(ctx.substate):
868 sub = ctx.sub(subpath)
868 sub = ctx.sub(subpath)
869 submatch = match_.narrowmatcher(subpath, matchfn)
869 submatch = match_.narrowmatcher(subpath, matchfn)
870 sub.archive(repo.ui, archiver, prefix, submatch)
870 sub.archive(repo.ui, archiver, prefix, submatch)
871
871
872 archiver.done()
872 archiver.done()
873
873
874 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
874 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
875 repo._get(repo._state + ('hg',))
875 repo._get(repo._state + ('hg',))
876 rev = repo._state[1]
876 rev = repo._state[1]
877 ctx = repo._repo[rev]
877 ctx = repo._repo[rev]
878
878
879 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
879 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
880
880
881 def write(name, mode, islink, getdata):
881 def write(name, mode, islink, getdata):
882 # At this point, the standin has been replaced with the largefile name,
882 # At this point, the standin has been replaced with the largefile name,
883 # so the normal matcher works here without the lfutil variants.
883 # so the normal matcher works here without the lfutil variants.
884 if match and not match(f):
884 if match and not match(f):
885 return
885 return
886 data = getdata()
886 data = getdata()
887
887
888 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
888 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
889
889
890 for f in ctx:
890 for f in ctx:
891 ff = ctx.flags(f)
891 ff = ctx.flags(f)
892 getdata = ctx[f].data
892 getdata = ctx[f].data
893 if lfutil.isstandin(f):
893 if lfutil.isstandin(f):
894 path = lfutil.findfile(repo._repo, getdata().strip())
894 path = lfutil.findfile(repo._repo, getdata().strip())
895 if path is None:
895 if path is None:
896 raise util.Abort(
896 raise util.Abort(
897 _('largefile %s not found in repo store or system cache')
897 _('largefile %s not found in repo store or system cache')
898 % lfutil.splitstandin(f))
898 % lfutil.splitstandin(f))
899 f = lfutil.splitstandin(f)
899 f = lfutil.splitstandin(f)
900
900
901 def getdatafn():
901 def getdatafn():
902 fd = None
902 fd = None
903 try:
903 try:
904 fd = open(os.path.join(prefix, path), 'rb')
904 fd = open(os.path.join(prefix, path), 'rb')
905 return fd.read()
905 return fd.read()
906 finally:
906 finally:
907 if fd:
907 if fd:
908 fd.close()
908 fd.close()
909
909
910 getdata = getdatafn
910 getdata = getdatafn
911
911
912 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
912 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
913
913
914 for subpath in sorted(ctx.substate):
914 for subpath in sorted(ctx.substate):
915 sub = ctx.sub(subpath)
915 sub = ctx.sub(subpath)
916 submatch = match_.narrowmatcher(subpath, match)
916 submatch = match_.narrowmatcher(subpath, match)
917 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
917 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
918 submatch)
918 submatch)
919
919
920 # If a largefile is modified, the change is not reflected in its
920 # If a largefile is modified, the change is not reflected in its
921 # standin until a commit. cmdutil.bailifchanged() raises an exception
921 # standin until a commit. cmdutil.bailifchanged() raises an exception
922 # if the repo has uncommitted changes. Wrap it to also check if
922 # if the repo has uncommitted changes. Wrap it to also check if
923 # largefiles were changed. This is used by bisect and backout.
923 # largefiles were changed. This is used by bisect and backout.
924 def overridebailifchanged(orig, repo):
924 def overridebailifchanged(orig, repo):
925 orig(repo)
925 orig(repo)
926 repo.lfstatus = True
926 repo.lfstatus = True
927 modified, added, removed, deleted = repo.status()[:4]
927 modified, added, removed, deleted = repo.status()[:4]
928 repo.lfstatus = False
928 repo.lfstatus = False
929 if modified or added or removed or deleted:
929 if modified or added or removed or deleted:
930 raise util.Abort(_('uncommitted changes'))
930 raise util.Abort(_('uncommitted changes'))
931
931
932 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
932 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
933 def overridefetch(orig, ui, repo, *pats, **opts):
933 def overridefetch(orig, ui, repo, *pats, **opts):
934 repo.lfstatus = True
934 repo.lfstatus = True
935 modified, added, removed, deleted = repo.status()[:4]
935 modified, added, removed, deleted = repo.status()[:4]
936 repo.lfstatus = False
936 repo.lfstatus = False
937 if modified or added or removed or deleted:
937 if modified or added or removed or deleted:
938 raise util.Abort(_('uncommitted changes'))
938 raise util.Abort(_('uncommitted changes'))
939 return orig(ui, repo, *pats, **opts)
939 return orig(ui, repo, *pats, **opts)
940
940
941 def overrideforget(orig, ui, repo, *pats, **opts):
941 def overrideforget(orig, ui, repo, *pats, **opts):
942 installnormalfilesmatchfn(repo[None].manifest())
942 installnormalfilesmatchfn(repo[None].manifest())
943 result = orig(ui, repo, *pats, **opts)
943 result = orig(ui, repo, *pats, **opts)
944 restorematchfn()
944 restorematchfn()
945 m = scmutil.match(repo[None], pats, opts)
945 m = scmutil.match(repo[None], pats, opts)
946
946
947 try:
947 try:
948 repo.lfstatus = True
948 repo.lfstatus = True
949 s = repo.status(match=m, clean=True)
949 s = repo.status(match=m, clean=True)
950 finally:
950 finally:
951 repo.lfstatus = False
951 repo.lfstatus = False
952 forget = sorted(s[0] + s[1] + s[3] + s[6])
952 forget = sorted(s[0] + s[1] + s[3] + s[6])
953 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
953 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
954
954
955 for f in forget:
955 for f in forget:
956 if lfutil.standin(f) not in repo.dirstate and not \
956 if lfutil.standin(f) not in repo.dirstate and not \
957 os.path.isdir(m.rel(lfutil.standin(f))):
957 os.path.isdir(m.rel(lfutil.standin(f))):
958 ui.warn(_('not removing %s: file is already untracked\n')
958 ui.warn(_('not removing %s: file is already untracked\n')
959 % m.rel(f))
959 % m.rel(f))
960 result = 1
960 result = 1
961
961
962 for f in forget:
962 for f in forget:
963 if ui.verbose or not m.exact(f):
963 if ui.verbose or not m.exact(f):
964 ui.status(_('removing %s\n') % m.rel(f))
964 ui.status(_('removing %s\n') % m.rel(f))
965
965
966 # Need to lock because standin files are deleted then removed from the
966 # Need to lock because standin files are deleted then removed from the
967 # repository and we could race in-between.
967 # repository and we could race in-between.
968 wlock = repo.wlock()
968 wlock = repo.wlock()
969 try:
969 try:
970 lfdirstate = lfutil.openlfdirstate(ui, repo)
970 lfdirstate = lfutil.openlfdirstate(ui, repo)
971 for f in forget:
971 for f in forget:
972 if lfdirstate[f] == 'a':
972 if lfdirstate[f] == 'a':
973 lfdirstate.drop(f)
973 lfdirstate.drop(f)
974 else:
974 else:
975 lfdirstate.remove(f)
975 lfdirstate.remove(f)
976 lfdirstate.write()
976 lfdirstate.write()
977 standins = [lfutil.standin(f) for f in forget]
977 standins = [lfutil.standin(f) for f in forget]
978 for f in standins:
978 for f in standins:
979 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
979 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
980 repo[None].forget(standins)
980 repo[None].forget(standins)
981 finally:
981 finally:
982 wlock.release()
982 wlock.release()
983
983
984 return result
984 return result
985
985
986 def outgoinghook(ui, repo, other, opts, missing):
986 def outgoinghook(ui, repo, other, opts, missing):
987 if opts.pop('large', None):
987 if opts.pop('large', None):
988 toupload = set()
988 toupload = set()
989 lfutil.getlfilestoupload(repo, missing,
989 lfutil.getlfilestoupload(repo, missing,
990 lambda fn, lfhash: toupload.add(fn))
990 lambda fn, lfhash: toupload.add(fn))
991 if not toupload:
991 if not toupload:
992 ui.status(_('largefiles: no files to upload\n'))
992 ui.status(_('largefiles: no files to upload\n'))
993 else:
993 else:
994 ui.status(_('largefiles to upload:\n'))
994 ui.status(_('largefiles to upload:\n'))
995 for file in sorted(toupload):
995 for file in sorted(toupload):
996 ui.status(lfutil.splitstandin(file) + '\n')
996 ui.status(lfutil.splitstandin(file) + '\n')
997 ui.status('\n')
997 ui.status('\n')
998
998
999 def summaryremotehook(ui, repo, opts, changes):
999 def summaryremotehook(ui, repo, opts, changes):
1000 largeopt = opts.get('large', False)
1000 largeopt = opts.get('large', False)
1001 if changes is None:
1001 if changes is None:
1002 if largeopt:
1002 if largeopt:
1003 return (False, True) # only outgoing check is needed
1003 return (False, True) # only outgoing check is needed
1004 else:
1004 else:
1005 return (False, False)
1005 return (False, False)
1006 elif largeopt:
1006 elif largeopt:
1007 url, branch, peer, outgoing = changes[1]
1007 url, branch, peer, outgoing = changes[1]
1008 if peer is None:
1008 if peer is None:
1009 # i18n: column positioning for "hg summary"
1009 # i18n: column positioning for "hg summary"
1010 ui.status(_('largefiles: (no remote repo)\n'))
1010 ui.status(_('largefiles: (no remote repo)\n'))
1011 return
1011 return
1012
1012
1013 toupload = set()
1013 toupload = set()
1014 lfutil.getlfilestoupload(repo, outgoing.missing,
1014 lfutil.getlfilestoupload(repo, outgoing.missing,
1015 lambda fn, lfhash: toupload.add(fn))
1015 lambda fn, lfhash: toupload.add(fn))
1016 if not toupload:
1016 if not toupload:
1017 # i18n: column positioning for "hg summary"
1017 # i18n: column positioning for "hg summary"
1018 ui.status(_('largefiles: (no files to upload)\n'))
1018 ui.status(_('largefiles: (no files to upload)\n'))
1019 else:
1019 else:
1020 # i18n: column positioning for "hg summary"
1020 # i18n: column positioning for "hg summary"
1021 ui.status(_('largefiles: %d to upload\n') % len(toupload))
1021 ui.status(_('largefiles: %d to upload\n') % len(toupload))
1022
1022
1023 def overridesummary(orig, ui, repo, *pats, **opts):
1023 def overridesummary(orig, ui, repo, *pats, **opts):
1024 try:
1024 try:
1025 repo.lfstatus = True
1025 repo.lfstatus = True
1026 orig(ui, repo, *pats, **opts)
1026 orig(ui, repo, *pats, **opts)
1027 finally:
1027 finally:
1028 repo.lfstatus = False
1028 repo.lfstatus = False
1029
1029
1030 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1030 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1031 similarity=None):
1031 similarity=None):
1032 if not lfutil.islfilesrepo(repo):
1032 if not lfutil.islfilesrepo(repo):
1033 return orig(repo, pats, opts, dry_run, similarity)
1033 return orig(repo, pats, opts, dry_run, similarity)
1034 # Get the list of missing largefiles so we can remove them
1034 # Get the list of missing largefiles so we can remove them
1035 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1035 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1036 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1036 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1037 False, False)
1037 False, False)
1038 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1038 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1039
1039
1040 # Call into the normal remove code, but the removing of the standin, we want
1040 # Call into the normal remove code, but the removing of the standin, we want
1041 # to have handled by original addremove. Monkey patching here makes sure
1041 # to have handled by original addremove. Monkey patching here makes sure
1042 # we don't remove the standin in the largefiles code, preventing a very
1042 # we don't remove the standin in the largefiles code, preventing a very
1043 # confused state later.
1043 # confused state later.
1044 if missing:
1044 if missing:
1045 m = [repo.wjoin(f) for f in missing]
1045 m = [repo.wjoin(f) for f in missing]
1046 repo._isaddremove = True
1046 repo._isaddremove = True
1047 removelargefiles(repo.ui, repo, *m, **opts)
1047 removelargefiles(repo.ui, repo, *m, **opts)
1048 repo._isaddremove = False
1048 repo._isaddremove = False
1049 # Call into the normal add code, and any files that *should* be added as
1049 # Call into the normal add code, and any files that *should* be added as
1050 # largefiles will be
1050 # largefiles will be
1051 addlargefiles(repo.ui, repo, *pats, **opts)
1051 addlargefiles(repo.ui, repo, *pats, **opts)
1052 # Now that we've handled largefiles, hand off to the original addremove
1052 # Now that we've handled largefiles, hand off to the original addremove
1053 # function to take care of the rest. Make sure it doesn't do anything with
1053 # function to take care of the rest. Make sure it doesn't do anything with
1054 # largefiles by installing a matcher that will ignore them.
1054 # largefiles by installing a matcher that will ignore them.
1055 installnormalfilesmatchfn(repo[None].manifest())
1055 installnormalfilesmatchfn(repo[None].manifest())
1056 result = orig(repo, pats, opts, dry_run, similarity)
1056 result = orig(repo, pats, opts, dry_run, similarity)
1057 restorematchfn()
1057 restorematchfn()
1058 return result
1058 return result
1059
1059
1060 # Calling purge with --all will cause the largefiles to be deleted.
1060 # Calling purge with --all will cause the largefiles to be deleted.
1061 # Override repo.status to prevent this from happening.
1061 # Override repo.status to prevent this from happening.
1062 def overridepurge(orig, ui, repo, *dirs, **opts):
1062 def overridepurge(orig, ui, repo, *dirs, **opts):
1063 # XXX large file status is buggy when used on repo proxy.
1063 # XXX large file status is buggy when used on repo proxy.
1064 # XXX this needs to be investigate.
1064 # XXX this needs to be investigate.
1065 repo = repo.unfiltered()
1065 repo = repo.unfiltered()
1066 oldstatus = repo.status
1066 oldstatus = repo.status
1067 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1067 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1068 clean=False, unknown=False, listsubrepos=False):
1068 clean=False, unknown=False, listsubrepos=False):
1069 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1069 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1070 listsubrepos)
1070 listsubrepos)
1071 lfdirstate = lfutil.openlfdirstate(ui, repo)
1071 lfdirstate = lfutil.openlfdirstate(ui, repo)
1072 modified, added, removed, deleted, unknown, ignored, clean = r
1072 modified, added, removed, deleted, unknown, ignored, clean = r
1073 unknown = [f for f in unknown if lfdirstate[f] == '?']
1073 unknown = [f for f in unknown if lfdirstate[f] == '?']
1074 ignored = [f for f in ignored if lfdirstate[f] == '?']
1074 ignored = [f for f in ignored if lfdirstate[f] == '?']
1075 return modified, added, removed, deleted, unknown, ignored, clean
1075 return modified, added, removed, deleted, unknown, ignored, clean
1076 repo.status = overridestatus
1076 repo.status = overridestatus
1077 orig(ui, repo, *dirs, **opts)
1077 orig(ui, repo, *dirs, **opts)
1078 repo.status = oldstatus
1078 repo.status = oldstatus
1079
1079
1080 def overriderollback(orig, ui, repo, **opts):
1080 def overriderollback(orig, ui, repo, **opts):
1081 result = orig(ui, repo, **opts)
1081 result = orig(ui, repo, **opts)
1082 merge.update(repo, node=None, branchmerge=False, force=True,
1082 merge.update(repo, node=None, branchmerge=False, force=True,
1083 partial=lfutil.isstandin)
1083 partial=lfutil.isstandin)
1084 wlock = repo.wlock()
1084 wlock = repo.wlock()
1085 try:
1085 try:
1086 lfdirstate = lfutil.openlfdirstate(ui, repo)
1086 lfdirstate = lfutil.openlfdirstate(ui, repo)
1087 lfiles = lfutil.listlfiles(repo)
1087 lfiles = lfutil.listlfiles(repo)
1088 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1088 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1089 for file in lfiles:
1089 for file in lfiles:
1090 if file in oldlfiles:
1090 if file in oldlfiles:
1091 lfdirstate.normallookup(file)
1091 lfdirstate.normallookup(file)
1092 else:
1092 else:
1093 lfdirstate.add(file)
1093 lfdirstate.add(file)
1094 lfdirstate.write()
1094 lfdirstate.write()
1095 finally:
1095 finally:
1096 wlock.release()
1096 wlock.release()
1097 return result
1097 return result
1098
1098
1099 def overridetransplant(orig, ui, repo, *revs, **opts):
1099 def overridetransplant(orig, ui, repo, *revs, **opts):
1100 try:
1100 try:
1101 oldstandins = lfutil.getstandinsstate(repo)
1101 oldstandins = lfutil.getstandinsstate(repo)
1102 repo._istransplanting = True
1102 repo._istransplanting = True
1103 result = orig(ui, repo, *revs, **opts)
1103 result = orig(ui, repo, *revs, **opts)
1104 newstandins = lfutil.getstandinsstate(repo)
1104 newstandins = lfutil.getstandinsstate(repo)
1105 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1105 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1106 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1106 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1107 printmessage=True)
1107 printmessage=True)
1108 finally:
1108 finally:
1109 repo._istransplanting = False
1109 repo._istransplanting = False
1110 return result
1110 return result
1111
1111
1112 def overridecat(orig, ui, repo, file1, *pats, **opts):
1112 def overridecat(orig, ui, repo, file1, *pats, **opts):
1113 ctx = scmutil.revsingle(repo, opts.get('rev'))
1113 ctx = scmutil.revsingle(repo, opts.get('rev'))
1114 err = 1
1114 err = 1
1115 notbad = set()
1115 notbad = set()
1116 m = scmutil.match(ctx, (file1,) + pats, opts)
1116 m = scmutil.match(ctx, (file1,) + pats, opts)
1117 origmatchfn = m.matchfn
1117 origmatchfn = m.matchfn
1118 def lfmatchfn(f):
1118 def lfmatchfn(f):
1119 lf = lfutil.splitstandin(f)
1119 lf = lfutil.splitstandin(f)
1120 if lf is None:
1120 if lf is None:
1121 return origmatchfn(f)
1121 return origmatchfn(f)
1122 notbad.add(lf)
1122 notbad.add(lf)
1123 return origmatchfn(lf)
1123 return origmatchfn(lf)
1124 m.matchfn = lfmatchfn
1124 m.matchfn = lfmatchfn
1125 origbadfn = m.bad
1125 origbadfn = m.bad
1126 def lfbadfn(f, msg):
1126 def lfbadfn(f, msg):
1127 if not f in notbad:
1127 if not f in notbad:
1128 return origbadfn(f, msg)
1128 origbadfn(f, msg)
1129 m.bad = lfbadfn
1129 m.bad = lfbadfn
1130 for f in ctx.walk(m):
1130 for f in ctx.walk(m):
1131 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1131 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1132 pathname=f)
1132 pathname=f)
1133 lf = lfutil.splitstandin(f)
1133 lf = lfutil.splitstandin(f)
1134 if lf is None:
1134 if lf is None:
1135 # duplicating unreachable code from commands.cat
1135 # duplicating unreachable code from commands.cat
1136 data = ctx[f].data()
1136 data = ctx[f].data()
1137 if opts.get('decode'):
1137 if opts.get('decode'):
1138 data = repo.wwritedata(f, data)
1138 data = repo.wwritedata(f, data)
1139 fp.write(data)
1139 fp.write(data)
1140 else:
1140 else:
1141 hash = lfutil.readstandin(repo, lf, ctx.rev())
1141 hash = lfutil.readstandin(repo, lf, ctx.rev())
1142 if not lfutil.inusercache(repo.ui, hash):
1142 if not lfutil.inusercache(repo.ui, hash):
1143 store = basestore._openstore(repo)
1143 store = basestore._openstore(repo)
1144 success, missing = store.get([(lf, hash)])
1144 success, missing = store.get([(lf, hash)])
1145 if len(success) != 1:
1145 if len(success) != 1:
1146 raise util.Abort(
1146 raise util.Abort(
1147 _('largefile %s is not in cache and could not be '
1147 _('largefile %s is not in cache and could not be '
1148 'downloaded') % lf)
1148 'downloaded') % lf)
1149 path = lfutil.usercachepath(repo.ui, hash)
1149 path = lfutil.usercachepath(repo.ui, hash)
1150 fpin = open(path, "rb")
1150 fpin = open(path, "rb")
1151 for chunk in util.filechunkiter(fpin, 128 * 1024):
1151 for chunk in util.filechunkiter(fpin, 128 * 1024):
1152 fp.write(chunk)
1152 fp.write(chunk)
1153 fpin.close()
1153 fpin.close()
1154 fp.close()
1154 fp.close()
1155 err = 0
1155 err = 0
1156 return err
1156 return err
1157
1157
1158 def mercurialsinkbefore(orig, sink):
1158 def mercurialsinkbefore(orig, sink):
1159 sink.repo._isconverting = True
1159 sink.repo._isconverting = True
1160 orig(sink)
1160 orig(sink)
1161
1161
1162 def mercurialsinkafter(orig, sink):
1162 def mercurialsinkafter(orig, sink):
1163 sink.repo._isconverting = False
1163 sink.repo._isconverting = False
1164 orig(sink)
1164 orig(sink)
General Comments 0
You need to be logged in to leave comments. Login now