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