##// END OF EJS Templates
largefiles: remove useless overrideupdate...
FUJIWARA Katsunori -
r24474:61a99993 default
parent child Browse files
Show More
@@ -1,1406 +1,1376 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, util, cmdutil, scmutil, match as match_, \
14 from mercurial import hg, util, cmdutil, scmutil, match as match_, \
15 archival, pathutil, revset
15 archival, pathutil, revset
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial.node import hex
17 from mercurial.node import hex
18
18
19 import lfutil
19 import lfutil
20 import lfcommands
20 import lfcommands
21 import basestore
21 import basestore
22
22
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24
24
25 def composelargefilematcher(match, manifest):
25 def composelargefilematcher(match, manifest):
26 '''create a matcher that matches only the largefiles in the original
26 '''create a matcher that matches only the largefiles in the original
27 matcher'''
27 matcher'''
28 m = copy.copy(match)
28 m = copy.copy(match)
29 lfile = lambda f: lfutil.standin(f) in manifest
29 lfile = lambda f: lfutil.standin(f) in manifest
30 m._files = filter(lfile, m._files)
30 m._files = filter(lfile, m._files)
31 m._fmap = set(m._files)
31 m._fmap = set(m._files)
32 m._always = False
32 m._always = False
33 origmatchfn = m.matchfn
33 origmatchfn = m.matchfn
34 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
34 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
35 return m
35 return m
36
36
37 def composenormalfilematcher(match, manifest, exclude=None):
37 def composenormalfilematcher(match, manifest, exclude=None):
38 excluded = set()
38 excluded = set()
39 if exclude is not None:
39 if exclude is not None:
40 excluded.update(exclude)
40 excluded.update(exclude)
41
41
42 m = copy.copy(match)
42 m = copy.copy(match)
43 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
43 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
44 manifest or f in excluded)
44 manifest or f in excluded)
45 m._files = filter(notlfile, m._files)
45 m._files = filter(notlfile, m._files)
46 m._fmap = set(m._files)
46 m._fmap = set(m._files)
47 m._always = False
47 m._always = False
48 origmatchfn = m.matchfn
48 origmatchfn = m.matchfn
49 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
49 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
50 return m
50 return m
51
51
52 def installnormalfilesmatchfn(manifest):
52 def installnormalfilesmatchfn(manifest):
53 '''installmatchfn with a matchfn that ignores all largefiles'''
53 '''installmatchfn with a matchfn that ignores all largefiles'''
54 def overridematch(ctx, pats=[], opts={}, globbed=False,
54 def overridematch(ctx, pats=[], opts={}, globbed=False,
55 default='relpath'):
55 default='relpath'):
56 match = oldmatch(ctx, pats, opts, globbed, default)
56 match = oldmatch(ctx, pats, opts, globbed, default)
57 return composenormalfilematcher(match, manifest)
57 return composenormalfilematcher(match, manifest)
58 oldmatch = installmatchfn(overridematch)
58 oldmatch = installmatchfn(overridematch)
59
59
60 def installmatchfn(f):
60 def installmatchfn(f):
61 '''monkey patch the scmutil module with a custom match function.
61 '''monkey patch the scmutil module with a custom match function.
62 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
62 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
63 oldmatch = scmutil.match
63 oldmatch = scmutil.match
64 setattr(f, 'oldmatch', oldmatch)
64 setattr(f, 'oldmatch', oldmatch)
65 scmutil.match = f
65 scmutil.match = f
66 return oldmatch
66 return oldmatch
67
67
68 def restorematchfn():
68 def restorematchfn():
69 '''restores scmutil.match to what it was before installmatchfn
69 '''restores scmutil.match to what it was before installmatchfn
70 was called. no-op if scmutil.match is its original function.
70 was called. no-op if scmutil.match is its original function.
71
71
72 Note that n calls to installmatchfn will require n calls to
72 Note that n calls to installmatchfn will require n calls to
73 restore the original matchfn.'''
73 restore the original matchfn.'''
74 scmutil.match = getattr(scmutil.match, 'oldmatch')
74 scmutil.match = getattr(scmutil.match, 'oldmatch')
75
75
76 def installmatchandpatsfn(f):
76 def installmatchandpatsfn(f):
77 oldmatchandpats = scmutil.matchandpats
77 oldmatchandpats = scmutil.matchandpats
78 setattr(f, 'oldmatchandpats', oldmatchandpats)
78 setattr(f, 'oldmatchandpats', oldmatchandpats)
79 scmutil.matchandpats = f
79 scmutil.matchandpats = f
80 return oldmatchandpats
80 return oldmatchandpats
81
81
82 def restorematchandpatsfn():
82 def restorematchandpatsfn():
83 '''restores scmutil.matchandpats to what it was before
83 '''restores scmutil.matchandpats to what it was before
84 installmatchandpatsfn was called. No-op if scmutil.matchandpats
84 installmatchandpatsfn was called. No-op if scmutil.matchandpats
85 is its original function.
85 is its original function.
86
86
87 Note that n calls to installmatchandpatsfn will require n calls
87 Note that n calls to installmatchandpatsfn will require n calls
88 to restore the original matchfn.'''
88 to restore the original matchfn.'''
89 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
89 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
90 scmutil.matchandpats)
90 scmutil.matchandpats)
91
91
92 def addlargefiles(ui, repo, isaddremove, matcher, **opts):
92 def addlargefiles(ui, repo, isaddremove, matcher, **opts):
93 large = opts.get('large')
93 large = opts.get('large')
94 lfsize = lfutil.getminsize(
94 lfsize = lfutil.getminsize(
95 ui, lfutil.islfilesrepo(repo), opts.get('lfsize'))
95 ui, lfutil.islfilesrepo(repo), opts.get('lfsize'))
96
96
97 lfmatcher = None
97 lfmatcher = None
98 if lfutil.islfilesrepo(repo):
98 if lfutil.islfilesrepo(repo):
99 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
99 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
100 if lfpats:
100 if lfpats:
101 lfmatcher = match_.match(repo.root, '', list(lfpats))
101 lfmatcher = match_.match(repo.root, '', list(lfpats))
102
102
103 lfnames = []
103 lfnames = []
104 m = copy.copy(matcher)
104 m = copy.copy(matcher)
105 m.bad = lambda x, y: None
105 m.bad = lambda x, y: None
106 wctx = repo[None]
106 wctx = repo[None]
107 for f in repo.walk(m):
107 for f in repo.walk(m):
108 exact = m.exact(f)
108 exact = m.exact(f)
109 lfile = lfutil.standin(f) in wctx
109 lfile = lfutil.standin(f) in wctx
110 nfile = f in wctx
110 nfile = f in wctx
111 exists = lfile or nfile
111 exists = lfile or nfile
112
112
113 # addremove in core gets fancy with the name, add doesn't
113 # addremove in core gets fancy with the name, add doesn't
114 if isaddremove:
114 if isaddremove:
115 name = m.uipath(f)
115 name = m.uipath(f)
116 else:
116 else:
117 name = m.rel(f)
117 name = m.rel(f)
118
118
119 # Don't warn the user when they attempt to add a normal tracked file.
119 # Don't warn the user when they attempt to add a normal tracked file.
120 # The normal add code will do that for us.
120 # The normal add code will do that for us.
121 if exact and exists:
121 if exact and exists:
122 if lfile:
122 if lfile:
123 ui.warn(_('%s already a largefile\n') % name)
123 ui.warn(_('%s already a largefile\n') % name)
124 continue
124 continue
125
125
126 if (exact or not exists) and not lfutil.isstandin(f):
126 if (exact or not exists) and not lfutil.isstandin(f):
127 # In case the file was removed previously, but not committed
127 # In case the file was removed previously, but not committed
128 # (issue3507)
128 # (issue3507)
129 if not repo.wvfs.exists(f):
129 if not repo.wvfs.exists(f):
130 continue
130 continue
131
131
132 abovemin = (lfsize and
132 abovemin = (lfsize and
133 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
133 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
134 if large or abovemin or (lfmatcher and lfmatcher(f)):
134 if large or abovemin or (lfmatcher and lfmatcher(f)):
135 lfnames.append(f)
135 lfnames.append(f)
136 if ui.verbose or not exact:
136 if ui.verbose or not exact:
137 ui.status(_('adding %s as a largefile\n') % name)
137 ui.status(_('adding %s as a largefile\n') % name)
138
138
139 bad = []
139 bad = []
140
140
141 # Need to lock, otherwise there could be a race condition between
141 # Need to lock, otherwise there could be a race condition between
142 # when standins are created and added to the repo.
142 # when standins are created and added to the repo.
143 wlock = repo.wlock()
143 wlock = repo.wlock()
144 try:
144 try:
145 if not opts.get('dry_run'):
145 if not opts.get('dry_run'):
146 standins = []
146 standins = []
147 lfdirstate = lfutil.openlfdirstate(ui, repo)
147 lfdirstate = lfutil.openlfdirstate(ui, repo)
148 for f in lfnames:
148 for f in lfnames:
149 standinname = lfutil.standin(f)
149 standinname = lfutil.standin(f)
150 lfutil.writestandin(repo, standinname, hash='',
150 lfutil.writestandin(repo, standinname, hash='',
151 executable=lfutil.getexecutable(repo.wjoin(f)))
151 executable=lfutil.getexecutable(repo.wjoin(f)))
152 standins.append(standinname)
152 standins.append(standinname)
153 if lfdirstate[f] == 'r':
153 if lfdirstate[f] == 'r':
154 lfdirstate.normallookup(f)
154 lfdirstate.normallookup(f)
155 else:
155 else:
156 lfdirstate.add(f)
156 lfdirstate.add(f)
157 lfdirstate.write()
157 lfdirstate.write()
158 bad += [lfutil.splitstandin(f)
158 bad += [lfutil.splitstandin(f)
159 for f in repo[None].add(standins)
159 for f in repo[None].add(standins)
160 if f in m.files()]
160 if f in m.files()]
161
161
162 added = [f for f in lfnames if f not in bad]
162 added = [f for f in lfnames if f not in bad]
163 finally:
163 finally:
164 wlock.release()
164 wlock.release()
165 return added, bad
165 return added, bad
166
166
167 def removelargefiles(ui, repo, isaddremove, matcher, **opts):
167 def removelargefiles(ui, repo, isaddremove, matcher, **opts):
168 after = opts.get('after')
168 after = opts.get('after')
169 m = composelargefilematcher(matcher, repo[None].manifest())
169 m = composelargefilematcher(matcher, repo[None].manifest())
170 try:
170 try:
171 repo.lfstatus = True
171 repo.lfstatus = True
172 s = repo.status(match=m, clean=not isaddremove)
172 s = repo.status(match=m, clean=not isaddremove)
173 finally:
173 finally:
174 repo.lfstatus = False
174 repo.lfstatus = False
175 manifest = repo[None].manifest()
175 manifest = repo[None].manifest()
176 modified, added, deleted, clean = [[f for f in list
176 modified, added, deleted, clean = [[f for f in list
177 if lfutil.standin(f) in manifest]
177 if lfutil.standin(f) in manifest]
178 for list in (s.modified, s.added,
178 for list in (s.modified, s.added,
179 s.deleted, s.clean)]
179 s.deleted, s.clean)]
180
180
181 def warn(files, msg):
181 def warn(files, msg):
182 for f in files:
182 for f in files:
183 ui.warn(msg % m.rel(f))
183 ui.warn(msg % m.rel(f))
184 return int(len(files) > 0)
184 return int(len(files) > 0)
185
185
186 result = 0
186 result = 0
187
187
188 if after:
188 if after:
189 remove = deleted
189 remove = deleted
190 result = warn(modified + added + clean,
190 result = warn(modified + added + clean,
191 _('not removing %s: file still exists\n'))
191 _('not removing %s: file still exists\n'))
192 else:
192 else:
193 remove = deleted + clean
193 remove = deleted + clean
194 result = warn(modified, _('not removing %s: file is modified (use -f'
194 result = warn(modified, _('not removing %s: file is modified (use -f'
195 ' to force removal)\n'))
195 ' to force removal)\n'))
196 result = warn(added, _('not removing %s: file has been marked for add'
196 result = warn(added, _('not removing %s: file has been marked for add'
197 ' (use forget to undo)\n')) or result
197 ' (use forget to undo)\n')) or result
198
198
199 # Need to lock because standin files are deleted then removed from the
199 # Need to lock because standin files are deleted then removed from the
200 # repository and we could race in-between.
200 # repository and we could race in-between.
201 wlock = repo.wlock()
201 wlock = repo.wlock()
202 try:
202 try:
203 lfdirstate = lfutil.openlfdirstate(ui, repo)
203 lfdirstate = lfutil.openlfdirstate(ui, repo)
204 for f in sorted(remove):
204 for f in sorted(remove):
205 if ui.verbose or not m.exact(f):
205 if ui.verbose or not m.exact(f):
206 # addremove in core gets fancy with the name, remove doesn't
206 # addremove in core gets fancy with the name, remove doesn't
207 if isaddremove:
207 if isaddremove:
208 name = m.uipath(f)
208 name = m.uipath(f)
209 else:
209 else:
210 name = m.rel(f)
210 name = m.rel(f)
211 ui.status(_('removing %s\n') % name)
211 ui.status(_('removing %s\n') % name)
212
212
213 if not opts.get('dry_run'):
213 if not opts.get('dry_run'):
214 if not after:
214 if not after:
215 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
215 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
216
216
217 if opts.get('dry_run'):
217 if opts.get('dry_run'):
218 return result
218 return result
219
219
220 remove = [lfutil.standin(f) for f in remove]
220 remove = [lfutil.standin(f) for f in remove]
221 # If this is being called by addremove, let the original addremove
221 # If this is being called by addremove, let the original addremove
222 # function handle this.
222 # function handle this.
223 if not isaddremove:
223 if not isaddremove:
224 for f in remove:
224 for f in remove:
225 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
225 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
226 repo[None].forget(remove)
226 repo[None].forget(remove)
227
227
228 for f in remove:
228 for f in remove:
229 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
229 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
230 False)
230 False)
231
231
232 lfdirstate.write()
232 lfdirstate.write()
233 finally:
233 finally:
234 wlock.release()
234 wlock.release()
235
235
236 return result
236 return result
237
237
238 # For overriding mercurial.hgweb.webcommands so that largefiles will
238 # For overriding mercurial.hgweb.webcommands so that largefiles will
239 # appear at their right place in the manifests.
239 # appear at their right place in the manifests.
240 def decodepath(orig, path):
240 def decodepath(orig, path):
241 return lfutil.splitstandin(path) or path
241 return lfutil.splitstandin(path) or path
242
242
243 # -- Wrappers: modify existing commands --------------------------------
243 # -- Wrappers: modify existing commands --------------------------------
244
244
245 def overrideadd(orig, ui, repo, *pats, **opts):
245 def overrideadd(orig, ui, repo, *pats, **opts):
246 if opts.get('normal') and opts.get('large'):
246 if opts.get('normal') and opts.get('large'):
247 raise util.Abort(_('--normal cannot be used with --large'))
247 raise util.Abort(_('--normal cannot be used with --large'))
248 return orig(ui, repo, *pats, **opts)
248 return orig(ui, repo, *pats, **opts)
249
249
250 def cmdutiladd(orig, ui, repo, matcher, prefix, explicitonly, **opts):
250 def cmdutiladd(orig, ui, repo, matcher, prefix, explicitonly, **opts):
251 # The --normal flag short circuits this override
251 # The --normal flag short circuits this override
252 if opts.get('normal'):
252 if opts.get('normal'):
253 return orig(ui, repo, matcher, prefix, explicitonly, **opts)
253 return orig(ui, repo, matcher, prefix, explicitonly, **opts)
254
254
255 ladded, lbad = addlargefiles(ui, repo, False, matcher, **opts)
255 ladded, lbad = addlargefiles(ui, repo, False, matcher, **opts)
256 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(),
256 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest(),
257 ladded)
257 ladded)
258 bad = orig(ui, repo, normalmatcher, prefix, explicitonly, **opts)
258 bad = orig(ui, repo, normalmatcher, prefix, explicitonly, **opts)
259
259
260 bad.extend(f for f in lbad)
260 bad.extend(f for f in lbad)
261 return bad
261 return bad
262
262
263 def cmdutilremove(orig, ui, repo, matcher, prefix, after, force, subrepos):
263 def cmdutilremove(orig, ui, repo, matcher, prefix, after, force, subrepos):
264 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
264 normalmatcher = composenormalfilematcher(matcher, repo[None].manifest())
265 result = orig(ui, repo, normalmatcher, prefix, after, force, subrepos)
265 result = orig(ui, repo, normalmatcher, prefix, after, force, subrepos)
266 return removelargefiles(ui, repo, False, matcher, after=after,
266 return removelargefiles(ui, repo, False, matcher, after=after,
267 force=force) or result
267 force=force) or result
268
268
269 def overridestatusfn(orig, repo, rev2, **opts):
269 def overridestatusfn(orig, repo, rev2, **opts):
270 try:
270 try:
271 repo._repo.lfstatus = True
271 repo._repo.lfstatus = True
272 return orig(repo, rev2, **opts)
272 return orig(repo, rev2, **opts)
273 finally:
273 finally:
274 repo._repo.lfstatus = False
274 repo._repo.lfstatus = False
275
275
276 def overridestatus(orig, ui, repo, *pats, **opts):
276 def overridestatus(orig, ui, repo, *pats, **opts):
277 try:
277 try:
278 repo.lfstatus = True
278 repo.lfstatus = True
279 return orig(ui, repo, *pats, **opts)
279 return orig(ui, repo, *pats, **opts)
280 finally:
280 finally:
281 repo.lfstatus = False
281 repo.lfstatus = False
282
282
283 def overridedirty(orig, repo, ignoreupdate=False):
283 def overridedirty(orig, repo, ignoreupdate=False):
284 try:
284 try:
285 repo._repo.lfstatus = True
285 repo._repo.lfstatus = True
286 return orig(repo, ignoreupdate)
286 return orig(repo, ignoreupdate)
287 finally:
287 finally:
288 repo._repo.lfstatus = False
288 repo._repo.lfstatus = False
289
289
290 def overridelog(orig, ui, repo, *pats, **opts):
290 def overridelog(orig, ui, repo, *pats, **opts):
291 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
291 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
292 default='relpath'):
292 default='relpath'):
293 """Matcher that merges root directory with .hglf, suitable for log.
293 """Matcher that merges root directory with .hglf, suitable for log.
294 It is still possible to match .hglf directly.
294 It is still possible to match .hglf directly.
295 For any listed files run log on the standin too.
295 For any listed files run log on the standin too.
296 matchfn tries both the given filename and with .hglf stripped.
296 matchfn tries both the given filename and with .hglf stripped.
297 """
297 """
298 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
298 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
299 m, p = copy.copy(matchandpats)
299 m, p = copy.copy(matchandpats)
300
300
301 if m.always():
301 if m.always():
302 # We want to match everything anyway, so there's no benefit trying
302 # We want to match everything anyway, so there's no benefit trying
303 # to add standins.
303 # to add standins.
304 return matchandpats
304 return matchandpats
305
305
306 pats = set(p)
306 pats = set(p)
307
307
308 def fixpats(pat, tostandin=lfutil.standin):
308 def fixpats(pat, tostandin=lfutil.standin):
309 kindpat = match_._patsplit(pat, None)
309 kindpat = match_._patsplit(pat, None)
310
310
311 if kindpat[0] is not None:
311 if kindpat[0] is not None:
312 return kindpat[0] + ':' + tostandin(kindpat[1])
312 return kindpat[0] + ':' + tostandin(kindpat[1])
313 return tostandin(kindpat[1])
313 return tostandin(kindpat[1])
314
314
315 if m._cwd:
315 if m._cwd:
316 hglf = lfutil.shortname
316 hglf = lfutil.shortname
317 back = util.pconvert(m.rel(hglf)[:-len(hglf)])
317 back = util.pconvert(m.rel(hglf)[:-len(hglf)])
318
318
319 def tostandin(f):
319 def tostandin(f):
320 # The file may already be a standin, so trucate the back
320 # The file may already be a standin, so trucate the back
321 # prefix and test before mangling it. This avoids turning
321 # prefix and test before mangling it. This avoids turning
322 # 'glob:../.hglf/foo*' into 'glob:../.hglf/../.hglf/foo*'.
322 # 'glob:../.hglf/foo*' into 'glob:../.hglf/../.hglf/foo*'.
323 if f.startswith(back) and lfutil.splitstandin(f[len(back):]):
323 if f.startswith(back) and lfutil.splitstandin(f[len(back):]):
324 return f
324 return f
325
325
326 # An absolute path is from outside the repo, so truncate the
326 # An absolute path is from outside the repo, so truncate the
327 # path to the root before building the standin. Otherwise cwd
327 # path to the root before building the standin. Otherwise cwd
328 # is somewhere in the repo, relative to root, and needs to be
328 # is somewhere in the repo, relative to root, and needs to be
329 # prepended before building the standin.
329 # prepended before building the standin.
330 if os.path.isabs(m._cwd):
330 if os.path.isabs(m._cwd):
331 f = f[len(back):]
331 f = f[len(back):]
332 else:
332 else:
333 f = m._cwd + '/' + f
333 f = m._cwd + '/' + f
334 return back + lfutil.standin(f)
334 return back + lfutil.standin(f)
335
335
336 pats.update(fixpats(f, tostandin) for f in p)
336 pats.update(fixpats(f, tostandin) for f in p)
337 else:
337 else:
338 def tostandin(f):
338 def tostandin(f):
339 if lfutil.splitstandin(f):
339 if lfutil.splitstandin(f):
340 return f
340 return f
341 return lfutil.standin(f)
341 return lfutil.standin(f)
342 pats.update(fixpats(f, tostandin) for f in p)
342 pats.update(fixpats(f, tostandin) for f in p)
343
343
344 for i in range(0, len(m._files)):
344 for i in range(0, len(m._files)):
345 # Don't add '.hglf' to m.files, since that is already covered by '.'
345 # Don't add '.hglf' to m.files, since that is already covered by '.'
346 if m._files[i] == '.':
346 if m._files[i] == '.':
347 continue
347 continue
348 standin = lfutil.standin(m._files[i])
348 standin = lfutil.standin(m._files[i])
349 # If the "standin" is a directory, append instead of replace to
349 # If the "standin" is a directory, append instead of replace to
350 # support naming a directory on the command line with only
350 # support naming a directory on the command line with only
351 # largefiles. The original directory is kept to support normal
351 # largefiles. The original directory is kept to support normal
352 # files.
352 # files.
353 if standin in repo[ctx.node()]:
353 if standin in repo[ctx.node()]:
354 m._files[i] = standin
354 m._files[i] = standin
355 elif m._files[i] not in repo[ctx.node()] \
355 elif m._files[i] not in repo[ctx.node()] \
356 and repo.wvfs.isdir(standin):
356 and repo.wvfs.isdir(standin):
357 m._files.append(standin)
357 m._files.append(standin)
358
358
359 m._fmap = set(m._files)
359 m._fmap = set(m._files)
360 m._always = False
360 m._always = False
361 origmatchfn = m.matchfn
361 origmatchfn = m.matchfn
362 def lfmatchfn(f):
362 def lfmatchfn(f):
363 lf = lfutil.splitstandin(f)
363 lf = lfutil.splitstandin(f)
364 if lf is not None and origmatchfn(lf):
364 if lf is not None and origmatchfn(lf):
365 return True
365 return True
366 r = origmatchfn(f)
366 r = origmatchfn(f)
367 return r
367 return r
368 m.matchfn = lfmatchfn
368 m.matchfn = lfmatchfn
369
369
370 ui.debug('updated patterns: %s\n' % sorted(pats))
370 ui.debug('updated patterns: %s\n' % sorted(pats))
371 return m, pats
371 return m, pats
372
372
373 # For hg log --patch, the match object is used in two different senses:
373 # For hg log --patch, the match object is used in two different senses:
374 # (1) to determine what revisions should be printed out, and
374 # (1) to determine what revisions should be printed out, and
375 # (2) to determine what files to print out diffs for.
375 # (2) to determine what files to print out diffs for.
376 # The magic matchandpats override should be used for case (1) but not for
376 # The magic matchandpats override should be used for case (1) but not for
377 # case (2).
377 # case (2).
378 def overridemakelogfilematcher(repo, pats, opts):
378 def overridemakelogfilematcher(repo, pats, opts):
379 pctx = repo[None]
379 pctx = repo[None]
380 match, pats = oldmatchandpats(pctx, pats, opts)
380 match, pats = oldmatchandpats(pctx, pats, opts)
381 return lambda rev: match
381 return lambda rev: match
382
382
383 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
383 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
384 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
384 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
385 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
385 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
386
386
387 try:
387 try:
388 return orig(ui, repo, *pats, **opts)
388 return orig(ui, repo, *pats, **opts)
389 finally:
389 finally:
390 restorematchandpatsfn()
390 restorematchandpatsfn()
391 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
391 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
392
392
393 def overrideverify(orig, ui, repo, *pats, **opts):
393 def overrideverify(orig, ui, repo, *pats, **opts):
394 large = opts.pop('large', False)
394 large = opts.pop('large', False)
395 all = opts.pop('lfa', False)
395 all = opts.pop('lfa', False)
396 contents = opts.pop('lfc', False)
396 contents = opts.pop('lfc', False)
397
397
398 result = orig(ui, repo, *pats, **opts)
398 result = orig(ui, repo, *pats, **opts)
399 if large or all or contents:
399 if large or all or contents:
400 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
400 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
401 return result
401 return result
402
402
403 def overridedebugstate(orig, ui, repo, *pats, **opts):
403 def overridedebugstate(orig, ui, repo, *pats, **opts):
404 large = opts.pop('large', False)
404 large = opts.pop('large', False)
405 if large:
405 if large:
406 class fakerepo(object):
406 class fakerepo(object):
407 dirstate = lfutil.openlfdirstate(ui, repo)
407 dirstate = lfutil.openlfdirstate(ui, repo)
408 orig(ui, fakerepo, *pats, **opts)
408 orig(ui, fakerepo, *pats, **opts)
409 else:
409 else:
410 orig(ui, repo, *pats, **opts)
410 orig(ui, repo, *pats, **opts)
411
411
412 # Override needs to refresh standins so that update's normal merge
413 # will go through properly. Then the other update hook (overriding repo.update)
414 # will get the new files. Filemerge is also overridden so that the merge
415 # will merge standins correctly.
416 def overrideupdate(orig, ui, repo, *pats, **opts):
417 # Need to lock between the standins getting updated and their
418 # largefiles getting updated
419 wlock = repo.wlock()
420 try:
421 if opts['check']:
422 lfdirstate = lfutil.openlfdirstate(ui, repo)
423 unsure, s = lfdirstate.status(
424 match_.always(repo.root, repo.getcwd()),
425 [], False, False, False)
426
427 mod = len(s.modified) > 0
428 for lfile in unsure:
429 standin = lfutil.standin(lfile)
430 if repo['.'][standin].data().strip() != \
431 lfutil.hashfile(repo.wjoin(lfile)):
432 mod = True
433 else:
434 lfdirstate.normal(lfile)
435 lfdirstate.write()
436 if mod:
437 raise util.Abort(_('uncommitted changes'))
438 return orig(ui, repo, *pats, **opts)
439 finally:
440 wlock.release()
441
442 # Before starting the manifest merge, merge.updates will call
412 # Before starting the manifest merge, merge.updates will call
443 # _checkunknownfile to check if there are any files in the merged-in
413 # _checkunknownfile to check if there are any files in the merged-in
444 # changeset that collide with unknown files in the working copy.
414 # changeset that collide with unknown files in the working copy.
445 #
415 #
446 # The largefiles are seen as unknown, so this prevents us from merging
416 # The largefiles are seen as unknown, so this prevents us from merging
447 # in a file 'foo' if we already have a largefile with the same name.
417 # in a file 'foo' if we already have a largefile with the same name.
448 #
418 #
449 # The overridden function filters the unknown files by removing any
419 # The overridden function filters the unknown files by removing any
450 # largefiles. This makes the merge proceed and we can then handle this
420 # largefiles. This makes the merge proceed and we can then handle this
451 # case further in the overridden calculateupdates function below.
421 # case further in the overridden calculateupdates function below.
452 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
422 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
453 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
423 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
454 return False
424 return False
455 return origfn(repo, wctx, mctx, f, f2)
425 return origfn(repo, wctx, mctx, f, f2)
456
426
457 # The manifest merge handles conflicts on the manifest level. We want
427 # The manifest merge handles conflicts on the manifest level. We want
458 # to handle changes in largefile-ness of files at this level too.
428 # to handle changes in largefile-ness of files at this level too.
459 #
429 #
460 # The strategy is to run the original calculateupdates and then process
430 # The strategy is to run the original calculateupdates and then process
461 # the action list it outputs. There are two cases we need to deal with:
431 # the action list it outputs. There are two cases we need to deal with:
462 #
432 #
463 # 1. Normal file in p1, largefile in p2. Here the largefile is
433 # 1. Normal file in p1, largefile in p2. Here the largefile is
464 # detected via its standin file, which will enter the working copy
434 # detected via its standin file, which will enter the working copy
465 # with a "get" action. It is not "merge" since the standin is all
435 # with a "get" action. It is not "merge" since the standin is all
466 # Mercurial is concerned with at this level -- the link to the
436 # Mercurial is concerned with at this level -- the link to the
467 # existing normal file is not relevant here.
437 # existing normal file is not relevant here.
468 #
438 #
469 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
439 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
470 # since the largefile will be present in the working copy and
440 # since the largefile will be present in the working copy and
471 # different from the normal file in p2. Mercurial therefore
441 # different from the normal file in p2. Mercurial therefore
472 # triggers a merge action.
442 # triggers a merge action.
473 #
443 #
474 # In both cases, we prompt the user and emit new actions to either
444 # In both cases, we prompt the user and emit new actions to either
475 # remove the standin (if the normal file was kept) or to remove the
445 # remove the standin (if the normal file was kept) or to remove the
476 # normal file and get the standin (if the largefile was kept). The
446 # normal file and get the standin (if the largefile was kept). The
477 # default prompt answer is to use the largefile version since it was
447 # default prompt answer is to use the largefile version since it was
478 # presumably changed on purpose.
448 # presumably changed on purpose.
479 #
449 #
480 # Finally, the merge.applyupdates function will then take care of
450 # Finally, the merge.applyupdates function will then take care of
481 # writing the files into the working copy and lfcommands.updatelfiles
451 # writing the files into the working copy and lfcommands.updatelfiles
482 # will update the largefiles.
452 # will update the largefiles.
483 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
453 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
484 partial, acceptremote, followcopies):
454 partial, acceptremote, followcopies):
485 overwrite = force and not branchmerge
455 overwrite = force and not branchmerge
486 actions, diverge, renamedelete = origfn(
456 actions, diverge, renamedelete = origfn(
487 repo, p1, p2, pas, branchmerge, force, partial, acceptremote,
457 repo, p1, p2, pas, branchmerge, force, partial, acceptremote,
488 followcopies)
458 followcopies)
489
459
490 if overwrite:
460 if overwrite:
491 return actions, diverge, renamedelete
461 return actions, diverge, renamedelete
492
462
493 # Convert to dictionary with filename as key and action as value.
463 # Convert to dictionary with filename as key and action as value.
494 lfiles = set()
464 lfiles = set()
495 for f in actions:
465 for f in actions:
496 splitstandin = f and lfutil.splitstandin(f)
466 splitstandin = f and lfutil.splitstandin(f)
497 if splitstandin in p1:
467 if splitstandin in p1:
498 lfiles.add(splitstandin)
468 lfiles.add(splitstandin)
499 elif lfutil.standin(f) in p1:
469 elif lfutil.standin(f) in p1:
500 lfiles.add(f)
470 lfiles.add(f)
501
471
502 for lfile in lfiles:
472 for lfile in lfiles:
503 standin = lfutil.standin(lfile)
473 standin = lfutil.standin(lfile)
504 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
474 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
505 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
475 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
506 if sm in ('g', 'dc') and lm != 'r':
476 if sm in ('g', 'dc') and lm != 'r':
507 # Case 1: normal file in the working copy, largefile in
477 # Case 1: normal file in the working copy, largefile in
508 # the second parent
478 # the second parent
509 usermsg = _('remote turned local normal file %s into a largefile\n'
479 usermsg = _('remote turned local normal file %s into a largefile\n'
510 'use (l)argefile or keep (n)ormal file?'
480 'use (l)argefile or keep (n)ormal file?'
511 '$$ &Largefile $$ &Normal file') % lfile
481 '$$ &Largefile $$ &Normal file') % lfile
512 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
482 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
513 actions[lfile] = ('r', None, 'replaced by standin')
483 actions[lfile] = ('r', None, 'replaced by standin')
514 actions[standin] = ('g', sargs, 'replaces standin')
484 actions[standin] = ('g', sargs, 'replaces standin')
515 else: # keep local normal file
485 else: # keep local normal file
516 actions[lfile] = ('k', None, 'replaces standin')
486 actions[lfile] = ('k', None, 'replaces standin')
517 if branchmerge:
487 if branchmerge:
518 actions[standin] = ('k', None, 'replaced by non-standin')
488 actions[standin] = ('k', None, 'replaced by non-standin')
519 else:
489 else:
520 actions[standin] = ('r', None, 'replaced by non-standin')
490 actions[standin] = ('r', None, 'replaced by non-standin')
521 elif lm in ('g', 'dc') and sm != 'r':
491 elif lm in ('g', 'dc') and sm != 'r':
522 # Case 2: largefile in the working copy, normal file in
492 # Case 2: largefile in the working copy, normal file in
523 # the second parent
493 # the second parent
524 usermsg = _('remote turned local largefile %s into a normal file\n'
494 usermsg = _('remote turned local largefile %s into a normal file\n'
525 'keep (l)argefile or use (n)ormal file?'
495 'keep (l)argefile or use (n)ormal file?'
526 '$$ &Largefile $$ &Normal file') % lfile
496 '$$ &Largefile $$ &Normal file') % lfile
527 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
497 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
528 if branchmerge:
498 if branchmerge:
529 # largefile can be restored from standin safely
499 # largefile can be restored from standin safely
530 actions[lfile] = ('k', None, 'replaced by standin')
500 actions[lfile] = ('k', None, 'replaced by standin')
531 actions[standin] = ('k', None, 'replaces standin')
501 actions[standin] = ('k', None, 'replaces standin')
532 else:
502 else:
533 # "lfile" should be marked as "removed" without
503 # "lfile" should be marked as "removed" without
534 # removal of itself
504 # removal of itself
535 actions[lfile] = ('lfmr', None,
505 actions[lfile] = ('lfmr', None,
536 'forget non-standin largefile')
506 'forget non-standin largefile')
537
507
538 # linear-merge should treat this largefile as 're-added'
508 # linear-merge should treat this largefile as 're-added'
539 actions[standin] = ('a', None, 'keep standin')
509 actions[standin] = ('a', None, 'keep standin')
540 else: # pick remote normal file
510 else: # pick remote normal file
541 actions[lfile] = ('g', largs, 'replaces standin')
511 actions[lfile] = ('g', largs, 'replaces standin')
542 actions[standin] = ('r', None, 'replaced by non-standin')
512 actions[standin] = ('r', None, 'replaced by non-standin')
543
513
544 return actions, diverge, renamedelete
514 return actions, diverge, renamedelete
545
515
546 def mergerecordupdates(orig, repo, actions, branchmerge):
516 def mergerecordupdates(orig, repo, actions, branchmerge):
547 if 'lfmr' in actions:
517 if 'lfmr' in actions:
548 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
518 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
549 for lfile, args, msg in actions['lfmr']:
519 for lfile, args, msg in actions['lfmr']:
550 # this should be executed before 'orig', to execute 'remove'
520 # this should be executed before 'orig', to execute 'remove'
551 # before all other actions
521 # before all other actions
552 repo.dirstate.remove(lfile)
522 repo.dirstate.remove(lfile)
553 # make sure lfile doesn't get synclfdirstate'd as normal
523 # make sure lfile doesn't get synclfdirstate'd as normal
554 lfdirstate.add(lfile)
524 lfdirstate.add(lfile)
555 lfdirstate.write()
525 lfdirstate.write()
556
526
557 return orig(repo, actions, branchmerge)
527 return orig(repo, actions, branchmerge)
558
528
559
529
560 # Override filemerge to prompt the user about how they wish to merge
530 # Override filemerge to prompt the user about how they wish to merge
561 # largefiles. This will handle identical edits without prompting the user.
531 # largefiles. This will handle identical edits without prompting the user.
562 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
532 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
563 if not lfutil.isstandin(orig):
533 if not lfutil.isstandin(orig):
564 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
534 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
565
535
566 ahash = fca.data().strip().lower()
536 ahash = fca.data().strip().lower()
567 dhash = fcd.data().strip().lower()
537 dhash = fcd.data().strip().lower()
568 ohash = fco.data().strip().lower()
538 ohash = fco.data().strip().lower()
569 if (ohash != ahash and
539 if (ohash != ahash and
570 ohash != dhash and
540 ohash != dhash and
571 (dhash == ahash or
541 (dhash == ahash or
572 repo.ui.promptchoice(
542 repo.ui.promptchoice(
573 _('largefile %s has a merge conflict\nancestor was %s\n'
543 _('largefile %s has a merge conflict\nancestor was %s\n'
574 'keep (l)ocal %s or\ntake (o)ther %s?'
544 'keep (l)ocal %s or\ntake (o)ther %s?'
575 '$$ &Local $$ &Other') %
545 '$$ &Local $$ &Other') %
576 (lfutil.splitstandin(orig), ahash, dhash, ohash),
546 (lfutil.splitstandin(orig), ahash, dhash, ohash),
577 0) == 1)):
547 0) == 1)):
578 repo.wwrite(fcd.path(), fco.data(), fco.flags())
548 repo.wwrite(fcd.path(), fco.data(), fco.flags())
579 return 0
549 return 0
580
550
581 def copiespathcopies(orig, ctx1, ctx2):
551 def copiespathcopies(orig, ctx1, ctx2):
582 copies = orig(ctx1, ctx2)
552 copies = orig(ctx1, ctx2)
583 updated = {}
553 updated = {}
584
554
585 for k, v in copies.iteritems():
555 for k, v in copies.iteritems():
586 updated[lfutil.splitstandin(k) or k] = lfutil.splitstandin(v) or v
556 updated[lfutil.splitstandin(k) or k] = lfutil.splitstandin(v) or v
587
557
588 return updated
558 return updated
589
559
590 # Copy first changes the matchers to match standins instead of
560 # Copy first changes the matchers to match standins instead of
591 # largefiles. Then it overrides util.copyfile in that function it
561 # largefiles. Then it overrides util.copyfile in that function it
592 # checks if the destination largefile already exists. It also keeps a
562 # checks if the destination largefile already exists. It also keeps a
593 # list of copied files so that the largefiles can be copied and the
563 # list of copied files so that the largefiles can be copied and the
594 # dirstate updated.
564 # dirstate updated.
595 def overridecopy(orig, ui, repo, pats, opts, rename=False):
565 def overridecopy(orig, ui, repo, pats, opts, rename=False):
596 # doesn't remove largefile on rename
566 # doesn't remove largefile on rename
597 if len(pats) < 2:
567 if len(pats) < 2:
598 # this isn't legal, let the original function deal with it
568 # this isn't legal, let the original function deal with it
599 return orig(ui, repo, pats, opts, rename)
569 return orig(ui, repo, pats, opts, rename)
600
570
601 # This could copy both lfiles and normal files in one command,
571 # This could copy both lfiles and normal files in one command,
602 # but we don't want to do that. First replace their matcher to
572 # but we don't want to do that. First replace their matcher to
603 # only match normal files and run it, then replace it to just
573 # only match normal files and run it, then replace it to just
604 # match largefiles and run it again.
574 # match largefiles and run it again.
605 nonormalfiles = False
575 nonormalfiles = False
606 nolfiles = False
576 nolfiles = False
607 installnormalfilesmatchfn(repo[None].manifest())
577 installnormalfilesmatchfn(repo[None].manifest())
608 try:
578 try:
609 try:
579 try:
610 result = orig(ui, repo, pats, opts, rename)
580 result = orig(ui, repo, pats, opts, rename)
611 except util.Abort, e:
581 except util.Abort, e:
612 if str(e) != _('no files to copy'):
582 if str(e) != _('no files to copy'):
613 raise e
583 raise e
614 else:
584 else:
615 nonormalfiles = True
585 nonormalfiles = True
616 result = 0
586 result = 0
617 finally:
587 finally:
618 restorematchfn()
588 restorematchfn()
619
589
620 # The first rename can cause our current working directory to be removed.
590 # The first rename can cause our current working directory to be removed.
621 # In that case there is nothing left to copy/rename so just quit.
591 # In that case there is nothing left to copy/rename so just quit.
622 try:
592 try:
623 repo.getcwd()
593 repo.getcwd()
624 except OSError:
594 except OSError:
625 return result
595 return result
626
596
627 def makestandin(relpath):
597 def makestandin(relpath):
628 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
598 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
629 return os.path.join(repo.wjoin(lfutil.standin(path)))
599 return os.path.join(repo.wjoin(lfutil.standin(path)))
630
600
631 fullpats = scmutil.expandpats(pats)
601 fullpats = scmutil.expandpats(pats)
632 dest = fullpats[-1]
602 dest = fullpats[-1]
633
603
634 if os.path.isdir(dest):
604 if os.path.isdir(dest):
635 if not os.path.isdir(makestandin(dest)):
605 if not os.path.isdir(makestandin(dest)):
636 os.makedirs(makestandin(dest))
606 os.makedirs(makestandin(dest))
637
607
638 try:
608 try:
639 try:
609 try:
640 # When we call orig below it creates the standins but we don't add
610 # When we call orig below it creates the standins but we don't add
641 # them to the dir state until later so lock during that time.
611 # them to the dir state until later so lock during that time.
642 wlock = repo.wlock()
612 wlock = repo.wlock()
643
613
644 manifest = repo[None].manifest()
614 manifest = repo[None].manifest()
645 def overridematch(ctx, pats=[], opts={}, globbed=False,
615 def overridematch(ctx, pats=[], opts={}, globbed=False,
646 default='relpath'):
616 default='relpath'):
647 newpats = []
617 newpats = []
648 # The patterns were previously mangled to add the standin
618 # The patterns were previously mangled to add the standin
649 # directory; we need to remove that now
619 # directory; we need to remove that now
650 for pat in pats:
620 for pat in pats:
651 if match_.patkind(pat) is None and lfutil.shortname in pat:
621 if match_.patkind(pat) is None and lfutil.shortname in pat:
652 newpats.append(pat.replace(lfutil.shortname, ''))
622 newpats.append(pat.replace(lfutil.shortname, ''))
653 else:
623 else:
654 newpats.append(pat)
624 newpats.append(pat)
655 match = oldmatch(ctx, newpats, opts, globbed, default)
625 match = oldmatch(ctx, newpats, opts, globbed, default)
656 m = copy.copy(match)
626 m = copy.copy(match)
657 lfile = lambda f: lfutil.standin(f) in manifest
627 lfile = lambda f: lfutil.standin(f) in manifest
658 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
628 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
659 m._fmap = set(m._files)
629 m._fmap = set(m._files)
660 origmatchfn = m.matchfn
630 origmatchfn = m.matchfn
661 m.matchfn = lambda f: (lfutil.isstandin(f) and
631 m.matchfn = lambda f: (lfutil.isstandin(f) and
662 (f in manifest) and
632 (f in manifest) and
663 origmatchfn(lfutil.splitstandin(f)) or
633 origmatchfn(lfutil.splitstandin(f)) or
664 None)
634 None)
665 return m
635 return m
666 oldmatch = installmatchfn(overridematch)
636 oldmatch = installmatchfn(overridematch)
667 listpats = []
637 listpats = []
668 for pat in pats:
638 for pat in pats:
669 if match_.patkind(pat) is not None:
639 if match_.patkind(pat) is not None:
670 listpats.append(pat)
640 listpats.append(pat)
671 else:
641 else:
672 listpats.append(makestandin(pat))
642 listpats.append(makestandin(pat))
673
643
674 try:
644 try:
675 origcopyfile = util.copyfile
645 origcopyfile = util.copyfile
676 copiedfiles = []
646 copiedfiles = []
677 def overridecopyfile(src, dest):
647 def overridecopyfile(src, dest):
678 if (lfutil.shortname in src and
648 if (lfutil.shortname in src and
679 dest.startswith(repo.wjoin(lfutil.shortname))):
649 dest.startswith(repo.wjoin(lfutil.shortname))):
680 destlfile = dest.replace(lfutil.shortname, '')
650 destlfile = dest.replace(lfutil.shortname, '')
681 if not opts['force'] and os.path.exists(destlfile):
651 if not opts['force'] and os.path.exists(destlfile):
682 raise IOError('',
652 raise IOError('',
683 _('destination largefile already exists'))
653 _('destination largefile already exists'))
684 copiedfiles.append((src, dest))
654 copiedfiles.append((src, dest))
685 origcopyfile(src, dest)
655 origcopyfile(src, dest)
686
656
687 util.copyfile = overridecopyfile
657 util.copyfile = overridecopyfile
688 result += orig(ui, repo, listpats, opts, rename)
658 result += orig(ui, repo, listpats, opts, rename)
689 finally:
659 finally:
690 util.copyfile = origcopyfile
660 util.copyfile = origcopyfile
691
661
692 lfdirstate = lfutil.openlfdirstate(ui, repo)
662 lfdirstate = lfutil.openlfdirstate(ui, repo)
693 for (src, dest) in copiedfiles:
663 for (src, dest) in copiedfiles:
694 if (lfutil.shortname in src and
664 if (lfutil.shortname in src and
695 dest.startswith(repo.wjoin(lfutil.shortname))):
665 dest.startswith(repo.wjoin(lfutil.shortname))):
696 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
666 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
697 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
667 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
698 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
668 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
699 if not os.path.isdir(destlfiledir):
669 if not os.path.isdir(destlfiledir):
700 os.makedirs(destlfiledir)
670 os.makedirs(destlfiledir)
701 if rename:
671 if rename:
702 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
672 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
703
673
704 # The file is gone, but this deletes any empty parent
674 # The file is gone, but this deletes any empty parent
705 # directories as a side-effect.
675 # directories as a side-effect.
706 util.unlinkpath(repo.wjoin(srclfile), True)
676 util.unlinkpath(repo.wjoin(srclfile), True)
707 lfdirstate.remove(srclfile)
677 lfdirstate.remove(srclfile)
708 else:
678 else:
709 util.copyfile(repo.wjoin(srclfile),
679 util.copyfile(repo.wjoin(srclfile),
710 repo.wjoin(destlfile))
680 repo.wjoin(destlfile))
711
681
712 lfdirstate.add(destlfile)
682 lfdirstate.add(destlfile)
713 lfdirstate.write()
683 lfdirstate.write()
714 except util.Abort, e:
684 except util.Abort, e:
715 if str(e) != _('no files to copy'):
685 if str(e) != _('no files to copy'):
716 raise e
686 raise e
717 else:
687 else:
718 nolfiles = True
688 nolfiles = True
719 finally:
689 finally:
720 restorematchfn()
690 restorematchfn()
721 wlock.release()
691 wlock.release()
722
692
723 if nolfiles and nonormalfiles:
693 if nolfiles and nonormalfiles:
724 raise util.Abort(_('no files to copy'))
694 raise util.Abort(_('no files to copy'))
725
695
726 return result
696 return result
727
697
728 # When the user calls revert, we have to be careful to not revert any
698 # When the user calls revert, we have to be careful to not revert any
729 # changes to other largefiles accidentally. This means we have to keep
699 # changes to other largefiles accidentally. This means we have to keep
730 # track of the largefiles that are being reverted so we only pull down
700 # track of the largefiles that are being reverted so we only pull down
731 # the necessary largefiles.
701 # the necessary largefiles.
732 #
702 #
733 # Standins are only updated (to match the hash of largefiles) before
703 # Standins are only updated (to match the hash of largefiles) before
734 # commits. Update the standins then run the original revert, changing
704 # commits. Update the standins then run the original revert, changing
735 # the matcher to hit standins instead of largefiles. Based on the
705 # the matcher to hit standins instead of largefiles. Based on the
736 # resulting standins update the largefiles.
706 # resulting standins update the largefiles.
737 def overriderevert(orig, ui, repo, ctx, parents, *pats, **opts):
707 def overriderevert(orig, ui, repo, ctx, parents, *pats, **opts):
738 # Because we put the standins in a bad state (by updating them)
708 # Because we put the standins in a bad state (by updating them)
739 # and then return them to a correct state we need to lock to
709 # and then return them to a correct state we need to lock to
740 # prevent others from changing them in their incorrect state.
710 # prevent others from changing them in their incorrect state.
741 wlock = repo.wlock()
711 wlock = repo.wlock()
742 try:
712 try:
743 lfdirstate = lfutil.openlfdirstate(ui, repo)
713 lfdirstate = lfutil.openlfdirstate(ui, repo)
744 s = lfutil.lfdirstatestatus(lfdirstate, repo)
714 s = lfutil.lfdirstatestatus(lfdirstate, repo)
745 lfdirstate.write()
715 lfdirstate.write()
746 for lfile in s.modified:
716 for lfile in s.modified:
747 lfutil.updatestandin(repo, lfutil.standin(lfile))
717 lfutil.updatestandin(repo, lfutil.standin(lfile))
748 for lfile in s.deleted:
718 for lfile in s.deleted:
749 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
719 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
750 os.unlink(repo.wjoin(lfutil.standin(lfile)))
720 os.unlink(repo.wjoin(lfutil.standin(lfile)))
751
721
752 oldstandins = lfutil.getstandinsstate(repo)
722 oldstandins = lfutil.getstandinsstate(repo)
753
723
754 def overridematch(mctx, pats=[], opts={}, globbed=False,
724 def overridematch(mctx, pats=[], opts={}, globbed=False,
755 default='relpath'):
725 default='relpath'):
756 match = oldmatch(mctx, pats, opts, globbed, default)
726 match = oldmatch(mctx, pats, opts, globbed, default)
757 m = copy.copy(match)
727 m = copy.copy(match)
758
728
759 # revert supports recursing into subrepos, and though largefiles
729 # revert supports recursing into subrepos, and though largefiles
760 # currently doesn't work correctly in that case, this match is
730 # currently doesn't work correctly in that case, this match is
761 # called, so the lfdirstate above may not be the correct one for
731 # called, so the lfdirstate above may not be the correct one for
762 # this invocation of match.
732 # this invocation of match.
763 lfdirstate = lfutil.openlfdirstate(mctx.repo().ui, mctx.repo(),
733 lfdirstate = lfutil.openlfdirstate(mctx.repo().ui, mctx.repo(),
764 False)
734 False)
765
735
766 def tostandin(f):
736 def tostandin(f):
767 standin = lfutil.standin(f)
737 standin = lfutil.standin(f)
768 if standin in ctx or standin in mctx:
738 if standin in ctx or standin in mctx:
769 return standin
739 return standin
770 elif standin in repo[None] or lfdirstate[f] == 'r':
740 elif standin in repo[None] or lfdirstate[f] == 'r':
771 return None
741 return None
772 return f
742 return f
773 m._files = [tostandin(f) for f in m._files]
743 m._files = [tostandin(f) for f in m._files]
774 m._files = [f for f in m._files if f is not None]
744 m._files = [f for f in m._files if f is not None]
775 m._fmap = set(m._files)
745 m._fmap = set(m._files)
776 origmatchfn = m.matchfn
746 origmatchfn = m.matchfn
777 def matchfn(f):
747 def matchfn(f):
778 if lfutil.isstandin(f):
748 if lfutil.isstandin(f):
779 return (origmatchfn(lfutil.splitstandin(f)) and
749 return (origmatchfn(lfutil.splitstandin(f)) and
780 (f in ctx or f in mctx))
750 (f in ctx or f in mctx))
781 return origmatchfn(f)
751 return origmatchfn(f)
782 m.matchfn = matchfn
752 m.matchfn = matchfn
783 return m
753 return m
784 oldmatch = installmatchfn(overridematch)
754 oldmatch = installmatchfn(overridematch)
785 try:
755 try:
786 orig(ui, repo, ctx, parents, *pats, **opts)
756 orig(ui, repo, ctx, parents, *pats, **opts)
787 finally:
757 finally:
788 restorematchfn()
758 restorematchfn()
789
759
790 newstandins = lfutil.getstandinsstate(repo)
760 newstandins = lfutil.getstandinsstate(repo)
791 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
761 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
792 # lfdirstate should be 'normallookup'-ed for updated files,
762 # lfdirstate should be 'normallookup'-ed for updated files,
793 # because reverting doesn't touch dirstate for 'normal' files
763 # because reverting doesn't touch dirstate for 'normal' files
794 # when target revision is explicitly specified: in such case,
764 # when target revision is explicitly specified: in such case,
795 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
765 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
796 # of target (standin) file.
766 # of target (standin) file.
797 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
767 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
798 normallookup=True)
768 normallookup=True)
799
769
800 finally:
770 finally:
801 wlock.release()
771 wlock.release()
802
772
803 # after pulling changesets, we need to take some extra care to get
773 # after pulling changesets, we need to take some extra care to get
804 # largefiles updated remotely
774 # largefiles updated remotely
805 def overridepull(orig, ui, repo, source=None, **opts):
775 def overridepull(orig, ui, repo, source=None, **opts):
806 revsprepull = len(repo)
776 revsprepull = len(repo)
807 if not source:
777 if not source:
808 source = 'default'
778 source = 'default'
809 repo.lfpullsource = source
779 repo.lfpullsource = source
810 result = orig(ui, repo, source, **opts)
780 result = orig(ui, repo, source, **opts)
811 revspostpull = len(repo)
781 revspostpull = len(repo)
812 lfrevs = opts.get('lfrev', [])
782 lfrevs = opts.get('lfrev', [])
813 if opts.get('all_largefiles'):
783 if opts.get('all_largefiles'):
814 lfrevs.append('pulled()')
784 lfrevs.append('pulled()')
815 if lfrevs and revspostpull > revsprepull:
785 if lfrevs and revspostpull > revsprepull:
816 numcached = 0
786 numcached = 0
817 repo.firstpulled = revsprepull # for pulled() revset expression
787 repo.firstpulled = revsprepull # for pulled() revset expression
818 try:
788 try:
819 for rev in scmutil.revrange(repo, lfrevs):
789 for rev in scmutil.revrange(repo, lfrevs):
820 ui.note(_('pulling largefiles for revision %s\n') % rev)
790 ui.note(_('pulling largefiles for revision %s\n') % rev)
821 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
791 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
822 numcached += len(cached)
792 numcached += len(cached)
823 finally:
793 finally:
824 del repo.firstpulled
794 del repo.firstpulled
825 ui.status(_("%d largefiles cached\n") % numcached)
795 ui.status(_("%d largefiles cached\n") % numcached)
826 return result
796 return result
827
797
828 def pulledrevsetsymbol(repo, subset, x):
798 def pulledrevsetsymbol(repo, subset, x):
829 """``pulled()``
799 """``pulled()``
830 Changesets that just has been pulled.
800 Changesets that just has been pulled.
831
801
832 Only available with largefiles from pull --lfrev expressions.
802 Only available with largefiles from pull --lfrev expressions.
833
803
834 .. container:: verbose
804 .. container:: verbose
835
805
836 Some examples:
806 Some examples:
837
807
838 - pull largefiles for all new changesets::
808 - pull largefiles for all new changesets::
839
809
840 hg pull -lfrev "pulled()"
810 hg pull -lfrev "pulled()"
841
811
842 - pull largefiles for all new branch heads::
812 - pull largefiles for all new branch heads::
843
813
844 hg pull -lfrev "head(pulled()) and not closed()"
814 hg pull -lfrev "head(pulled()) and not closed()"
845
815
846 """
816 """
847
817
848 try:
818 try:
849 firstpulled = repo.firstpulled
819 firstpulled = repo.firstpulled
850 except AttributeError:
820 except AttributeError:
851 raise util.Abort(_("pulled() only available in --lfrev"))
821 raise util.Abort(_("pulled() only available in --lfrev"))
852 return revset.baseset([r for r in subset if r >= firstpulled])
822 return revset.baseset([r for r in subset if r >= firstpulled])
853
823
854 def overrideclone(orig, ui, source, dest=None, **opts):
824 def overrideclone(orig, ui, source, dest=None, **opts):
855 d = dest
825 d = dest
856 if d is None:
826 if d is None:
857 d = hg.defaultdest(source)
827 d = hg.defaultdest(source)
858 if opts.get('all_largefiles') and not hg.islocal(d):
828 if opts.get('all_largefiles') and not hg.islocal(d):
859 raise util.Abort(_(
829 raise util.Abort(_(
860 '--all-largefiles is incompatible with non-local destination %s') %
830 '--all-largefiles is incompatible with non-local destination %s') %
861 d)
831 d)
862
832
863 return orig(ui, source, dest, **opts)
833 return orig(ui, source, dest, **opts)
864
834
865 def hgclone(orig, ui, opts, *args, **kwargs):
835 def hgclone(orig, ui, opts, *args, **kwargs):
866 result = orig(ui, opts, *args, **kwargs)
836 result = orig(ui, opts, *args, **kwargs)
867
837
868 if result is not None:
838 if result is not None:
869 sourcerepo, destrepo = result
839 sourcerepo, destrepo = result
870 repo = destrepo.local()
840 repo = destrepo.local()
871
841
872 # If largefiles is required for this repo, permanently enable it locally
842 # If largefiles is required for this repo, permanently enable it locally
873 if 'largefiles' in repo.requirements:
843 if 'largefiles' in repo.requirements:
874 fp = repo.vfs('hgrc', 'a', text=True)
844 fp = repo.vfs('hgrc', 'a', text=True)
875 try:
845 try:
876 fp.write('\n[extensions]\nlargefiles=\n')
846 fp.write('\n[extensions]\nlargefiles=\n')
877 finally:
847 finally:
878 fp.close()
848 fp.close()
879
849
880 # Caching is implicitly limited to 'rev' option, since the dest repo was
850 # Caching is implicitly limited to 'rev' option, since the dest repo was
881 # truncated at that point. The user may expect a download count with
851 # truncated at that point. The user may expect a download count with
882 # this option, so attempt whether or not this is a largefile repo.
852 # this option, so attempt whether or not this is a largefile repo.
883 if opts.get('all_largefiles'):
853 if opts.get('all_largefiles'):
884 success, missing = lfcommands.downloadlfiles(ui, repo, None)
854 success, missing = lfcommands.downloadlfiles(ui, repo, None)
885
855
886 if missing != 0:
856 if missing != 0:
887 return None
857 return None
888
858
889 return result
859 return result
890
860
891 def overriderebase(orig, ui, repo, **opts):
861 def overriderebase(orig, ui, repo, **opts):
892 if not util.safehasattr(repo, '_largefilesenabled'):
862 if not util.safehasattr(repo, '_largefilesenabled'):
893 return orig(ui, repo, **opts)
863 return orig(ui, repo, **opts)
894
864
895 resuming = opts.get('continue')
865 resuming = opts.get('continue')
896 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
866 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
897 repo._lfstatuswriters.append(lambda *msg, **opts: None)
867 repo._lfstatuswriters.append(lambda *msg, **opts: None)
898 try:
868 try:
899 return orig(ui, repo, **opts)
869 return orig(ui, repo, **opts)
900 finally:
870 finally:
901 repo._lfstatuswriters.pop()
871 repo._lfstatuswriters.pop()
902 repo._lfcommithooks.pop()
872 repo._lfcommithooks.pop()
903
873
904 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
874 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
905 prefix='', mtime=None, subrepos=None):
875 prefix='', mtime=None, subrepos=None):
906 # No need to lock because we are only reading history and
876 # No need to lock because we are only reading history and
907 # largefile caches, neither of which are modified.
877 # largefile caches, neither of which are modified.
908 lfcommands.cachelfiles(repo.ui, repo, node)
878 lfcommands.cachelfiles(repo.ui, repo, node)
909
879
910 if kind not in archival.archivers:
880 if kind not in archival.archivers:
911 raise util.Abort(_("unknown archive type '%s'") % kind)
881 raise util.Abort(_("unknown archive type '%s'") % kind)
912
882
913 ctx = repo[node]
883 ctx = repo[node]
914
884
915 if kind == 'files':
885 if kind == 'files':
916 if prefix:
886 if prefix:
917 raise util.Abort(
887 raise util.Abort(
918 _('cannot give prefix when archiving to files'))
888 _('cannot give prefix when archiving to files'))
919 else:
889 else:
920 prefix = archival.tidyprefix(dest, kind, prefix)
890 prefix = archival.tidyprefix(dest, kind, prefix)
921
891
922 def write(name, mode, islink, getdata):
892 def write(name, mode, islink, getdata):
923 if matchfn and not matchfn(name):
893 if matchfn and not matchfn(name):
924 return
894 return
925 data = getdata()
895 data = getdata()
926 if decode:
896 if decode:
927 data = repo.wwritedata(name, data)
897 data = repo.wwritedata(name, data)
928 archiver.addfile(prefix + name, mode, islink, data)
898 archiver.addfile(prefix + name, mode, islink, data)
929
899
930 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
900 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
931
901
932 if repo.ui.configbool("ui", "archivemeta", True):
902 if repo.ui.configbool("ui", "archivemeta", True):
933 def metadata():
903 def metadata():
934 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
904 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
935 hex(repo.changelog.node(0)), hex(node), ctx.branch())
905 hex(repo.changelog.node(0)), hex(node), ctx.branch())
936
906
937 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
907 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
938 if repo.tagtype(t) == 'global')
908 if repo.tagtype(t) == 'global')
939 if not tags:
909 if not tags:
940 repo.ui.pushbuffer()
910 repo.ui.pushbuffer()
941 opts = {'template': '{latesttag}\n{latesttagdistance}',
911 opts = {'template': '{latesttag}\n{latesttagdistance}',
942 'style': '', 'patch': None, 'git': None}
912 'style': '', 'patch': None, 'git': None}
943 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
913 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
944 ltags, dist = repo.ui.popbuffer().split('\n')
914 ltags, dist = repo.ui.popbuffer().split('\n')
945 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
915 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
946 tags += 'latesttagdistance: %s\n' % dist
916 tags += 'latesttagdistance: %s\n' % dist
947
917
948 return base + tags
918 return base + tags
949
919
950 write('.hg_archival.txt', 0644, False, metadata)
920 write('.hg_archival.txt', 0644, False, metadata)
951
921
952 for f in ctx:
922 for f in ctx:
953 ff = ctx.flags(f)
923 ff = ctx.flags(f)
954 getdata = ctx[f].data
924 getdata = ctx[f].data
955 if lfutil.isstandin(f):
925 if lfutil.isstandin(f):
956 path = lfutil.findfile(repo, getdata().strip())
926 path = lfutil.findfile(repo, getdata().strip())
957 if path is None:
927 if path is None:
958 raise util.Abort(
928 raise util.Abort(
959 _('largefile %s not found in repo store or system cache')
929 _('largefile %s not found in repo store or system cache')
960 % lfutil.splitstandin(f))
930 % lfutil.splitstandin(f))
961 f = lfutil.splitstandin(f)
931 f = lfutil.splitstandin(f)
962
932
963 def getdatafn():
933 def getdatafn():
964 fd = None
934 fd = None
965 try:
935 try:
966 fd = open(path, 'rb')
936 fd = open(path, 'rb')
967 return fd.read()
937 return fd.read()
968 finally:
938 finally:
969 if fd:
939 if fd:
970 fd.close()
940 fd.close()
971
941
972 getdata = getdatafn
942 getdata = getdatafn
973 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
943 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
974
944
975 if subrepos:
945 if subrepos:
976 for subpath in sorted(ctx.substate):
946 for subpath in sorted(ctx.substate):
977 sub = ctx.sub(subpath)
947 sub = ctx.sub(subpath)
978 submatch = match_.narrowmatcher(subpath, matchfn)
948 submatch = match_.narrowmatcher(subpath, matchfn)
979 sub.archive(archiver, prefix, submatch)
949 sub.archive(archiver, prefix, submatch)
980
950
981 archiver.done()
951 archiver.done()
982
952
983 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None):
953 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None):
984 repo._get(repo._state + ('hg',))
954 repo._get(repo._state + ('hg',))
985 rev = repo._state[1]
955 rev = repo._state[1]
986 ctx = repo._repo[rev]
956 ctx = repo._repo[rev]
987
957
988 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
958 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
989
959
990 def write(name, mode, islink, getdata):
960 def write(name, mode, islink, getdata):
991 # At this point, the standin has been replaced with the largefile name,
961 # At this point, the standin has been replaced with the largefile name,
992 # so the normal matcher works here without the lfutil variants.
962 # so the normal matcher works here without the lfutil variants.
993 if match and not match(f):
963 if match and not match(f):
994 return
964 return
995 data = getdata()
965 data = getdata()
996
966
997 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
967 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
998
968
999 for f in ctx:
969 for f in ctx:
1000 ff = ctx.flags(f)
970 ff = ctx.flags(f)
1001 getdata = ctx[f].data
971 getdata = ctx[f].data
1002 if lfutil.isstandin(f):
972 if lfutil.isstandin(f):
1003 path = lfutil.findfile(repo._repo, getdata().strip())
973 path = lfutil.findfile(repo._repo, getdata().strip())
1004 if path is None:
974 if path is None:
1005 raise util.Abort(
975 raise util.Abort(
1006 _('largefile %s not found in repo store or system cache')
976 _('largefile %s not found in repo store or system cache')
1007 % lfutil.splitstandin(f))
977 % lfutil.splitstandin(f))
1008 f = lfutil.splitstandin(f)
978 f = lfutil.splitstandin(f)
1009
979
1010 def getdatafn():
980 def getdatafn():
1011 fd = None
981 fd = None
1012 try:
982 try:
1013 fd = open(os.path.join(prefix, path), 'rb')
983 fd = open(os.path.join(prefix, path), 'rb')
1014 return fd.read()
984 return fd.read()
1015 finally:
985 finally:
1016 if fd:
986 if fd:
1017 fd.close()
987 fd.close()
1018
988
1019 getdata = getdatafn
989 getdata = getdatafn
1020
990
1021 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
991 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
1022
992
1023 for subpath in sorted(ctx.substate):
993 for subpath in sorted(ctx.substate):
1024 sub = ctx.sub(subpath)
994 sub = ctx.sub(subpath)
1025 submatch = match_.narrowmatcher(subpath, match)
995 submatch = match_.narrowmatcher(subpath, match)
1026 sub.archive(archiver, os.path.join(prefix, repo._path) + '/', submatch)
996 sub.archive(archiver, os.path.join(prefix, repo._path) + '/', submatch)
1027
997
1028 # If a largefile is modified, the change is not reflected in its
998 # If a largefile is modified, the change is not reflected in its
1029 # standin until a commit. cmdutil.bailifchanged() raises an exception
999 # standin until a commit. cmdutil.bailifchanged() raises an exception
1030 # if the repo has uncommitted changes. Wrap it to also check if
1000 # if the repo has uncommitted changes. Wrap it to also check if
1031 # largefiles were changed. This is used by bisect, backout and fetch.
1001 # largefiles were changed. This is used by bisect, backout and fetch.
1032 def overridebailifchanged(orig, repo, *args, **kwargs):
1002 def overridebailifchanged(orig, repo, *args, **kwargs):
1033 orig(repo, *args, **kwargs)
1003 orig(repo, *args, **kwargs)
1034 repo.lfstatus = True
1004 repo.lfstatus = True
1035 s = repo.status()
1005 s = repo.status()
1036 repo.lfstatus = False
1006 repo.lfstatus = False
1037 if s.modified or s.added or s.removed or s.deleted:
1007 if s.modified or s.added or s.removed or s.deleted:
1038 raise util.Abort(_('uncommitted changes'))
1008 raise util.Abort(_('uncommitted changes'))
1039
1009
1040 def cmdutilforget(orig, ui, repo, match, prefix, explicitonly):
1010 def cmdutilforget(orig, ui, repo, match, prefix, explicitonly):
1041 normalmatcher = composenormalfilematcher(match, repo[None].manifest())
1011 normalmatcher = composenormalfilematcher(match, repo[None].manifest())
1042 bad, forgot = orig(ui, repo, normalmatcher, prefix, explicitonly)
1012 bad, forgot = orig(ui, repo, normalmatcher, prefix, explicitonly)
1043 m = composelargefilematcher(match, repo[None].manifest())
1013 m = composelargefilematcher(match, repo[None].manifest())
1044
1014
1045 try:
1015 try:
1046 repo.lfstatus = True
1016 repo.lfstatus = True
1047 s = repo.status(match=m, clean=True)
1017 s = repo.status(match=m, clean=True)
1048 finally:
1018 finally:
1049 repo.lfstatus = False
1019 repo.lfstatus = False
1050 forget = sorted(s.modified + s.added + s.deleted + s.clean)
1020 forget = sorted(s.modified + s.added + s.deleted + s.clean)
1051 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
1021 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
1052
1022
1053 for f in forget:
1023 for f in forget:
1054 if lfutil.standin(f) not in repo.dirstate and not \
1024 if lfutil.standin(f) not in repo.dirstate and not \
1055 repo.wvfs.isdir(lfutil.standin(f)):
1025 repo.wvfs.isdir(lfutil.standin(f)):
1056 ui.warn(_('not removing %s: file is already untracked\n')
1026 ui.warn(_('not removing %s: file is already untracked\n')
1057 % m.rel(f))
1027 % m.rel(f))
1058 bad.append(f)
1028 bad.append(f)
1059
1029
1060 for f in forget:
1030 for f in forget:
1061 if ui.verbose or not m.exact(f):
1031 if ui.verbose or not m.exact(f):
1062 ui.status(_('removing %s\n') % m.rel(f))
1032 ui.status(_('removing %s\n') % m.rel(f))
1063
1033
1064 # Need to lock because standin files are deleted then removed from the
1034 # Need to lock because standin files are deleted then removed from the
1065 # repository and we could race in-between.
1035 # repository and we could race in-between.
1066 wlock = repo.wlock()
1036 wlock = repo.wlock()
1067 try:
1037 try:
1068 lfdirstate = lfutil.openlfdirstate(ui, repo)
1038 lfdirstate = lfutil.openlfdirstate(ui, repo)
1069 for f in forget:
1039 for f in forget:
1070 if lfdirstate[f] == 'a':
1040 if lfdirstate[f] == 'a':
1071 lfdirstate.drop(f)
1041 lfdirstate.drop(f)
1072 else:
1042 else:
1073 lfdirstate.remove(f)
1043 lfdirstate.remove(f)
1074 lfdirstate.write()
1044 lfdirstate.write()
1075 standins = [lfutil.standin(f) for f in forget]
1045 standins = [lfutil.standin(f) for f in forget]
1076 for f in standins:
1046 for f in standins:
1077 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1047 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1078 rejected = repo[None].forget(standins)
1048 rejected = repo[None].forget(standins)
1079 finally:
1049 finally:
1080 wlock.release()
1050 wlock.release()
1081
1051
1082 bad.extend(f for f in rejected if f in m.files())
1052 bad.extend(f for f in rejected if f in m.files())
1083 forgot.extend(f for f in forget if f not in rejected)
1053 forgot.extend(f for f in forget if f not in rejected)
1084 return bad, forgot
1054 return bad, forgot
1085
1055
1086 def _getoutgoings(repo, other, missing, addfunc):
1056 def _getoutgoings(repo, other, missing, addfunc):
1087 """get pairs of filename and largefile hash in outgoing revisions
1057 """get pairs of filename and largefile hash in outgoing revisions
1088 in 'missing'.
1058 in 'missing'.
1089
1059
1090 largefiles already existing on 'other' repository are ignored.
1060 largefiles already existing on 'other' repository are ignored.
1091
1061
1092 'addfunc' is invoked with each unique pairs of filename and
1062 'addfunc' is invoked with each unique pairs of filename and
1093 largefile hash value.
1063 largefile hash value.
1094 """
1064 """
1095 knowns = set()
1065 knowns = set()
1096 lfhashes = set()
1066 lfhashes = set()
1097 def dedup(fn, lfhash):
1067 def dedup(fn, lfhash):
1098 k = (fn, lfhash)
1068 k = (fn, lfhash)
1099 if k not in knowns:
1069 if k not in knowns:
1100 knowns.add(k)
1070 knowns.add(k)
1101 lfhashes.add(lfhash)
1071 lfhashes.add(lfhash)
1102 lfutil.getlfilestoupload(repo, missing, dedup)
1072 lfutil.getlfilestoupload(repo, missing, dedup)
1103 if lfhashes:
1073 if lfhashes:
1104 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1074 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1105 for fn, lfhash in knowns:
1075 for fn, lfhash in knowns:
1106 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1076 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1107 addfunc(fn, lfhash)
1077 addfunc(fn, lfhash)
1108
1078
1109 def outgoinghook(ui, repo, other, opts, missing):
1079 def outgoinghook(ui, repo, other, opts, missing):
1110 if opts.pop('large', None):
1080 if opts.pop('large', None):
1111 lfhashes = set()
1081 lfhashes = set()
1112 if ui.debugflag:
1082 if ui.debugflag:
1113 toupload = {}
1083 toupload = {}
1114 def addfunc(fn, lfhash):
1084 def addfunc(fn, lfhash):
1115 if fn not in toupload:
1085 if fn not in toupload:
1116 toupload[fn] = []
1086 toupload[fn] = []
1117 toupload[fn].append(lfhash)
1087 toupload[fn].append(lfhash)
1118 lfhashes.add(lfhash)
1088 lfhashes.add(lfhash)
1119 def showhashes(fn):
1089 def showhashes(fn):
1120 for lfhash in sorted(toupload[fn]):
1090 for lfhash in sorted(toupload[fn]):
1121 ui.debug(' %s\n' % (lfhash))
1091 ui.debug(' %s\n' % (lfhash))
1122 else:
1092 else:
1123 toupload = set()
1093 toupload = set()
1124 def addfunc(fn, lfhash):
1094 def addfunc(fn, lfhash):
1125 toupload.add(fn)
1095 toupload.add(fn)
1126 lfhashes.add(lfhash)
1096 lfhashes.add(lfhash)
1127 def showhashes(fn):
1097 def showhashes(fn):
1128 pass
1098 pass
1129 _getoutgoings(repo, other, missing, addfunc)
1099 _getoutgoings(repo, other, missing, addfunc)
1130
1100
1131 if not toupload:
1101 if not toupload:
1132 ui.status(_('largefiles: no files to upload\n'))
1102 ui.status(_('largefiles: no files to upload\n'))
1133 else:
1103 else:
1134 ui.status(_('largefiles to upload (%d entities):\n')
1104 ui.status(_('largefiles to upload (%d entities):\n')
1135 % (len(lfhashes)))
1105 % (len(lfhashes)))
1136 for file in sorted(toupload):
1106 for file in sorted(toupload):
1137 ui.status(lfutil.splitstandin(file) + '\n')
1107 ui.status(lfutil.splitstandin(file) + '\n')
1138 showhashes(file)
1108 showhashes(file)
1139 ui.status('\n')
1109 ui.status('\n')
1140
1110
1141 def summaryremotehook(ui, repo, opts, changes):
1111 def summaryremotehook(ui, repo, opts, changes):
1142 largeopt = opts.get('large', False)
1112 largeopt = opts.get('large', False)
1143 if changes is None:
1113 if changes is None:
1144 if largeopt:
1114 if largeopt:
1145 return (False, True) # only outgoing check is needed
1115 return (False, True) # only outgoing check is needed
1146 else:
1116 else:
1147 return (False, False)
1117 return (False, False)
1148 elif largeopt:
1118 elif largeopt:
1149 url, branch, peer, outgoing = changes[1]
1119 url, branch, peer, outgoing = changes[1]
1150 if peer is None:
1120 if peer is None:
1151 # i18n: column positioning for "hg summary"
1121 # i18n: column positioning for "hg summary"
1152 ui.status(_('largefiles: (no remote repo)\n'))
1122 ui.status(_('largefiles: (no remote repo)\n'))
1153 return
1123 return
1154
1124
1155 toupload = set()
1125 toupload = set()
1156 lfhashes = set()
1126 lfhashes = set()
1157 def addfunc(fn, lfhash):
1127 def addfunc(fn, lfhash):
1158 toupload.add(fn)
1128 toupload.add(fn)
1159 lfhashes.add(lfhash)
1129 lfhashes.add(lfhash)
1160 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1130 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1161
1131
1162 if not toupload:
1132 if not toupload:
1163 # i18n: column positioning for "hg summary"
1133 # i18n: column positioning for "hg summary"
1164 ui.status(_('largefiles: (no files to upload)\n'))
1134 ui.status(_('largefiles: (no files to upload)\n'))
1165 else:
1135 else:
1166 # i18n: column positioning for "hg summary"
1136 # i18n: column positioning for "hg summary"
1167 ui.status(_('largefiles: %d entities for %d files to upload\n')
1137 ui.status(_('largefiles: %d entities for %d files to upload\n')
1168 % (len(lfhashes), len(toupload)))
1138 % (len(lfhashes), len(toupload)))
1169
1139
1170 def overridesummary(orig, ui, repo, *pats, **opts):
1140 def overridesummary(orig, ui, repo, *pats, **opts):
1171 try:
1141 try:
1172 repo.lfstatus = True
1142 repo.lfstatus = True
1173 orig(ui, repo, *pats, **opts)
1143 orig(ui, repo, *pats, **opts)
1174 finally:
1144 finally:
1175 repo.lfstatus = False
1145 repo.lfstatus = False
1176
1146
1177 def scmutiladdremove(orig, repo, matcher, prefix, opts={}, dry_run=None,
1147 def scmutiladdremove(orig, repo, matcher, prefix, opts={}, dry_run=None,
1178 similarity=None):
1148 similarity=None):
1179 if not lfutil.islfilesrepo(repo):
1149 if not lfutil.islfilesrepo(repo):
1180 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1150 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1181 # Get the list of missing largefiles so we can remove them
1151 # Get the list of missing largefiles so we can remove them
1182 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1152 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1183 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1153 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1184 False, False, False)
1154 False, False, False)
1185
1155
1186 # Call into the normal remove code, but the removing of the standin, we want
1156 # Call into the normal remove code, but the removing of the standin, we want
1187 # to have handled by original addremove. Monkey patching here makes sure
1157 # to have handled by original addremove. Monkey patching here makes sure
1188 # we don't remove the standin in the largefiles code, preventing a very
1158 # we don't remove the standin in the largefiles code, preventing a very
1189 # confused state later.
1159 # confused state later.
1190 if s.deleted:
1160 if s.deleted:
1191 m = copy.copy(matcher)
1161 m = copy.copy(matcher)
1192
1162
1193 # The m._files and m._map attributes are not changed to the deleted list
1163 # The m._files and m._map attributes are not changed to the deleted list
1194 # because that affects the m.exact() test, which in turn governs whether
1164 # because that affects the m.exact() test, which in turn governs whether
1195 # or not the file name is printed, and how. Simply limit the original
1165 # or not the file name is printed, and how. Simply limit the original
1196 # matches to those in the deleted status list.
1166 # matches to those in the deleted status list.
1197 matchfn = m.matchfn
1167 matchfn = m.matchfn
1198 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1168 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1199
1169
1200 removelargefiles(repo.ui, repo, True, m, **opts)
1170 removelargefiles(repo.ui, repo, True, m, **opts)
1201 # Call into the normal add code, and any files that *should* be added as
1171 # Call into the normal add code, and any files that *should* be added as
1202 # largefiles will be
1172 # largefiles will be
1203 added, bad = addlargefiles(repo.ui, repo, True, matcher, **opts)
1173 added, bad = addlargefiles(repo.ui, repo, True, matcher, **opts)
1204 # Now that we've handled largefiles, hand off to the original addremove
1174 # Now that we've handled largefiles, hand off to the original addremove
1205 # function to take care of the rest. Make sure it doesn't do anything with
1175 # function to take care of the rest. Make sure it doesn't do anything with
1206 # largefiles by passing a matcher that will ignore them.
1176 # largefiles by passing a matcher that will ignore them.
1207 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1177 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1208 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1178 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1209
1179
1210 # Calling purge with --all will cause the largefiles to be deleted.
1180 # Calling purge with --all will cause the largefiles to be deleted.
1211 # Override repo.status to prevent this from happening.
1181 # Override repo.status to prevent this from happening.
1212 def overridepurge(orig, ui, repo, *dirs, **opts):
1182 def overridepurge(orig, ui, repo, *dirs, **opts):
1213 # XXX Monkey patching a repoview will not work. The assigned attribute will
1183 # XXX Monkey patching a repoview will not work. The assigned attribute will
1214 # be set on the unfiltered repo, but we will only lookup attributes in the
1184 # be set on the unfiltered repo, but we will only lookup attributes in the
1215 # unfiltered repo if the lookup in the repoview object itself fails. As the
1185 # unfiltered repo if the lookup in the repoview object itself fails. As the
1216 # monkey patched method exists on the repoview class the lookup will not
1186 # monkey patched method exists on the repoview class the lookup will not
1217 # fail. As a result, the original version will shadow the monkey patched
1187 # fail. As a result, the original version will shadow the monkey patched
1218 # one, defeating the monkey patch.
1188 # one, defeating the monkey patch.
1219 #
1189 #
1220 # As a work around we use an unfiltered repo here. We should do something
1190 # As a work around we use an unfiltered repo here. We should do something
1221 # cleaner instead.
1191 # cleaner instead.
1222 repo = repo.unfiltered()
1192 repo = repo.unfiltered()
1223 oldstatus = repo.status
1193 oldstatus = repo.status
1224 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1194 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1225 clean=False, unknown=False, listsubrepos=False):
1195 clean=False, unknown=False, listsubrepos=False):
1226 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1196 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1227 listsubrepos)
1197 listsubrepos)
1228 lfdirstate = lfutil.openlfdirstate(ui, repo)
1198 lfdirstate = lfutil.openlfdirstate(ui, repo)
1229 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1199 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1230 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1200 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1231 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1201 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1232 unknown, ignored, r.clean)
1202 unknown, ignored, r.clean)
1233 repo.status = overridestatus
1203 repo.status = overridestatus
1234 orig(ui, repo, *dirs, **opts)
1204 orig(ui, repo, *dirs, **opts)
1235 repo.status = oldstatus
1205 repo.status = oldstatus
1236 def overriderollback(orig, ui, repo, **opts):
1206 def overriderollback(orig, ui, repo, **opts):
1237 wlock = repo.wlock()
1207 wlock = repo.wlock()
1238 try:
1208 try:
1239 before = repo.dirstate.parents()
1209 before = repo.dirstate.parents()
1240 orphans = set(f for f in repo.dirstate
1210 orphans = set(f for f in repo.dirstate
1241 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1211 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1242 result = orig(ui, repo, **opts)
1212 result = orig(ui, repo, **opts)
1243 after = repo.dirstate.parents()
1213 after = repo.dirstate.parents()
1244 if before == after:
1214 if before == after:
1245 return result # no need to restore standins
1215 return result # no need to restore standins
1246
1216
1247 pctx = repo['.']
1217 pctx = repo['.']
1248 for f in repo.dirstate:
1218 for f in repo.dirstate:
1249 if lfutil.isstandin(f):
1219 if lfutil.isstandin(f):
1250 orphans.discard(f)
1220 orphans.discard(f)
1251 if repo.dirstate[f] == 'r':
1221 if repo.dirstate[f] == 'r':
1252 repo.wvfs.unlinkpath(f, ignoremissing=True)
1222 repo.wvfs.unlinkpath(f, ignoremissing=True)
1253 elif f in pctx:
1223 elif f in pctx:
1254 fctx = pctx[f]
1224 fctx = pctx[f]
1255 repo.wwrite(f, fctx.data(), fctx.flags())
1225 repo.wwrite(f, fctx.data(), fctx.flags())
1256 else:
1226 else:
1257 # content of standin is not so important in 'a',
1227 # content of standin is not so important in 'a',
1258 # 'm' or 'n' (coming from the 2nd parent) cases
1228 # 'm' or 'n' (coming from the 2nd parent) cases
1259 lfutil.writestandin(repo, f, '', False)
1229 lfutil.writestandin(repo, f, '', False)
1260 for standin in orphans:
1230 for standin in orphans:
1261 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1231 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1262
1232
1263 lfdirstate = lfutil.openlfdirstate(ui, repo)
1233 lfdirstate = lfutil.openlfdirstate(ui, repo)
1264 orphans = set(lfdirstate)
1234 orphans = set(lfdirstate)
1265 lfiles = lfutil.listlfiles(repo)
1235 lfiles = lfutil.listlfiles(repo)
1266 for file in lfiles:
1236 for file in lfiles:
1267 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1237 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1268 orphans.discard(file)
1238 orphans.discard(file)
1269 for lfile in orphans:
1239 for lfile in orphans:
1270 lfdirstate.drop(lfile)
1240 lfdirstate.drop(lfile)
1271 lfdirstate.write()
1241 lfdirstate.write()
1272 finally:
1242 finally:
1273 wlock.release()
1243 wlock.release()
1274 return result
1244 return result
1275
1245
1276 def overridetransplant(orig, ui, repo, *revs, **opts):
1246 def overridetransplant(orig, ui, repo, *revs, **opts):
1277 resuming = opts.get('continue')
1247 resuming = opts.get('continue')
1278 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1248 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1279 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1249 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1280 try:
1250 try:
1281 result = orig(ui, repo, *revs, **opts)
1251 result = orig(ui, repo, *revs, **opts)
1282 finally:
1252 finally:
1283 repo._lfstatuswriters.pop()
1253 repo._lfstatuswriters.pop()
1284 repo._lfcommithooks.pop()
1254 repo._lfcommithooks.pop()
1285 return result
1255 return result
1286
1256
1287 def overridecat(orig, ui, repo, file1, *pats, **opts):
1257 def overridecat(orig, ui, repo, file1, *pats, **opts):
1288 ctx = scmutil.revsingle(repo, opts.get('rev'))
1258 ctx = scmutil.revsingle(repo, opts.get('rev'))
1289 err = 1
1259 err = 1
1290 notbad = set()
1260 notbad = set()
1291 m = scmutil.match(ctx, (file1,) + pats, opts)
1261 m = scmutil.match(ctx, (file1,) + pats, opts)
1292 origmatchfn = m.matchfn
1262 origmatchfn = m.matchfn
1293 def lfmatchfn(f):
1263 def lfmatchfn(f):
1294 if origmatchfn(f):
1264 if origmatchfn(f):
1295 return True
1265 return True
1296 lf = lfutil.splitstandin(f)
1266 lf = lfutil.splitstandin(f)
1297 if lf is None:
1267 if lf is None:
1298 return False
1268 return False
1299 notbad.add(lf)
1269 notbad.add(lf)
1300 return origmatchfn(lf)
1270 return origmatchfn(lf)
1301 m.matchfn = lfmatchfn
1271 m.matchfn = lfmatchfn
1302 origbadfn = m.bad
1272 origbadfn = m.bad
1303 def lfbadfn(f, msg):
1273 def lfbadfn(f, msg):
1304 if not f in notbad:
1274 if not f in notbad:
1305 origbadfn(f, msg)
1275 origbadfn(f, msg)
1306 m.bad = lfbadfn
1276 m.bad = lfbadfn
1307 for f in ctx.walk(m):
1277 for f in ctx.walk(m):
1308 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1278 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1309 pathname=f)
1279 pathname=f)
1310 lf = lfutil.splitstandin(f)
1280 lf = lfutil.splitstandin(f)
1311 if lf is None or origmatchfn(f):
1281 if lf is None or origmatchfn(f):
1312 # duplicating unreachable code from commands.cat
1282 # duplicating unreachable code from commands.cat
1313 data = ctx[f].data()
1283 data = ctx[f].data()
1314 if opts.get('decode'):
1284 if opts.get('decode'):
1315 data = repo.wwritedata(f, data)
1285 data = repo.wwritedata(f, data)
1316 fp.write(data)
1286 fp.write(data)
1317 else:
1287 else:
1318 hash = lfutil.readstandin(repo, lf, ctx.rev())
1288 hash = lfutil.readstandin(repo, lf, ctx.rev())
1319 if not lfutil.inusercache(repo.ui, hash):
1289 if not lfutil.inusercache(repo.ui, hash):
1320 store = basestore._openstore(repo)
1290 store = basestore._openstore(repo)
1321 success, missing = store.get([(lf, hash)])
1291 success, missing = store.get([(lf, hash)])
1322 if len(success) != 1:
1292 if len(success) != 1:
1323 raise util.Abort(
1293 raise util.Abort(
1324 _('largefile %s is not in cache and could not be '
1294 _('largefile %s is not in cache and could not be '
1325 'downloaded') % lf)
1295 'downloaded') % lf)
1326 path = lfutil.usercachepath(repo.ui, hash)
1296 path = lfutil.usercachepath(repo.ui, hash)
1327 fpin = open(path, "rb")
1297 fpin = open(path, "rb")
1328 for chunk in util.filechunkiter(fpin, 128 * 1024):
1298 for chunk in util.filechunkiter(fpin, 128 * 1024):
1329 fp.write(chunk)
1299 fp.write(chunk)
1330 fpin.close()
1300 fpin.close()
1331 fp.close()
1301 fp.close()
1332 err = 0
1302 err = 0
1333 return err
1303 return err
1334
1304
1335 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1305 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1336 *args, **kwargs):
1306 *args, **kwargs):
1337 wlock = repo.wlock()
1307 wlock = repo.wlock()
1338 try:
1308 try:
1339 # branch | | |
1309 # branch | | |
1340 # merge | force | partial | action
1310 # merge | force | partial | action
1341 # -------+-------+---------+--------------
1311 # -------+-------+---------+--------------
1342 # x | x | x | linear-merge
1312 # x | x | x | linear-merge
1343 # o | x | x | branch-merge
1313 # o | x | x | branch-merge
1344 # x | o | x | overwrite (as clean update)
1314 # x | o | x | overwrite (as clean update)
1345 # o | o | x | force-branch-merge (*1)
1315 # o | o | x | force-branch-merge (*1)
1346 # x | x | o | (*)
1316 # x | x | o | (*)
1347 # o | x | o | (*)
1317 # o | x | o | (*)
1348 # x | o | o | overwrite (as revert)
1318 # x | o | o | overwrite (as revert)
1349 # o | o | o | (*)
1319 # o | o | o | (*)
1350 #
1320 #
1351 # (*) don't care
1321 # (*) don't care
1352 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1322 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1353
1323
1354 linearmerge = not branchmerge and not force and not partial
1324 linearmerge = not branchmerge and not force and not partial
1355
1325
1356 if linearmerge or (branchmerge and force and not partial):
1326 if linearmerge or (branchmerge and force and not partial):
1357 # update standins for linear-merge or force-branch-merge,
1327 # update standins for linear-merge or force-branch-merge,
1358 # because largefiles in the working directory may be modified
1328 # because largefiles in the working directory may be modified
1359 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1329 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1360 unsure, s = lfdirstate.status(match_.always(repo.root,
1330 unsure, s = lfdirstate.status(match_.always(repo.root,
1361 repo.getcwd()),
1331 repo.getcwd()),
1362 [], False, False, False)
1332 [], False, False, False)
1363 pctx = repo['.']
1333 pctx = repo['.']
1364 for lfile in unsure + s.modified:
1334 for lfile in unsure + s.modified:
1365 lfileabs = repo.wvfs.join(lfile)
1335 lfileabs = repo.wvfs.join(lfile)
1366 if not os.path.exists(lfileabs):
1336 if not os.path.exists(lfileabs):
1367 continue
1337 continue
1368 lfhash = lfutil.hashrepofile(repo, lfile)
1338 lfhash = lfutil.hashrepofile(repo, lfile)
1369 standin = lfutil.standin(lfile)
1339 standin = lfutil.standin(lfile)
1370 lfutil.writestandin(repo, standin, lfhash,
1340 lfutil.writestandin(repo, standin, lfhash,
1371 lfutil.getexecutable(lfileabs))
1341 lfutil.getexecutable(lfileabs))
1372 if (standin in pctx and
1342 if (standin in pctx and
1373 lfhash == lfutil.readstandin(repo, lfile, '.')):
1343 lfhash == lfutil.readstandin(repo, lfile, '.')):
1374 lfdirstate.normal(lfile)
1344 lfdirstate.normal(lfile)
1375 for lfile in s.added:
1345 for lfile in s.added:
1376 lfutil.updatestandin(repo, lfutil.standin(lfile))
1346 lfutil.updatestandin(repo, lfutil.standin(lfile))
1377 lfdirstate.write()
1347 lfdirstate.write()
1378
1348
1379 if linearmerge:
1349 if linearmerge:
1380 # Only call updatelfiles on the standins that have changed
1350 # Only call updatelfiles on the standins that have changed
1381 # to save time
1351 # to save time
1382 oldstandins = lfutil.getstandinsstate(repo)
1352 oldstandins = lfutil.getstandinsstate(repo)
1383
1353
1384 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1354 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1385
1355
1386 filelist = None
1356 filelist = None
1387 if linearmerge:
1357 if linearmerge:
1388 newstandins = lfutil.getstandinsstate(repo)
1358 newstandins = lfutil.getstandinsstate(repo)
1389 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1359 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1390
1360
1391 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1361 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1392 normallookup=partial, checked=linearmerge)
1362 normallookup=partial, checked=linearmerge)
1393
1363
1394 return result
1364 return result
1395 finally:
1365 finally:
1396 wlock.release()
1366 wlock.release()
1397
1367
1398 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1368 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1399 result = orig(repo, files, *args, **kwargs)
1369 result = orig(repo, files, *args, **kwargs)
1400
1370
1401 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1371 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1402 if filelist:
1372 if filelist:
1403 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1373 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1404 printmessage=False, normallookup=True)
1374 printmessage=False, normallookup=True)
1405
1375
1406 return result
1376 return result
@@ -1,170 +1,168 b''
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''setup for largefiles extension: uisetup'''
9 '''setup for largefiles extension: uisetup'''
10
10
11 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
11 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
12 httppeer, merge, scmutil, sshpeer, wireproto, revset, subrepo, copies
12 httppeer, merge, scmutil, sshpeer, wireproto, revset, subrepo, copies
13 from mercurial.i18n import _
13 from mercurial.i18n import _
14 from mercurial.hgweb import hgweb_mod, webcommands
14 from mercurial.hgweb import hgweb_mod, webcommands
15
15
16 import overrides
16 import overrides
17 import proto
17 import proto
18
18
19 def uisetup(ui):
19 def uisetup(ui):
20 # Disable auto-status for some commands which assume that all
20 # Disable auto-status for some commands which assume that all
21 # files in the result are under Mercurial's control
21 # files in the result are under Mercurial's control
22
22
23 entry = extensions.wrapcommand(commands.table, 'add',
23 entry = extensions.wrapcommand(commands.table, 'add',
24 overrides.overrideadd)
24 overrides.overrideadd)
25 addopt = [('', 'large', None, _('add as largefile')),
25 addopt = [('', 'large', None, _('add as largefile')),
26 ('', 'normal', None, _('add as normal file')),
26 ('', 'normal', None, _('add as normal file')),
27 ('', 'lfsize', '', _('add all files above this size '
27 ('', 'lfsize', '', _('add all files above this size '
28 '(in megabytes) as largefiles '
28 '(in megabytes) as largefiles '
29 '(default: 10)'))]
29 '(default: 10)'))]
30 entry[1].extend(addopt)
30 entry[1].extend(addopt)
31
31
32 # The scmutil function is called both by the (trivial) addremove command,
32 # The scmutil function is called both by the (trivial) addremove command,
33 # and in the process of handling commit -A (issue3542)
33 # and in the process of handling commit -A (issue3542)
34 entry = extensions.wrapfunction(scmutil, 'addremove',
34 entry = extensions.wrapfunction(scmutil, 'addremove',
35 overrides.scmutiladdremove)
35 overrides.scmutiladdremove)
36 extensions.wrapfunction(cmdutil, 'add', overrides.cmdutiladd)
36 extensions.wrapfunction(cmdutil, 'add', overrides.cmdutiladd)
37 extensions.wrapfunction(cmdutil, 'remove', overrides.cmdutilremove)
37 extensions.wrapfunction(cmdutil, 'remove', overrides.cmdutilremove)
38 extensions.wrapfunction(cmdutil, 'forget', overrides.cmdutilforget)
38 extensions.wrapfunction(cmdutil, 'forget', overrides.cmdutilforget)
39
39
40 extensions.wrapfunction(copies, 'pathcopies', overrides.copiespathcopies)
40 extensions.wrapfunction(copies, 'pathcopies', overrides.copiespathcopies)
41
41
42 # Subrepos call status function
42 # Subrepos call status function
43 entry = extensions.wrapcommand(commands.table, 'status',
43 entry = extensions.wrapcommand(commands.table, 'status',
44 overrides.overridestatus)
44 overrides.overridestatus)
45 entry = extensions.wrapfunction(subrepo.hgsubrepo, 'status',
45 entry = extensions.wrapfunction(subrepo.hgsubrepo, 'status',
46 overrides.overridestatusfn)
46 overrides.overridestatusfn)
47
47
48 entry = extensions.wrapcommand(commands.table, 'log',
48 entry = extensions.wrapcommand(commands.table, 'log',
49 overrides.overridelog)
49 overrides.overridelog)
50 entry = extensions.wrapcommand(commands.table, 'rollback',
50 entry = extensions.wrapcommand(commands.table, 'rollback',
51 overrides.overriderollback)
51 overrides.overriderollback)
52 entry = extensions.wrapcommand(commands.table, 'verify',
52 entry = extensions.wrapcommand(commands.table, 'verify',
53 overrides.overrideverify)
53 overrides.overrideverify)
54
54
55 verifyopt = [('', 'large', None,
55 verifyopt = [('', 'large', None,
56 _('verify that all largefiles in current revision exists')),
56 _('verify that all largefiles in current revision exists')),
57 ('', 'lfa', None,
57 ('', 'lfa', None,
58 _('verify largefiles in all revisions, not just current')),
58 _('verify largefiles in all revisions, not just current')),
59 ('', 'lfc', None,
59 ('', 'lfc', None,
60 _('verify local largefile contents, not just existence'))]
60 _('verify local largefile contents, not just existence'))]
61 entry[1].extend(verifyopt)
61 entry[1].extend(verifyopt)
62
62
63 entry = extensions.wrapcommand(commands.table, 'debugstate',
63 entry = extensions.wrapcommand(commands.table, 'debugstate',
64 overrides.overridedebugstate)
64 overrides.overridedebugstate)
65 debugstateopt = [('', 'large', None, _('display largefiles dirstate'))]
65 debugstateopt = [('', 'large', None, _('display largefiles dirstate'))]
66 entry[1].extend(debugstateopt)
66 entry[1].extend(debugstateopt)
67
67
68 outgoing = lambda orgfunc, *arg, **kwargs: orgfunc(*arg, **kwargs)
68 outgoing = lambda orgfunc, *arg, **kwargs: orgfunc(*arg, **kwargs)
69 entry = extensions.wrapcommand(commands.table, 'outgoing', outgoing)
69 entry = extensions.wrapcommand(commands.table, 'outgoing', outgoing)
70 outgoingopt = [('', 'large', None, _('display outgoing largefiles'))]
70 outgoingopt = [('', 'large', None, _('display outgoing largefiles'))]
71 entry[1].extend(outgoingopt)
71 entry[1].extend(outgoingopt)
72 cmdutil.outgoinghooks.add('largefiles', overrides.outgoinghook)
72 cmdutil.outgoinghooks.add('largefiles', overrides.outgoinghook)
73 entry = extensions.wrapcommand(commands.table, 'summary',
73 entry = extensions.wrapcommand(commands.table, 'summary',
74 overrides.overridesummary)
74 overrides.overridesummary)
75 summaryopt = [('', 'large', None, _('display outgoing largefiles'))]
75 summaryopt = [('', 'large', None, _('display outgoing largefiles'))]
76 entry[1].extend(summaryopt)
76 entry[1].extend(summaryopt)
77 cmdutil.summaryremotehooks.add('largefiles', overrides.summaryremotehook)
77 cmdutil.summaryremotehooks.add('largefiles', overrides.summaryremotehook)
78
78
79 entry = extensions.wrapcommand(commands.table, 'update',
80 overrides.overrideupdate)
81 entry = extensions.wrapcommand(commands.table, 'pull',
79 entry = extensions.wrapcommand(commands.table, 'pull',
82 overrides.overridepull)
80 overrides.overridepull)
83 pullopt = [('', 'all-largefiles', None,
81 pullopt = [('', 'all-largefiles', None,
84 _('download all pulled versions of largefiles (DEPRECATED)')),
82 _('download all pulled versions of largefiles (DEPRECATED)')),
85 ('', 'lfrev', [],
83 ('', 'lfrev', [],
86 _('download largefiles for these revisions'), _('REV'))]
84 _('download largefiles for these revisions'), _('REV'))]
87 entry[1].extend(pullopt)
85 entry[1].extend(pullopt)
88 revset.symbols['pulled'] = overrides.pulledrevsetsymbol
86 revset.symbols['pulled'] = overrides.pulledrevsetsymbol
89
87
90 entry = extensions.wrapcommand(commands.table, 'clone',
88 entry = extensions.wrapcommand(commands.table, 'clone',
91 overrides.overrideclone)
89 overrides.overrideclone)
92 cloneopt = [('', 'all-largefiles', None,
90 cloneopt = [('', 'all-largefiles', None,
93 _('download all versions of all largefiles'))]
91 _('download all versions of all largefiles'))]
94 entry[1].extend(cloneopt)
92 entry[1].extend(cloneopt)
95 entry = extensions.wrapfunction(hg, 'clone', overrides.hgclone)
93 entry = extensions.wrapfunction(hg, 'clone', overrides.hgclone)
96
94
97 entry = extensions.wrapcommand(commands.table, 'cat',
95 entry = extensions.wrapcommand(commands.table, 'cat',
98 overrides.overridecat)
96 overrides.overridecat)
99 entry = extensions.wrapfunction(merge, '_checkunknownfile',
97 entry = extensions.wrapfunction(merge, '_checkunknownfile',
100 overrides.overridecheckunknownfile)
98 overrides.overridecheckunknownfile)
101 entry = extensions.wrapfunction(merge, 'calculateupdates',
99 entry = extensions.wrapfunction(merge, 'calculateupdates',
102 overrides.overridecalculateupdates)
100 overrides.overridecalculateupdates)
103 entry = extensions.wrapfunction(merge, 'recordupdates',
101 entry = extensions.wrapfunction(merge, 'recordupdates',
104 overrides.mergerecordupdates)
102 overrides.mergerecordupdates)
105 entry = extensions.wrapfunction(merge, 'update',
103 entry = extensions.wrapfunction(merge, 'update',
106 overrides.mergeupdate)
104 overrides.mergeupdate)
107 entry = extensions.wrapfunction(filemerge, 'filemerge',
105 entry = extensions.wrapfunction(filemerge, 'filemerge',
108 overrides.overridefilemerge)
106 overrides.overridefilemerge)
109 entry = extensions.wrapfunction(cmdutil, 'copy',
107 entry = extensions.wrapfunction(cmdutil, 'copy',
110 overrides.overridecopy)
108 overrides.overridecopy)
111
109
112 # Summary calls dirty on the subrepos
110 # Summary calls dirty on the subrepos
113 entry = extensions.wrapfunction(subrepo.hgsubrepo, 'dirty',
111 entry = extensions.wrapfunction(subrepo.hgsubrepo, 'dirty',
114 overrides.overridedirty)
112 overrides.overridedirty)
115
113
116 entry = extensions.wrapfunction(cmdutil, 'revert',
114 entry = extensions.wrapfunction(cmdutil, 'revert',
117 overrides.overriderevert)
115 overrides.overriderevert)
118
116
119 extensions.wrapfunction(archival, 'archive', overrides.overridearchive)
117 extensions.wrapfunction(archival, 'archive', overrides.overridearchive)
120 extensions.wrapfunction(subrepo.hgsubrepo, 'archive',
118 extensions.wrapfunction(subrepo.hgsubrepo, 'archive',
121 overrides.hgsubrepoarchive)
119 overrides.hgsubrepoarchive)
122 extensions.wrapfunction(cmdutil, 'bailifchanged',
120 extensions.wrapfunction(cmdutil, 'bailifchanged',
123 overrides.overridebailifchanged)
121 overrides.overridebailifchanged)
124
122
125 extensions.wrapfunction(scmutil, 'marktouched',
123 extensions.wrapfunction(scmutil, 'marktouched',
126 overrides.scmutilmarktouched)
124 overrides.scmutilmarktouched)
127
125
128 # create the new wireproto commands ...
126 # create the new wireproto commands ...
129 wireproto.commands['putlfile'] = (proto.putlfile, 'sha')
127 wireproto.commands['putlfile'] = (proto.putlfile, 'sha')
130 wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
128 wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
131 wireproto.commands['statlfile'] = (proto.statlfile, 'sha')
129 wireproto.commands['statlfile'] = (proto.statlfile, 'sha')
132
130
133 # ... and wrap some existing ones
131 # ... and wrap some existing ones
134 wireproto.commands['capabilities'] = (proto.capabilities, '')
132 wireproto.commands['capabilities'] = (proto.capabilities, '')
135 wireproto.commands['heads'] = (proto.heads, '')
133 wireproto.commands['heads'] = (proto.heads, '')
136 wireproto.commands['lheads'] = (wireproto.heads, '')
134 wireproto.commands['lheads'] = (wireproto.heads, '')
137
135
138 # make putlfile behave the same as push and {get,stat}lfile behave
136 # make putlfile behave the same as push and {get,stat}lfile behave
139 # the same as pull w.r.t. permissions checks
137 # the same as pull w.r.t. permissions checks
140 hgweb_mod.perms['putlfile'] = 'push'
138 hgweb_mod.perms['putlfile'] = 'push'
141 hgweb_mod.perms['getlfile'] = 'pull'
139 hgweb_mod.perms['getlfile'] = 'pull'
142 hgweb_mod.perms['statlfile'] = 'pull'
140 hgweb_mod.perms['statlfile'] = 'pull'
143
141
144 extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
142 extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
145
143
146 # the hello wireproto command uses wireproto.capabilities, so it won't see
144 # the hello wireproto command uses wireproto.capabilities, so it won't see
147 # our largefiles capability unless we replace the actual function as well.
145 # our largefiles capability unless we replace the actual function as well.
148 proto.capabilitiesorig = wireproto.capabilities
146 proto.capabilitiesorig = wireproto.capabilities
149 wireproto.capabilities = proto.capabilities
147 wireproto.capabilities = proto.capabilities
150
148
151 # can't do this in reposetup because it needs to have happened before
149 # can't do this in reposetup because it needs to have happened before
152 # wirerepo.__init__ is called
150 # wirerepo.__init__ is called
153 proto.ssholdcallstream = sshpeer.sshpeer._callstream
151 proto.ssholdcallstream = sshpeer.sshpeer._callstream
154 proto.httpoldcallstream = httppeer.httppeer._callstream
152 proto.httpoldcallstream = httppeer.httppeer._callstream
155 sshpeer.sshpeer._callstream = proto.sshrepocallstream
153 sshpeer.sshpeer._callstream = proto.sshrepocallstream
156 httppeer.httppeer._callstream = proto.httprepocallstream
154 httppeer.httppeer._callstream = proto.httprepocallstream
157
155
158 # override some extensions' stuff as well
156 # override some extensions' stuff as well
159 for name, module in extensions.extensions():
157 for name, module in extensions.extensions():
160 if name == 'purge':
158 if name == 'purge':
161 extensions.wrapcommand(getattr(module, 'cmdtable'), 'purge',
159 extensions.wrapcommand(getattr(module, 'cmdtable'), 'purge',
162 overrides.overridepurge)
160 overrides.overridepurge)
163 if name == 'rebase':
161 if name == 'rebase':
164 extensions.wrapcommand(getattr(module, 'cmdtable'), 'rebase',
162 extensions.wrapcommand(getattr(module, 'cmdtable'), 'rebase',
165 overrides.overriderebase)
163 overrides.overriderebase)
166 extensions.wrapfunction(module, 'rebase',
164 extensions.wrapfunction(module, 'rebase',
167 overrides.overriderebase)
165 overrides.overriderebase)
168 if name == 'transplant':
166 if name == 'transplant':
169 extensions.wrapcommand(getattr(module, 'cmdtable'), 'transplant',
167 extensions.wrapcommand(getattr(module, 'cmdtable'), 'transplant',
170 overrides.overridetransplant)
168 overrides.overridetransplant)
General Comments 0
You need to be logged in to leave comments. Login now