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