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