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