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