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