##// END OF EJS Templates
largefiles: only update changed largefiles when transplanting
Na'Tosha Bard -
r16246:169525f8 default
parent child Browse files
Show More
@@ -1,965 +1,968 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 node, archival, error, merge
15 node, archival, error, merge
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
22
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24
24
25 def installnormalfilesmatchfn(manifest):
25 def installnormalfilesmatchfn(manifest):
26 '''overrides scmutil.match so that the matcher it returns will ignore all
26 '''overrides scmutil.match so that the matcher it returns will ignore all
27 largefiles'''
27 largefiles'''
28 oldmatch = None # for the closure
28 oldmatch = None # for the closure
29 def override_match(ctx, pats=[], opts={}, globbed=False,
29 def override_match(ctx, pats=[], opts={}, globbed=False,
30 default='relpath'):
30 default='relpath'):
31 match = oldmatch(ctx, pats, opts, globbed, default)
31 match = oldmatch(ctx, pats, opts, globbed, default)
32 m = copy.copy(match)
32 m = copy.copy(match)
33 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
33 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
34 manifest)
34 manifest)
35 m._files = filter(notlfile, m._files)
35 m._files = filter(notlfile, m._files)
36 m._fmap = set(m._files)
36 m._fmap = set(m._files)
37 orig_matchfn = m.matchfn
37 orig_matchfn = m.matchfn
38 m.matchfn = lambda f: notlfile(f) and orig_matchfn(f) or None
38 m.matchfn = lambda f: notlfile(f) and orig_matchfn(f) or None
39 return m
39 return m
40 oldmatch = installmatchfn(override_match)
40 oldmatch = installmatchfn(override_match)
41
41
42 def installmatchfn(f):
42 def installmatchfn(f):
43 oldmatch = scmutil.match
43 oldmatch = scmutil.match
44 setattr(f, 'oldmatch', oldmatch)
44 setattr(f, 'oldmatch', oldmatch)
45 scmutil.match = f
45 scmutil.match = f
46 return oldmatch
46 return oldmatch
47
47
48 def restorematchfn():
48 def restorematchfn():
49 '''restores scmutil.match to what it was before installnormalfilesmatchfn
49 '''restores scmutil.match to what it was before installnormalfilesmatchfn
50 was called. no-op if scmutil.match is its original function.
50 was called. no-op if scmutil.match is its original function.
51
51
52 Note that n calls to installnormalfilesmatchfn will require n calls to
52 Note that n calls to installnormalfilesmatchfn will require n calls to
53 restore matchfn to reverse'''
53 restore matchfn to reverse'''
54 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
54 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
55
55
56 def add_largefiles(ui, repo, *pats, **opts):
56 def add_largefiles(ui, repo, *pats, **opts):
57 large = opts.pop('large', None)
57 large = opts.pop('large', None)
58 lfsize = lfutil.getminsize(
58 lfsize = lfutil.getminsize(
59 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
59 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
60
60
61 lfmatcher = None
61 lfmatcher = None
62 if lfutil.islfilesrepo(repo):
62 if lfutil.islfilesrepo(repo):
63 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
63 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
64 if lfpats:
64 if lfpats:
65 lfmatcher = match_.match(repo.root, '', list(lfpats))
65 lfmatcher = match_.match(repo.root, '', list(lfpats))
66
66
67 lfnames = []
67 lfnames = []
68 m = scmutil.match(repo[None], pats, opts)
68 m = scmutil.match(repo[None], pats, opts)
69 m.bad = lambda x, y: None
69 m.bad = lambda x, y: None
70 wctx = repo[None]
70 wctx = repo[None]
71 for f in repo.walk(m):
71 for f in repo.walk(m):
72 exact = m.exact(f)
72 exact = m.exact(f)
73 lfile = lfutil.standin(f) in wctx
73 lfile = lfutil.standin(f) in wctx
74 nfile = f in wctx
74 nfile = f in wctx
75 exists = lfile or nfile
75 exists = lfile or nfile
76
76
77 # Don't warn the user when they attempt to add a normal tracked file.
77 # Don't warn the user when they attempt to add a normal tracked file.
78 # The normal add code will do that for us.
78 # The normal add code will do that for us.
79 if exact and exists:
79 if exact and exists:
80 if lfile:
80 if lfile:
81 ui.warn(_('%s already a largefile\n') % f)
81 ui.warn(_('%s already a largefile\n') % f)
82 continue
82 continue
83
83
84 if exact or not exists:
84 if exact or not exists:
85 abovemin = (lfsize and
85 abovemin = (lfsize and
86 os.lstat(repo.wjoin(f)).st_size >= lfsize * 1024 * 1024)
86 os.lstat(repo.wjoin(f)).st_size >= lfsize * 1024 * 1024)
87 if large or abovemin or (lfmatcher and lfmatcher(f)):
87 if large or abovemin or (lfmatcher and lfmatcher(f)):
88 lfnames.append(f)
88 lfnames.append(f)
89 if ui.verbose or not exact:
89 if ui.verbose or not exact:
90 ui.status(_('adding %s as a largefile\n') % m.rel(f))
90 ui.status(_('adding %s as a largefile\n') % m.rel(f))
91
91
92 bad = []
92 bad = []
93 standins = []
93 standins = []
94
94
95 # Need to lock, otherwise there could be a race condition between
95 # Need to lock, otherwise there could be a race condition between
96 # when standins are created and added to the repo.
96 # when standins are created and added to the repo.
97 wlock = repo.wlock()
97 wlock = repo.wlock()
98 try:
98 try:
99 if not opts.get('dry_run'):
99 if not opts.get('dry_run'):
100 lfdirstate = lfutil.openlfdirstate(ui, repo)
100 lfdirstate = lfutil.openlfdirstate(ui, repo)
101 for f in lfnames:
101 for f in lfnames:
102 standinname = lfutil.standin(f)
102 standinname = lfutil.standin(f)
103 lfutil.writestandin(repo, standinname, hash='',
103 lfutil.writestandin(repo, standinname, hash='',
104 executable=lfutil.getexecutable(repo.wjoin(f)))
104 executable=lfutil.getexecutable(repo.wjoin(f)))
105 standins.append(standinname)
105 standins.append(standinname)
106 if lfdirstate[f] == 'r':
106 if lfdirstate[f] == 'r':
107 lfdirstate.normallookup(f)
107 lfdirstate.normallookup(f)
108 else:
108 else:
109 lfdirstate.add(f)
109 lfdirstate.add(f)
110 lfdirstate.write()
110 lfdirstate.write()
111 bad += [lfutil.splitstandin(f)
111 bad += [lfutil.splitstandin(f)
112 for f in lfutil.repo_add(repo, standins)
112 for f in lfutil.repo_add(repo, standins)
113 if f in m.files()]
113 if f in m.files()]
114 finally:
114 finally:
115 wlock.release()
115 wlock.release()
116 return bad
116 return bad
117
117
118 def remove_largefiles(ui, repo, *pats, **opts):
118 def remove_largefiles(ui, repo, *pats, **opts):
119 after = opts.get('after')
119 after = opts.get('after')
120 if not pats and not after:
120 if not pats and not after:
121 raise util.Abort(_('no files specified'))
121 raise util.Abort(_('no files specified'))
122 m = scmutil.match(repo[None], pats, opts)
122 m = scmutil.match(repo[None], pats, opts)
123 try:
123 try:
124 repo.lfstatus = True
124 repo.lfstatus = True
125 s = repo.status(match=m, clean=True)
125 s = repo.status(match=m, clean=True)
126 finally:
126 finally:
127 repo.lfstatus = False
127 repo.lfstatus = False
128 manifest = repo[None].manifest()
128 manifest = repo[None].manifest()
129 modified, added, deleted, clean = [[f for f in list
129 modified, added, deleted, clean = [[f for f in list
130 if lfutil.standin(f) in manifest]
130 if lfutil.standin(f) in manifest]
131 for list in [s[0], s[1], s[3], s[6]]]
131 for list in [s[0], s[1], s[3], s[6]]]
132
132
133 def warn(files, reason):
133 def warn(files, reason):
134 for f in files:
134 for f in files:
135 ui.warn(_('not removing %s: %s (use forget to undo)\n')
135 ui.warn(_('not removing %s: %s (use forget to undo)\n')
136 % (m.rel(f), reason))
136 % (m.rel(f), reason))
137
137
138 if after:
138 if after:
139 remove, forget = deleted, []
139 remove, forget = deleted, []
140 warn(modified + added + clean, _('file still exists'))
140 warn(modified + added + clean, _('file still exists'))
141 else:
141 else:
142 remove, forget = deleted + clean, []
142 remove, forget = deleted + clean, []
143 warn(modified, _('file is modified'))
143 warn(modified, _('file is modified'))
144 warn(added, _('file has been marked for add'))
144 warn(added, _('file has been marked for add'))
145
145
146 for f in sorted(remove + forget):
146 for f in sorted(remove + forget):
147 if ui.verbose or not m.exact(f):
147 if ui.verbose or not m.exact(f):
148 ui.status(_('removing %s\n') % m.rel(f))
148 ui.status(_('removing %s\n') % m.rel(f))
149
149
150 # Need to lock because standin files are deleted then removed from the
150 # Need to lock because standin files are deleted then removed from the
151 # repository and we could race inbetween.
151 # repository and we could race inbetween.
152 wlock = repo.wlock()
152 wlock = repo.wlock()
153 try:
153 try:
154 lfdirstate = lfutil.openlfdirstate(ui, repo)
154 lfdirstate = lfutil.openlfdirstate(ui, repo)
155 for f in remove:
155 for f in remove:
156 if not after:
156 if not after:
157 # If this is being called by addremove, notify the user that we
157 # If this is being called by addremove, notify the user that we
158 # are removing the file.
158 # are removing the file.
159 if getattr(repo, "_isaddremove", False):
159 if getattr(repo, "_isaddremove", False):
160 ui.status(_('removing %s\n') % f)
160 ui.status(_('removing %s\n') % f)
161 if os.path.exists(repo.wjoin(f)):
161 if os.path.exists(repo.wjoin(f)):
162 util.unlinkpath(repo.wjoin(f))
162 util.unlinkpath(repo.wjoin(f))
163 lfdirstate.remove(f)
163 lfdirstate.remove(f)
164 lfdirstate.write()
164 lfdirstate.write()
165 forget = [lfutil.standin(f) for f in forget]
165 forget = [lfutil.standin(f) for f in forget]
166 remove = [lfutil.standin(f) for f in remove]
166 remove = [lfutil.standin(f) for f in remove]
167 lfutil.repo_forget(repo, forget)
167 lfutil.repo_forget(repo, forget)
168 # If this is being called by addremove, let the original addremove
168 # If this is being called by addremove, let the original addremove
169 # function handle this.
169 # function handle this.
170 if not getattr(repo, "_isaddremove", False):
170 if not getattr(repo, "_isaddremove", False):
171 lfutil.repo_remove(repo, remove, unlink=True)
171 lfutil.repo_remove(repo, remove, unlink=True)
172 finally:
172 finally:
173 wlock.release()
173 wlock.release()
174
174
175 # -- Wrappers: modify existing commands --------------------------------
175 # -- Wrappers: modify existing commands --------------------------------
176
176
177 # Add works by going through the files that the user wanted to add and
177 # Add works by going through the files that the user wanted to add and
178 # checking if they should be added as largefiles. Then it makes a new
178 # checking if they should be added as largefiles. Then it makes a new
179 # matcher which matches only the normal files and runs the original
179 # matcher which matches only the normal files and runs the original
180 # version of add.
180 # version of add.
181 def override_add(orig, ui, repo, *pats, **opts):
181 def override_add(orig, ui, repo, *pats, **opts):
182 normal = opts.pop('normal')
182 normal = opts.pop('normal')
183 if normal:
183 if normal:
184 if opts.get('large'):
184 if opts.get('large'):
185 raise util.Abort(_('--normal cannot be used with --large'))
185 raise util.Abort(_('--normal cannot be used with --large'))
186 return orig(ui, repo, *pats, **opts)
186 return orig(ui, repo, *pats, **opts)
187 bad = add_largefiles(ui, repo, *pats, **opts)
187 bad = add_largefiles(ui, repo, *pats, **opts)
188 installnormalfilesmatchfn(repo[None].manifest())
188 installnormalfilesmatchfn(repo[None].manifest())
189 result = orig(ui, repo, *pats, **opts)
189 result = orig(ui, repo, *pats, **opts)
190 restorematchfn()
190 restorematchfn()
191
191
192 return (result == 1 or bad) and 1 or 0
192 return (result == 1 or bad) and 1 or 0
193
193
194 def override_remove(orig, ui, repo, *pats, **opts):
194 def override_remove(orig, ui, repo, *pats, **opts):
195 installnormalfilesmatchfn(repo[None].manifest())
195 installnormalfilesmatchfn(repo[None].manifest())
196 orig(ui, repo, *pats, **opts)
196 orig(ui, repo, *pats, **opts)
197 restorematchfn()
197 restorematchfn()
198 remove_largefiles(ui, repo, *pats, **opts)
198 remove_largefiles(ui, repo, *pats, **opts)
199
199
200 def override_status(orig, ui, repo, *pats, **opts):
200 def override_status(orig, ui, repo, *pats, **opts):
201 try:
201 try:
202 repo.lfstatus = True
202 repo.lfstatus = True
203 return orig(ui, repo, *pats, **opts)
203 return orig(ui, repo, *pats, **opts)
204 finally:
204 finally:
205 repo.lfstatus = False
205 repo.lfstatus = False
206
206
207 def override_log(orig, ui, repo, *pats, **opts):
207 def override_log(orig, ui, repo, *pats, **opts):
208 try:
208 try:
209 repo.lfstatus = True
209 repo.lfstatus = True
210 orig(ui, repo, *pats, **opts)
210 orig(ui, repo, *pats, **opts)
211 finally:
211 finally:
212 repo.lfstatus = False
212 repo.lfstatus = False
213
213
214 def override_verify(orig, ui, repo, *pats, **opts):
214 def override_verify(orig, ui, repo, *pats, **opts):
215 large = opts.pop('large', False)
215 large = opts.pop('large', False)
216 all = opts.pop('lfa', False)
216 all = opts.pop('lfa', False)
217 contents = opts.pop('lfc', False)
217 contents = opts.pop('lfc', False)
218
218
219 result = orig(ui, repo, *pats, **opts)
219 result = orig(ui, repo, *pats, **opts)
220 if large:
220 if large:
221 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
221 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
222 return result
222 return result
223
223
224 # Override needs to refresh standins so that update's normal merge
224 # Override needs to refresh standins so that update's normal merge
225 # will go through properly. Then the other update hook (overriding repo.update)
225 # will go through properly. Then the other update hook (overriding repo.update)
226 # will get the new files. Filemerge is also overriden so that the merge
226 # will get the new files. Filemerge is also overriden so that the merge
227 # will merge standins correctly.
227 # will merge standins correctly.
228 def override_update(orig, ui, repo, *pats, **opts):
228 def override_update(orig, ui, repo, *pats, **opts):
229 lfdirstate = lfutil.openlfdirstate(ui, repo)
229 lfdirstate = lfutil.openlfdirstate(ui, repo)
230 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
230 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
231 False, False)
231 False, False)
232 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
232 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
233
233
234 # Need to lock between the standins getting updated and their
234 # Need to lock between the standins getting updated and their
235 # largefiles getting updated
235 # largefiles getting updated
236 wlock = repo.wlock()
236 wlock = repo.wlock()
237 try:
237 try:
238 if opts['check']:
238 if opts['check']:
239 mod = len(modified) > 0
239 mod = len(modified) > 0
240 for lfile in unsure:
240 for lfile in unsure:
241 standin = lfutil.standin(lfile)
241 standin = lfutil.standin(lfile)
242 if repo['.'][standin].data().strip() != \
242 if repo['.'][standin].data().strip() != \
243 lfutil.hashfile(repo.wjoin(lfile)):
243 lfutil.hashfile(repo.wjoin(lfile)):
244 mod = True
244 mod = True
245 else:
245 else:
246 lfdirstate.normal(lfile)
246 lfdirstate.normal(lfile)
247 lfdirstate.write()
247 lfdirstate.write()
248 if mod:
248 if mod:
249 raise util.Abort(_('uncommitted local changes'))
249 raise util.Abort(_('uncommitted local changes'))
250 # XXX handle removed differently
250 # XXX handle removed differently
251 if not opts['clean']:
251 if not opts['clean']:
252 for lfile in unsure + modified + added:
252 for lfile in unsure + modified + added:
253 lfutil.updatestandin(repo, lfutil.standin(lfile))
253 lfutil.updatestandin(repo, lfutil.standin(lfile))
254 finally:
254 finally:
255 wlock.release()
255 wlock.release()
256 return orig(ui, repo, *pats, **opts)
256 return orig(ui, repo, *pats, **opts)
257
257
258 # Before starting the manifest merge, merge.updates will call
258 # Before starting the manifest merge, merge.updates will call
259 # _checkunknown to check if there are any files in the merged-in
259 # _checkunknown to check if there are any files in the merged-in
260 # changeset that collide with unknown files in the working copy.
260 # changeset that collide with unknown files in the working copy.
261 #
261 #
262 # The largefiles are seen as unknown, so this prevents us from merging
262 # The largefiles are seen as unknown, so this prevents us from merging
263 # in a file 'foo' if we already have a largefile with the same name.
263 # in a file 'foo' if we already have a largefile with the same name.
264 #
264 #
265 # The overridden function filters the unknown files by removing any
265 # The overridden function filters the unknown files by removing any
266 # largefiles. This makes the merge proceed and we can then handle this
266 # largefiles. This makes the merge proceed and we can then handle this
267 # case further in the overridden manifestmerge function below.
267 # case further in the overridden manifestmerge function below.
268 def override_checkunknownfile(origfn, repo, wctx, mctx, f):
268 def override_checkunknownfile(origfn, repo, wctx, mctx, f):
269 if lfutil.standin(f) in wctx:
269 if lfutil.standin(f) in wctx:
270 return False
270 return False
271 return origfn(repo, wctx, mctx, f)
271 return origfn(repo, wctx, mctx, f)
272
272
273 # The manifest merge handles conflicts on the manifest level. We want
273 # The manifest merge handles conflicts on the manifest level. We want
274 # to handle changes in largefile-ness of files at this level too.
274 # to handle changes in largefile-ness of files at this level too.
275 #
275 #
276 # The strategy is to run the original manifestmerge and then process
276 # The strategy is to run the original manifestmerge and then process
277 # the action list it outputs. There are two cases we need to deal with:
277 # the action list it outputs. There are two cases we need to deal with:
278 #
278 #
279 # 1. Normal file in p1, largefile in p2. Here the largefile is
279 # 1. Normal file in p1, largefile in p2. Here the largefile is
280 # detected via its standin file, which will enter the working copy
280 # detected via its standin file, which will enter the working copy
281 # with a "get" action. It is not "merge" since the standin is all
281 # with a "get" action. It is not "merge" since the standin is all
282 # Mercurial is concerned with at this level -- the link to the
282 # Mercurial is concerned with at this level -- the link to the
283 # existing normal file is not relevant here.
283 # existing normal file is not relevant here.
284 #
284 #
285 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
285 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
286 # since the largefile will be present in the working copy and
286 # since the largefile will be present in the working copy and
287 # different from the normal file in p2. Mercurial therefore
287 # different from the normal file in p2. Mercurial therefore
288 # triggers a merge action.
288 # triggers a merge action.
289 #
289 #
290 # In both cases, we prompt the user and emit new actions to either
290 # In both cases, we prompt the user and emit new actions to either
291 # remove the standin (if the normal file was kept) or to remove the
291 # remove the standin (if the normal file was kept) or to remove the
292 # normal file and get the standin (if the largefile was kept). The
292 # normal file and get the standin (if the largefile was kept). The
293 # default prompt answer is to use the largefile version since it was
293 # default prompt answer is to use the largefile version since it was
294 # presumably changed on purpose.
294 # presumably changed on purpose.
295 #
295 #
296 # Finally, the merge.applyupdates function will then take care of
296 # Finally, the merge.applyupdates function will then take care of
297 # writing the files into the working copy and lfcommands.updatelfiles
297 # writing the files into the working copy and lfcommands.updatelfiles
298 # will update the largefiles.
298 # will update the largefiles.
299 def override_manifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
299 def override_manifestmerge(origfn, repo, p1, p2, pa, overwrite, partial):
300 actions = origfn(repo, p1, p2, pa, overwrite, partial)
300 actions = origfn(repo, p1, p2, pa, overwrite, partial)
301 processed = []
301 processed = []
302
302
303 for action in actions:
303 for action in actions:
304 if overwrite:
304 if overwrite:
305 processed.append(action)
305 processed.append(action)
306 continue
306 continue
307 f, m = action[:2]
307 f, m = action[:2]
308
308
309 choices = (_('&Largefile'), _('&Normal file'))
309 choices = (_('&Largefile'), _('&Normal file'))
310 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
310 if m == "g" and lfutil.splitstandin(f) in p1 and f in p2:
311 # Case 1: normal file in the working copy, largefile in
311 # Case 1: normal file in the working copy, largefile in
312 # the second parent
312 # the second parent
313 lfile = lfutil.splitstandin(f)
313 lfile = lfutil.splitstandin(f)
314 standin = f
314 standin = f
315 msg = _('%s has been turned into a largefile\n'
315 msg = _('%s has been turned into a largefile\n'
316 'use (l)argefile or keep as (n)ormal file?') % lfile
316 'use (l)argefile or keep as (n)ormal file?') % lfile
317 if repo.ui.promptchoice(msg, choices, 0) == 0:
317 if repo.ui.promptchoice(msg, choices, 0) == 0:
318 processed.append((lfile, "r"))
318 processed.append((lfile, "r"))
319 processed.append((standin, "g", p2.flags(standin)))
319 processed.append((standin, "g", p2.flags(standin)))
320 else:
320 else:
321 processed.append((standin, "r"))
321 processed.append((standin, "r"))
322 elif m == "g" and lfutil.standin(f) in p1 and f in p2:
322 elif m == "g" and lfutil.standin(f) in p1 and f in p2:
323 # Case 2: largefile in the working copy, normal file in
323 # Case 2: largefile in the working copy, normal file in
324 # the second parent
324 # the second parent
325 standin = lfutil.standin(f)
325 standin = lfutil.standin(f)
326 lfile = f
326 lfile = f
327 msg = _('%s has been turned into a normal file\n'
327 msg = _('%s has been turned into a normal file\n'
328 'keep as (l)argefile or use (n)ormal file?') % lfile
328 'keep as (l)argefile or use (n)ormal file?') % lfile
329 if repo.ui.promptchoice(msg, choices, 0) == 0:
329 if repo.ui.promptchoice(msg, choices, 0) == 0:
330 processed.append((lfile, "r"))
330 processed.append((lfile, "r"))
331 else:
331 else:
332 processed.append((standin, "r"))
332 processed.append((standin, "r"))
333 processed.append((lfile, "g", p2.flags(lfile)))
333 processed.append((lfile, "g", p2.flags(lfile)))
334 else:
334 else:
335 processed.append(action)
335 processed.append(action)
336
336
337 return processed
337 return processed
338
338
339 # Override filemerge to prompt the user about how they wish to merge
339 # Override filemerge to prompt the user about how they wish to merge
340 # largefiles. This will handle identical edits, and copy/rename +
340 # largefiles. This will handle identical edits, and copy/rename +
341 # edit without prompting the user.
341 # edit without prompting the user.
342 def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca):
342 def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca):
343 # Use better variable names here. Because this is a wrapper we cannot
343 # Use better variable names here. Because this is a wrapper we cannot
344 # change the variable names in the function declaration.
344 # change the variable names in the function declaration.
345 fcdest, fcother, fcancestor = fcd, fco, fca
345 fcdest, fcother, fcancestor = fcd, fco, fca
346 if not lfutil.isstandin(orig):
346 if not lfutil.isstandin(orig):
347 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
347 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
348 else:
348 else:
349 if not fcother.cmp(fcdest): # files identical?
349 if not fcother.cmp(fcdest): # files identical?
350 return None
350 return None
351
351
352 # backwards, use working dir parent as ancestor
352 # backwards, use working dir parent as ancestor
353 if fcancestor == fcother:
353 if fcancestor == fcother:
354 fcancestor = fcdest.parents()[0]
354 fcancestor = fcdest.parents()[0]
355
355
356 if orig != fcother.path():
356 if orig != fcother.path():
357 repo.ui.status(_('merging %s and %s to %s\n')
357 repo.ui.status(_('merging %s and %s to %s\n')
358 % (lfutil.splitstandin(orig),
358 % (lfutil.splitstandin(orig),
359 lfutil.splitstandin(fcother.path()),
359 lfutil.splitstandin(fcother.path()),
360 lfutil.splitstandin(fcdest.path())))
360 lfutil.splitstandin(fcdest.path())))
361 else:
361 else:
362 repo.ui.status(_('merging %s\n')
362 repo.ui.status(_('merging %s\n')
363 % lfutil.splitstandin(fcdest.path()))
363 % lfutil.splitstandin(fcdest.path()))
364
364
365 if fcancestor.path() != fcother.path() and fcother.data() == \
365 if fcancestor.path() != fcother.path() and fcother.data() == \
366 fcancestor.data():
366 fcancestor.data():
367 return 0
367 return 0
368 if fcancestor.path() != fcdest.path() and fcdest.data() == \
368 if fcancestor.path() != fcdest.path() and fcdest.data() == \
369 fcancestor.data():
369 fcancestor.data():
370 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
370 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
371 return 0
371 return 0
372
372
373 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
373 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
374 'keep (l)ocal or take (o)ther?') %
374 'keep (l)ocal or take (o)ther?') %
375 lfutil.splitstandin(orig),
375 lfutil.splitstandin(orig),
376 (_('&Local'), _('&Other')), 0) == 0:
376 (_('&Local'), _('&Other')), 0) == 0:
377 return 0
377 return 0
378 else:
378 else:
379 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
379 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
380 return 0
380 return 0
381
381
382 # Copy first changes the matchers to match standins instead of
382 # Copy first changes the matchers to match standins instead of
383 # largefiles. Then it overrides util.copyfile in that function it
383 # largefiles. Then it overrides util.copyfile in that function it
384 # checks if the destination largefile already exists. It also keeps a
384 # checks if the destination largefile already exists. It also keeps a
385 # list of copied files so that the largefiles can be copied and the
385 # list of copied files so that the largefiles can be copied and the
386 # dirstate updated.
386 # dirstate updated.
387 def override_copy(orig, ui, repo, pats, opts, rename=False):
387 def override_copy(orig, ui, repo, pats, opts, rename=False):
388 # doesn't remove largefile on rename
388 # doesn't remove largefile on rename
389 if len(pats) < 2:
389 if len(pats) < 2:
390 # this isn't legal, let the original function deal with it
390 # this isn't legal, let the original function deal with it
391 return orig(ui, repo, pats, opts, rename)
391 return orig(ui, repo, pats, opts, rename)
392
392
393 def makestandin(relpath):
393 def makestandin(relpath):
394 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
394 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
395 return os.path.join(repo.wjoin(lfutil.standin(path)))
395 return os.path.join(repo.wjoin(lfutil.standin(path)))
396
396
397 fullpats = scmutil.expandpats(pats)
397 fullpats = scmutil.expandpats(pats)
398 dest = fullpats[-1]
398 dest = fullpats[-1]
399
399
400 if os.path.isdir(dest):
400 if os.path.isdir(dest):
401 if not os.path.isdir(makestandin(dest)):
401 if not os.path.isdir(makestandin(dest)):
402 os.makedirs(makestandin(dest))
402 os.makedirs(makestandin(dest))
403 # This could copy both lfiles and normal files in one command,
403 # This could copy both lfiles and normal files in one command,
404 # but we don't want to do that. First replace their matcher to
404 # but we don't want to do that. First replace their matcher to
405 # only match normal files and run it, then replace it to just
405 # only match normal files and run it, then replace it to just
406 # match largefiles and run it again.
406 # match largefiles and run it again.
407 nonormalfiles = False
407 nonormalfiles = False
408 nolfiles = False
408 nolfiles = False
409 try:
409 try:
410 try:
410 try:
411 installnormalfilesmatchfn(repo[None].manifest())
411 installnormalfilesmatchfn(repo[None].manifest())
412 result = orig(ui, repo, pats, opts, rename)
412 result = orig(ui, repo, pats, opts, rename)
413 except util.Abort, e:
413 except util.Abort, e:
414 if str(e) != 'no files to copy':
414 if str(e) != 'no files to copy':
415 raise e
415 raise e
416 else:
416 else:
417 nonormalfiles = True
417 nonormalfiles = True
418 result = 0
418 result = 0
419 finally:
419 finally:
420 restorematchfn()
420 restorematchfn()
421
421
422 # The first rename can cause our current working directory to be removed.
422 # The first rename can cause our current working directory to be removed.
423 # In that case there is nothing left to copy/rename so just quit.
423 # In that case there is nothing left to copy/rename so just quit.
424 try:
424 try:
425 repo.getcwd()
425 repo.getcwd()
426 except OSError:
426 except OSError:
427 return result
427 return result
428
428
429 try:
429 try:
430 try:
430 try:
431 # When we call orig below it creates the standins but we don't add them
431 # When we call orig below it creates the standins but we don't add them
432 # to the dir state until later so lock during that time.
432 # to the dir state until later so lock during that time.
433 wlock = repo.wlock()
433 wlock = repo.wlock()
434
434
435 manifest = repo[None].manifest()
435 manifest = repo[None].manifest()
436 oldmatch = None # for the closure
436 oldmatch = None # for the closure
437 def override_match(ctx, pats=[], opts={}, globbed=False,
437 def override_match(ctx, pats=[], opts={}, globbed=False,
438 default='relpath'):
438 default='relpath'):
439 newpats = []
439 newpats = []
440 # The patterns were previously mangled to add the standin
440 # The patterns were previously mangled to add the standin
441 # directory; we need to remove that now
441 # directory; we need to remove that now
442 for pat in pats:
442 for pat in pats:
443 if match_.patkind(pat) is None and lfutil.shortname in pat:
443 if match_.patkind(pat) is None and lfutil.shortname in pat:
444 newpats.append(pat.replace(lfutil.shortname, ''))
444 newpats.append(pat.replace(lfutil.shortname, ''))
445 else:
445 else:
446 newpats.append(pat)
446 newpats.append(pat)
447 match = oldmatch(ctx, newpats, opts, globbed, default)
447 match = oldmatch(ctx, newpats, opts, globbed, default)
448 m = copy.copy(match)
448 m = copy.copy(match)
449 lfile = lambda f: lfutil.standin(f) in manifest
449 lfile = lambda f: lfutil.standin(f) in manifest
450 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
450 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
451 m._fmap = set(m._files)
451 m._fmap = set(m._files)
452 orig_matchfn = m.matchfn
452 orig_matchfn = m.matchfn
453 m.matchfn = lambda f: (lfutil.isstandin(f) and
453 m.matchfn = lambda f: (lfutil.isstandin(f) and
454 (f in manifest) and
454 (f in manifest) and
455 orig_matchfn(lfutil.splitstandin(f)) or
455 orig_matchfn(lfutil.splitstandin(f)) or
456 None)
456 None)
457 return m
457 return m
458 oldmatch = installmatchfn(override_match)
458 oldmatch = installmatchfn(override_match)
459 listpats = []
459 listpats = []
460 for pat in pats:
460 for pat in pats:
461 if match_.patkind(pat) is not None:
461 if match_.patkind(pat) is not None:
462 listpats.append(pat)
462 listpats.append(pat)
463 else:
463 else:
464 listpats.append(makestandin(pat))
464 listpats.append(makestandin(pat))
465
465
466 try:
466 try:
467 origcopyfile = util.copyfile
467 origcopyfile = util.copyfile
468 copiedfiles = []
468 copiedfiles = []
469 def override_copyfile(src, dest):
469 def override_copyfile(src, dest):
470 if (lfutil.shortname in src and
470 if (lfutil.shortname in src and
471 dest.startswith(repo.wjoin(lfutil.shortname))):
471 dest.startswith(repo.wjoin(lfutil.shortname))):
472 destlfile = dest.replace(lfutil.shortname, '')
472 destlfile = dest.replace(lfutil.shortname, '')
473 if not opts['force'] and os.path.exists(destlfile):
473 if not opts['force'] and os.path.exists(destlfile):
474 raise IOError('',
474 raise IOError('',
475 _('destination largefile already exists'))
475 _('destination largefile already exists'))
476 copiedfiles.append((src, dest))
476 copiedfiles.append((src, dest))
477 origcopyfile(src, dest)
477 origcopyfile(src, dest)
478
478
479 util.copyfile = override_copyfile
479 util.copyfile = override_copyfile
480 result += orig(ui, repo, listpats, opts, rename)
480 result += orig(ui, repo, listpats, opts, rename)
481 finally:
481 finally:
482 util.copyfile = origcopyfile
482 util.copyfile = origcopyfile
483
483
484 lfdirstate = lfutil.openlfdirstate(ui, repo)
484 lfdirstate = lfutil.openlfdirstate(ui, repo)
485 for (src, dest) in copiedfiles:
485 for (src, dest) in copiedfiles:
486 if (lfutil.shortname in src and
486 if (lfutil.shortname in src and
487 dest.startswith(repo.wjoin(lfutil.shortname))):
487 dest.startswith(repo.wjoin(lfutil.shortname))):
488 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
488 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
489 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
489 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
490 destlfiledir = os.path.dirname(destlfile) or '.'
490 destlfiledir = os.path.dirname(destlfile) or '.'
491 if not os.path.isdir(destlfiledir):
491 if not os.path.isdir(destlfiledir):
492 os.makedirs(destlfiledir)
492 os.makedirs(destlfiledir)
493 if rename:
493 if rename:
494 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
494 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
495 lfdirstate.remove(srclfile)
495 lfdirstate.remove(srclfile)
496 else:
496 else:
497 util.copyfile(srclfile, destlfile)
497 util.copyfile(srclfile, destlfile)
498 lfdirstate.add(destlfile)
498 lfdirstate.add(destlfile)
499 lfdirstate.write()
499 lfdirstate.write()
500 except util.Abort, e:
500 except util.Abort, e:
501 if str(e) != 'no files to copy':
501 if str(e) != 'no files to copy':
502 raise e
502 raise e
503 else:
503 else:
504 nolfiles = True
504 nolfiles = True
505 finally:
505 finally:
506 restorematchfn()
506 restorematchfn()
507 wlock.release()
507 wlock.release()
508
508
509 if nolfiles and nonormalfiles:
509 if nolfiles and nonormalfiles:
510 raise util.Abort(_('no files to copy'))
510 raise util.Abort(_('no files to copy'))
511
511
512 return result
512 return result
513
513
514 # When the user calls revert, we have to be careful to not revert any
514 # When the user calls revert, we have to be careful to not revert any
515 # changes to other largefiles accidentally. This means we have to keep
515 # changes to other largefiles accidentally. This means we have to keep
516 # track of the largefiles that are being reverted so we only pull down
516 # track of the largefiles that are being reverted so we only pull down
517 # the necessary largefiles.
517 # the necessary largefiles.
518 #
518 #
519 # Standins are only updated (to match the hash of largefiles) before
519 # Standins are only updated (to match the hash of largefiles) before
520 # commits. Update the standins then run the original revert, changing
520 # commits. Update the standins then run the original revert, changing
521 # the matcher to hit standins instead of largefiles. Based on the
521 # the matcher to hit standins instead of largefiles. Based on the
522 # resulting standins update the largefiles. Then return the standins
522 # resulting standins update the largefiles. Then return the standins
523 # to their proper state
523 # to their proper state
524 def override_revert(orig, ui, repo, *pats, **opts):
524 def override_revert(orig, ui, repo, *pats, **opts):
525 # Because we put the standins in a bad state (by updating them)
525 # Because we put the standins in a bad state (by updating them)
526 # and then return them to a correct state we need to lock to
526 # and then return them to a correct state we need to lock to
527 # prevent others from changing them in their incorrect state.
527 # prevent others from changing them in their incorrect state.
528 wlock = repo.wlock()
528 wlock = repo.wlock()
529 try:
529 try:
530 lfdirstate = lfutil.openlfdirstate(ui, repo)
530 lfdirstate = lfutil.openlfdirstate(ui, repo)
531 (modified, added, removed, missing, unknown, ignored, clean) = \
531 (modified, added, removed, missing, unknown, ignored, clean) = \
532 lfutil.lfdirstate_status(lfdirstate, repo, repo['.'].rev())
532 lfutil.lfdirstate_status(lfdirstate, repo, repo['.'].rev())
533 for lfile in modified:
533 for lfile in modified:
534 lfutil.updatestandin(repo, lfutil.standin(lfile))
534 lfutil.updatestandin(repo, lfutil.standin(lfile))
535 for lfile in missing:
535 for lfile in missing:
536 os.unlink(repo.wjoin(lfutil.standin(lfile)))
536 os.unlink(repo.wjoin(lfutil.standin(lfile)))
537
537
538 try:
538 try:
539 ctx = repo[opts.get('rev')]
539 ctx = repo[opts.get('rev')]
540 oldmatch = None # for the closure
540 oldmatch = None # for the closure
541 def override_match(ctx, pats=[], opts={}, globbed=False,
541 def override_match(ctx, pats=[], opts={}, globbed=False,
542 default='relpath'):
542 default='relpath'):
543 match = oldmatch(ctx, pats, opts, globbed, default)
543 match = oldmatch(ctx, pats, opts, globbed, default)
544 m = copy.copy(match)
544 m = copy.copy(match)
545 def tostandin(f):
545 def tostandin(f):
546 if lfutil.standin(f) in ctx:
546 if lfutil.standin(f) in ctx:
547 return lfutil.standin(f)
547 return lfutil.standin(f)
548 elif lfutil.standin(f) in repo[None]:
548 elif lfutil.standin(f) in repo[None]:
549 return None
549 return None
550 return f
550 return f
551 m._files = [tostandin(f) for f in m._files]
551 m._files = [tostandin(f) for f in m._files]
552 m._files = [f for f in m._files if f is not None]
552 m._files = [f for f in m._files if f is not None]
553 m._fmap = set(m._files)
553 m._fmap = set(m._files)
554 orig_matchfn = m.matchfn
554 orig_matchfn = m.matchfn
555 def matchfn(f):
555 def matchfn(f):
556 if lfutil.isstandin(f):
556 if lfutil.isstandin(f):
557 # We need to keep track of what largefiles are being
557 # We need to keep track of what largefiles are being
558 # matched so we know which ones to update later --
558 # matched so we know which ones to update later --
559 # otherwise we accidentally revert changes to other
559 # otherwise we accidentally revert changes to other
560 # largefiles. This is repo-specific, so duckpunch the
560 # largefiles. This is repo-specific, so duckpunch the
561 # repo object to keep the list of largefiles for us
561 # repo object to keep the list of largefiles for us
562 # later.
562 # later.
563 if orig_matchfn(lfutil.splitstandin(f)) and \
563 if orig_matchfn(lfutil.splitstandin(f)) and \
564 (f in repo[None] or f in ctx):
564 (f in repo[None] or f in ctx):
565 lfileslist = getattr(repo, '_lfilestoupdate', [])
565 lfileslist = getattr(repo, '_lfilestoupdate', [])
566 lfileslist.append(lfutil.splitstandin(f))
566 lfileslist.append(lfutil.splitstandin(f))
567 repo._lfilestoupdate = lfileslist
567 repo._lfilestoupdate = lfileslist
568 return True
568 return True
569 else:
569 else:
570 return False
570 return False
571 return orig_matchfn(f)
571 return orig_matchfn(f)
572 m.matchfn = matchfn
572 m.matchfn = matchfn
573 return m
573 return m
574 oldmatch = installmatchfn(override_match)
574 oldmatch = installmatchfn(override_match)
575 scmutil.match
575 scmutil.match
576 matches = override_match(repo[None], pats, opts)
576 matches = override_match(repo[None], pats, opts)
577 orig(ui, repo, *pats, **opts)
577 orig(ui, repo, *pats, **opts)
578 finally:
578 finally:
579 restorematchfn()
579 restorematchfn()
580 lfileslist = getattr(repo, '_lfilestoupdate', [])
580 lfileslist = getattr(repo, '_lfilestoupdate', [])
581 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
581 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
582 printmessage=False)
582 printmessage=False)
583
583
584 # empty out the largefiles list so we start fresh next time
584 # empty out the largefiles list so we start fresh next time
585 repo._lfilestoupdate = []
585 repo._lfilestoupdate = []
586 for lfile in modified:
586 for lfile in modified:
587 if lfile in lfileslist:
587 if lfile in lfileslist:
588 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
588 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
589 in repo['.']:
589 in repo['.']:
590 lfutil.writestandin(repo, lfutil.standin(lfile),
590 lfutil.writestandin(repo, lfutil.standin(lfile),
591 repo['.'][lfile].data().strip(),
591 repo['.'][lfile].data().strip(),
592 'x' in repo['.'][lfile].flags())
592 'x' in repo['.'][lfile].flags())
593 lfdirstate = lfutil.openlfdirstate(ui, repo)
593 lfdirstate = lfutil.openlfdirstate(ui, repo)
594 for lfile in added:
594 for lfile in added:
595 standin = lfutil.standin(lfile)
595 standin = lfutil.standin(lfile)
596 if standin not in ctx and (standin in matches or opts.get('all')):
596 if standin not in ctx and (standin in matches or opts.get('all')):
597 if lfile in lfdirstate:
597 if lfile in lfdirstate:
598 lfdirstate.drop(lfile)
598 lfdirstate.drop(lfile)
599 util.unlinkpath(repo.wjoin(standin))
599 util.unlinkpath(repo.wjoin(standin))
600 lfdirstate.write()
600 lfdirstate.write()
601 finally:
601 finally:
602 wlock.release()
602 wlock.release()
603
603
604 def hg_update(orig, repo, node):
604 def hg_update(orig, repo, node):
605 # Only call updatelfiles the standins that have changed to save time
605 # Only call updatelfiles the standins that have changed to save time
606 oldstandins = lfutil.getstandinsstate(repo)
606 oldstandins = lfutil.getstandinsstate(repo)
607 result = orig(repo, node)
607 result = orig(repo, node)
608 newstandins = lfutil.getstandinsstate(repo)
608 newstandins = lfutil.getstandinsstate(repo)
609 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
609 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
610 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, printmessage=True)
610 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, printmessage=True)
611 return result
611 return result
612
612
613 def hg_clean(orig, repo, node, show_stats=True):
613 def hg_clean(orig, repo, node, show_stats=True):
614 result = orig(repo, node, show_stats)
614 result = orig(repo, node, show_stats)
615 lfcommands.updatelfiles(repo.ui, repo)
615 lfcommands.updatelfiles(repo.ui, repo)
616 return result
616 return result
617
617
618 def hg_merge(orig, repo, node, force=None, remind=True):
618 def hg_merge(orig, repo, node, force=None, remind=True):
619 # Mark the repo as being in the middle of a merge, so that
619 # Mark the repo as being in the middle of a merge, so that
620 # updatelfiles() will know that it needs to trust the standins in
620 # updatelfiles() will know that it needs to trust the standins in
621 # the working copy, not in the standins in the current node
621 # the working copy, not in the standins in the current node
622 repo._ismerging = True
622 repo._ismerging = True
623 try:
623 try:
624 result = orig(repo, node, force, remind)
624 result = orig(repo, node, force, remind)
625 lfcommands.updatelfiles(repo.ui, repo)
625 lfcommands.updatelfiles(repo.ui, repo)
626 finally:
626 finally:
627 repo._ismerging = False
627 repo._ismerging = False
628 return result
628 return result
629
629
630 # When we rebase a repository with remotely changed largefiles, we need to
630 # When we rebase a repository with remotely changed largefiles, we need to
631 # take some extra care so that the largefiles are correctly updated in the
631 # take some extra care so that the largefiles are correctly updated in the
632 # working copy
632 # working copy
633 def override_pull(orig, ui, repo, source=None, **opts):
633 def override_pull(orig, ui, repo, source=None, **opts):
634 if opts.get('rebase', False):
634 if opts.get('rebase', False):
635 repo._isrebasing = True
635 repo._isrebasing = True
636 try:
636 try:
637 if opts.get('update'):
637 if opts.get('update'):
638 del opts['update']
638 del opts['update']
639 ui.debug('--update and --rebase are not compatible, ignoring '
639 ui.debug('--update and --rebase are not compatible, ignoring '
640 'the update flag\n')
640 'the update flag\n')
641 del opts['rebase']
641 del opts['rebase']
642 cmdutil.bailifchanged(repo)
642 cmdutil.bailifchanged(repo)
643 revsprepull = len(repo)
643 revsprepull = len(repo)
644 origpostincoming = commands.postincoming
644 origpostincoming = commands.postincoming
645 def _dummy(*args, **kwargs):
645 def _dummy(*args, **kwargs):
646 pass
646 pass
647 commands.postincoming = _dummy
647 commands.postincoming = _dummy
648 repo.lfpullsource = source
648 repo.lfpullsource = source
649 if not source:
649 if not source:
650 source = 'default'
650 source = 'default'
651 try:
651 try:
652 result = commands.pull(ui, repo, source, **opts)
652 result = commands.pull(ui, repo, source, **opts)
653 finally:
653 finally:
654 commands.postincoming = origpostincoming
654 commands.postincoming = origpostincoming
655 revspostpull = len(repo)
655 revspostpull = len(repo)
656 if revspostpull > revsprepull:
656 if revspostpull > revsprepull:
657 result = result or rebase.rebase(ui, repo)
657 result = result or rebase.rebase(ui, repo)
658 finally:
658 finally:
659 repo._isrebasing = False
659 repo._isrebasing = False
660 else:
660 else:
661 repo.lfpullsource = source
661 repo.lfpullsource = source
662 if not source:
662 if not source:
663 source = 'default'
663 source = 'default'
664 oldheads = lfutil.getcurrentheads(repo)
664 oldheads = lfutil.getcurrentheads(repo)
665 result = orig(ui, repo, source, **opts)
665 result = orig(ui, repo, source, **opts)
666 # If we do not have the new largefiles for any new heads we pulled, we
666 # If we do not have the new largefiles for any new heads we pulled, we
667 # will run into a problem later if we try to merge or rebase with one of
667 # will run into a problem later if we try to merge or rebase with one of
668 # these heads, so cache the largefiles now direclty into the system
668 # these heads, so cache the largefiles now direclty into the system
669 # cache.
669 # cache.
670 ui.status(_("caching new largefiles\n"))
670 ui.status(_("caching new largefiles\n"))
671 numcached = 0
671 numcached = 0
672 heads = lfutil.getcurrentheads(repo)
672 heads = lfutil.getcurrentheads(repo)
673 newheads = set(heads).difference(set(oldheads))
673 newheads = set(heads).difference(set(oldheads))
674 for head in newheads:
674 for head in newheads:
675 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
675 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
676 numcached += len(cached)
676 numcached += len(cached)
677 ui.status(_("%d largefiles cached\n") % numcached)
677 ui.status(_("%d largefiles cached\n") % numcached)
678 return result
678 return result
679
679
680 def override_rebase(orig, ui, repo, **opts):
680 def override_rebase(orig, ui, repo, **opts):
681 repo._isrebasing = True
681 repo._isrebasing = True
682 try:
682 try:
683 orig(ui, repo, **opts)
683 orig(ui, repo, **opts)
684 finally:
684 finally:
685 repo._isrebasing = False
685 repo._isrebasing = False
686
686
687 def override_archive(orig, repo, dest, node, kind, decode=True, matchfn=None,
687 def override_archive(orig, repo, dest, node, kind, decode=True, matchfn=None,
688 prefix=None, mtime=None, subrepos=None):
688 prefix=None, mtime=None, subrepos=None):
689 # No need to lock because we are only reading history and
689 # No need to lock because we are only reading history and
690 # largefile caches, neither of which are modified.
690 # largefile caches, neither of which are modified.
691 lfcommands.cachelfiles(repo.ui, repo, node)
691 lfcommands.cachelfiles(repo.ui, repo, node)
692
692
693 if kind not in archival.archivers:
693 if kind not in archival.archivers:
694 raise util.Abort(_("unknown archive type '%s'") % kind)
694 raise util.Abort(_("unknown archive type '%s'") % kind)
695
695
696 ctx = repo[node]
696 ctx = repo[node]
697
697
698 if kind == 'files':
698 if kind == 'files':
699 if prefix:
699 if prefix:
700 raise util.Abort(
700 raise util.Abort(
701 _('cannot give prefix when archiving to files'))
701 _('cannot give prefix when archiving to files'))
702 else:
702 else:
703 prefix = archival.tidyprefix(dest, kind, prefix)
703 prefix = archival.tidyprefix(dest, kind, prefix)
704
704
705 def write(name, mode, islink, getdata):
705 def write(name, mode, islink, getdata):
706 if matchfn and not matchfn(name):
706 if matchfn and not matchfn(name):
707 return
707 return
708 data = getdata()
708 data = getdata()
709 if decode:
709 if decode:
710 data = repo.wwritedata(name, data)
710 data = repo.wwritedata(name, data)
711 archiver.addfile(prefix + name, mode, islink, data)
711 archiver.addfile(prefix + name, mode, islink, data)
712
712
713 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
713 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
714
714
715 if repo.ui.configbool("ui", "archivemeta", True):
715 if repo.ui.configbool("ui", "archivemeta", True):
716 def metadata():
716 def metadata():
717 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
717 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
718 hex(repo.changelog.node(0)), hex(node), ctx.branch())
718 hex(repo.changelog.node(0)), hex(node), ctx.branch())
719
719
720 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
720 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
721 if repo.tagtype(t) == 'global')
721 if repo.tagtype(t) == 'global')
722 if not tags:
722 if not tags:
723 repo.ui.pushbuffer()
723 repo.ui.pushbuffer()
724 opts = {'template': '{latesttag}\n{latesttagdistance}',
724 opts = {'template': '{latesttag}\n{latesttagdistance}',
725 'style': '', 'patch': None, 'git': None}
725 'style': '', 'patch': None, 'git': None}
726 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
726 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
727 ltags, dist = repo.ui.popbuffer().split('\n')
727 ltags, dist = repo.ui.popbuffer().split('\n')
728 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
728 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
729 tags += 'latesttagdistance: %s\n' % dist
729 tags += 'latesttagdistance: %s\n' % dist
730
730
731 return base + tags
731 return base + tags
732
732
733 write('.hg_archival.txt', 0644, False, metadata)
733 write('.hg_archival.txt', 0644, False, metadata)
734
734
735 for f in ctx:
735 for f in ctx:
736 ff = ctx.flags(f)
736 ff = ctx.flags(f)
737 getdata = ctx[f].data
737 getdata = ctx[f].data
738 if lfutil.isstandin(f):
738 if lfutil.isstandin(f):
739 path = lfutil.findfile(repo, getdata().strip())
739 path = lfutil.findfile(repo, getdata().strip())
740 if path is None:
740 if path is None:
741 raise util.Abort(
741 raise util.Abort(
742 _('largefile %s not found in repo store or system cache')
742 _('largefile %s not found in repo store or system cache')
743 % lfutil.splitstandin(f))
743 % lfutil.splitstandin(f))
744 f = lfutil.splitstandin(f)
744 f = lfutil.splitstandin(f)
745
745
746 def getdatafn():
746 def getdatafn():
747 fd = None
747 fd = None
748 try:
748 try:
749 fd = open(path, 'rb')
749 fd = open(path, 'rb')
750 return fd.read()
750 return fd.read()
751 finally:
751 finally:
752 if fd:
752 if fd:
753 fd.close()
753 fd.close()
754
754
755 getdata = getdatafn
755 getdata = getdatafn
756 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
756 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
757
757
758 if subrepos:
758 if subrepos:
759 for subpath in ctx.substate:
759 for subpath in ctx.substate:
760 sub = ctx.sub(subpath)
760 sub = ctx.sub(subpath)
761 sub.archive(repo.ui, archiver, prefix)
761 sub.archive(repo.ui, archiver, prefix)
762
762
763 archiver.done()
763 archiver.done()
764
764
765 # If a largefile is modified, the change is not reflected in its
765 # If a largefile is modified, the change is not reflected in its
766 # standin until a commit. cmdutil.bailifchanged() raises an exception
766 # standin until a commit. cmdutil.bailifchanged() raises an exception
767 # if the repo has uncommitted changes. Wrap it to also check if
767 # if the repo has uncommitted changes. Wrap it to also check if
768 # largefiles were changed. This is used by bisect and backout.
768 # largefiles were changed. This is used by bisect and backout.
769 def override_bailifchanged(orig, repo):
769 def override_bailifchanged(orig, repo):
770 orig(repo)
770 orig(repo)
771 repo.lfstatus = True
771 repo.lfstatus = True
772 modified, added, removed, deleted = repo.status()[:4]
772 modified, added, removed, deleted = repo.status()[:4]
773 repo.lfstatus = False
773 repo.lfstatus = False
774 if modified or added or removed or deleted:
774 if modified or added or removed or deleted:
775 raise util.Abort(_('outstanding uncommitted changes'))
775 raise util.Abort(_('outstanding uncommitted changes'))
776
776
777 # Fetch doesn't use cmdutil.bail_if_changed so override it to add the check
777 # Fetch doesn't use cmdutil.bail_if_changed so override it to add the check
778 def override_fetch(orig, ui, repo, *pats, **opts):
778 def override_fetch(orig, ui, repo, *pats, **opts):
779 repo.lfstatus = True
779 repo.lfstatus = True
780 modified, added, removed, deleted = repo.status()[:4]
780 modified, added, removed, deleted = repo.status()[:4]
781 repo.lfstatus = False
781 repo.lfstatus = False
782 if modified or added or removed or deleted:
782 if modified or added or removed or deleted:
783 raise util.Abort(_('outstanding uncommitted changes'))
783 raise util.Abort(_('outstanding uncommitted changes'))
784 return orig(ui, repo, *pats, **opts)
784 return orig(ui, repo, *pats, **opts)
785
785
786 def override_forget(orig, ui, repo, *pats, **opts):
786 def override_forget(orig, ui, repo, *pats, **opts):
787 installnormalfilesmatchfn(repo[None].manifest())
787 installnormalfilesmatchfn(repo[None].manifest())
788 orig(ui, repo, *pats, **opts)
788 orig(ui, repo, *pats, **opts)
789 restorematchfn()
789 restorematchfn()
790 m = scmutil.match(repo[None], pats, opts)
790 m = scmutil.match(repo[None], pats, opts)
791
791
792 try:
792 try:
793 repo.lfstatus = True
793 repo.lfstatus = True
794 s = repo.status(match=m, clean=True)
794 s = repo.status(match=m, clean=True)
795 finally:
795 finally:
796 repo.lfstatus = False
796 repo.lfstatus = False
797 forget = sorted(s[0] + s[1] + s[3] + s[6])
797 forget = sorted(s[0] + s[1] + s[3] + s[6])
798 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
798 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
799
799
800 for f in forget:
800 for f in forget:
801 if lfutil.standin(f) not in repo.dirstate and not \
801 if lfutil.standin(f) not in repo.dirstate and not \
802 os.path.isdir(m.rel(lfutil.standin(f))):
802 os.path.isdir(m.rel(lfutil.standin(f))):
803 ui.warn(_('not removing %s: file is already untracked\n')
803 ui.warn(_('not removing %s: file is already untracked\n')
804 % m.rel(f))
804 % m.rel(f))
805
805
806 for f in forget:
806 for f in forget:
807 if ui.verbose or not m.exact(f):
807 if ui.verbose or not m.exact(f):
808 ui.status(_('removing %s\n') % m.rel(f))
808 ui.status(_('removing %s\n') % m.rel(f))
809
809
810 # Need to lock because standin files are deleted then removed from the
810 # Need to lock because standin files are deleted then removed from the
811 # repository and we could race inbetween.
811 # repository and we could race inbetween.
812 wlock = repo.wlock()
812 wlock = repo.wlock()
813 try:
813 try:
814 lfdirstate = lfutil.openlfdirstate(ui, repo)
814 lfdirstate = lfutil.openlfdirstate(ui, repo)
815 for f in forget:
815 for f in forget:
816 if lfdirstate[f] == 'a':
816 if lfdirstate[f] == 'a':
817 lfdirstate.drop(f)
817 lfdirstate.drop(f)
818 else:
818 else:
819 lfdirstate.remove(f)
819 lfdirstate.remove(f)
820 lfdirstate.write()
820 lfdirstate.write()
821 lfutil.repo_remove(repo, [lfutil.standin(f) for f in forget],
821 lfutil.repo_remove(repo, [lfutil.standin(f) for f in forget],
822 unlink=True)
822 unlink=True)
823 finally:
823 finally:
824 wlock.release()
824 wlock.release()
825
825
826 def getoutgoinglfiles(ui, repo, dest=None, **opts):
826 def getoutgoinglfiles(ui, repo, dest=None, **opts):
827 dest = ui.expandpath(dest or 'default-push', dest or 'default')
827 dest = ui.expandpath(dest or 'default-push', dest or 'default')
828 dest, branches = hg.parseurl(dest, opts.get('branch'))
828 dest, branches = hg.parseurl(dest, opts.get('branch'))
829 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
829 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
830 if revs:
830 if revs:
831 revs = [repo.lookup(rev) for rev in revs]
831 revs = [repo.lookup(rev) for rev in revs]
832
832
833 remoteui = hg.remoteui
833 remoteui = hg.remoteui
834
834
835 try:
835 try:
836 remote = hg.repository(remoteui(repo, opts), dest)
836 remote = hg.repository(remoteui(repo, opts), dest)
837 except error.RepoError:
837 except error.RepoError:
838 return None
838 return None
839 o = lfutil.findoutgoing(repo, remote, False)
839 o = lfutil.findoutgoing(repo, remote, False)
840 if not o:
840 if not o:
841 return None
841 return None
842 o = repo.changelog.nodesbetween(o, revs)[0]
842 o = repo.changelog.nodesbetween(o, revs)[0]
843 if opts.get('newest_first'):
843 if opts.get('newest_first'):
844 o.reverse()
844 o.reverse()
845
845
846 toupload = set()
846 toupload = set()
847 for n in o:
847 for n in o:
848 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
848 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
849 ctx = repo[n]
849 ctx = repo[n]
850 files = set(ctx.files())
850 files = set(ctx.files())
851 if len(parents) == 2:
851 if len(parents) == 2:
852 mc = ctx.manifest()
852 mc = ctx.manifest()
853 mp1 = ctx.parents()[0].manifest()
853 mp1 = ctx.parents()[0].manifest()
854 mp2 = ctx.parents()[1].manifest()
854 mp2 = ctx.parents()[1].manifest()
855 for f in mp1:
855 for f in mp1:
856 if f not in mc:
856 if f not in mc:
857 files.add(f)
857 files.add(f)
858 for f in mp2:
858 for f in mp2:
859 if f not in mc:
859 if f not in mc:
860 files.add(f)
860 files.add(f)
861 for f in mc:
861 for f in mc:
862 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
862 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
863 files.add(f)
863 files.add(f)
864 toupload = toupload.union(
864 toupload = toupload.union(
865 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
865 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
866 return toupload
866 return toupload
867
867
868 def override_outgoing(orig, ui, repo, dest=None, **opts):
868 def override_outgoing(orig, ui, repo, dest=None, **opts):
869 orig(ui, repo, dest, **opts)
869 orig(ui, repo, dest, **opts)
870
870
871 if opts.pop('large', None):
871 if opts.pop('large', None):
872 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
872 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
873 if toupload is None:
873 if toupload is None:
874 ui.status(_('largefiles: No remote repo\n'))
874 ui.status(_('largefiles: No remote repo\n'))
875 else:
875 else:
876 ui.status(_('largefiles to upload:\n'))
876 ui.status(_('largefiles to upload:\n'))
877 for file in toupload:
877 for file in toupload:
878 ui.status(lfutil.splitstandin(file) + '\n')
878 ui.status(lfutil.splitstandin(file) + '\n')
879 ui.status('\n')
879 ui.status('\n')
880
880
881 def override_summary(orig, ui, repo, *pats, **opts):
881 def override_summary(orig, ui, repo, *pats, **opts):
882 try:
882 try:
883 repo.lfstatus = True
883 repo.lfstatus = True
884 orig(ui, repo, *pats, **opts)
884 orig(ui, repo, *pats, **opts)
885 finally:
885 finally:
886 repo.lfstatus = False
886 repo.lfstatus = False
887
887
888 if opts.pop('large', None):
888 if opts.pop('large', None):
889 toupload = getoutgoinglfiles(ui, repo, None, **opts)
889 toupload = getoutgoinglfiles(ui, repo, None, **opts)
890 if toupload is None:
890 if toupload is None:
891 ui.status(_('largefiles: No remote repo\n'))
891 ui.status(_('largefiles: No remote repo\n'))
892 else:
892 else:
893 ui.status(_('largefiles: %d to upload\n') % len(toupload))
893 ui.status(_('largefiles: %d to upload\n') % len(toupload))
894
894
895 def override_addremove(orig, ui, repo, *pats, **opts):
895 def override_addremove(orig, ui, repo, *pats, **opts):
896 # Get the list of missing largefiles so we can remove them
896 # Get the list of missing largefiles so we can remove them
897 lfdirstate = lfutil.openlfdirstate(ui, repo)
897 lfdirstate = lfutil.openlfdirstate(ui, repo)
898 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
898 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
899 False, False)
899 False, False)
900 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
900 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
901
901
902 # Call into the normal remove code, but the removing of the standin, we want
902 # Call into the normal remove code, but the removing of the standin, we want
903 # to have handled by original addremove. Monkey patching here makes sure
903 # to have handled by original addremove. Monkey patching here makes sure
904 # we don't remove the standin in the largefiles code, preventing a very
904 # we don't remove the standin in the largefiles code, preventing a very
905 # confused state later.
905 # confused state later.
906 if missing:
906 if missing:
907 repo._isaddremove = True
907 repo._isaddremove = True
908 remove_largefiles(ui, repo, *missing, **opts)
908 remove_largefiles(ui, repo, *missing, **opts)
909 repo._isaddremove = False
909 repo._isaddremove = False
910 # Call into the normal add code, and any files that *should* be added as
910 # Call into the normal add code, and any files that *should* be added as
911 # largefiles will be
911 # largefiles will be
912 add_largefiles(ui, repo, *pats, **opts)
912 add_largefiles(ui, repo, *pats, **opts)
913 # Now that we've handled largefiles, hand off to the original addremove
913 # Now that we've handled largefiles, hand off to the original addremove
914 # function to take care of the rest. Make sure it doesn't do anything with
914 # function to take care of the rest. Make sure it doesn't do anything with
915 # largefiles by installing a matcher that will ignore them.
915 # largefiles by installing a matcher that will ignore them.
916 installnormalfilesmatchfn(repo[None].manifest())
916 installnormalfilesmatchfn(repo[None].manifest())
917 result = orig(ui, repo, *pats, **opts)
917 result = orig(ui, repo, *pats, **opts)
918 restorematchfn()
918 restorematchfn()
919 return result
919 return result
920
920
921 # Calling purge with --all will cause the largefiles to be deleted.
921 # Calling purge with --all will cause the largefiles to be deleted.
922 # Override repo.status to prevent this from happening.
922 # Override repo.status to prevent this from happening.
923 def override_purge(orig, ui, repo, *dirs, **opts):
923 def override_purge(orig, ui, repo, *dirs, **opts):
924 oldstatus = repo.status
924 oldstatus = repo.status
925 def override_status(node1='.', node2=None, match=None, ignored=False,
925 def override_status(node1='.', node2=None, match=None, ignored=False,
926 clean=False, unknown=False, listsubrepos=False):
926 clean=False, unknown=False, listsubrepos=False):
927 r = oldstatus(node1, node2, match, ignored, clean, unknown,
927 r = oldstatus(node1, node2, match, ignored, clean, unknown,
928 listsubrepos)
928 listsubrepos)
929 lfdirstate = lfutil.openlfdirstate(ui, repo)
929 lfdirstate = lfutil.openlfdirstate(ui, repo)
930 modified, added, removed, deleted, unknown, ignored, clean = r
930 modified, added, removed, deleted, unknown, ignored, clean = r
931 unknown = [f for f in unknown if lfdirstate[f] == '?']
931 unknown = [f for f in unknown if lfdirstate[f] == '?']
932 ignored = [f for f in ignored if lfdirstate[f] == '?']
932 ignored = [f for f in ignored if lfdirstate[f] == '?']
933 return modified, added, removed, deleted, unknown, ignored, clean
933 return modified, added, removed, deleted, unknown, ignored, clean
934 repo.status = override_status
934 repo.status = override_status
935 orig(ui, repo, *dirs, **opts)
935 orig(ui, repo, *dirs, **opts)
936 repo.status = oldstatus
936 repo.status = oldstatus
937
937
938 def override_rollback(orig, ui, repo, **opts):
938 def override_rollback(orig, ui, repo, **opts):
939 result = orig(ui, repo, **opts)
939 result = orig(ui, repo, **opts)
940 merge.update(repo, node=None, branchmerge=False, force=True,
940 merge.update(repo, node=None, branchmerge=False, force=True,
941 partial=lfutil.isstandin)
941 partial=lfutil.isstandin)
942 wlock = repo.wlock()
942 wlock = repo.wlock()
943 try:
943 try:
944 lfdirstate = lfutil.openlfdirstate(ui, repo)
944 lfdirstate = lfutil.openlfdirstate(ui, repo)
945 lfiles = lfutil.listlfiles(repo)
945 lfiles = lfutil.listlfiles(repo)
946 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
946 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
947 for file in lfiles:
947 for file in lfiles:
948 if file in oldlfiles:
948 if file in oldlfiles:
949 lfdirstate.normallookup(file)
949 lfdirstate.normallookup(file)
950 else:
950 else:
951 lfdirstate.add(file)
951 lfdirstate.add(file)
952 lfdirstate.write()
952 lfdirstate.write()
953 finally:
953 finally:
954 wlock.release()
954 wlock.release()
955 return result
955 return result
956
956
957 def override_transplant(orig, ui, repo, *revs, **opts):
957 def override_transplant(orig, ui, repo, *revs, **opts):
958 try:
958 try:
959 oldstandins = lfutil.getstandinsstate(repo)
959 repo._istransplanting = True
960 repo._istransplanting = True
960 result = orig(ui, repo, *revs, **opts)
961 result = orig(ui, repo, *revs, **opts)
961 lfcommands.updatelfiles(ui, repo, filelist=None,
962 newstandins = lfutil.getstandinsstate(repo)
962 printmessage=False)
963 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
964 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
965 printmessage=True)
963 finally:
966 finally:
964 repo._istransplanting = False
967 repo._istransplanting = False
965 return result
968 return result
@@ -1,1007 +1,1009 b''
1 $ "$TESTDIR/hghave" symlink unix-permissions serve || exit 80
1 $ "$TESTDIR/hghave" symlink unix-permissions serve || exit 80
2 $ USERCACHE=`pwd`/cache; export USERCACHE
2 $ USERCACHE=`pwd`/cache; export USERCACHE
3 $ mkdir -p ${USERCACHE}
3 $ mkdir -p ${USERCACHE}
4 $ cat >> $HGRCPATH <<EOF
4 $ cat >> $HGRCPATH <<EOF
5 > [extensions]
5 > [extensions]
6 > largefiles=
6 > largefiles=
7 > purge=
7 > purge=
8 > rebase=
8 > rebase=
9 > transplant=
9 > transplant=
10 > [phases]
10 > [phases]
11 > publish=False
11 > publish=False
12 > [largefiles]
12 > [largefiles]
13 > minsize=2
13 > minsize=2
14 > patterns=glob:**.dat
14 > patterns=glob:**.dat
15 > usercache=${USERCACHE}
15 > usercache=${USERCACHE}
16 > [hooks]
16 > [hooks]
17 > precommit=echo "Invoking status precommit hook"; hg status
17 > precommit=echo "Invoking status precommit hook"; hg status
18 > EOF
18 > EOF
19
19
20 Create the repo with a couple of revisions of both large and normal
20 Create the repo with a couple of revisions of both large and normal
21 files, testing that status correctly shows largefiles and that summary output
21 files, testing that status correctly shows largefiles and that summary output
22 is correct.
22 is correct.
23
23
24 $ hg init a
24 $ hg init a
25 $ cd a
25 $ cd a
26 $ mkdir sub
26 $ mkdir sub
27 $ echo normal1 > normal1
27 $ echo normal1 > normal1
28 $ echo normal2 > sub/normal2
28 $ echo normal2 > sub/normal2
29 $ echo large1 > large1
29 $ echo large1 > large1
30 $ echo large2 > sub/large2
30 $ echo large2 > sub/large2
31 $ hg add normal1 sub/normal2
31 $ hg add normal1 sub/normal2
32 $ hg add --large large1 sub/large2
32 $ hg add --large large1 sub/large2
33 $ hg commit -m "add files"
33 $ hg commit -m "add files"
34 Invoking status precommit hook
34 Invoking status precommit hook
35 A large1
35 A large1
36 A normal1
36 A normal1
37 A sub/large2
37 A sub/large2
38 A sub/normal2
38 A sub/normal2
39 $ echo normal11 > normal1
39 $ echo normal11 > normal1
40 $ echo normal22 > sub/normal2
40 $ echo normal22 > sub/normal2
41 $ echo large11 > large1
41 $ echo large11 > large1
42 $ echo large22 > sub/large2
42 $ echo large22 > sub/large2
43 $ hg commit -m "edit files"
43 $ hg commit -m "edit files"
44 Invoking status precommit hook
44 Invoking status precommit hook
45 M large1
45 M large1
46 M normal1
46 M normal1
47 M sub/large2
47 M sub/large2
48 M sub/normal2
48 M sub/normal2
49 $ hg sum --large
49 $ hg sum --large
50 parent: 1:ce8896473775 tip
50 parent: 1:ce8896473775 tip
51 edit files
51 edit files
52 branch: default
52 branch: default
53 commit: (clean)
53 commit: (clean)
54 update: (current)
54 update: (current)
55 largefiles: No remote repo
55 largefiles: No remote repo
56
56
57 Commit preserved largefile contents.
57 Commit preserved largefile contents.
58
58
59 $ cat normal1
59 $ cat normal1
60 normal11
60 normal11
61 $ cat large1
61 $ cat large1
62 large11
62 large11
63 $ cat sub/normal2
63 $ cat sub/normal2
64 normal22
64 normal22
65 $ cat sub/large2
65 $ cat sub/large2
66 large22
66 large22
67
67
68 Remove both largefiles and normal files.
68 Remove both largefiles and normal files.
69
69
70 $ hg remove normal1 large1
70 $ hg remove normal1 large1
71 $ hg commit -m "remove files"
71 $ hg commit -m "remove files"
72 Invoking status precommit hook
72 Invoking status precommit hook
73 R large1
73 R large1
74 R normal1
74 R normal1
75 $ ls
75 $ ls
76 sub
76 sub
77 $ echo "testlargefile" > large1-test
77 $ echo "testlargefile" > large1-test
78 $ hg add --large large1-test
78 $ hg add --large large1-test
79 $ hg st
79 $ hg st
80 A large1-test
80 A large1-test
81 $ hg rm large1-test
81 $ hg rm large1-test
82 not removing large1-test: file has been marked for add (use forget to undo)
82 not removing large1-test: file has been marked for add (use forget to undo)
83 $ hg st
83 $ hg st
84 A large1-test
84 A large1-test
85 $ hg forget large1-test
85 $ hg forget large1-test
86 $ hg st
86 $ hg st
87 ? large1-test
87 ? large1-test
88 $ rm large1-test
88 $ rm large1-test
89
89
90 Copy both largefiles and normal files (testing that status output is correct).
90 Copy both largefiles and normal files (testing that status output is correct).
91
91
92 $ hg cp sub/normal2 normal1
92 $ hg cp sub/normal2 normal1
93 $ hg cp sub/large2 large1
93 $ hg cp sub/large2 large1
94 $ hg commit -m "copy files"
94 $ hg commit -m "copy files"
95 Invoking status precommit hook
95 Invoking status precommit hook
96 A large1
96 A large1
97 A normal1
97 A normal1
98 $ cat normal1
98 $ cat normal1
99 normal22
99 normal22
100 $ cat large1
100 $ cat large1
101 large22
101 large22
102
102
103 Test moving largefiles and verify that normal files are also unaffected.
103 Test moving largefiles and verify that normal files are also unaffected.
104
104
105 $ hg mv normal1 normal3
105 $ hg mv normal1 normal3
106 $ hg mv large1 large3
106 $ hg mv large1 large3
107 $ hg mv sub/normal2 sub/normal4
107 $ hg mv sub/normal2 sub/normal4
108 $ hg mv sub/large2 sub/large4
108 $ hg mv sub/large2 sub/large4
109 $ hg commit -m "move files"
109 $ hg commit -m "move files"
110 Invoking status precommit hook
110 Invoking status precommit hook
111 A large3
111 A large3
112 A normal3
112 A normal3
113 A sub/large4
113 A sub/large4
114 A sub/normal4
114 A sub/normal4
115 R large1
115 R large1
116 R normal1
116 R normal1
117 R sub/large2
117 R sub/large2
118 R sub/normal2
118 R sub/normal2
119 $ cat normal3
119 $ cat normal3
120 normal22
120 normal22
121 $ cat large3
121 $ cat large3
122 large22
122 large22
123 $ cat sub/normal4
123 $ cat sub/normal4
124 normal22
124 normal22
125 $ cat sub/large4
125 $ cat sub/large4
126 large22
126 large22
127
127
128 Test archiving the various revisions. These hit corner cases known with
128 Test archiving the various revisions. These hit corner cases known with
129 archiving.
129 archiving.
130
130
131 $ hg archive -r 0 ../archive0
131 $ hg archive -r 0 ../archive0
132 $ hg archive -r 1 ../archive1
132 $ hg archive -r 1 ../archive1
133 $ hg archive -r 2 ../archive2
133 $ hg archive -r 2 ../archive2
134 $ hg archive -r 3 ../archive3
134 $ hg archive -r 3 ../archive3
135 $ hg archive -r 4 ../archive4
135 $ hg archive -r 4 ../archive4
136 $ cd ../archive0
136 $ cd ../archive0
137 $ cat normal1
137 $ cat normal1
138 normal1
138 normal1
139 $ cat large1
139 $ cat large1
140 large1
140 large1
141 $ cat sub/normal2
141 $ cat sub/normal2
142 normal2
142 normal2
143 $ cat sub/large2
143 $ cat sub/large2
144 large2
144 large2
145 $ cd ../archive1
145 $ cd ../archive1
146 $ cat normal1
146 $ cat normal1
147 normal11
147 normal11
148 $ cat large1
148 $ cat large1
149 large11
149 large11
150 $ cat sub/normal2
150 $ cat sub/normal2
151 normal22
151 normal22
152 $ cat sub/large2
152 $ cat sub/large2
153 large22
153 large22
154 $ cd ../archive2
154 $ cd ../archive2
155 $ ls
155 $ ls
156 sub
156 sub
157 $ cat sub/normal2
157 $ cat sub/normal2
158 normal22
158 normal22
159 $ cat sub/large2
159 $ cat sub/large2
160 large22
160 large22
161 $ cd ../archive3
161 $ cd ../archive3
162 $ cat normal1
162 $ cat normal1
163 normal22
163 normal22
164 $ cat large1
164 $ cat large1
165 large22
165 large22
166 $ cat sub/normal2
166 $ cat sub/normal2
167 normal22
167 normal22
168 $ cat sub/large2
168 $ cat sub/large2
169 large22
169 large22
170 $ cd ../archive4
170 $ cd ../archive4
171 $ cat normal3
171 $ cat normal3
172 normal22
172 normal22
173 $ cat large3
173 $ cat large3
174 large22
174 large22
175 $ cat sub/normal4
175 $ cat sub/normal4
176 normal22
176 normal22
177 $ cat sub/large4
177 $ cat sub/large4
178 large22
178 large22
179
179
180 Commit corner case: specify files to commit.
180 Commit corner case: specify files to commit.
181
181
182 $ cd ../a
182 $ cd ../a
183 $ echo normal3 > normal3
183 $ echo normal3 > normal3
184 $ echo large3 > large3
184 $ echo large3 > large3
185 $ echo normal4 > sub/normal4
185 $ echo normal4 > sub/normal4
186 $ echo large4 > sub/large4
186 $ echo large4 > sub/large4
187 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
187 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
188 Invoking status precommit hook
188 Invoking status precommit hook
189 M large3
189 M large3
190 M normal3
190 M normal3
191 M sub/large4
191 M sub/large4
192 M sub/normal4
192 M sub/normal4
193 $ cat normal3
193 $ cat normal3
194 normal3
194 normal3
195 $ cat large3
195 $ cat large3
196 large3
196 large3
197 $ cat sub/normal4
197 $ cat sub/normal4
198 normal4
198 normal4
199 $ cat sub/large4
199 $ cat sub/large4
200 large4
200 large4
201
201
202 One more commit corner case: commit from a subdirectory.
202 One more commit corner case: commit from a subdirectory.
203
203
204 $ cd ../a
204 $ cd ../a
205 $ echo normal33 > normal3
205 $ echo normal33 > normal3
206 $ echo large33 > large3
206 $ echo large33 > large3
207 $ echo normal44 > sub/normal4
207 $ echo normal44 > sub/normal4
208 $ echo large44 > sub/large4
208 $ echo large44 > sub/large4
209 $ cd sub
209 $ cd sub
210 $ hg commit -m "edit files yet again"
210 $ hg commit -m "edit files yet again"
211 Invoking status precommit hook
211 Invoking status precommit hook
212 M large3
212 M large3
213 M normal3
213 M normal3
214 M sub/large4
214 M sub/large4
215 M sub/normal4
215 M sub/normal4
216 $ cat ../normal3
216 $ cat ../normal3
217 normal33
217 normal33
218 $ cat ../large3
218 $ cat ../large3
219 large33
219 large33
220 $ cat normal4
220 $ cat normal4
221 normal44
221 normal44
222 $ cat large4
222 $ cat large4
223 large44
223 large44
224
224
225 Committing standins is not allowed.
225 Committing standins is not allowed.
226
226
227 $ cd ..
227 $ cd ..
228 $ echo large3 > large3
228 $ echo large3 > large3
229 $ hg commit .hglf/large3 -m "try to commit standin"
229 $ hg commit .hglf/large3 -m "try to commit standin"
230 abort: file ".hglf/large3" is a largefile standin
230 abort: file ".hglf/large3" is a largefile standin
231 (commit the largefile itself instead)
231 (commit the largefile itself instead)
232 [255]
232 [255]
233
233
234 Corner cases for adding largefiles.
234 Corner cases for adding largefiles.
235
235
236 $ echo large5 > large5
236 $ echo large5 > large5
237 $ hg add --large large5
237 $ hg add --large large5
238 $ hg add --large large5
238 $ hg add --large large5
239 large5 already a largefile
239 large5 already a largefile
240 $ mkdir sub2
240 $ mkdir sub2
241 $ echo large6 > sub2/large6
241 $ echo large6 > sub2/large6
242 $ echo large7 > sub2/large7
242 $ echo large7 > sub2/large7
243 $ hg add --large sub2
243 $ hg add --large sub2
244 adding sub2/large6 as a largefile (glob)
244 adding sub2/large6 as a largefile (glob)
245 adding sub2/large7 as a largefile (glob)
245 adding sub2/large7 as a largefile (glob)
246 $ hg st
246 $ hg st
247 M large3
247 M large3
248 A large5
248 A large5
249 A sub2/large6
249 A sub2/large6
250 A sub2/large7
250 A sub2/large7
251
251
252 Config settings (pattern **.dat, minsize 2 MB) are respected.
252 Config settings (pattern **.dat, minsize 2 MB) are respected.
253
253
254 $ echo testdata > test.dat
254 $ echo testdata > test.dat
255 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
255 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
256 $ hg add
256 $ hg add
257 adding reallylarge as a largefile
257 adding reallylarge as a largefile
258 adding test.dat as a largefile
258 adding test.dat as a largefile
259
259
260 Test that minsize and --lfsize handle float values;
260 Test that minsize and --lfsize handle float values;
261 also tests that --lfsize overrides largefiles.minsize.
261 also tests that --lfsize overrides largefiles.minsize.
262 (0.250 MB = 256 kB = 262144 B)
262 (0.250 MB = 256 kB = 262144 B)
263
263
264 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
264 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
265 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
265 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
266 $ hg --config largefiles.minsize=.25 add
266 $ hg --config largefiles.minsize=.25 add
267 adding ratherlarge as a largefile
267 adding ratherlarge as a largefile
268 adding medium
268 adding medium
269 $ hg forget medium
269 $ hg forget medium
270 $ hg --config largefiles.minsize=.25 add --lfsize=.125
270 $ hg --config largefiles.minsize=.25 add --lfsize=.125
271 adding medium as a largefile
271 adding medium as a largefile
272 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
272 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
273 $ hg --config largefiles.minsize=.25 add --lfsize=.125
273 $ hg --config largefiles.minsize=.25 add --lfsize=.125
274 adding notlarge
274 adding notlarge
275 $ hg forget notlarge
275 $ hg forget notlarge
276
276
277 Test forget on largefiles.
277 Test forget on largefiles.
278
278
279 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
279 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
280 $ hg commit -m "add/edit more largefiles"
280 $ hg commit -m "add/edit more largefiles"
281 Invoking status precommit hook
281 Invoking status precommit hook
282 A sub2/large6
282 A sub2/large6
283 A sub2/large7
283 A sub2/large7
284 R large3
284 R large3
285 ? large5
285 ? large5
286 ? medium
286 ? medium
287 ? notlarge
287 ? notlarge
288 ? ratherlarge
288 ? ratherlarge
289 ? reallylarge
289 ? reallylarge
290 ? test.dat
290 ? test.dat
291 $ hg st
291 $ hg st
292 ? large3
292 ? large3
293 ? large5
293 ? large5
294 ? medium
294 ? medium
295 ? notlarge
295 ? notlarge
296 ? ratherlarge
296 ? ratherlarge
297 ? reallylarge
297 ? reallylarge
298 ? test.dat
298 ? test.dat
299
299
300 Purge with largefiles: verify that largefiles are still in the working
300 Purge with largefiles: verify that largefiles are still in the working
301 dir after a purge.
301 dir after a purge.
302
302
303 $ hg purge --all
303 $ hg purge --all
304 $ cat sub/large4
304 $ cat sub/large4
305 large44
305 large44
306 $ cat sub2/large6
306 $ cat sub2/large6
307 large6
307 large6
308 $ cat sub2/large7
308 $ cat sub2/large7
309 large7
309 large7
310
310
311 Test addremove: verify that files that should be added as largfiles are added as
311 Test addremove: verify that files that should be added as largfiles are added as
312 such and that already-existing largfiles are not added as normal files by
312 such and that already-existing largfiles are not added as normal files by
313 accident.
313 accident.
314
314
315 $ rm normal3
315 $ rm normal3
316 $ rm sub/large4
316 $ rm sub/large4
317 $ echo "testing addremove with patterns" > testaddremove.dat
317 $ echo "testing addremove with patterns" > testaddremove.dat
318 $ echo "normaladdremove" > normaladdremove
318 $ echo "normaladdremove" > normaladdremove
319 $ hg addremove
319 $ hg addremove
320 removing sub/large4
320 removing sub/large4
321 adding testaddremove.dat as a largefile
321 adding testaddremove.dat as a largefile
322 removing normal3
322 removing normal3
323 adding normaladdremove
323 adding normaladdremove
324
324
325 Clone a largefiles repo.
325 Clone a largefiles repo.
326
326
327 $ hg clone . ../b
327 $ hg clone . ../b
328 updating to branch default
328 updating to branch default
329 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 getting changed largefiles
330 getting changed largefiles
331 3 largefiles updated, 0 removed
331 3 largefiles updated, 0 removed
332 $ cd ../b
332 $ cd ../b
333 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
333 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
334 7:daea875e9014 add/edit more largefiles
334 7:daea875e9014 add/edit more largefiles
335 6:4355d653f84f edit files yet again
335 6:4355d653f84f edit files yet again
336 5:9d5af5072dbd edit files again
336 5:9d5af5072dbd edit files again
337 4:74c02385b94c move files
337 4:74c02385b94c move files
338 3:9e8fbc4bce62 copy files
338 3:9e8fbc4bce62 copy files
339 2:51a0ae4d5864 remove files
339 2:51a0ae4d5864 remove files
340 1:ce8896473775 edit files
340 1:ce8896473775 edit files
341 0:30d30fe6a5be add files
341 0:30d30fe6a5be add files
342 $ cat normal3
342 $ cat normal3
343 normal33
343 normal33
344 $ cat sub/normal4
344 $ cat sub/normal4
345 normal44
345 normal44
346 $ cat sub/large4
346 $ cat sub/large4
347 large44
347 large44
348 $ cat sub2/large6
348 $ cat sub2/large6
349 large6
349 large6
350 $ cat sub2/large7
350 $ cat sub2/large7
351 large7
351 large7
352 $ cd ..
352 $ cd ..
353 $ hg clone a -r 3 c
353 $ hg clone a -r 3 c
354 adding changesets
354 adding changesets
355 adding manifests
355 adding manifests
356 adding file changes
356 adding file changes
357 added 4 changesets with 10 changes to 4 files
357 added 4 changesets with 10 changes to 4 files
358 updating to branch default
358 updating to branch default
359 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
360 getting changed largefiles
360 getting changed largefiles
361 2 largefiles updated, 0 removed
361 2 largefiles updated, 0 removed
362 $ cd c
362 $ cd c
363 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
363 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
364 3:9e8fbc4bce62 copy files
364 3:9e8fbc4bce62 copy files
365 2:51a0ae4d5864 remove files
365 2:51a0ae4d5864 remove files
366 1:ce8896473775 edit files
366 1:ce8896473775 edit files
367 0:30d30fe6a5be add files
367 0:30d30fe6a5be add files
368 $ cat normal1
368 $ cat normal1
369 normal22
369 normal22
370 $ cat large1
370 $ cat large1
371 large22
371 large22
372 $ cat sub/normal2
372 $ cat sub/normal2
373 normal22
373 normal22
374 $ cat sub/large2
374 $ cat sub/large2
375 large22
375 large22
376
376
377 Old revisions of a clone have correct largefiles content (this also
377 Old revisions of a clone have correct largefiles content (this also
378 tests update).
378 tests update).
379
379
380 $ hg update -r 1
380 $ hg update -r 1
381 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
382 getting changed largefiles
382 getting changed largefiles
383 1 largefiles updated, 0 removed
383 1 largefiles updated, 0 removed
384 $ cat large1
384 $ cat large1
385 large11
385 large11
386 $ cat sub/large2
386 $ cat sub/large2
387 large22
387 large22
388
388
389 Rebasing between two repositories does not revert largefiles to old
389 Rebasing between two repositories does not revert largefiles to old
390 revisions (this was a very bad bug that took a lot of work to fix).
390 revisions (this was a very bad bug that took a lot of work to fix).
391
391
392 $ cd ..
392 $ cd ..
393 $ hg clone a d
393 $ hg clone a d
394 updating to branch default
394 updating to branch default
395 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
396 getting changed largefiles
396 getting changed largefiles
397 3 largefiles updated, 0 removed
397 3 largefiles updated, 0 removed
398 $ cd b
398 $ cd b
399 $ echo large4-modified > sub/large4
399 $ echo large4-modified > sub/large4
400 $ echo normal3-modified > normal3
400 $ echo normal3-modified > normal3
401 $ hg commit -m "modify normal file and largefile in repo b"
401 $ hg commit -m "modify normal file and largefile in repo b"
402 Invoking status precommit hook
402 Invoking status precommit hook
403 M normal3
403 M normal3
404 M sub/large4
404 M sub/large4
405 $ cd ../d
405 $ cd ../d
406 $ echo large6-modified > sub2/large6
406 $ echo large6-modified > sub2/large6
407 $ echo normal4-modified > sub/normal4
407 $ echo normal4-modified > sub/normal4
408 $ hg commit -m "modify normal file largefile in repo d"
408 $ hg commit -m "modify normal file largefile in repo d"
409 Invoking status precommit hook
409 Invoking status precommit hook
410 M sub/normal4
410 M sub/normal4
411 M sub2/large6
411 M sub2/large6
412 $ cd ..
412 $ cd ..
413 $ hg clone d e
413 $ hg clone d e
414 updating to branch default
414 updating to branch default
415 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
415 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
416 getting changed largefiles
416 getting changed largefiles
417 3 largefiles updated, 0 removed
417 3 largefiles updated, 0 removed
418 $ cd d
418 $ cd d
419 $ hg pull --rebase ../b
419 $ hg pull --rebase ../b
420 pulling from ../b
420 pulling from ../b
421 searching for changes
421 searching for changes
422 adding changesets
422 adding changesets
423 adding manifests
423 adding manifests
424 adding file changes
424 adding file changes
425 added 1 changesets with 2 changes to 2 files (+1 heads)
425 added 1 changesets with 2 changes to 2 files (+1 heads)
426 Invoking status precommit hook
426 Invoking status precommit hook
427 M sub/normal4
427 M sub/normal4
428 M sub2/large6
428 M sub2/large6
429 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
429 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
430 nothing to rebase
430 nothing to rebase
431 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
431 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
432 9:598410d3eb9a modify normal file largefile in repo d
432 9:598410d3eb9a modify normal file largefile in repo d
433 8:a381d2c8c80e modify normal file and largefile in repo b
433 8:a381d2c8c80e modify normal file and largefile in repo b
434 7:daea875e9014 add/edit more largefiles
434 7:daea875e9014 add/edit more largefiles
435 6:4355d653f84f edit files yet again
435 6:4355d653f84f edit files yet again
436 5:9d5af5072dbd edit files again
436 5:9d5af5072dbd edit files again
437 4:74c02385b94c move files
437 4:74c02385b94c move files
438 3:9e8fbc4bce62 copy files
438 3:9e8fbc4bce62 copy files
439 2:51a0ae4d5864 remove files
439 2:51a0ae4d5864 remove files
440 1:ce8896473775 edit files
440 1:ce8896473775 edit files
441 0:30d30fe6a5be add files
441 0:30d30fe6a5be add files
442 $ cat normal3
442 $ cat normal3
443 normal3-modified
443 normal3-modified
444 $ cat sub/normal4
444 $ cat sub/normal4
445 normal4-modified
445 normal4-modified
446 $ cat sub/large4
446 $ cat sub/large4
447 large4-modified
447 large4-modified
448 $ cat sub2/large6
448 $ cat sub2/large6
449 large6-modified
449 large6-modified
450 $ cat sub2/large7
450 $ cat sub2/large7
451 large7
451 large7
452 $ cd ../e
452 $ cd ../e
453 $ hg pull ../b
453 $ hg pull ../b
454 pulling from ../b
454 pulling from ../b
455 searching for changes
455 searching for changes
456 adding changesets
456 adding changesets
457 adding manifests
457 adding manifests
458 adding file changes
458 adding file changes
459 added 1 changesets with 2 changes to 2 files (+1 heads)
459 added 1 changesets with 2 changes to 2 files (+1 heads)
460 (run 'hg heads' to see heads, 'hg merge' to merge)
460 (run 'hg heads' to see heads, 'hg merge' to merge)
461 caching new largefiles
461 caching new largefiles
462 0 largefiles cached
462 0 largefiles cached
463 $ hg rebase
463 $ hg rebase
464 Invoking status precommit hook
464 Invoking status precommit hook
465 M sub/normal4
465 M sub/normal4
466 M sub2/large6
466 M sub2/large6
467 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
467 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
468 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
468 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
469 9:598410d3eb9a modify normal file largefile in repo d
469 9:598410d3eb9a modify normal file largefile in repo d
470 8:a381d2c8c80e modify normal file and largefile in repo b
470 8:a381d2c8c80e modify normal file and largefile in repo b
471 7:daea875e9014 add/edit more largefiles
471 7:daea875e9014 add/edit more largefiles
472 6:4355d653f84f edit files yet again
472 6:4355d653f84f edit files yet again
473 5:9d5af5072dbd edit files again
473 5:9d5af5072dbd edit files again
474 4:74c02385b94c move files
474 4:74c02385b94c move files
475 3:9e8fbc4bce62 copy files
475 3:9e8fbc4bce62 copy files
476 2:51a0ae4d5864 remove files
476 2:51a0ae4d5864 remove files
477 1:ce8896473775 edit files
477 1:ce8896473775 edit files
478 0:30d30fe6a5be add files
478 0:30d30fe6a5be add files
479 $ cat normal3
479 $ cat normal3
480 normal3-modified
480 normal3-modified
481 $ cat sub/normal4
481 $ cat sub/normal4
482 normal4-modified
482 normal4-modified
483 $ cat sub/large4
483 $ cat sub/large4
484 large4-modified
484 large4-modified
485 $ cat sub2/large6
485 $ cat sub2/large6
486 large6-modified
486 large6-modified
487 $ cat sub2/large7
487 $ cat sub2/large7
488 large7
488 large7
489
489
490 Rollback on largefiles.
490 Rollback on largefiles.
491
491
492 $ echo large4-modified-again > sub/large4
492 $ echo large4-modified-again > sub/large4
493 $ hg commit -m "Modify large4 again"
493 $ hg commit -m "Modify large4 again"
494 Invoking status precommit hook
494 Invoking status precommit hook
495 M sub/large4
495 M sub/large4
496 $ hg rollback
496 $ hg rollback
497 repository tip rolled back to revision 9 (undo commit)
497 repository tip rolled back to revision 9 (undo commit)
498 working directory now based on revision 9
498 working directory now based on revision 9
499 $ hg st
499 $ hg st
500 M sub/large4
500 M sub/large4
501 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
501 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
502 9:598410d3eb9a modify normal file largefile in repo d
502 9:598410d3eb9a modify normal file largefile in repo d
503 8:a381d2c8c80e modify normal file and largefile in repo b
503 8:a381d2c8c80e modify normal file and largefile in repo b
504 7:daea875e9014 add/edit more largefiles
504 7:daea875e9014 add/edit more largefiles
505 6:4355d653f84f edit files yet again
505 6:4355d653f84f edit files yet again
506 5:9d5af5072dbd edit files again
506 5:9d5af5072dbd edit files again
507 4:74c02385b94c move files
507 4:74c02385b94c move files
508 3:9e8fbc4bce62 copy files
508 3:9e8fbc4bce62 copy files
509 2:51a0ae4d5864 remove files
509 2:51a0ae4d5864 remove files
510 1:ce8896473775 edit files
510 1:ce8896473775 edit files
511 0:30d30fe6a5be add files
511 0:30d30fe6a5be add files
512 $ cat sub/large4
512 $ cat sub/large4
513 large4-modified-again
513 large4-modified-again
514
514
515 "update --check" refuses to update with uncommitted changes.
515 "update --check" refuses to update with uncommitted changes.
516 $ hg update --check 8
516 $ hg update --check 8
517 abort: uncommitted local changes
517 abort: uncommitted local changes
518 [255]
518 [255]
519
519
520 "update --clean" leaves correct largefiles in working copy.
520 "update --clean" leaves correct largefiles in working copy.
521
521
522 $ hg update --clean
522 $ hg update --clean
523 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
523 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
524 getting changed largefiles
524 getting changed largefiles
525 1 largefiles updated, 0 removed
525 1 largefiles updated, 0 removed
526 $ cat normal3
526 $ cat normal3
527 normal3-modified
527 normal3-modified
528 $ cat sub/normal4
528 $ cat sub/normal4
529 normal4-modified
529 normal4-modified
530 $ cat sub/large4
530 $ cat sub/large4
531 large4-modified
531 large4-modified
532 $ cat sub2/large6
532 $ cat sub2/large6
533 large6-modified
533 large6-modified
534 $ cat sub2/large7
534 $ cat sub2/large7
535 large7
535 large7
536
536
537 Now "update check" is happy.
537 Now "update check" is happy.
538 $ hg update --check 8
538 $ hg update --check 8
539 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
539 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
540 getting changed largefiles
540 getting changed largefiles
541 1 largefiles updated, 0 removed
541 1 largefiles updated, 0 removed
542 $ hg update --check
542 $ hg update --check
543 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
543 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
544 getting changed largefiles
544 getting changed largefiles
545 1 largefiles updated, 0 removed
545 1 largefiles updated, 0 removed
546
546
547 Test removing empty largefiles directories on update
547 Test removing empty largefiles directories on update
548 $ test -d sub2 && echo "sub2 exists"
548 $ test -d sub2 && echo "sub2 exists"
549 sub2 exists
549 sub2 exists
550 $ hg update -q null
550 $ hg update -q null
551 $ test -d sub2 && echo "error: sub2 should not exist anymore"
551 $ test -d sub2 && echo "error: sub2 should not exist anymore"
552 [1]
552 [1]
553 $ hg update -q
553 $ hg update -q
554
554
555 Test hg remove removes empty largefiles directories
555 Test hg remove removes empty largefiles directories
556 $ test -d sub2 && echo "sub2 exists"
556 $ test -d sub2 && echo "sub2 exists"
557 sub2 exists
557 sub2 exists
558 $ hg remove sub2/*
558 $ hg remove sub2/*
559 $ test -d sub2 && echo "error: sub2 should not exist anymore"
559 $ test -d sub2 && echo "error: sub2 should not exist anymore"
560 [1]
560 [1]
561 $ hg revert sub2/large6 sub2/large7
561 $ hg revert sub2/large6 sub2/large7
562
562
563 "revert" works on largefiles (and normal files too).
563 "revert" works on largefiles (and normal files too).
564 $ echo hack3 >> normal3
564 $ echo hack3 >> normal3
565 $ echo hack4 >> sub/normal4
565 $ echo hack4 >> sub/normal4
566 $ echo hack4 >> sub/large4
566 $ echo hack4 >> sub/large4
567 $ rm sub2/large6
567 $ rm sub2/large6
568 $ hg revert sub2/large6
568 $ hg revert sub2/large6
569 $ hg rm sub2/large6
569 $ hg rm sub2/large6
570 $ echo new >> sub2/large8
570 $ echo new >> sub2/large8
571 $ hg add --large sub2/large8
571 $ hg add --large sub2/large8
572 # XXX we don't really want to report that we're reverting the standin;
572 # XXX we don't really want to report that we're reverting the standin;
573 # that's just an implementation detail. But I don't see an obvious fix. ;-(
573 # that's just an implementation detail. But I don't see an obvious fix. ;-(
574 $ hg revert sub
574 $ hg revert sub
575 reverting .hglf/sub/large4 (glob)
575 reverting .hglf/sub/large4 (glob)
576 reverting sub/normal4 (glob)
576 reverting sub/normal4 (glob)
577 $ hg status
577 $ hg status
578 M normal3
578 M normal3
579 A sub2/large8
579 A sub2/large8
580 R sub2/large6
580 R sub2/large6
581 ? sub/large4.orig
581 ? sub/large4.orig
582 ? sub/normal4.orig
582 ? sub/normal4.orig
583 $ cat sub/normal4
583 $ cat sub/normal4
584 normal4-modified
584 normal4-modified
585 $ cat sub/large4
585 $ cat sub/large4
586 large4-modified
586 large4-modified
587 $ hg revert -a --no-backup
587 $ hg revert -a --no-backup
588 undeleting .hglf/sub2/large6 (glob)
588 undeleting .hglf/sub2/large6 (glob)
589 forgetting .hglf/sub2/large8 (glob)
589 forgetting .hglf/sub2/large8 (glob)
590 reverting normal3
590 reverting normal3
591 $ hg status
591 $ hg status
592 ? sub/large4.orig
592 ? sub/large4.orig
593 ? sub/normal4.orig
593 ? sub/normal4.orig
594 ? sub2/large8
594 ? sub2/large8
595 $ cat normal3
595 $ cat normal3
596 normal3-modified
596 normal3-modified
597 $ cat sub2/large6
597 $ cat sub2/large6
598 large6-modified
598 large6-modified
599 $ rm sub/*.orig sub2/large8
599 $ rm sub/*.orig sub2/large8
600
600
601 revert some files to an older revision
601 revert some files to an older revision
602 $ hg revert --no-backup -r 8 sub2
602 $ hg revert --no-backup -r 8 sub2
603 reverting .hglf/sub2/large6 (glob)
603 reverting .hglf/sub2/large6 (glob)
604 $ cat sub2/large6
604 $ cat sub2/large6
605 large6
605 large6
606 $ hg revert --no-backup sub2
606 $ hg revert --no-backup sub2
607 reverting .hglf/sub2/large6 (glob)
607 reverting .hglf/sub2/large6 (glob)
608 $ hg status
608 $ hg status
609
609
610 "verify --large" actually verifies largefiles
610 "verify --large" actually verifies largefiles
611
611
612 $ hg verify --large
612 $ hg verify --large
613 checking changesets
613 checking changesets
614 checking manifests
614 checking manifests
615 crosschecking files in changesets and manifests
615 crosschecking files in changesets and manifests
616 checking files
616 checking files
617 10 files, 10 changesets, 28 total revisions
617 10 files, 10 changesets, 28 total revisions
618 searching 1 changesets for largefiles
618 searching 1 changesets for largefiles
619 verified existence of 3 revisions of 3 largefiles
619 verified existence of 3 revisions of 3 largefiles
620
620
621 Merging does not revert to old versions of largefiles and also check
621 Merging does not revert to old versions of largefiles and also check
622 that merging after having pulled from a non-default remote works
622 that merging after having pulled from a non-default remote works
623 correctly.
623 correctly.
624
624
625 $ cd ..
625 $ cd ..
626 $ hg clone -r 7 e temp
626 $ hg clone -r 7 e temp
627 adding changesets
627 adding changesets
628 adding manifests
628 adding manifests
629 adding file changes
629 adding file changes
630 added 8 changesets with 24 changes to 10 files
630 added 8 changesets with 24 changes to 10 files
631 updating to branch default
631 updating to branch default
632 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
632 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
633 getting changed largefiles
633 getting changed largefiles
634 3 largefiles updated, 0 removed
634 3 largefiles updated, 0 removed
635 $ hg clone temp f
635 $ hg clone temp f
636 updating to branch default
636 updating to branch default
637 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
637 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
638 getting changed largefiles
638 getting changed largefiles
639 3 largefiles updated, 0 removed
639 3 largefiles updated, 0 removed
640 # Delete the largefiles in the largefiles system cache so that we have an
640 # Delete the largefiles in the largefiles system cache so that we have an
641 # opportunity to test that caching after a pull works.
641 # opportunity to test that caching after a pull works.
642 $ rm ${USERCACHE}/*
642 $ rm ${USERCACHE}/*
643 $ cd f
643 $ cd f
644 $ echo "large4-merge-test" > sub/large4
644 $ echo "large4-merge-test" > sub/large4
645 $ hg commit -m "Modify large4 to test merge"
645 $ hg commit -m "Modify large4 to test merge"
646 Invoking status precommit hook
646 Invoking status precommit hook
647 M sub/large4
647 M sub/large4
648 $ hg pull ../e
648 $ hg pull ../e
649 pulling from ../e
649 pulling from ../e
650 searching for changes
650 searching for changes
651 adding changesets
651 adding changesets
652 adding manifests
652 adding manifests
653 adding file changes
653 adding file changes
654 added 2 changesets with 4 changes to 4 files (+1 heads)
654 added 2 changesets with 4 changes to 4 files (+1 heads)
655 (run 'hg heads' to see heads, 'hg merge' to merge)
655 (run 'hg heads' to see heads, 'hg merge' to merge)
656 caching new largefiles
656 caching new largefiles
657 2 largefiles cached
657 2 largefiles cached
658 $ hg merge
658 $ hg merge
659 merging sub/large4
659 merging sub/large4
660 largefile sub/large4 has a merge conflict
660 largefile sub/large4 has a merge conflict
661 keep (l)ocal or take (o)ther? l
661 keep (l)ocal or take (o)ther? l
662 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
662 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
663 (branch merge, don't forget to commit)
663 (branch merge, don't forget to commit)
664 getting changed largefiles
664 getting changed largefiles
665 1 largefiles updated, 0 removed
665 1 largefiles updated, 0 removed
666 $ hg commit -m "Merge repos e and f"
666 $ hg commit -m "Merge repos e and f"
667 Invoking status precommit hook
667 Invoking status precommit hook
668 M normal3
668 M normal3
669 M sub/normal4
669 M sub/normal4
670 M sub2/large6
670 M sub2/large6
671 $ cat normal3
671 $ cat normal3
672 normal3-modified
672 normal3-modified
673 $ cat sub/normal4
673 $ cat sub/normal4
674 normal4-modified
674 normal4-modified
675 $ cat sub/large4
675 $ cat sub/large4
676 large4-merge-test
676 large4-merge-test
677 $ cat sub2/large6
677 $ cat sub2/large6
678 large6-modified
678 large6-modified
679 $ cat sub2/large7
679 $ cat sub2/large7
680 large7
680 large7
681
681
682 Test status after merging with a branch that introduces a new largefile:
682 Test status after merging with a branch that introduces a new largefile:
683
683
684 $ echo large > large
684 $ echo large > large
685 $ hg add --large large
685 $ hg add --large large
686 $ hg commit -m 'add largefile'
686 $ hg commit -m 'add largefile'
687 Invoking status precommit hook
687 Invoking status precommit hook
688 A large
688 A large
689 $ hg update -q ".^"
689 $ hg update -q ".^"
690 $ echo change >> normal3
690 $ echo change >> normal3
691 $ hg commit -m 'some change'
691 $ hg commit -m 'some change'
692 Invoking status precommit hook
692 Invoking status precommit hook
693 M normal3
693 M normal3
694 created new head
694 created new head
695 $ hg merge
695 $ hg merge
696 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
696 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
697 (branch merge, don't forget to commit)
697 (branch merge, don't forget to commit)
698 getting changed largefiles
698 getting changed largefiles
699 1 largefiles updated, 0 removed
699 1 largefiles updated, 0 removed
700 $ hg status
700 $ hg status
701 M large
701 M large
702
702
703 Test that a normal file and a largefile with the same name and path cannot
703 Test that a normal file and a largefile with the same name and path cannot
704 coexist.
704 coexist.
705
705
706 $ rm sub2/large7
706 $ rm sub2/large7
707 $ echo "largeasnormal" > sub2/large7
707 $ echo "largeasnormal" > sub2/large7
708 $ hg add sub2/large7
708 $ hg add sub2/large7
709 sub2/large7 already a largefile
709 sub2/large7 already a largefile
710
710
711 Test that transplanting a largefile change works correctly.
711 Test that transplanting a largefile change works correctly.
712
712
713 $ cd ..
713 $ cd ..
714 $ hg clone -r 8 d g
714 $ hg clone -r 8 d g
715 adding changesets
715 adding changesets
716 adding manifests
716 adding manifests
717 adding file changes
717 adding file changes
718 added 9 changesets with 26 changes to 10 files
718 added 9 changesets with 26 changes to 10 files
719 updating to branch default
719 updating to branch default
720 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
720 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
721 getting changed largefiles
721 getting changed largefiles
722 3 largefiles updated, 0 removed
722 3 largefiles updated, 0 removed
723 $ cd g
723 $ cd g
724 $ hg transplant -s ../d 598410d3eb9a
724 $ hg transplant -s ../d 598410d3eb9a
725 searching for changes
725 searching for changes
726 searching for changes
726 searching for changes
727 adding changesets
727 adding changesets
728 adding manifests
728 adding manifests
729 adding file changes
729 adding file changes
730 added 1 changesets with 2 changes to 2 files
730 added 1 changesets with 2 changes to 2 files
731 getting changed largefiles
732 1 largefiles updated, 0 removed
731 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
733 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
732 9:598410d3eb9a modify normal file largefile in repo d
734 9:598410d3eb9a modify normal file largefile in repo d
733 8:a381d2c8c80e modify normal file and largefile in repo b
735 8:a381d2c8c80e modify normal file and largefile in repo b
734 7:daea875e9014 add/edit more largefiles
736 7:daea875e9014 add/edit more largefiles
735 6:4355d653f84f edit files yet again
737 6:4355d653f84f edit files yet again
736 5:9d5af5072dbd edit files again
738 5:9d5af5072dbd edit files again
737 4:74c02385b94c move files
739 4:74c02385b94c move files
738 3:9e8fbc4bce62 copy files
740 3:9e8fbc4bce62 copy files
739 2:51a0ae4d5864 remove files
741 2:51a0ae4d5864 remove files
740 1:ce8896473775 edit files
742 1:ce8896473775 edit files
741 0:30d30fe6a5be add files
743 0:30d30fe6a5be add files
742 $ cat normal3
744 $ cat normal3
743 normal3-modified
745 normal3-modified
744 $ cat sub/normal4
746 $ cat sub/normal4
745 normal4-modified
747 normal4-modified
746 $ cat sub/large4
748 $ cat sub/large4
747 large4-modified
749 large4-modified
748 $ cat sub2/large6
750 $ cat sub2/large6
749 large6-modified
751 large6-modified
750 $ cat sub2/large7
752 $ cat sub2/large7
751 large7
753 large7
752
754
753 Test that renaming a largefile results in correct output for status
755 Test that renaming a largefile results in correct output for status
754
756
755 $ hg rename sub/large4 large4-renamed
757 $ hg rename sub/large4 large4-renamed
756 $ hg commit -m "test rename output"
758 $ hg commit -m "test rename output"
757 Invoking status precommit hook
759 Invoking status precommit hook
758 A large4-renamed
760 A large4-renamed
759 R sub/large4
761 R sub/large4
760 $ cat large4-renamed
762 $ cat large4-renamed
761 large4-modified
763 large4-modified
762 $ cd sub2
764 $ cd sub2
763 $ hg rename large6 large6-renamed
765 $ hg rename large6 large6-renamed
764 $ hg st
766 $ hg st
765 A sub2/large6-renamed
767 A sub2/large6-renamed
766 R sub2/large6
768 R sub2/large6
767 $ cd ..
769 $ cd ..
768
770
769 Test --normal flag
771 Test --normal flag
770
772
771 $ dd if=/dev/urandom bs=2k count=11k > new-largefile 2> /dev/null
773 $ dd if=/dev/urandom bs=2k count=11k > new-largefile 2> /dev/null
772 $ hg add --normal --large new-largefile
774 $ hg add --normal --large new-largefile
773 abort: --normal cannot be used with --large
775 abort: --normal cannot be used with --large
774 [255]
776 [255]
775 $ hg add --normal new-largefile
777 $ hg add --normal new-largefile
776 new-largefile: up to 69 MB of RAM may be required to manage this file
778 new-largefile: up to 69 MB of RAM may be required to manage this file
777 (use 'hg revert new-largefile' to cancel the pending addition)
779 (use 'hg revert new-largefile' to cancel the pending addition)
778 $ cd ..
780 $ cd ..
779
781
780 vanilla clients not locked out from largefiles servers on vanilla repos
782 vanilla clients not locked out from largefiles servers on vanilla repos
781 $ mkdir r1
783 $ mkdir r1
782 $ cd r1
784 $ cd r1
783 $ hg init
785 $ hg init
784 $ echo c1 > f1
786 $ echo c1 > f1
785 $ hg add f1
787 $ hg add f1
786 $ hg commit -m "m1"
788 $ hg commit -m "m1"
787 Invoking status precommit hook
789 Invoking status precommit hook
788 A f1
790 A f1
789 $ cd ..
791 $ cd ..
790 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
792 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
791 $ cat hg.pid >> $DAEMON_PIDS
793 $ cat hg.pid >> $DAEMON_PIDS
792 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
794 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
793 requesting all changes
795 requesting all changes
794 adding changesets
796 adding changesets
795 adding manifests
797 adding manifests
796 adding file changes
798 adding file changes
797 added 1 changesets with 1 changes to 1 files
799 added 1 changesets with 1 changes to 1 files
798 updating to branch default
800 updating to branch default
799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
801 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
800
802
801 largefiles clients still work with vanilla servers
803 largefiles clients still work with vanilla servers
802 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
804 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
803 $ cat hg.pid >> $DAEMON_PIDS
805 $ cat hg.pid >> $DAEMON_PIDS
804 $ hg clone http://localhost:$HGPORT1 r3
806 $ hg clone http://localhost:$HGPORT1 r3
805 requesting all changes
807 requesting all changes
806 adding changesets
808 adding changesets
807 adding manifests
809 adding manifests
808 adding file changes
810 adding file changes
809 added 1 changesets with 1 changes to 1 files
811 added 1 changesets with 1 changes to 1 files
810 updating to branch default
812 updating to branch default
811 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
813 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
812
814
813 vanilla clients locked out from largefiles http repos
815 vanilla clients locked out from largefiles http repos
814 $ mkdir r4
816 $ mkdir r4
815 $ cd r4
817 $ cd r4
816 $ hg init
818 $ hg init
817 $ echo c1 > f1
819 $ echo c1 > f1
818 $ hg add --large f1
820 $ hg add --large f1
819 $ hg commit -m "m1"
821 $ hg commit -m "m1"
820 Invoking status precommit hook
822 Invoking status precommit hook
821 A f1
823 A f1
822 $ cd ..
824 $ cd ..
823 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
825 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
824 $ cat hg.pid >> $DAEMON_PIDS
826 $ cat hg.pid >> $DAEMON_PIDS
825 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
827 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
826 abort: remote error:
828 abort: remote error:
827
829
828 This repository uses the largefiles extension.
830 This repository uses the largefiles extension.
829
831
830 Please enable it in your Mercurial config file.
832 Please enable it in your Mercurial config file.
831 [255]
833 [255]
832
834
833 used all HGPORTs, kill all daemons
835 used all HGPORTs, kill all daemons
834 $ "$TESTDIR/killdaemons.py"
836 $ "$TESTDIR/killdaemons.py"
835
837
836 vanilla clients locked out from largefiles ssh repos
838 vanilla clients locked out from largefiles ssh repos
837 $ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
839 $ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
838 abort: remote error:
840 abort: remote error:
839
841
840 This repository uses the largefiles extension.
842 This repository uses the largefiles extension.
841
843
842 Please enable it in your Mercurial config file.
844 Please enable it in your Mercurial config file.
843 [255]
845 [255]
844
846
845 largefiles clients refuse to push largefiles repos to vanilla servers
847 largefiles clients refuse to push largefiles repos to vanilla servers
846 $ mkdir r6
848 $ mkdir r6
847 $ cd r6
849 $ cd r6
848 $ hg init
850 $ hg init
849 $ echo c1 > f1
851 $ echo c1 > f1
850 $ hg add f1
852 $ hg add f1
851 $ hg commit -m "m1"
853 $ hg commit -m "m1"
852 Invoking status precommit hook
854 Invoking status precommit hook
853 A f1
855 A f1
854 $ cat >> .hg/hgrc <<!
856 $ cat >> .hg/hgrc <<!
855 > [web]
857 > [web]
856 > push_ssl = false
858 > push_ssl = false
857 > allow_push = *
859 > allow_push = *
858 > !
860 > !
859 $ cd ..
861 $ cd ..
860 $ hg clone r6 r7
862 $ hg clone r6 r7
861 updating to branch default
863 updating to branch default
862 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
864 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
863 $ cd r7
865 $ cd r7
864 $ echo c2 > f2
866 $ echo c2 > f2
865 $ hg add --large f2
867 $ hg add --large f2
866 $ hg commit -m "m2"
868 $ hg commit -m "m2"
867 Invoking status precommit hook
869 Invoking status precommit hook
868 A f2
870 A f2
869 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
871 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
870 $ cat ../hg.pid >> $DAEMON_PIDS
872 $ cat ../hg.pid >> $DAEMON_PIDS
871 $ hg push http://localhost:$HGPORT
873 $ hg push http://localhost:$HGPORT
872 pushing to http://localhost:$HGPORT/
874 pushing to http://localhost:$HGPORT/
873 searching for changes
875 searching for changes
874 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
876 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
875 [255]
877 [255]
876 $ cd ..
878 $ cd ..
877
879
878 putlfile errors are shown (issue3123)
880 putlfile errors are shown (issue3123)
879 Corrupt the cached largefile in r7
881 Corrupt the cached largefile in r7
880 $ echo corruption > $USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8
882 $ echo corruption > $USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8
881 $ hg init empty
883 $ hg init empty
882 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
884 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
883 > --config 'web.allow_push=*' --config web.push_ssl=False
885 > --config 'web.allow_push=*' --config web.push_ssl=False
884 $ cat hg.pid >> $DAEMON_PIDS
886 $ cat hg.pid >> $DAEMON_PIDS
885 $ hg push -R r7 http://localhost:$HGPORT1
887 $ hg push -R r7 http://localhost:$HGPORT1
886 pushing to http://localhost:$HGPORT1/
888 pushing to http://localhost:$HGPORT1/
887 searching for changes
889 searching for changes
888 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
890 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
889 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/
891 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/
890 [255]
892 [255]
891 $ rm -rf empty
893 $ rm -rf empty
892
894
893 Clone a local repository owned by another user
895 Clone a local repository owned by another user
894 We have to simulate that here by setting $HOME and removing write permissions
896 We have to simulate that here by setting $HOME and removing write permissions
895 $ ORIGHOME="$HOME"
897 $ ORIGHOME="$HOME"
896 $ mkdir alice
898 $ mkdir alice
897 $ HOME="`pwd`/alice"
899 $ HOME="`pwd`/alice"
898 $ cd alice
900 $ cd alice
899 $ hg init pubrepo
901 $ hg init pubrepo
900 $ cd pubrepo
902 $ cd pubrepo
901 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
903 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
902 $ hg add --large a-large-file
904 $ hg add --large a-large-file
903 $ hg commit -m "Add a large file"
905 $ hg commit -m "Add a large file"
904 Invoking status precommit hook
906 Invoking status precommit hook
905 A a-large-file
907 A a-large-file
906 $ cd ..
908 $ cd ..
907 $ chmod -R a-w pubrepo
909 $ chmod -R a-w pubrepo
908 $ cd ..
910 $ cd ..
909 $ mkdir bob
911 $ mkdir bob
910 $ HOME="`pwd`/bob"
912 $ HOME="`pwd`/bob"
911 $ cd bob
913 $ cd bob
912 $ hg clone --pull ../alice/pubrepo pubrepo
914 $ hg clone --pull ../alice/pubrepo pubrepo
913 requesting all changes
915 requesting all changes
914 adding changesets
916 adding changesets
915 adding manifests
917 adding manifests
916 adding file changes
918 adding file changes
917 added 1 changesets with 1 changes to 1 files
919 added 1 changesets with 1 changes to 1 files
918 updating to branch default
920 updating to branch default
919 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
921 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
920 getting changed largefiles
922 getting changed largefiles
921 1 largefiles updated, 0 removed
923 1 largefiles updated, 0 removed
922 $ cd ..
924 $ cd ..
923 $ chmod -R u+w alice/pubrepo
925 $ chmod -R u+w alice/pubrepo
924 $ HOME="$ORIGHOME"
926 $ HOME="$ORIGHOME"
925
927
926 Symlink to a large largefile should behave the same as a symlink to a normal file
928 Symlink to a large largefile should behave the same as a symlink to a normal file
927 $ hg init largesymlink
929 $ hg init largesymlink
928 $ cd largesymlink
930 $ cd largesymlink
929 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
931 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
930 $ hg add --large largefile
932 $ hg add --large largefile
931 $ hg commit -m "commit a large file"
933 $ hg commit -m "commit a large file"
932 Invoking status precommit hook
934 Invoking status precommit hook
933 A largefile
935 A largefile
934 $ ln -s largefile largelink
936 $ ln -s largefile largelink
935 $ hg add largelink
937 $ hg add largelink
936 $ hg commit -m "commit a large symlink"
938 $ hg commit -m "commit a large symlink"
937 Invoking status precommit hook
939 Invoking status precommit hook
938 A largelink
940 A largelink
939 $ rm -f largelink
941 $ rm -f largelink
940 $ hg up >/dev/null
942 $ hg up >/dev/null
941 $ test -f largelink
943 $ test -f largelink
942 [1]
944 [1]
943 $ test -L largelink
945 $ test -L largelink
944 [1]
946 [1]
945 $ rm -f largelink # make next part of the test independent of the previous
947 $ rm -f largelink # make next part of the test independent of the previous
946 $ hg up -C >/dev/null
948 $ hg up -C >/dev/null
947 $ test -f largelink
949 $ test -f largelink
948 $ test -L largelink
950 $ test -L largelink
949 $ cd ..
951 $ cd ..
950
952
951 test for pattern matching on 'hg status':
953 test for pattern matching on 'hg status':
952 to boost performance, largefiles checks whether specified patterns are
954 to boost performance, largefiles checks whether specified patterns are
953 related to largefiles in working directory (NOT to STANDIN) or not.
955 related to largefiles in working directory (NOT to STANDIN) or not.
954
956
955 $ hg init statusmatch
957 $ hg init statusmatch
956 $ cd statusmatch
958 $ cd statusmatch
957
959
958 $ mkdir -p a/b/c/d
960 $ mkdir -p a/b/c/d
959 $ echo normal > a/b/c/d/e.normal.txt
961 $ echo normal > a/b/c/d/e.normal.txt
960 $ hg add a/b/c/d/e.normal.txt
962 $ hg add a/b/c/d/e.normal.txt
961 $ echo large > a/b/c/d/e.large.txt
963 $ echo large > a/b/c/d/e.large.txt
962 $ hg add --large a/b/c/d/e.large.txt
964 $ hg add --large a/b/c/d/e.large.txt
963 $ mkdir -p a/b/c/x
965 $ mkdir -p a/b/c/x
964 $ echo normal > a/b/c/x/y.normal.txt
966 $ echo normal > a/b/c/x/y.normal.txt
965 $ hg add a/b/c/x/y.normal.txt
967 $ hg add a/b/c/x/y.normal.txt
966 $ hg commit -m 'add files'
968 $ hg commit -m 'add files'
967 Invoking status precommit hook
969 Invoking status precommit hook
968 A a/b/c/d/e.large.txt
970 A a/b/c/d/e.large.txt
969 A a/b/c/d/e.normal.txt
971 A a/b/c/d/e.normal.txt
970 A a/b/c/x/y.normal.txt
972 A a/b/c/x/y.normal.txt
971
973
972 (1) no pattern: no performance boost
974 (1) no pattern: no performance boost
973 $ hg status -A
975 $ hg status -A
974 C a/b/c/d/e.large.txt
976 C a/b/c/d/e.large.txt
975 C a/b/c/d/e.normal.txt
977 C a/b/c/d/e.normal.txt
976 C a/b/c/x/y.normal.txt
978 C a/b/c/x/y.normal.txt
977
979
978 (2) pattern not related to largefiles: performance boost
980 (2) pattern not related to largefiles: performance boost
979 $ hg status -A a/b/c/x
981 $ hg status -A a/b/c/x
980 C a/b/c/x/y.normal.txt
982 C a/b/c/x/y.normal.txt
981
983
982 (3) pattern related to largefiles: no performance boost
984 (3) pattern related to largefiles: no performance boost
983 $ hg status -A a/b/c/d
985 $ hg status -A a/b/c/d
984 C a/b/c/d/e.large.txt
986 C a/b/c/d/e.large.txt
985 C a/b/c/d/e.normal.txt
987 C a/b/c/d/e.normal.txt
986
988
987 (4) pattern related to STANDIN (not to largefiles): performance boost
989 (4) pattern related to STANDIN (not to largefiles): performance boost
988 $ hg status -A .hglf/a
990 $ hg status -A .hglf/a
989 C .hglf/a/b/c/d/e.large.txt
991 C .hglf/a/b/c/d/e.large.txt
990
992
991 (5) mixed case: no performance boost
993 (5) mixed case: no performance boost
992 $ hg status -A a/b/c/x a/b/c/d
994 $ hg status -A a/b/c/x a/b/c/d
993 C a/b/c/d/e.large.txt
995 C a/b/c/d/e.large.txt
994 C a/b/c/d/e.normal.txt
996 C a/b/c/d/e.normal.txt
995 C a/b/c/x/y.normal.txt
997 C a/b/c/x/y.normal.txt
996
998
997 verify that largefiles doesn't break filesets
999 verify that largefiles doesn't break filesets
998
1000
999 $ hg log --rev . --exclude "set:binary()"
1001 $ hg log --rev . --exclude "set:binary()"
1000 changeset: 0:41bd42f10efa
1002 changeset: 0:41bd42f10efa
1001 tag: tip
1003 tag: tip
1002 user: test
1004 user: test
1003 date: Thu Jan 01 00:00:00 1970 +0000
1005 date: Thu Jan 01 00:00:00 1970 +0000
1004 summary: add files
1006 summary: add files
1005
1007
1006
1008
1007 $ cd ..
1009 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now