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