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