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