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