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