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