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