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