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