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