##// END OF EJS Templates
largefiles: pass a matcher instead of a raw file list to removelargefiles()...
Matt Harbison -
r23741:f2893cd8 default
parent child Browse files
Show More
@@ -1,1306 +1,1314 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, util, cmdutil, scmutil, match as match_, \
14 from mercurial import hg, util, cmdutil, scmutil, match as match_, \
15 archival, pathutil, revset
15 archival, pathutil, revset
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial.node import hex
17 from mercurial.node import hex
18
18
19 import lfutil
19 import lfutil
20 import lfcommands
20 import lfcommands
21 import basestore
21 import basestore
22
22
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
23 # -- Utility functions: commonly/repeatedly needed functionality ---------------
24
24
25 def composelargefilematcher(match, manifest):
25 def composelargefilematcher(match, manifest):
26 '''create a matcher that matches only the largefiles in the original
26 '''create a matcher that matches only the largefiles in the original
27 matcher'''
27 matcher'''
28 m = copy.copy(match)
28 m = copy.copy(match)
29 lfile = lambda f: lfutil.standin(f) in manifest
29 lfile = lambda f: lfutil.standin(f) in manifest
30 m._files = filter(lfile, m._files)
30 m._files = filter(lfile, m._files)
31 m._fmap = set(m._files)
31 m._fmap = set(m._files)
32 m._always = False
32 m._always = False
33 origmatchfn = m.matchfn
33 origmatchfn = m.matchfn
34 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
34 m.matchfn = lambda f: lfile(f) and origmatchfn(f)
35 return m
35 return m
36
36
37 def composenormalfilematcher(match, manifest):
37 def composenormalfilematcher(match, manifest):
38 m = copy.copy(match)
38 m = copy.copy(match)
39 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
39 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
40 manifest)
40 manifest)
41 m._files = filter(notlfile, m._files)
41 m._files = filter(notlfile, m._files)
42 m._fmap = set(m._files)
42 m._fmap = set(m._files)
43 m._always = False
43 m._always = False
44 origmatchfn = m.matchfn
44 origmatchfn = m.matchfn
45 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
45 m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
46 return m
46 return m
47
47
48 def installnormalfilesmatchfn(manifest):
48 def installnormalfilesmatchfn(manifest):
49 '''installmatchfn with a matchfn that ignores all largefiles'''
49 '''installmatchfn with a matchfn that ignores all largefiles'''
50 def overridematch(ctx, pats=[], opts={}, globbed=False,
50 def overridematch(ctx, pats=[], opts={}, globbed=False,
51 default='relpath'):
51 default='relpath'):
52 match = oldmatch(ctx, pats, opts, globbed, default)
52 match = oldmatch(ctx, pats, opts, globbed, default)
53 return composenormalfilematcher(match, manifest)
53 return composenormalfilematcher(match, manifest)
54 oldmatch = installmatchfn(overridematch)
54 oldmatch = installmatchfn(overridematch)
55
55
56 def installmatchfn(f):
56 def installmatchfn(f):
57 '''monkey patch the scmutil module with a custom match function.
57 '''monkey patch the scmutil module with a custom match function.
58 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
58 Warning: it is monkey patching the _module_ on runtime! Not thread safe!'''
59 oldmatch = scmutil.match
59 oldmatch = scmutil.match
60 setattr(f, 'oldmatch', oldmatch)
60 setattr(f, 'oldmatch', oldmatch)
61 scmutil.match = f
61 scmutil.match = f
62 return oldmatch
62 return oldmatch
63
63
64 def restorematchfn():
64 def restorematchfn():
65 '''restores scmutil.match to what it was before installmatchfn
65 '''restores scmutil.match to what it was before installmatchfn
66 was called. no-op if scmutil.match is its original function.
66 was called. no-op if scmutil.match is its original function.
67
67
68 Note that n calls to installmatchfn will require n calls to
68 Note that n calls to installmatchfn will require n calls to
69 restore the original matchfn.'''
69 restore the original matchfn.'''
70 scmutil.match = getattr(scmutil.match, 'oldmatch')
70 scmutil.match = getattr(scmutil.match, 'oldmatch')
71
71
72 def installmatchandpatsfn(f):
72 def installmatchandpatsfn(f):
73 oldmatchandpats = scmutil.matchandpats
73 oldmatchandpats = scmutil.matchandpats
74 setattr(f, 'oldmatchandpats', oldmatchandpats)
74 setattr(f, 'oldmatchandpats', oldmatchandpats)
75 scmutil.matchandpats = f
75 scmutil.matchandpats = f
76 return oldmatchandpats
76 return oldmatchandpats
77
77
78 def restorematchandpatsfn():
78 def restorematchandpatsfn():
79 '''restores scmutil.matchandpats to what it was before
79 '''restores scmutil.matchandpats to what it was before
80 installmatchandpatsfn was called. No-op if scmutil.matchandpats
80 installmatchandpatsfn was called. No-op if scmutil.matchandpats
81 is its original function.
81 is its original function.
82
82
83 Note that n calls to installmatchandpatsfn will require n calls
83 Note that n calls to installmatchandpatsfn will require n calls
84 to restore the original matchfn.'''
84 to restore the original matchfn.'''
85 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
85 scmutil.matchandpats = getattr(scmutil.matchandpats, 'oldmatchandpats',
86 scmutil.matchandpats)
86 scmutil.matchandpats)
87
87
88 def addlargefiles(ui, repo, matcher, **opts):
88 def addlargefiles(ui, repo, matcher, **opts):
89 large = opts.pop('large', None)
89 large = opts.pop('large', None)
90 lfsize = lfutil.getminsize(
90 lfsize = lfutil.getminsize(
91 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
91 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
92
92
93 lfmatcher = None
93 lfmatcher = None
94 if lfutil.islfilesrepo(repo):
94 if lfutil.islfilesrepo(repo):
95 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
95 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
96 if lfpats:
96 if lfpats:
97 lfmatcher = match_.match(repo.root, '', list(lfpats))
97 lfmatcher = match_.match(repo.root, '', list(lfpats))
98
98
99 lfnames = []
99 lfnames = []
100 m = copy.copy(matcher)
100 m = copy.copy(matcher)
101 m.bad = lambda x, y: None
101 m.bad = lambda x, y: None
102 wctx = repo[None]
102 wctx = repo[None]
103 for f in repo.walk(m):
103 for f in repo.walk(m):
104 exact = m.exact(f)
104 exact = m.exact(f)
105 lfile = lfutil.standin(f) in wctx
105 lfile = lfutil.standin(f) in wctx
106 nfile = f in wctx
106 nfile = f in wctx
107 exists = lfile or nfile
107 exists = lfile or nfile
108
108
109 # Don't warn the user when they attempt to add a normal tracked file.
109 # Don't warn the user when they attempt to add a normal tracked file.
110 # The normal add code will do that for us.
110 # The normal add code will do that for us.
111 if exact and exists:
111 if exact and exists:
112 if lfile:
112 if lfile:
113 ui.warn(_('%s already a largefile\n') % f)
113 ui.warn(_('%s already a largefile\n') % f)
114 continue
114 continue
115
115
116 if (exact or not exists) and not lfutil.isstandin(f):
116 if (exact or not exists) and not lfutil.isstandin(f):
117 # In case the file was removed previously, but not committed
117 # In case the file was removed previously, but not committed
118 # (issue3507)
118 # (issue3507)
119 if not repo.wvfs.exists(f):
119 if not repo.wvfs.exists(f):
120 continue
120 continue
121
121
122 abovemin = (lfsize and
122 abovemin = (lfsize and
123 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
123 repo.wvfs.lstat(f).st_size >= lfsize * 1024 * 1024)
124 if large or abovemin or (lfmatcher and lfmatcher(f)):
124 if large or abovemin or (lfmatcher and lfmatcher(f)):
125 lfnames.append(f)
125 lfnames.append(f)
126 if ui.verbose or not exact:
126 if ui.verbose or not exact:
127 ui.status(_('adding %s as a largefile\n') % m.rel(f))
127 ui.status(_('adding %s as a largefile\n') % m.rel(f))
128
128
129 bad = []
129 bad = []
130
130
131 # Need to lock, otherwise there could be a race condition between
131 # Need to lock, otherwise there could be a race condition between
132 # when standins are created and added to the repo.
132 # when standins are created and added to the repo.
133 wlock = repo.wlock()
133 wlock = repo.wlock()
134 try:
134 try:
135 if not opts.get('dry_run'):
135 if not opts.get('dry_run'):
136 standins = []
136 standins = []
137 lfdirstate = lfutil.openlfdirstate(ui, repo)
137 lfdirstate = lfutil.openlfdirstate(ui, repo)
138 for f in lfnames:
138 for f in lfnames:
139 standinname = lfutil.standin(f)
139 standinname = lfutil.standin(f)
140 lfutil.writestandin(repo, standinname, hash='',
140 lfutil.writestandin(repo, standinname, hash='',
141 executable=lfutil.getexecutable(repo.wjoin(f)))
141 executable=lfutil.getexecutable(repo.wjoin(f)))
142 standins.append(standinname)
142 standins.append(standinname)
143 if lfdirstate[f] == 'r':
143 if lfdirstate[f] == 'r':
144 lfdirstate.normallookup(f)
144 lfdirstate.normallookup(f)
145 else:
145 else:
146 lfdirstate.add(f)
146 lfdirstate.add(f)
147 lfdirstate.write()
147 lfdirstate.write()
148 bad += [lfutil.splitstandin(f)
148 bad += [lfutil.splitstandin(f)
149 for f in repo[None].add(standins)
149 for f in repo[None].add(standins)
150 if f in m.files()]
150 if f in m.files()]
151 finally:
151 finally:
152 wlock.release()
152 wlock.release()
153 return bad
153 return bad
154
154
155 def removelargefiles(ui, repo, isaddremove, *pats, **opts):
155 def removelargefiles(ui, repo, isaddremove, matcher, **opts):
156 after = opts.get('after')
156 after = opts.get('after')
157 m = composelargefilematcher(scmutil.match(repo[None], pats, opts),
157 m = composelargefilematcher(matcher, repo[None].manifest())
158 repo[None].manifest())
159 try:
158 try:
160 repo.lfstatus = True
159 repo.lfstatus = True
161 s = repo.status(match=m, clean=True)
160 s = repo.status(match=m, clean=not isaddremove)
162 finally:
161 finally:
163 repo.lfstatus = False
162 repo.lfstatus = False
164 manifest = repo[None].manifest()
163 manifest = repo[None].manifest()
165 modified, added, deleted, clean = [[f for f in list
164 modified, added, deleted, clean = [[f for f in list
166 if lfutil.standin(f) in manifest]
165 if lfutil.standin(f) in manifest]
167 for list in (s.modified, s.added,
166 for list in (s.modified, s.added,
168 s.deleted, s.clean)]
167 s.deleted, s.clean)]
169
168
170 def warn(files, msg):
169 def warn(files, msg):
171 for f in files:
170 for f in files:
172 ui.warn(msg % m.rel(f))
171 ui.warn(msg % m.rel(f))
173 return int(len(files) > 0)
172 return int(len(files) > 0)
174
173
175 result = 0
174 result = 0
176
175
177 if after:
176 if after:
178 remove = deleted
177 remove = deleted
179 result = warn(modified + added + clean,
178 result = warn(modified + added + clean,
180 _('not removing %s: file still exists\n'))
179 _('not removing %s: file still exists\n'))
181 else:
180 else:
182 remove = deleted + clean
181 remove = deleted + clean
183 result = warn(modified, _('not removing %s: file is modified (use -f'
182 result = warn(modified, _('not removing %s: file is modified (use -f'
184 ' to force removal)\n'))
183 ' to force removal)\n'))
185 result = warn(added, _('not removing %s: file has been marked for add'
184 result = warn(added, _('not removing %s: file has been marked for add'
186 ' (use forget to undo)\n')) or result
185 ' (use forget to undo)\n')) or result
187
186
188 # Need to lock because standin files are deleted then removed from the
187 # Need to lock because standin files are deleted then removed from the
189 # repository and we could race in-between.
188 # repository and we could race in-between.
190 wlock = repo.wlock()
189 wlock = repo.wlock()
191 try:
190 try:
192 lfdirstate = lfutil.openlfdirstate(ui, repo)
191 lfdirstate = lfutil.openlfdirstate(ui, repo)
193 for f in sorted(remove):
192 for f in sorted(remove):
194 if isaddremove:
193 if isaddremove:
195 ui.status(_('removing %s\n') % f)
194 ui.status(_('removing %s\n') % f)
196 elif ui.verbose or not m.exact(f):
195 elif ui.verbose or not m.exact(f):
197 ui.status(_('removing %s\n') % m.rel(f))
196 ui.status(_('removing %s\n') % m.rel(f))
198
197
199 if not opts.get('dry_run'):
198 if not opts.get('dry_run'):
200 if not after:
199 if not after:
201 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
200 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
202
201
203 if opts.get('dry_run'):
202 if opts.get('dry_run'):
204 return result
203 return result
205
204
206 remove = [lfutil.standin(f) for f in remove]
205 remove = [lfutil.standin(f) for f in remove]
207 # If this is being called by addremove, let the original addremove
206 # If this is being called by addremove, let the original addremove
208 # function handle this.
207 # function handle this.
209 if not isaddremove:
208 if not isaddremove:
210 for f in remove:
209 for f in remove:
211 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
210 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
212 repo[None].forget(remove)
211 repo[None].forget(remove)
213
212
214 for f in remove:
213 for f in remove:
215 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
214 lfutil.synclfdirstate(repo, lfdirstate, lfutil.splitstandin(f),
216 False)
215 False)
217
216
218 lfdirstate.write()
217 lfdirstate.write()
219 finally:
218 finally:
220 wlock.release()
219 wlock.release()
221
220
222 return result
221 return result
223
222
224 # For overriding mercurial.hgweb.webcommands so that largefiles will
223 # For overriding mercurial.hgweb.webcommands so that largefiles will
225 # appear at their right place in the manifests.
224 # appear at their right place in the manifests.
226 def decodepath(orig, path):
225 def decodepath(orig, path):
227 return lfutil.splitstandin(path) or path
226 return lfutil.splitstandin(path) or path
228
227
229 # -- Wrappers: modify existing commands --------------------------------
228 # -- Wrappers: modify existing commands --------------------------------
230
229
231 # Add works by going through the files that the user wanted to add and
230 # Add works by going through the files that the user wanted to add and
232 # checking if they should be added as largefiles. Then it makes a new
231 # checking if they should be added as largefiles. Then it makes a new
233 # matcher which matches only the normal files and runs the original
232 # matcher which matches only the normal files and runs the original
234 # version of add.
233 # version of add.
235 def overrideadd(orig, ui, repo, *pats, **opts):
234 def overrideadd(orig, ui, repo, *pats, **opts):
236 normal = opts.pop('normal')
235 normal = opts.pop('normal')
237 if normal:
236 if normal:
238 if opts.get('large'):
237 if opts.get('large'):
239 raise util.Abort(_('--normal cannot be used with --large'))
238 raise util.Abort(_('--normal cannot be used with --large'))
240 return orig(ui, repo, *pats, **opts)
239 return orig(ui, repo, *pats, **opts)
241 matcher = scmutil.match(repo[None], pats, opts)
240 matcher = scmutil.match(repo[None], pats, opts)
242 bad = addlargefiles(ui, repo, matcher, **opts)
241 bad = addlargefiles(ui, repo, matcher, **opts)
243 installnormalfilesmatchfn(repo[None].manifest())
242 installnormalfilesmatchfn(repo[None].manifest())
244 result = orig(ui, repo, *pats, **opts)
243 result = orig(ui, repo, *pats, **opts)
245 restorematchfn()
244 restorematchfn()
246
245
247 return (result == 1 or bad) and 1 or 0
246 return (result == 1 or bad) and 1 or 0
248
247
249 def overrideremove(orig, ui, repo, *pats, **opts):
248 def overrideremove(orig, ui, repo, *pats, **opts):
250 installnormalfilesmatchfn(repo[None].manifest())
249 installnormalfilesmatchfn(repo[None].manifest())
251 result = orig(ui, repo, *pats, **opts)
250 result = orig(ui, repo, *pats, **opts)
252 restorematchfn()
251 restorematchfn()
253 return removelargefiles(ui, repo, False, *pats, **opts) or result
252 matcher = scmutil.match(repo[None], pats, opts)
253 return removelargefiles(ui, repo, False, matcher, **opts) or result
254
254
255 def overridestatusfn(orig, repo, rev2, **opts):
255 def overridestatusfn(orig, repo, rev2, **opts):
256 try:
256 try:
257 repo._repo.lfstatus = True
257 repo._repo.lfstatus = True
258 return orig(repo, rev2, **opts)
258 return orig(repo, rev2, **opts)
259 finally:
259 finally:
260 repo._repo.lfstatus = False
260 repo._repo.lfstatus = False
261
261
262 def overridestatus(orig, ui, repo, *pats, **opts):
262 def overridestatus(orig, ui, repo, *pats, **opts):
263 try:
263 try:
264 repo.lfstatus = True
264 repo.lfstatus = True
265 return orig(ui, repo, *pats, **opts)
265 return orig(ui, repo, *pats, **opts)
266 finally:
266 finally:
267 repo.lfstatus = False
267 repo.lfstatus = False
268
268
269 def overridedirty(orig, repo, ignoreupdate=False):
269 def overridedirty(orig, repo, ignoreupdate=False):
270 try:
270 try:
271 repo._repo.lfstatus = True
271 repo._repo.lfstatus = True
272 return orig(repo, ignoreupdate)
272 return orig(repo, ignoreupdate)
273 finally:
273 finally:
274 repo._repo.lfstatus = False
274 repo._repo.lfstatus = False
275
275
276 def overridelog(orig, ui, repo, *pats, **opts):
276 def overridelog(orig, ui, repo, *pats, **opts):
277 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
277 def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
278 default='relpath'):
278 default='relpath'):
279 """Matcher that merges root directory with .hglf, suitable for log.
279 """Matcher that merges root directory with .hglf, suitable for log.
280 It is still possible to match .hglf directly.
280 It is still possible to match .hglf directly.
281 For any listed files run log on the standin too.
281 For any listed files run log on the standin too.
282 matchfn tries both the given filename and with .hglf stripped.
282 matchfn tries both the given filename and with .hglf stripped.
283 """
283 """
284 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
284 matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
285 m, p = copy.copy(matchandpats)
285 m, p = copy.copy(matchandpats)
286
286
287 if m.always():
287 if m.always():
288 # We want to match everything anyway, so there's no benefit trying
288 # We want to match everything anyway, so there's no benefit trying
289 # to add standins.
289 # to add standins.
290 return matchandpats
290 return matchandpats
291
291
292 pats = set(p)
292 pats = set(p)
293 # TODO: handling of patterns in both cases below
293 # TODO: handling of patterns in both cases below
294 if m._cwd:
294 if m._cwd:
295 if os.path.isabs(m._cwd):
295 if os.path.isabs(m._cwd):
296 # TODO: handle largefile magic when invoked from other cwd
296 # TODO: handle largefile magic when invoked from other cwd
297 return matchandpats
297 return matchandpats
298 back = (m._cwd.count('/') + 1) * '../'
298 back = (m._cwd.count('/') + 1) * '../'
299 pats.update(back + lfutil.standin(m._cwd + '/' + f) for f in p)
299 pats.update(back + lfutil.standin(m._cwd + '/' + f) for f in p)
300 else:
300 else:
301 pats.update(lfutil.standin(f) for f in p)
301 pats.update(lfutil.standin(f) for f in p)
302
302
303 for i in range(0, len(m._files)):
303 for i in range(0, len(m._files)):
304 standin = lfutil.standin(m._files[i])
304 standin = lfutil.standin(m._files[i])
305 if standin in repo[ctx.node()]:
305 if standin in repo[ctx.node()]:
306 m._files[i] = standin
306 m._files[i] = standin
307 elif m._files[i] not in repo[ctx.node()]:
307 elif m._files[i] not in repo[ctx.node()]:
308 m._files.append(standin)
308 m._files.append(standin)
309 pats.add(standin)
309 pats.add(standin)
310
310
311 m._fmap = set(m._files)
311 m._fmap = set(m._files)
312 m._always = False
312 m._always = False
313 origmatchfn = m.matchfn
313 origmatchfn = m.matchfn
314 def lfmatchfn(f):
314 def lfmatchfn(f):
315 lf = lfutil.splitstandin(f)
315 lf = lfutil.splitstandin(f)
316 if lf is not None and origmatchfn(lf):
316 if lf is not None and origmatchfn(lf):
317 return True
317 return True
318 r = origmatchfn(f)
318 r = origmatchfn(f)
319 return r
319 return r
320 m.matchfn = lfmatchfn
320 m.matchfn = lfmatchfn
321
321
322 return m, pats
322 return m, pats
323
323
324 # For hg log --patch, the match object is used in two different senses:
324 # For hg log --patch, the match object is used in two different senses:
325 # (1) to determine what revisions should be printed out, and
325 # (1) to determine what revisions should be printed out, and
326 # (2) to determine what files to print out diffs for.
326 # (2) to determine what files to print out diffs for.
327 # The magic matchandpats override should be used for case (1) but not for
327 # The magic matchandpats override should be used for case (1) but not for
328 # case (2).
328 # case (2).
329 def overridemakelogfilematcher(repo, pats, opts):
329 def overridemakelogfilematcher(repo, pats, opts):
330 pctx = repo[None]
330 pctx = repo[None]
331 match, pats = oldmatchandpats(pctx, pats, opts)
331 match, pats = oldmatchandpats(pctx, pats, opts)
332 return lambda rev: match
332 return lambda rev: match
333
333
334 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
334 oldmatchandpats = installmatchandpatsfn(overridematchandpats)
335 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
335 oldmakelogfilematcher = cmdutil._makenofollowlogfilematcher
336 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
336 setattr(cmdutil, '_makenofollowlogfilematcher', overridemakelogfilematcher)
337
337
338 try:
338 try:
339 return orig(ui, repo, *pats, **opts)
339 return orig(ui, repo, *pats, **opts)
340 finally:
340 finally:
341 restorematchandpatsfn()
341 restorematchandpatsfn()
342 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
342 setattr(cmdutil, '_makenofollowlogfilematcher', oldmakelogfilematcher)
343
343
344 def overrideverify(orig, ui, repo, *pats, **opts):
344 def overrideverify(orig, ui, repo, *pats, **opts):
345 large = opts.pop('large', False)
345 large = opts.pop('large', False)
346 all = opts.pop('lfa', False)
346 all = opts.pop('lfa', False)
347 contents = opts.pop('lfc', False)
347 contents = opts.pop('lfc', False)
348
348
349 result = orig(ui, repo, *pats, **opts)
349 result = orig(ui, repo, *pats, **opts)
350 if large or all or contents:
350 if large or all or contents:
351 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
351 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
352 return result
352 return result
353
353
354 def overridedebugstate(orig, ui, repo, *pats, **opts):
354 def overridedebugstate(orig, ui, repo, *pats, **opts):
355 large = opts.pop('large', False)
355 large = opts.pop('large', False)
356 if large:
356 if large:
357 class fakerepo(object):
357 class fakerepo(object):
358 dirstate = lfutil.openlfdirstate(ui, repo)
358 dirstate = lfutil.openlfdirstate(ui, repo)
359 orig(ui, fakerepo, *pats, **opts)
359 orig(ui, fakerepo, *pats, **opts)
360 else:
360 else:
361 orig(ui, repo, *pats, **opts)
361 orig(ui, repo, *pats, **opts)
362
362
363 # Override needs to refresh standins so that update's normal merge
363 # Override needs to refresh standins so that update's normal merge
364 # will go through properly. Then the other update hook (overriding repo.update)
364 # will go through properly. Then the other update hook (overriding repo.update)
365 # will get the new files. Filemerge is also overridden so that the merge
365 # will get the new files. Filemerge is also overridden so that the merge
366 # will merge standins correctly.
366 # will merge standins correctly.
367 def overrideupdate(orig, ui, repo, *pats, **opts):
367 def overrideupdate(orig, ui, repo, *pats, **opts):
368 # Need to lock between the standins getting updated and their
368 # Need to lock between the standins getting updated and their
369 # largefiles getting updated
369 # largefiles getting updated
370 wlock = repo.wlock()
370 wlock = repo.wlock()
371 try:
371 try:
372 if opts['check']:
372 if opts['check']:
373 lfdirstate = lfutil.openlfdirstate(ui, repo)
373 lfdirstate = lfutil.openlfdirstate(ui, repo)
374 unsure, s = lfdirstate.status(
374 unsure, s = lfdirstate.status(
375 match_.always(repo.root, repo.getcwd()),
375 match_.always(repo.root, repo.getcwd()),
376 [], False, False, False)
376 [], False, False, False)
377
377
378 mod = len(s.modified) > 0
378 mod = len(s.modified) > 0
379 for lfile in unsure:
379 for lfile in unsure:
380 standin = lfutil.standin(lfile)
380 standin = lfutil.standin(lfile)
381 if repo['.'][standin].data().strip() != \
381 if repo['.'][standin].data().strip() != \
382 lfutil.hashfile(repo.wjoin(lfile)):
382 lfutil.hashfile(repo.wjoin(lfile)):
383 mod = True
383 mod = True
384 else:
384 else:
385 lfdirstate.normal(lfile)
385 lfdirstate.normal(lfile)
386 lfdirstate.write()
386 lfdirstate.write()
387 if mod:
387 if mod:
388 raise util.Abort(_('uncommitted changes'))
388 raise util.Abort(_('uncommitted changes'))
389 return orig(ui, repo, *pats, **opts)
389 return orig(ui, repo, *pats, **opts)
390 finally:
390 finally:
391 wlock.release()
391 wlock.release()
392
392
393 # Before starting the manifest merge, merge.updates will call
393 # Before starting the manifest merge, merge.updates will call
394 # _checkunknownfile to check if there are any files in the merged-in
394 # _checkunknownfile to check if there are any files in the merged-in
395 # changeset that collide with unknown files in the working copy.
395 # changeset that collide with unknown files in the working copy.
396 #
396 #
397 # The largefiles are seen as unknown, so this prevents us from merging
397 # The largefiles are seen as unknown, so this prevents us from merging
398 # in a file 'foo' if we already have a largefile with the same name.
398 # in a file 'foo' if we already have a largefile with the same name.
399 #
399 #
400 # The overridden function filters the unknown files by removing any
400 # The overridden function filters the unknown files by removing any
401 # largefiles. This makes the merge proceed and we can then handle this
401 # largefiles. This makes the merge proceed and we can then handle this
402 # case further in the overridden calculateupdates function below.
402 # case further in the overridden calculateupdates function below.
403 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
403 def overridecheckunknownfile(origfn, repo, wctx, mctx, f, f2=None):
404 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
404 if lfutil.standin(repo.dirstate.normalize(f)) in wctx:
405 return False
405 return False
406 return origfn(repo, wctx, mctx, f, f2)
406 return origfn(repo, wctx, mctx, f, f2)
407
407
408 # The manifest merge handles conflicts on the manifest level. We want
408 # The manifest merge handles conflicts on the manifest level. We want
409 # to handle changes in largefile-ness of files at this level too.
409 # to handle changes in largefile-ness of files at this level too.
410 #
410 #
411 # The strategy is to run the original calculateupdates and then process
411 # The strategy is to run the original calculateupdates and then process
412 # the action list it outputs. There are two cases we need to deal with:
412 # the action list it outputs. There are two cases we need to deal with:
413 #
413 #
414 # 1. Normal file in p1, largefile in p2. Here the largefile is
414 # 1. Normal file in p1, largefile in p2. Here the largefile is
415 # detected via its standin file, which will enter the working copy
415 # detected via its standin file, which will enter the working copy
416 # with a "get" action. It is not "merge" since the standin is all
416 # with a "get" action. It is not "merge" since the standin is all
417 # Mercurial is concerned with at this level -- the link to the
417 # Mercurial is concerned with at this level -- the link to the
418 # existing normal file is not relevant here.
418 # existing normal file is not relevant here.
419 #
419 #
420 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
420 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
421 # since the largefile will be present in the working copy and
421 # since the largefile will be present in the working copy and
422 # different from the normal file in p2. Mercurial therefore
422 # different from the normal file in p2. Mercurial therefore
423 # triggers a merge action.
423 # triggers a merge action.
424 #
424 #
425 # In both cases, we prompt the user and emit new actions to either
425 # In both cases, we prompt the user and emit new actions to either
426 # remove the standin (if the normal file was kept) or to remove the
426 # remove the standin (if the normal file was kept) or to remove the
427 # normal file and get the standin (if the largefile was kept). The
427 # normal file and get the standin (if the largefile was kept). The
428 # default prompt answer is to use the largefile version since it was
428 # default prompt answer is to use the largefile version since it was
429 # presumably changed on purpose.
429 # presumably changed on purpose.
430 #
430 #
431 # Finally, the merge.applyupdates function will then take care of
431 # Finally, the merge.applyupdates function will then take care of
432 # writing the files into the working copy and lfcommands.updatelfiles
432 # writing the files into the working copy and lfcommands.updatelfiles
433 # will update the largefiles.
433 # will update the largefiles.
434 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
434 def overridecalculateupdates(origfn, repo, p1, p2, pas, branchmerge, force,
435 partial, acceptremote, followcopies):
435 partial, acceptremote, followcopies):
436 overwrite = force and not branchmerge
436 overwrite = force and not branchmerge
437 actions, diverge, renamedelete = origfn(
437 actions, diverge, renamedelete = origfn(
438 repo, p1, p2, pas, branchmerge, force, partial, acceptremote,
438 repo, p1, p2, pas, branchmerge, force, partial, acceptremote,
439 followcopies)
439 followcopies)
440
440
441 if overwrite:
441 if overwrite:
442 return actions, diverge, renamedelete
442 return actions, diverge, renamedelete
443
443
444 # Convert to dictionary with filename as key and action as value.
444 # Convert to dictionary with filename as key and action as value.
445 lfiles = set()
445 lfiles = set()
446 for f in actions:
446 for f in actions:
447 splitstandin = f and lfutil.splitstandin(f)
447 splitstandin = f and lfutil.splitstandin(f)
448 if splitstandin in p1:
448 if splitstandin in p1:
449 lfiles.add(splitstandin)
449 lfiles.add(splitstandin)
450 elif lfutil.standin(f) in p1:
450 elif lfutil.standin(f) in p1:
451 lfiles.add(f)
451 lfiles.add(f)
452
452
453 for lfile in lfiles:
453 for lfile in lfiles:
454 standin = lfutil.standin(lfile)
454 standin = lfutil.standin(lfile)
455 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
455 (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
456 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
456 (sm, sargs, smsg) = actions.get(standin, (None, None, None))
457 if sm in ('g', 'dc') and lm != 'r':
457 if sm in ('g', 'dc') and lm != 'r':
458 # Case 1: normal file in the working copy, largefile in
458 # Case 1: normal file in the working copy, largefile in
459 # the second parent
459 # the second parent
460 usermsg = _('remote turned local normal file %s into a largefile\n'
460 usermsg = _('remote turned local normal file %s into a largefile\n'
461 'use (l)argefile or keep (n)ormal file?'
461 'use (l)argefile or keep (n)ormal file?'
462 '$$ &Largefile $$ &Normal file') % lfile
462 '$$ &Largefile $$ &Normal file') % lfile
463 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
463 if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile
464 actions[lfile] = ('r', None, 'replaced by standin')
464 actions[lfile] = ('r', None, 'replaced by standin')
465 actions[standin] = ('g', sargs, 'replaces standin')
465 actions[standin] = ('g', sargs, 'replaces standin')
466 else: # keep local normal file
466 else: # keep local normal file
467 actions[lfile] = ('k', None, 'replaces standin')
467 actions[lfile] = ('k', None, 'replaces standin')
468 if branchmerge:
468 if branchmerge:
469 actions[standin] = ('k', None, 'replaced by non-standin')
469 actions[standin] = ('k', None, 'replaced by non-standin')
470 else:
470 else:
471 actions[standin] = ('r', None, 'replaced by non-standin')
471 actions[standin] = ('r', None, 'replaced by non-standin')
472 elif lm in ('g', 'dc') and sm != 'r':
472 elif lm in ('g', 'dc') and sm != 'r':
473 # Case 2: largefile in the working copy, normal file in
473 # Case 2: largefile in the working copy, normal file in
474 # the second parent
474 # the second parent
475 usermsg = _('remote turned local largefile %s into a normal file\n'
475 usermsg = _('remote turned local largefile %s into a normal file\n'
476 'keep (l)argefile or use (n)ormal file?'
476 'keep (l)argefile or use (n)ormal file?'
477 '$$ &Largefile $$ &Normal file') % lfile
477 '$$ &Largefile $$ &Normal file') % lfile
478 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
478 if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile
479 if branchmerge:
479 if branchmerge:
480 # largefile can be restored from standin safely
480 # largefile can be restored from standin safely
481 actions[lfile] = ('k', None, 'replaced by standin')
481 actions[lfile] = ('k', None, 'replaced by standin')
482 actions[standin] = ('k', None, 'replaces standin')
482 actions[standin] = ('k', None, 'replaces standin')
483 else:
483 else:
484 # "lfile" should be marked as "removed" without
484 # "lfile" should be marked as "removed" without
485 # removal of itself
485 # removal of itself
486 actions[lfile] = ('lfmr', None,
486 actions[lfile] = ('lfmr', None,
487 'forget non-standin largefile')
487 'forget non-standin largefile')
488
488
489 # linear-merge should treat this largefile as 're-added'
489 # linear-merge should treat this largefile as 're-added'
490 actions[standin] = ('a', None, 'keep standin')
490 actions[standin] = ('a', None, 'keep standin')
491 else: # pick remote normal file
491 else: # pick remote normal file
492 actions[lfile] = ('g', largs, 'replaces standin')
492 actions[lfile] = ('g', largs, 'replaces standin')
493 actions[standin] = ('r', None, 'replaced by non-standin')
493 actions[standin] = ('r', None, 'replaced by non-standin')
494
494
495 return actions, diverge, renamedelete
495 return actions, diverge, renamedelete
496
496
497 def mergerecordupdates(orig, repo, actions, branchmerge):
497 def mergerecordupdates(orig, repo, actions, branchmerge):
498 if 'lfmr' in actions:
498 if 'lfmr' in actions:
499 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
499 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
500 for lfile, args, msg in actions['lfmr']:
500 for lfile, args, msg in actions['lfmr']:
501 # this should be executed before 'orig', to execute 'remove'
501 # this should be executed before 'orig', to execute 'remove'
502 # before all other actions
502 # before all other actions
503 repo.dirstate.remove(lfile)
503 repo.dirstate.remove(lfile)
504 # make sure lfile doesn't get synclfdirstate'd as normal
504 # make sure lfile doesn't get synclfdirstate'd as normal
505 lfdirstate.add(lfile)
505 lfdirstate.add(lfile)
506 lfdirstate.write()
506 lfdirstate.write()
507
507
508 return orig(repo, actions, branchmerge)
508 return orig(repo, actions, branchmerge)
509
509
510
510
511 # Override filemerge to prompt the user about how they wish to merge
511 # Override filemerge to prompt the user about how they wish to merge
512 # largefiles. This will handle identical edits without prompting the user.
512 # largefiles. This will handle identical edits without prompting the user.
513 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
513 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None):
514 if not lfutil.isstandin(orig):
514 if not lfutil.isstandin(orig):
515 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
515 return origfn(repo, mynode, orig, fcd, fco, fca, labels=labels)
516
516
517 ahash = fca.data().strip().lower()
517 ahash = fca.data().strip().lower()
518 dhash = fcd.data().strip().lower()
518 dhash = fcd.data().strip().lower()
519 ohash = fco.data().strip().lower()
519 ohash = fco.data().strip().lower()
520 if (ohash != ahash and
520 if (ohash != ahash and
521 ohash != dhash and
521 ohash != dhash and
522 (dhash == ahash or
522 (dhash == ahash or
523 repo.ui.promptchoice(
523 repo.ui.promptchoice(
524 _('largefile %s has a merge conflict\nancestor was %s\n'
524 _('largefile %s has a merge conflict\nancestor was %s\n'
525 'keep (l)ocal %s or\ntake (o)ther %s?'
525 'keep (l)ocal %s or\ntake (o)ther %s?'
526 '$$ &Local $$ &Other') %
526 '$$ &Local $$ &Other') %
527 (lfutil.splitstandin(orig), ahash, dhash, ohash),
527 (lfutil.splitstandin(orig), ahash, dhash, ohash),
528 0) == 1)):
528 0) == 1)):
529 repo.wwrite(fcd.path(), fco.data(), fco.flags())
529 repo.wwrite(fcd.path(), fco.data(), fco.flags())
530 return 0
530 return 0
531
531
532 # Copy first changes the matchers to match standins instead of
532 # Copy first changes the matchers to match standins instead of
533 # largefiles. Then it overrides util.copyfile in that function it
533 # largefiles. Then it overrides util.copyfile in that function it
534 # checks if the destination largefile already exists. It also keeps a
534 # checks if the destination largefile already exists. It also keeps a
535 # list of copied files so that the largefiles can be copied and the
535 # list of copied files so that the largefiles can be copied and the
536 # dirstate updated.
536 # dirstate updated.
537 def overridecopy(orig, ui, repo, pats, opts, rename=False):
537 def overridecopy(orig, ui, repo, pats, opts, rename=False):
538 # doesn't remove largefile on rename
538 # doesn't remove largefile on rename
539 if len(pats) < 2:
539 if len(pats) < 2:
540 # this isn't legal, let the original function deal with it
540 # this isn't legal, let the original function deal with it
541 return orig(ui, repo, pats, opts, rename)
541 return orig(ui, repo, pats, opts, rename)
542
542
543 def makestandin(relpath):
543 def makestandin(relpath):
544 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
544 path = pathutil.canonpath(repo.root, repo.getcwd(), relpath)
545 return os.path.join(repo.wjoin(lfutil.standin(path)))
545 return os.path.join(repo.wjoin(lfutil.standin(path)))
546
546
547 fullpats = scmutil.expandpats(pats)
547 fullpats = scmutil.expandpats(pats)
548 dest = fullpats[-1]
548 dest = fullpats[-1]
549
549
550 if os.path.isdir(dest):
550 if os.path.isdir(dest):
551 if not os.path.isdir(makestandin(dest)):
551 if not os.path.isdir(makestandin(dest)):
552 os.makedirs(makestandin(dest))
552 os.makedirs(makestandin(dest))
553 # This could copy both lfiles and normal files in one command,
553 # This could copy both lfiles and normal files in one command,
554 # but we don't want to do that. First replace their matcher to
554 # but we don't want to do that. First replace their matcher to
555 # only match normal files and run it, then replace it to just
555 # only match normal files and run it, then replace it to just
556 # match largefiles and run it again.
556 # match largefiles and run it again.
557 nonormalfiles = False
557 nonormalfiles = False
558 nolfiles = False
558 nolfiles = False
559 installnormalfilesmatchfn(repo[None].manifest())
559 installnormalfilesmatchfn(repo[None].manifest())
560 try:
560 try:
561 try:
561 try:
562 result = orig(ui, repo, pats, opts, rename)
562 result = orig(ui, repo, pats, opts, rename)
563 except util.Abort, e:
563 except util.Abort, e:
564 if str(e) != _('no files to copy'):
564 if str(e) != _('no files to copy'):
565 raise e
565 raise e
566 else:
566 else:
567 nonormalfiles = True
567 nonormalfiles = True
568 result = 0
568 result = 0
569 finally:
569 finally:
570 restorematchfn()
570 restorematchfn()
571
571
572 # The first rename can cause our current working directory to be removed.
572 # The first rename can cause our current working directory to be removed.
573 # In that case there is nothing left to copy/rename so just quit.
573 # In that case there is nothing left to copy/rename so just quit.
574 try:
574 try:
575 repo.getcwd()
575 repo.getcwd()
576 except OSError:
576 except OSError:
577 return result
577 return result
578
578
579 try:
579 try:
580 try:
580 try:
581 # When we call orig below it creates the standins but we don't add
581 # When we call orig below it creates the standins but we don't add
582 # them to the dir state until later so lock during that time.
582 # them to the dir state until later so lock during that time.
583 wlock = repo.wlock()
583 wlock = repo.wlock()
584
584
585 manifest = repo[None].manifest()
585 manifest = repo[None].manifest()
586 def overridematch(ctx, pats=[], opts={}, globbed=False,
586 def overridematch(ctx, pats=[], opts={}, globbed=False,
587 default='relpath'):
587 default='relpath'):
588 newpats = []
588 newpats = []
589 # The patterns were previously mangled to add the standin
589 # The patterns were previously mangled to add the standin
590 # directory; we need to remove that now
590 # directory; we need to remove that now
591 for pat in pats:
591 for pat in pats:
592 if match_.patkind(pat) is None and lfutil.shortname in pat:
592 if match_.patkind(pat) is None and lfutil.shortname in pat:
593 newpats.append(pat.replace(lfutil.shortname, ''))
593 newpats.append(pat.replace(lfutil.shortname, ''))
594 else:
594 else:
595 newpats.append(pat)
595 newpats.append(pat)
596 match = oldmatch(ctx, newpats, opts, globbed, default)
596 match = oldmatch(ctx, newpats, opts, globbed, default)
597 m = copy.copy(match)
597 m = copy.copy(match)
598 lfile = lambda f: lfutil.standin(f) in manifest
598 lfile = lambda f: lfutil.standin(f) in manifest
599 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
599 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
600 m._fmap = set(m._files)
600 m._fmap = set(m._files)
601 origmatchfn = m.matchfn
601 origmatchfn = m.matchfn
602 m.matchfn = lambda f: (lfutil.isstandin(f) and
602 m.matchfn = lambda f: (lfutil.isstandin(f) and
603 (f in manifest) and
603 (f in manifest) and
604 origmatchfn(lfutil.splitstandin(f)) or
604 origmatchfn(lfutil.splitstandin(f)) or
605 None)
605 None)
606 return m
606 return m
607 oldmatch = installmatchfn(overridematch)
607 oldmatch = installmatchfn(overridematch)
608 listpats = []
608 listpats = []
609 for pat in pats:
609 for pat in pats:
610 if match_.patkind(pat) is not None:
610 if match_.patkind(pat) is not None:
611 listpats.append(pat)
611 listpats.append(pat)
612 else:
612 else:
613 listpats.append(makestandin(pat))
613 listpats.append(makestandin(pat))
614
614
615 try:
615 try:
616 origcopyfile = util.copyfile
616 origcopyfile = util.copyfile
617 copiedfiles = []
617 copiedfiles = []
618 def overridecopyfile(src, dest):
618 def overridecopyfile(src, dest):
619 if (lfutil.shortname in src and
619 if (lfutil.shortname in src and
620 dest.startswith(repo.wjoin(lfutil.shortname))):
620 dest.startswith(repo.wjoin(lfutil.shortname))):
621 destlfile = dest.replace(lfutil.shortname, '')
621 destlfile = dest.replace(lfutil.shortname, '')
622 if not opts['force'] and os.path.exists(destlfile):
622 if not opts['force'] and os.path.exists(destlfile):
623 raise IOError('',
623 raise IOError('',
624 _('destination largefile already exists'))
624 _('destination largefile already exists'))
625 copiedfiles.append((src, dest))
625 copiedfiles.append((src, dest))
626 origcopyfile(src, dest)
626 origcopyfile(src, dest)
627
627
628 util.copyfile = overridecopyfile
628 util.copyfile = overridecopyfile
629 result += orig(ui, repo, listpats, opts, rename)
629 result += orig(ui, repo, listpats, opts, rename)
630 finally:
630 finally:
631 util.copyfile = origcopyfile
631 util.copyfile = origcopyfile
632
632
633 lfdirstate = lfutil.openlfdirstate(ui, repo)
633 lfdirstate = lfutil.openlfdirstate(ui, repo)
634 for (src, dest) in copiedfiles:
634 for (src, dest) in copiedfiles:
635 if (lfutil.shortname in src and
635 if (lfutil.shortname in src and
636 dest.startswith(repo.wjoin(lfutil.shortname))):
636 dest.startswith(repo.wjoin(lfutil.shortname))):
637 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
637 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
638 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
638 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
639 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
639 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
640 if not os.path.isdir(destlfiledir):
640 if not os.path.isdir(destlfiledir):
641 os.makedirs(destlfiledir)
641 os.makedirs(destlfiledir)
642 if rename:
642 if rename:
643 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
643 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
644
644
645 # The file is gone, but this deletes any empty parent
645 # The file is gone, but this deletes any empty parent
646 # directories as a side-effect.
646 # directories as a side-effect.
647 util.unlinkpath(repo.wjoin(srclfile), True)
647 util.unlinkpath(repo.wjoin(srclfile), True)
648 lfdirstate.remove(srclfile)
648 lfdirstate.remove(srclfile)
649 else:
649 else:
650 util.copyfile(repo.wjoin(srclfile),
650 util.copyfile(repo.wjoin(srclfile),
651 repo.wjoin(destlfile))
651 repo.wjoin(destlfile))
652
652
653 lfdirstate.add(destlfile)
653 lfdirstate.add(destlfile)
654 lfdirstate.write()
654 lfdirstate.write()
655 except util.Abort, e:
655 except util.Abort, e:
656 if str(e) != _('no files to copy'):
656 if str(e) != _('no files to copy'):
657 raise e
657 raise e
658 else:
658 else:
659 nolfiles = True
659 nolfiles = True
660 finally:
660 finally:
661 restorematchfn()
661 restorematchfn()
662 wlock.release()
662 wlock.release()
663
663
664 if nolfiles and nonormalfiles:
664 if nolfiles and nonormalfiles:
665 raise util.Abort(_('no files to copy'))
665 raise util.Abort(_('no files to copy'))
666
666
667 return result
667 return result
668
668
669 # When the user calls revert, we have to be careful to not revert any
669 # When the user calls revert, we have to be careful to not revert any
670 # changes to other largefiles accidentally. This means we have to keep
670 # changes to other largefiles accidentally. This means we have to keep
671 # track of the largefiles that are being reverted so we only pull down
671 # track of the largefiles that are being reverted so we only pull down
672 # the necessary largefiles.
672 # the necessary largefiles.
673 #
673 #
674 # Standins are only updated (to match the hash of largefiles) before
674 # Standins are only updated (to match the hash of largefiles) before
675 # commits. Update the standins then run the original revert, changing
675 # commits. Update the standins then run the original revert, changing
676 # the matcher to hit standins instead of largefiles. Based on the
676 # the matcher to hit standins instead of largefiles. Based on the
677 # resulting standins update the largefiles.
677 # resulting standins update the largefiles.
678 def overriderevert(orig, ui, repo, *pats, **opts):
678 def overriderevert(orig, ui, repo, *pats, **opts):
679 # Because we put the standins in a bad state (by updating them)
679 # Because we put the standins in a bad state (by updating them)
680 # and then return them to a correct state we need to lock to
680 # and then return them to a correct state we need to lock to
681 # prevent others from changing them in their incorrect state.
681 # prevent others from changing them in their incorrect state.
682 wlock = repo.wlock()
682 wlock = repo.wlock()
683 try:
683 try:
684 lfdirstate = lfutil.openlfdirstate(ui, repo)
684 lfdirstate = lfutil.openlfdirstate(ui, repo)
685 s = lfutil.lfdirstatestatus(lfdirstate, repo)
685 s = lfutil.lfdirstatestatus(lfdirstate, repo)
686 lfdirstate.write()
686 lfdirstate.write()
687 for lfile in s.modified:
687 for lfile in s.modified:
688 lfutil.updatestandin(repo, lfutil.standin(lfile))
688 lfutil.updatestandin(repo, lfutil.standin(lfile))
689 for lfile in s.deleted:
689 for lfile in s.deleted:
690 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
690 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
691 os.unlink(repo.wjoin(lfutil.standin(lfile)))
691 os.unlink(repo.wjoin(lfutil.standin(lfile)))
692
692
693 oldstandins = lfutil.getstandinsstate(repo)
693 oldstandins = lfutil.getstandinsstate(repo)
694
694
695 def overridematch(ctx, pats=[], opts={}, globbed=False,
695 def overridematch(ctx, pats=[], opts={}, globbed=False,
696 default='relpath'):
696 default='relpath'):
697 match = oldmatch(ctx, pats, opts, globbed, default)
697 match = oldmatch(ctx, pats, opts, globbed, default)
698 m = copy.copy(match)
698 m = copy.copy(match)
699 def tostandin(f):
699 def tostandin(f):
700 if lfutil.standin(f) in ctx:
700 if lfutil.standin(f) in ctx:
701 return lfutil.standin(f)
701 return lfutil.standin(f)
702 elif lfutil.standin(f) in repo[None]:
702 elif lfutil.standin(f) in repo[None]:
703 return None
703 return None
704 return f
704 return f
705 m._files = [tostandin(f) for f in m._files]
705 m._files = [tostandin(f) for f in m._files]
706 m._files = [f for f in m._files if f is not None]
706 m._files = [f for f in m._files if f is not None]
707 m._fmap = set(m._files)
707 m._fmap = set(m._files)
708 origmatchfn = m.matchfn
708 origmatchfn = m.matchfn
709 def matchfn(f):
709 def matchfn(f):
710 if lfutil.isstandin(f):
710 if lfutil.isstandin(f):
711 return (origmatchfn(lfutil.splitstandin(f)) and
711 return (origmatchfn(lfutil.splitstandin(f)) and
712 (f in repo[None] or f in ctx))
712 (f in repo[None] or f in ctx))
713 return origmatchfn(f)
713 return origmatchfn(f)
714 m.matchfn = matchfn
714 m.matchfn = matchfn
715 return m
715 return m
716 oldmatch = installmatchfn(overridematch)
716 oldmatch = installmatchfn(overridematch)
717 try:
717 try:
718 orig(ui, repo, *pats, **opts)
718 orig(ui, repo, *pats, **opts)
719 finally:
719 finally:
720 restorematchfn()
720 restorematchfn()
721
721
722 newstandins = lfutil.getstandinsstate(repo)
722 newstandins = lfutil.getstandinsstate(repo)
723 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
723 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
724 # lfdirstate should be 'normallookup'-ed for updated files,
724 # lfdirstate should be 'normallookup'-ed for updated files,
725 # because reverting doesn't touch dirstate for 'normal' files
725 # because reverting doesn't touch dirstate for 'normal' files
726 # when target revision is explicitly specified: in such case,
726 # when target revision is explicitly specified: in such case,
727 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
727 # 'n' and valid timestamp in dirstate doesn't ensure 'clean'
728 # of target (standin) file.
728 # of target (standin) file.
729 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
729 lfcommands.updatelfiles(ui, repo, filelist, printmessage=False,
730 normallookup=True)
730 normallookup=True)
731
731
732 finally:
732 finally:
733 wlock.release()
733 wlock.release()
734
734
735 # after pulling changesets, we need to take some extra care to get
735 # after pulling changesets, we need to take some extra care to get
736 # largefiles updated remotely
736 # largefiles updated remotely
737 def overridepull(orig, ui, repo, source=None, **opts):
737 def overridepull(orig, ui, repo, source=None, **opts):
738 revsprepull = len(repo)
738 revsprepull = len(repo)
739 if not source:
739 if not source:
740 source = 'default'
740 source = 'default'
741 repo.lfpullsource = source
741 repo.lfpullsource = source
742 result = orig(ui, repo, source, **opts)
742 result = orig(ui, repo, source, **opts)
743 revspostpull = len(repo)
743 revspostpull = len(repo)
744 lfrevs = opts.get('lfrev', [])
744 lfrevs = opts.get('lfrev', [])
745 if opts.get('all_largefiles'):
745 if opts.get('all_largefiles'):
746 lfrevs.append('pulled()')
746 lfrevs.append('pulled()')
747 if lfrevs and revspostpull > revsprepull:
747 if lfrevs and revspostpull > revsprepull:
748 numcached = 0
748 numcached = 0
749 repo.firstpulled = revsprepull # for pulled() revset expression
749 repo.firstpulled = revsprepull # for pulled() revset expression
750 try:
750 try:
751 for rev in scmutil.revrange(repo, lfrevs):
751 for rev in scmutil.revrange(repo, lfrevs):
752 ui.note(_('pulling largefiles for revision %s\n') % rev)
752 ui.note(_('pulling largefiles for revision %s\n') % rev)
753 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
753 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
754 numcached += len(cached)
754 numcached += len(cached)
755 finally:
755 finally:
756 del repo.firstpulled
756 del repo.firstpulled
757 ui.status(_("%d largefiles cached\n") % numcached)
757 ui.status(_("%d largefiles cached\n") % numcached)
758 return result
758 return result
759
759
760 def pulledrevsetsymbol(repo, subset, x):
760 def pulledrevsetsymbol(repo, subset, x):
761 """``pulled()``
761 """``pulled()``
762 Changesets that just has been pulled.
762 Changesets that just has been pulled.
763
763
764 Only available with largefiles from pull --lfrev expressions.
764 Only available with largefiles from pull --lfrev expressions.
765
765
766 .. container:: verbose
766 .. container:: verbose
767
767
768 Some examples:
768 Some examples:
769
769
770 - pull largefiles for all new changesets::
770 - pull largefiles for all new changesets::
771
771
772 hg pull -lfrev "pulled()"
772 hg pull -lfrev "pulled()"
773
773
774 - pull largefiles for all new branch heads::
774 - pull largefiles for all new branch heads::
775
775
776 hg pull -lfrev "head(pulled()) and not closed()"
776 hg pull -lfrev "head(pulled()) and not closed()"
777
777
778 """
778 """
779
779
780 try:
780 try:
781 firstpulled = repo.firstpulled
781 firstpulled = repo.firstpulled
782 except AttributeError:
782 except AttributeError:
783 raise util.Abort(_("pulled() only available in --lfrev"))
783 raise util.Abort(_("pulled() only available in --lfrev"))
784 return revset.baseset([r for r in subset if r >= firstpulled])
784 return revset.baseset([r for r in subset if r >= firstpulled])
785
785
786 def overrideclone(orig, ui, source, dest=None, **opts):
786 def overrideclone(orig, ui, source, dest=None, **opts):
787 d = dest
787 d = dest
788 if d is None:
788 if d is None:
789 d = hg.defaultdest(source)
789 d = hg.defaultdest(source)
790 if opts.get('all_largefiles') and not hg.islocal(d):
790 if opts.get('all_largefiles') and not hg.islocal(d):
791 raise util.Abort(_(
791 raise util.Abort(_(
792 '--all-largefiles is incompatible with non-local destination %s') %
792 '--all-largefiles is incompatible with non-local destination %s') %
793 d)
793 d)
794
794
795 return orig(ui, source, dest, **opts)
795 return orig(ui, source, dest, **opts)
796
796
797 def hgclone(orig, ui, opts, *args, **kwargs):
797 def hgclone(orig, ui, opts, *args, **kwargs):
798 result = orig(ui, opts, *args, **kwargs)
798 result = orig(ui, opts, *args, **kwargs)
799
799
800 if result is not None:
800 if result is not None:
801 sourcerepo, destrepo = result
801 sourcerepo, destrepo = result
802 repo = destrepo.local()
802 repo = destrepo.local()
803
803
804 # Caching is implicitly limited to 'rev' option, since the dest repo was
804 # Caching is implicitly limited to 'rev' option, since the dest repo was
805 # truncated at that point. The user may expect a download count with
805 # truncated at that point. The user may expect a download count with
806 # this option, so attempt whether or not this is a largefile repo.
806 # this option, so attempt whether or not this is a largefile repo.
807 if opts.get('all_largefiles'):
807 if opts.get('all_largefiles'):
808 success, missing = lfcommands.downloadlfiles(ui, repo, None)
808 success, missing = lfcommands.downloadlfiles(ui, repo, None)
809
809
810 if missing != 0:
810 if missing != 0:
811 return None
811 return None
812
812
813 return result
813 return result
814
814
815 def overriderebase(orig, ui, repo, **opts):
815 def overriderebase(orig, ui, repo, **opts):
816 resuming = opts.get('continue')
816 resuming = opts.get('continue')
817 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
817 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
818 repo._lfstatuswriters.append(lambda *msg, **opts: None)
818 repo._lfstatuswriters.append(lambda *msg, **opts: None)
819 try:
819 try:
820 return orig(ui, repo, **opts)
820 return orig(ui, repo, **opts)
821 finally:
821 finally:
822 repo._lfstatuswriters.pop()
822 repo._lfstatuswriters.pop()
823 repo._lfcommithooks.pop()
823 repo._lfcommithooks.pop()
824
824
825 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
825 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
826 prefix=None, mtime=None, subrepos=None):
826 prefix=None, mtime=None, subrepos=None):
827 # No need to lock because we are only reading history and
827 # No need to lock because we are only reading history and
828 # largefile caches, neither of which are modified.
828 # largefile caches, neither of which are modified.
829 lfcommands.cachelfiles(repo.ui, repo, node)
829 lfcommands.cachelfiles(repo.ui, repo, node)
830
830
831 if kind not in archival.archivers:
831 if kind not in archival.archivers:
832 raise util.Abort(_("unknown archive type '%s'") % kind)
832 raise util.Abort(_("unknown archive type '%s'") % kind)
833
833
834 ctx = repo[node]
834 ctx = repo[node]
835
835
836 if kind == 'files':
836 if kind == 'files':
837 if prefix:
837 if prefix:
838 raise util.Abort(
838 raise util.Abort(
839 _('cannot give prefix when archiving to files'))
839 _('cannot give prefix when archiving to files'))
840 else:
840 else:
841 prefix = archival.tidyprefix(dest, kind, prefix)
841 prefix = archival.tidyprefix(dest, kind, prefix)
842
842
843 def write(name, mode, islink, getdata):
843 def write(name, mode, islink, getdata):
844 if matchfn and not matchfn(name):
844 if matchfn and not matchfn(name):
845 return
845 return
846 data = getdata()
846 data = getdata()
847 if decode:
847 if decode:
848 data = repo.wwritedata(name, data)
848 data = repo.wwritedata(name, data)
849 archiver.addfile(prefix + name, mode, islink, data)
849 archiver.addfile(prefix + name, mode, islink, data)
850
850
851 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
851 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
852
852
853 if repo.ui.configbool("ui", "archivemeta", True):
853 if repo.ui.configbool("ui", "archivemeta", True):
854 def metadata():
854 def metadata():
855 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
855 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
856 hex(repo.changelog.node(0)), hex(node), ctx.branch())
856 hex(repo.changelog.node(0)), hex(node), ctx.branch())
857
857
858 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
858 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
859 if repo.tagtype(t) == 'global')
859 if repo.tagtype(t) == 'global')
860 if not tags:
860 if not tags:
861 repo.ui.pushbuffer()
861 repo.ui.pushbuffer()
862 opts = {'template': '{latesttag}\n{latesttagdistance}',
862 opts = {'template': '{latesttag}\n{latesttagdistance}',
863 'style': '', 'patch': None, 'git': None}
863 'style': '', 'patch': None, 'git': None}
864 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
864 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
865 ltags, dist = repo.ui.popbuffer().split('\n')
865 ltags, dist = repo.ui.popbuffer().split('\n')
866 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
866 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
867 tags += 'latesttagdistance: %s\n' % dist
867 tags += 'latesttagdistance: %s\n' % dist
868
868
869 return base + tags
869 return base + tags
870
870
871 write('.hg_archival.txt', 0644, False, metadata)
871 write('.hg_archival.txt', 0644, False, metadata)
872
872
873 for f in ctx:
873 for f in ctx:
874 ff = ctx.flags(f)
874 ff = ctx.flags(f)
875 getdata = ctx[f].data
875 getdata = ctx[f].data
876 if lfutil.isstandin(f):
876 if lfutil.isstandin(f):
877 path = lfutil.findfile(repo, getdata().strip())
877 path = lfutil.findfile(repo, getdata().strip())
878 if path is None:
878 if path is None:
879 raise util.Abort(
879 raise util.Abort(
880 _('largefile %s not found in repo store or system cache')
880 _('largefile %s not found in repo store or system cache')
881 % lfutil.splitstandin(f))
881 % lfutil.splitstandin(f))
882 f = lfutil.splitstandin(f)
882 f = lfutil.splitstandin(f)
883
883
884 def getdatafn():
884 def getdatafn():
885 fd = None
885 fd = None
886 try:
886 try:
887 fd = open(path, 'rb')
887 fd = open(path, 'rb')
888 return fd.read()
888 return fd.read()
889 finally:
889 finally:
890 if fd:
890 if fd:
891 fd.close()
891 fd.close()
892
892
893 getdata = getdatafn
893 getdata = getdatafn
894 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
894 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
895
895
896 if subrepos:
896 if subrepos:
897 for subpath in sorted(ctx.substate):
897 for subpath in sorted(ctx.substate):
898 sub = ctx.sub(subpath)
898 sub = ctx.sub(subpath)
899 submatch = match_.narrowmatcher(subpath, matchfn)
899 submatch = match_.narrowmatcher(subpath, matchfn)
900 sub.archive(archiver, prefix, submatch)
900 sub.archive(archiver, prefix, submatch)
901
901
902 archiver.done()
902 archiver.done()
903
903
904 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None):
904 def hgsubrepoarchive(orig, repo, archiver, prefix, match=None):
905 repo._get(repo._state + ('hg',))
905 repo._get(repo._state + ('hg',))
906 rev = repo._state[1]
906 rev = repo._state[1]
907 ctx = repo._repo[rev]
907 ctx = repo._repo[rev]
908
908
909 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
909 lfcommands.cachelfiles(repo.ui, repo._repo, ctx.node())
910
910
911 def write(name, mode, islink, getdata):
911 def write(name, mode, islink, getdata):
912 # At this point, the standin has been replaced with the largefile name,
912 # At this point, the standin has been replaced with the largefile name,
913 # so the normal matcher works here without the lfutil variants.
913 # so the normal matcher works here without the lfutil variants.
914 if match and not match(f):
914 if match and not match(f):
915 return
915 return
916 data = getdata()
916 data = getdata()
917
917
918 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
918 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
919
919
920 for f in ctx:
920 for f in ctx:
921 ff = ctx.flags(f)
921 ff = ctx.flags(f)
922 getdata = ctx[f].data
922 getdata = ctx[f].data
923 if lfutil.isstandin(f):
923 if lfutil.isstandin(f):
924 path = lfutil.findfile(repo._repo, getdata().strip())
924 path = lfutil.findfile(repo._repo, getdata().strip())
925 if path is None:
925 if path is None:
926 raise util.Abort(
926 raise util.Abort(
927 _('largefile %s not found in repo store or system cache')
927 _('largefile %s not found in repo store or system cache')
928 % lfutil.splitstandin(f))
928 % lfutil.splitstandin(f))
929 f = lfutil.splitstandin(f)
929 f = lfutil.splitstandin(f)
930
930
931 def getdatafn():
931 def getdatafn():
932 fd = None
932 fd = None
933 try:
933 try:
934 fd = open(os.path.join(prefix, path), 'rb')
934 fd = open(os.path.join(prefix, path), 'rb')
935 return fd.read()
935 return fd.read()
936 finally:
936 finally:
937 if fd:
937 if fd:
938 fd.close()
938 fd.close()
939
939
940 getdata = getdatafn
940 getdata = getdatafn
941
941
942 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
942 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
943
943
944 for subpath in sorted(ctx.substate):
944 for subpath in sorted(ctx.substate):
945 sub = ctx.sub(subpath)
945 sub = ctx.sub(subpath)
946 submatch = match_.narrowmatcher(subpath, match)
946 submatch = match_.narrowmatcher(subpath, match)
947 sub.archive(archiver, os.path.join(prefix, repo._path) + '/', submatch)
947 sub.archive(archiver, os.path.join(prefix, repo._path) + '/', submatch)
948
948
949 # If a largefile is modified, the change is not reflected in its
949 # If a largefile is modified, the change is not reflected in its
950 # standin until a commit. cmdutil.bailifchanged() raises an exception
950 # standin until a commit. cmdutil.bailifchanged() raises an exception
951 # if the repo has uncommitted changes. Wrap it to also check if
951 # if the repo has uncommitted changes. Wrap it to also check if
952 # largefiles were changed. This is used by bisect, backout and fetch.
952 # largefiles were changed. This is used by bisect, backout and fetch.
953 def overridebailifchanged(orig, repo):
953 def overridebailifchanged(orig, repo):
954 orig(repo)
954 orig(repo)
955 repo.lfstatus = True
955 repo.lfstatus = True
956 s = repo.status()
956 s = repo.status()
957 repo.lfstatus = False
957 repo.lfstatus = False
958 if s.modified or s.added or s.removed or s.deleted:
958 if s.modified or s.added or s.removed or s.deleted:
959 raise util.Abort(_('uncommitted changes'))
959 raise util.Abort(_('uncommitted changes'))
960
960
961 def overrideforget(orig, ui, repo, *pats, **opts):
961 def overrideforget(orig, ui, repo, *pats, **opts):
962 installnormalfilesmatchfn(repo[None].manifest())
962 installnormalfilesmatchfn(repo[None].manifest())
963 result = orig(ui, repo, *pats, **opts)
963 result = orig(ui, repo, *pats, **opts)
964 restorematchfn()
964 restorematchfn()
965 m = composelargefilematcher(scmutil.match(repo[None], pats, opts),
965 m = composelargefilematcher(scmutil.match(repo[None], pats, opts),
966 repo[None].manifest())
966 repo[None].manifest())
967
967
968 try:
968 try:
969 repo.lfstatus = True
969 repo.lfstatus = True
970 s = repo.status(match=m, clean=True)
970 s = repo.status(match=m, clean=True)
971 finally:
971 finally:
972 repo.lfstatus = False
972 repo.lfstatus = False
973 forget = sorted(s.modified + s.added + s.deleted + s.clean)
973 forget = sorted(s.modified + s.added + s.deleted + s.clean)
974 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
974 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
975
975
976 for f in forget:
976 for f in forget:
977 if lfutil.standin(f) not in repo.dirstate and not \
977 if lfutil.standin(f) not in repo.dirstate and not \
978 repo.wvfs.isdir(lfutil.standin(f)):
978 repo.wvfs.isdir(lfutil.standin(f)):
979 ui.warn(_('not removing %s: file is already untracked\n')
979 ui.warn(_('not removing %s: file is already untracked\n')
980 % m.rel(f))
980 % m.rel(f))
981 result = 1
981 result = 1
982
982
983 for f in forget:
983 for f in forget:
984 if ui.verbose or not m.exact(f):
984 if ui.verbose or not m.exact(f):
985 ui.status(_('removing %s\n') % m.rel(f))
985 ui.status(_('removing %s\n') % m.rel(f))
986
986
987 # Need to lock because standin files are deleted then removed from the
987 # Need to lock because standin files are deleted then removed from the
988 # repository and we could race in-between.
988 # repository and we could race in-between.
989 wlock = repo.wlock()
989 wlock = repo.wlock()
990 try:
990 try:
991 lfdirstate = lfutil.openlfdirstate(ui, repo)
991 lfdirstate = lfutil.openlfdirstate(ui, repo)
992 for f in forget:
992 for f in forget:
993 if lfdirstate[f] == 'a':
993 if lfdirstate[f] == 'a':
994 lfdirstate.drop(f)
994 lfdirstate.drop(f)
995 else:
995 else:
996 lfdirstate.remove(f)
996 lfdirstate.remove(f)
997 lfdirstate.write()
997 lfdirstate.write()
998 standins = [lfutil.standin(f) for f in forget]
998 standins = [lfutil.standin(f) for f in forget]
999 for f in standins:
999 for f in standins:
1000 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1000 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1001 repo[None].forget(standins)
1001 repo[None].forget(standins)
1002 finally:
1002 finally:
1003 wlock.release()
1003 wlock.release()
1004
1004
1005 return result
1005 return result
1006
1006
1007 def _getoutgoings(repo, other, missing, addfunc):
1007 def _getoutgoings(repo, other, missing, addfunc):
1008 """get pairs of filename and largefile hash in outgoing revisions
1008 """get pairs of filename and largefile hash in outgoing revisions
1009 in 'missing'.
1009 in 'missing'.
1010
1010
1011 largefiles already existing on 'other' repository are ignored.
1011 largefiles already existing on 'other' repository are ignored.
1012
1012
1013 'addfunc' is invoked with each unique pairs of filename and
1013 'addfunc' is invoked with each unique pairs of filename and
1014 largefile hash value.
1014 largefile hash value.
1015 """
1015 """
1016 knowns = set()
1016 knowns = set()
1017 lfhashes = set()
1017 lfhashes = set()
1018 def dedup(fn, lfhash):
1018 def dedup(fn, lfhash):
1019 k = (fn, lfhash)
1019 k = (fn, lfhash)
1020 if k not in knowns:
1020 if k not in knowns:
1021 knowns.add(k)
1021 knowns.add(k)
1022 lfhashes.add(lfhash)
1022 lfhashes.add(lfhash)
1023 lfutil.getlfilestoupload(repo, missing, dedup)
1023 lfutil.getlfilestoupload(repo, missing, dedup)
1024 if lfhashes:
1024 if lfhashes:
1025 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1025 lfexists = basestore._openstore(repo, other).exists(lfhashes)
1026 for fn, lfhash in knowns:
1026 for fn, lfhash in knowns:
1027 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1027 if not lfexists[lfhash]: # lfhash doesn't exist on "other"
1028 addfunc(fn, lfhash)
1028 addfunc(fn, lfhash)
1029
1029
1030 def outgoinghook(ui, repo, other, opts, missing):
1030 def outgoinghook(ui, repo, other, opts, missing):
1031 if opts.pop('large', None):
1031 if opts.pop('large', None):
1032 lfhashes = set()
1032 lfhashes = set()
1033 if ui.debugflag:
1033 if ui.debugflag:
1034 toupload = {}
1034 toupload = {}
1035 def addfunc(fn, lfhash):
1035 def addfunc(fn, lfhash):
1036 if fn not in toupload:
1036 if fn not in toupload:
1037 toupload[fn] = []
1037 toupload[fn] = []
1038 toupload[fn].append(lfhash)
1038 toupload[fn].append(lfhash)
1039 lfhashes.add(lfhash)
1039 lfhashes.add(lfhash)
1040 def showhashes(fn):
1040 def showhashes(fn):
1041 for lfhash in sorted(toupload[fn]):
1041 for lfhash in sorted(toupload[fn]):
1042 ui.debug(' %s\n' % (lfhash))
1042 ui.debug(' %s\n' % (lfhash))
1043 else:
1043 else:
1044 toupload = set()
1044 toupload = set()
1045 def addfunc(fn, lfhash):
1045 def addfunc(fn, lfhash):
1046 toupload.add(fn)
1046 toupload.add(fn)
1047 lfhashes.add(lfhash)
1047 lfhashes.add(lfhash)
1048 def showhashes(fn):
1048 def showhashes(fn):
1049 pass
1049 pass
1050 _getoutgoings(repo, other, missing, addfunc)
1050 _getoutgoings(repo, other, missing, addfunc)
1051
1051
1052 if not toupload:
1052 if not toupload:
1053 ui.status(_('largefiles: no files to upload\n'))
1053 ui.status(_('largefiles: no files to upload\n'))
1054 else:
1054 else:
1055 ui.status(_('largefiles to upload (%d entities):\n')
1055 ui.status(_('largefiles to upload (%d entities):\n')
1056 % (len(lfhashes)))
1056 % (len(lfhashes)))
1057 for file in sorted(toupload):
1057 for file in sorted(toupload):
1058 ui.status(lfutil.splitstandin(file) + '\n')
1058 ui.status(lfutil.splitstandin(file) + '\n')
1059 showhashes(file)
1059 showhashes(file)
1060 ui.status('\n')
1060 ui.status('\n')
1061
1061
1062 def summaryremotehook(ui, repo, opts, changes):
1062 def summaryremotehook(ui, repo, opts, changes):
1063 largeopt = opts.get('large', False)
1063 largeopt = opts.get('large', False)
1064 if changes is None:
1064 if changes is None:
1065 if largeopt:
1065 if largeopt:
1066 return (False, True) # only outgoing check is needed
1066 return (False, True) # only outgoing check is needed
1067 else:
1067 else:
1068 return (False, False)
1068 return (False, False)
1069 elif largeopt:
1069 elif largeopt:
1070 url, branch, peer, outgoing = changes[1]
1070 url, branch, peer, outgoing = changes[1]
1071 if peer is None:
1071 if peer is None:
1072 # i18n: column positioning for "hg summary"
1072 # i18n: column positioning for "hg summary"
1073 ui.status(_('largefiles: (no remote repo)\n'))
1073 ui.status(_('largefiles: (no remote repo)\n'))
1074 return
1074 return
1075
1075
1076 toupload = set()
1076 toupload = set()
1077 lfhashes = set()
1077 lfhashes = set()
1078 def addfunc(fn, lfhash):
1078 def addfunc(fn, lfhash):
1079 toupload.add(fn)
1079 toupload.add(fn)
1080 lfhashes.add(lfhash)
1080 lfhashes.add(lfhash)
1081 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1081 _getoutgoings(repo, peer, outgoing.missing, addfunc)
1082
1082
1083 if not toupload:
1083 if not toupload:
1084 # i18n: column positioning for "hg summary"
1084 # i18n: column positioning for "hg summary"
1085 ui.status(_('largefiles: (no files to upload)\n'))
1085 ui.status(_('largefiles: (no files to upload)\n'))
1086 else:
1086 else:
1087 # i18n: column positioning for "hg summary"
1087 # i18n: column positioning for "hg summary"
1088 ui.status(_('largefiles: %d entities for %d files to upload\n')
1088 ui.status(_('largefiles: %d entities for %d files to upload\n')
1089 % (len(lfhashes), len(toupload)))
1089 % (len(lfhashes), len(toupload)))
1090
1090
1091 def overridesummary(orig, ui, repo, *pats, **opts):
1091 def overridesummary(orig, ui, repo, *pats, **opts):
1092 try:
1092 try:
1093 repo.lfstatus = True
1093 repo.lfstatus = True
1094 orig(ui, repo, *pats, **opts)
1094 orig(ui, repo, *pats, **opts)
1095 finally:
1095 finally:
1096 repo.lfstatus = False
1096 repo.lfstatus = False
1097
1097
1098 def scmutiladdremove(orig, repo, matcher, prefix, opts={}, dry_run=None,
1098 def scmutiladdremove(orig, repo, matcher, prefix, opts={}, dry_run=None,
1099 similarity=None):
1099 similarity=None):
1100 if not lfutil.islfilesrepo(repo):
1100 if not lfutil.islfilesrepo(repo):
1101 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1101 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1102 # Get the list of missing largefiles so we can remove them
1102 # Get the list of missing largefiles so we can remove them
1103 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1103 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1104 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1104 unsure, s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [],
1105 False, False, False)
1105 False, False, False)
1106
1106
1107 # Call into the normal remove code, but the removing of the standin, we want
1107 # Call into the normal remove code, but the removing of the standin, we want
1108 # to have handled by original addremove. Monkey patching here makes sure
1108 # to have handled by original addremove. Monkey patching here makes sure
1109 # we don't remove the standin in the largefiles code, preventing a very
1109 # we don't remove the standin in the largefiles code, preventing a very
1110 # confused state later.
1110 # confused state later.
1111 if s.deleted:
1111 if s.deleted:
1112 m = [repo.wjoin(f) for f in s.deleted]
1112 m = copy.copy(matcher)
1113 removelargefiles(repo.ui, repo, True, *m, **opts)
1113
1114 # The m._files and m._map attributes are not changed to the deleted list
1115 # because that affects the m.exact() test, which in turn governs whether
1116 # or not the file name is printed, and how. Simply limit the original
1117 # matches to those in the deleted status list.
1118 matchfn = m.matchfn
1119 m.matchfn = lambda f: f in s.deleted and matchfn(f)
1120
1121 removelargefiles(repo.ui, repo, True, m, **opts)
1114 # Call into the normal add code, and any files that *should* be added as
1122 # Call into the normal add code, and any files that *should* be added as
1115 # largefiles will be
1123 # largefiles will be
1116 addlargefiles(repo.ui, repo, matcher, **opts)
1124 addlargefiles(repo.ui, repo, matcher, **opts)
1117 # Now that we've handled largefiles, hand off to the original addremove
1125 # Now that we've handled largefiles, hand off to the original addremove
1118 # function to take care of the rest. Make sure it doesn't do anything with
1126 # function to take care of the rest. Make sure it doesn't do anything with
1119 # largefiles by passing a matcher that will ignore them.
1127 # largefiles by passing a matcher that will ignore them.
1120 matcher = composenormalfilematcher(matcher, repo[None].manifest())
1128 matcher = composenormalfilematcher(matcher, repo[None].manifest())
1121 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1129 return orig(repo, matcher, prefix, opts, dry_run, similarity)
1122
1130
1123 # Calling purge with --all will cause the largefiles to be deleted.
1131 # Calling purge with --all will cause the largefiles to be deleted.
1124 # Override repo.status to prevent this from happening.
1132 # Override repo.status to prevent this from happening.
1125 def overridepurge(orig, ui, repo, *dirs, **opts):
1133 def overridepurge(orig, ui, repo, *dirs, **opts):
1126 # XXX Monkey patching a repoview will not work. The assigned attribute will
1134 # XXX Monkey patching a repoview will not work. The assigned attribute will
1127 # be set on the unfiltered repo, but we will only lookup attributes in the
1135 # be set on the unfiltered repo, but we will only lookup attributes in the
1128 # unfiltered repo if the lookup in the repoview object itself fails. As the
1136 # unfiltered repo if the lookup in the repoview object itself fails. As the
1129 # monkey patched method exists on the repoview class the lookup will not
1137 # monkey patched method exists on the repoview class the lookup will not
1130 # fail. As a result, the original version will shadow the monkey patched
1138 # fail. As a result, the original version will shadow the monkey patched
1131 # one, defeating the monkey patch.
1139 # one, defeating the monkey patch.
1132 #
1140 #
1133 # As a work around we use an unfiltered repo here. We should do something
1141 # As a work around we use an unfiltered repo here. We should do something
1134 # cleaner instead.
1142 # cleaner instead.
1135 repo = repo.unfiltered()
1143 repo = repo.unfiltered()
1136 oldstatus = repo.status
1144 oldstatus = repo.status
1137 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1145 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1138 clean=False, unknown=False, listsubrepos=False):
1146 clean=False, unknown=False, listsubrepos=False):
1139 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1147 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1140 listsubrepos)
1148 listsubrepos)
1141 lfdirstate = lfutil.openlfdirstate(ui, repo)
1149 lfdirstate = lfutil.openlfdirstate(ui, repo)
1142 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1150 unknown = [f for f in r.unknown if lfdirstate[f] == '?']
1143 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1151 ignored = [f for f in r.ignored if lfdirstate[f] == '?']
1144 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1152 return scmutil.status(r.modified, r.added, r.removed, r.deleted,
1145 unknown, ignored, r.clean)
1153 unknown, ignored, r.clean)
1146 repo.status = overridestatus
1154 repo.status = overridestatus
1147 orig(ui, repo, *dirs, **opts)
1155 orig(ui, repo, *dirs, **opts)
1148 repo.status = oldstatus
1156 repo.status = oldstatus
1149 def overriderollback(orig, ui, repo, **opts):
1157 def overriderollback(orig, ui, repo, **opts):
1150 wlock = repo.wlock()
1158 wlock = repo.wlock()
1151 try:
1159 try:
1152 before = repo.dirstate.parents()
1160 before = repo.dirstate.parents()
1153 orphans = set(f for f in repo.dirstate
1161 orphans = set(f for f in repo.dirstate
1154 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1162 if lfutil.isstandin(f) and repo.dirstate[f] != 'r')
1155 result = orig(ui, repo, **opts)
1163 result = orig(ui, repo, **opts)
1156 after = repo.dirstate.parents()
1164 after = repo.dirstate.parents()
1157 if before == after:
1165 if before == after:
1158 return result # no need to restore standins
1166 return result # no need to restore standins
1159
1167
1160 pctx = repo['.']
1168 pctx = repo['.']
1161 for f in repo.dirstate:
1169 for f in repo.dirstate:
1162 if lfutil.isstandin(f):
1170 if lfutil.isstandin(f):
1163 orphans.discard(f)
1171 orphans.discard(f)
1164 if repo.dirstate[f] == 'r':
1172 if repo.dirstate[f] == 'r':
1165 repo.wvfs.unlinkpath(f, ignoremissing=True)
1173 repo.wvfs.unlinkpath(f, ignoremissing=True)
1166 elif f in pctx:
1174 elif f in pctx:
1167 fctx = pctx[f]
1175 fctx = pctx[f]
1168 repo.wwrite(f, fctx.data(), fctx.flags())
1176 repo.wwrite(f, fctx.data(), fctx.flags())
1169 else:
1177 else:
1170 # content of standin is not so important in 'a',
1178 # content of standin is not so important in 'a',
1171 # 'm' or 'n' (coming from the 2nd parent) cases
1179 # 'm' or 'n' (coming from the 2nd parent) cases
1172 lfutil.writestandin(repo, f, '', False)
1180 lfutil.writestandin(repo, f, '', False)
1173 for standin in orphans:
1181 for standin in orphans:
1174 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1182 repo.wvfs.unlinkpath(standin, ignoremissing=True)
1175
1183
1176 lfdirstate = lfutil.openlfdirstate(ui, repo)
1184 lfdirstate = lfutil.openlfdirstate(ui, repo)
1177 orphans = set(lfdirstate)
1185 orphans = set(lfdirstate)
1178 lfiles = lfutil.listlfiles(repo)
1186 lfiles = lfutil.listlfiles(repo)
1179 for file in lfiles:
1187 for file in lfiles:
1180 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1188 lfutil.synclfdirstate(repo, lfdirstate, file, True)
1181 orphans.discard(file)
1189 orphans.discard(file)
1182 for lfile in orphans:
1190 for lfile in orphans:
1183 lfdirstate.drop(lfile)
1191 lfdirstate.drop(lfile)
1184 lfdirstate.write()
1192 lfdirstate.write()
1185 finally:
1193 finally:
1186 wlock.release()
1194 wlock.release()
1187 return result
1195 return result
1188
1196
1189 def overridetransplant(orig, ui, repo, *revs, **opts):
1197 def overridetransplant(orig, ui, repo, *revs, **opts):
1190 resuming = opts.get('continue')
1198 resuming = opts.get('continue')
1191 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1199 repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
1192 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1200 repo._lfstatuswriters.append(lambda *msg, **opts: None)
1193 try:
1201 try:
1194 result = orig(ui, repo, *revs, **opts)
1202 result = orig(ui, repo, *revs, **opts)
1195 finally:
1203 finally:
1196 repo._lfstatuswriters.pop()
1204 repo._lfstatuswriters.pop()
1197 repo._lfcommithooks.pop()
1205 repo._lfcommithooks.pop()
1198 return result
1206 return result
1199
1207
1200 def overridecat(orig, ui, repo, file1, *pats, **opts):
1208 def overridecat(orig, ui, repo, file1, *pats, **opts):
1201 ctx = scmutil.revsingle(repo, opts.get('rev'))
1209 ctx = scmutil.revsingle(repo, opts.get('rev'))
1202 err = 1
1210 err = 1
1203 notbad = set()
1211 notbad = set()
1204 m = scmutil.match(ctx, (file1,) + pats, opts)
1212 m = scmutil.match(ctx, (file1,) + pats, opts)
1205 origmatchfn = m.matchfn
1213 origmatchfn = m.matchfn
1206 def lfmatchfn(f):
1214 def lfmatchfn(f):
1207 if origmatchfn(f):
1215 if origmatchfn(f):
1208 return True
1216 return True
1209 lf = lfutil.splitstandin(f)
1217 lf = lfutil.splitstandin(f)
1210 if lf is None:
1218 if lf is None:
1211 return False
1219 return False
1212 notbad.add(lf)
1220 notbad.add(lf)
1213 return origmatchfn(lf)
1221 return origmatchfn(lf)
1214 m.matchfn = lfmatchfn
1222 m.matchfn = lfmatchfn
1215 origbadfn = m.bad
1223 origbadfn = m.bad
1216 def lfbadfn(f, msg):
1224 def lfbadfn(f, msg):
1217 if not f in notbad:
1225 if not f in notbad:
1218 origbadfn(f, msg)
1226 origbadfn(f, msg)
1219 m.bad = lfbadfn
1227 m.bad = lfbadfn
1220 for f in ctx.walk(m):
1228 for f in ctx.walk(m):
1221 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1229 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1222 pathname=f)
1230 pathname=f)
1223 lf = lfutil.splitstandin(f)
1231 lf = lfutil.splitstandin(f)
1224 if lf is None or origmatchfn(f):
1232 if lf is None or origmatchfn(f):
1225 # duplicating unreachable code from commands.cat
1233 # duplicating unreachable code from commands.cat
1226 data = ctx[f].data()
1234 data = ctx[f].data()
1227 if opts.get('decode'):
1235 if opts.get('decode'):
1228 data = repo.wwritedata(f, data)
1236 data = repo.wwritedata(f, data)
1229 fp.write(data)
1237 fp.write(data)
1230 else:
1238 else:
1231 hash = lfutil.readstandin(repo, lf, ctx.rev())
1239 hash = lfutil.readstandin(repo, lf, ctx.rev())
1232 if not lfutil.inusercache(repo.ui, hash):
1240 if not lfutil.inusercache(repo.ui, hash):
1233 store = basestore._openstore(repo)
1241 store = basestore._openstore(repo)
1234 success, missing = store.get([(lf, hash)])
1242 success, missing = store.get([(lf, hash)])
1235 if len(success) != 1:
1243 if len(success) != 1:
1236 raise util.Abort(
1244 raise util.Abort(
1237 _('largefile %s is not in cache and could not be '
1245 _('largefile %s is not in cache and could not be '
1238 'downloaded') % lf)
1246 'downloaded') % lf)
1239 path = lfutil.usercachepath(repo.ui, hash)
1247 path = lfutil.usercachepath(repo.ui, hash)
1240 fpin = open(path, "rb")
1248 fpin = open(path, "rb")
1241 for chunk in util.filechunkiter(fpin, 128 * 1024):
1249 for chunk in util.filechunkiter(fpin, 128 * 1024):
1242 fp.write(chunk)
1250 fp.write(chunk)
1243 fpin.close()
1251 fpin.close()
1244 fp.close()
1252 fp.close()
1245 err = 0
1253 err = 0
1246 return err
1254 return err
1247
1255
1248 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1256 def mergeupdate(orig, repo, node, branchmerge, force, partial,
1249 *args, **kwargs):
1257 *args, **kwargs):
1250 wlock = repo.wlock()
1258 wlock = repo.wlock()
1251 try:
1259 try:
1252 # branch | | |
1260 # branch | | |
1253 # merge | force | partial | action
1261 # merge | force | partial | action
1254 # -------+-------+---------+--------------
1262 # -------+-------+---------+--------------
1255 # x | x | x | linear-merge
1263 # x | x | x | linear-merge
1256 # o | x | x | branch-merge
1264 # o | x | x | branch-merge
1257 # x | o | x | overwrite (as clean update)
1265 # x | o | x | overwrite (as clean update)
1258 # o | o | x | force-branch-merge (*1)
1266 # o | o | x | force-branch-merge (*1)
1259 # x | x | o | (*)
1267 # x | x | o | (*)
1260 # o | x | o | (*)
1268 # o | x | o | (*)
1261 # x | o | o | overwrite (as revert)
1269 # x | o | o | overwrite (as revert)
1262 # o | o | o | (*)
1270 # o | o | o | (*)
1263 #
1271 #
1264 # (*) don't care
1272 # (*) don't care
1265 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1273 # (*1) deprecated, but used internally (e.g: "rebase --collapse")
1266
1274
1267 linearmerge = not branchmerge and not force and not partial
1275 linearmerge = not branchmerge and not force and not partial
1268
1276
1269 if linearmerge or (branchmerge and force and not partial):
1277 if linearmerge or (branchmerge and force and not partial):
1270 # update standins for linear-merge or force-branch-merge,
1278 # update standins for linear-merge or force-branch-merge,
1271 # because largefiles in the working directory may be modified
1279 # because largefiles in the working directory may be modified
1272 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1280 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1273 unsure, s = lfdirstate.status(match_.always(repo.root,
1281 unsure, s = lfdirstate.status(match_.always(repo.root,
1274 repo.getcwd()),
1282 repo.getcwd()),
1275 [], False, False, False)
1283 [], False, False, False)
1276 for lfile in unsure + s.modified + s.added:
1284 for lfile in unsure + s.modified + s.added:
1277 lfutil.updatestandin(repo, lfutil.standin(lfile))
1285 lfutil.updatestandin(repo, lfutil.standin(lfile))
1278
1286
1279 if linearmerge:
1287 if linearmerge:
1280 # Only call updatelfiles on the standins that have changed
1288 # Only call updatelfiles on the standins that have changed
1281 # to save time
1289 # to save time
1282 oldstandins = lfutil.getstandinsstate(repo)
1290 oldstandins = lfutil.getstandinsstate(repo)
1283
1291
1284 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1292 result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
1285
1293
1286 filelist = None
1294 filelist = None
1287 if linearmerge:
1295 if linearmerge:
1288 newstandins = lfutil.getstandinsstate(repo)
1296 newstandins = lfutil.getstandinsstate(repo)
1289 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1297 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1290
1298
1291 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1299 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1292 normallookup=partial)
1300 normallookup=partial)
1293
1301
1294 return result
1302 return result
1295 finally:
1303 finally:
1296 wlock.release()
1304 wlock.release()
1297
1305
1298 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1306 def scmutilmarktouched(orig, repo, files, *args, **kwargs):
1299 result = orig(repo, files, *args, **kwargs)
1307 result = orig(repo, files, *args, **kwargs)
1300
1308
1301 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1309 filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)]
1302 if filelist:
1310 if filelist:
1303 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1311 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1304 printmessage=False, normallookup=True)
1312 printmessage=False, normallookup=True)
1305
1313
1306 return result
1314 return result
@@ -1,888 +1,890 b''
1 This file contains testcases that tend to be related to special cases or less
1 This file contains testcases that tend to be related to special cases or less
2 common commands affecting largefile.
2 common commands affecting largefile.
3
3
4 Each sections should be independent of each others.
4 Each sections should be independent of each others.
5
5
6 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
6 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
7 $ mkdir "${USERCACHE}"
7 $ mkdir "${USERCACHE}"
8 $ cat >> $HGRCPATH <<EOF
8 $ cat >> $HGRCPATH <<EOF
9 > [extensions]
9 > [extensions]
10 > largefiles=
10 > largefiles=
11 > purge=
11 > purge=
12 > rebase=
12 > rebase=
13 > transplant=
13 > transplant=
14 > [phases]
14 > [phases]
15 > publish=False
15 > publish=False
16 > [largefiles]
16 > [largefiles]
17 > minsize=2
17 > minsize=2
18 > patterns=glob:**.dat
18 > patterns=glob:**.dat
19 > usercache=${USERCACHE}
19 > usercache=${USERCACHE}
20 > [hooks]
20 > [hooks]
21 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
21 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
22 > EOF
22 > EOF
23
23
24
24
25
25
26 Test copies and moves from a directory other than root (issue3516)
26 Test copies and moves from a directory other than root (issue3516)
27 =========================================================================
27 =========================================================================
28
28
29 $ hg init lf_cpmv
29 $ hg init lf_cpmv
30 $ cd lf_cpmv
30 $ cd lf_cpmv
31 $ mkdir dira
31 $ mkdir dira
32 $ mkdir dira/dirb
32 $ mkdir dira/dirb
33 $ touch dira/dirb/largefile
33 $ touch dira/dirb/largefile
34 $ hg add --large dira/dirb/largefile
34 $ hg add --large dira/dirb/largefile
35 $ hg commit -m "added"
35 $ hg commit -m "added"
36 Invoking status precommit hook
36 Invoking status precommit hook
37 A dira/dirb/largefile
37 A dira/dirb/largefile
38 $ cd dira
38 $ cd dira
39 $ hg cp dirb/largefile foo/largefile
39 $ hg cp dirb/largefile foo/largefile
40 $ hg ci -m "deep copy"
40 $ hg ci -m "deep copy"
41 Invoking status precommit hook
41 Invoking status precommit hook
42 A dira/foo/largefile
42 A dira/foo/largefile
43 $ find . | sort
43 $ find . | sort
44 .
44 .
45 ./dirb
45 ./dirb
46 ./dirb/largefile
46 ./dirb/largefile
47 ./foo
47 ./foo
48 ./foo/largefile
48 ./foo/largefile
49 $ hg mv foo/largefile baz/largefile
49 $ hg mv foo/largefile baz/largefile
50 $ hg ci -m "moved"
50 $ hg ci -m "moved"
51 Invoking status precommit hook
51 Invoking status precommit hook
52 A dira/baz/largefile
52 A dira/baz/largefile
53 R dira/foo/largefile
53 R dira/foo/largefile
54 $ find . | sort
54 $ find . | sort
55 .
55 .
56 ./baz
56 ./baz
57 ./baz/largefile
57 ./baz/largefile
58 ./dirb
58 ./dirb
59 ./dirb/largefile
59 ./dirb/largefile
60 $ cd ..
60 $ cd ..
61 $ hg mv dira dirc
61 $ hg mv dira dirc
62 moving .hglf/dira/baz/largefile to .hglf/dirc/baz/largefile (glob)
62 moving .hglf/dira/baz/largefile to .hglf/dirc/baz/largefile (glob)
63 moving .hglf/dira/dirb/largefile to .hglf/dirc/dirb/largefile (glob)
63 moving .hglf/dira/dirb/largefile to .hglf/dirc/dirb/largefile (glob)
64 $ find * | sort
64 $ find * | sort
65 dirc
65 dirc
66 dirc/baz
66 dirc/baz
67 dirc/baz/largefile
67 dirc/baz/largefile
68 dirc/dirb
68 dirc/dirb
69 dirc/dirb/largefile
69 dirc/dirb/largefile
70
70
71 $ hg clone -q . ../fetch
71 $ hg clone -q . ../fetch
72 $ hg --config extensions.fetch= fetch ../fetch
72 $ hg --config extensions.fetch= fetch ../fetch
73 abort: uncommitted changes
73 abort: uncommitted changes
74 [255]
74 [255]
75 $ hg up -qC
75 $ hg up -qC
76 $ cd ..
76 $ cd ..
77
77
78 Clone a local repository owned by another user
78 Clone a local repository owned by another user
79 ===================================================
79 ===================================================
80
80
81 #if unix-permissions
81 #if unix-permissions
82
82
83 We have to simulate that here by setting $HOME and removing write permissions
83 We have to simulate that here by setting $HOME and removing write permissions
84 $ ORIGHOME="$HOME"
84 $ ORIGHOME="$HOME"
85 $ mkdir alice
85 $ mkdir alice
86 $ HOME="`pwd`/alice"
86 $ HOME="`pwd`/alice"
87 $ cd alice
87 $ cd alice
88 $ hg init pubrepo
88 $ hg init pubrepo
89 $ cd pubrepo
89 $ cd pubrepo
90 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
90 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
91 $ hg add --large a-large-file
91 $ hg add --large a-large-file
92 $ hg commit -m "Add a large file"
92 $ hg commit -m "Add a large file"
93 Invoking status precommit hook
93 Invoking status precommit hook
94 A a-large-file
94 A a-large-file
95 $ cd ..
95 $ cd ..
96 $ chmod -R a-w pubrepo
96 $ chmod -R a-w pubrepo
97 $ cd ..
97 $ cd ..
98 $ mkdir bob
98 $ mkdir bob
99 $ HOME="`pwd`/bob"
99 $ HOME="`pwd`/bob"
100 $ cd bob
100 $ cd bob
101 $ hg clone --pull ../alice/pubrepo pubrepo
101 $ hg clone --pull ../alice/pubrepo pubrepo
102 requesting all changes
102 requesting all changes
103 adding changesets
103 adding changesets
104 adding manifests
104 adding manifests
105 adding file changes
105 adding file changes
106 added 1 changesets with 1 changes to 1 files
106 added 1 changesets with 1 changes to 1 files
107 updating to branch default
107 updating to branch default
108 getting changed largefiles
108 getting changed largefiles
109 1 largefiles updated, 0 removed
109 1 largefiles updated, 0 removed
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 $ cd ..
111 $ cd ..
112 $ chmod -R u+w alice/pubrepo
112 $ chmod -R u+w alice/pubrepo
113 $ HOME="$ORIGHOME"
113 $ HOME="$ORIGHOME"
114
114
115 #endif
115 #endif
116
116
117
117
118 Symlink to a large largefile should behave the same as a symlink to a normal file
118 Symlink to a large largefile should behave the same as a symlink to a normal file
119 =====================================================================================
119 =====================================================================================
120
120
121 #if symlink
121 #if symlink
122
122
123 $ hg init largesymlink
123 $ hg init largesymlink
124 $ cd largesymlink
124 $ cd largesymlink
125 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
125 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
126 $ hg add --large largefile
126 $ hg add --large largefile
127 $ hg commit -m "commit a large file"
127 $ hg commit -m "commit a large file"
128 Invoking status precommit hook
128 Invoking status precommit hook
129 A largefile
129 A largefile
130 $ ln -s largefile largelink
130 $ ln -s largefile largelink
131 $ hg add largelink
131 $ hg add largelink
132 $ hg commit -m "commit a large symlink"
132 $ hg commit -m "commit a large symlink"
133 Invoking status precommit hook
133 Invoking status precommit hook
134 A largelink
134 A largelink
135 $ rm -f largelink
135 $ rm -f largelink
136 $ hg up >/dev/null
136 $ hg up >/dev/null
137 $ test -f largelink
137 $ test -f largelink
138 [1]
138 [1]
139 $ test -L largelink
139 $ test -L largelink
140 [1]
140 [1]
141 $ rm -f largelink # make next part of the test independent of the previous
141 $ rm -f largelink # make next part of the test independent of the previous
142 $ hg up -C >/dev/null
142 $ hg up -C >/dev/null
143 $ test -f largelink
143 $ test -f largelink
144 $ test -L largelink
144 $ test -L largelink
145 $ cd ..
145 $ cd ..
146
146
147 #endif
147 #endif
148
148
149
149
150 test for pattern matching on 'hg status':
150 test for pattern matching on 'hg status':
151 ==============================================
151 ==============================================
152
152
153
153
154 to boost performance, largefiles checks whether specified patterns are
154 to boost performance, largefiles checks whether specified patterns are
155 related to largefiles in working directory (NOT to STANDIN) or not.
155 related to largefiles in working directory (NOT to STANDIN) or not.
156
156
157 $ hg init statusmatch
157 $ hg init statusmatch
158 $ cd statusmatch
158 $ cd statusmatch
159
159
160 $ mkdir -p a/b/c/d
160 $ mkdir -p a/b/c/d
161 $ echo normal > a/b/c/d/e.normal.txt
161 $ echo normal > a/b/c/d/e.normal.txt
162 $ hg add a/b/c/d/e.normal.txt
162 $ hg add a/b/c/d/e.normal.txt
163 $ echo large > a/b/c/d/e.large.txt
163 $ echo large > a/b/c/d/e.large.txt
164 $ hg add --large a/b/c/d/e.large.txt
164 $ hg add --large a/b/c/d/e.large.txt
165 $ mkdir -p a/b/c/x
165 $ mkdir -p a/b/c/x
166 $ echo normal > a/b/c/x/y.normal.txt
166 $ echo normal > a/b/c/x/y.normal.txt
167 $ hg add a/b/c/x/y.normal.txt
167 $ hg add a/b/c/x/y.normal.txt
168 $ hg commit -m 'add files'
168 $ hg commit -m 'add files'
169 Invoking status precommit hook
169 Invoking status precommit hook
170 A a/b/c/d/e.large.txt
170 A a/b/c/d/e.large.txt
171 A a/b/c/d/e.normal.txt
171 A a/b/c/d/e.normal.txt
172 A a/b/c/x/y.normal.txt
172 A a/b/c/x/y.normal.txt
173
173
174 (1) no pattern: no performance boost
174 (1) no pattern: no performance boost
175 $ hg status -A
175 $ hg status -A
176 C a/b/c/d/e.large.txt
176 C a/b/c/d/e.large.txt
177 C a/b/c/d/e.normal.txt
177 C a/b/c/d/e.normal.txt
178 C a/b/c/x/y.normal.txt
178 C a/b/c/x/y.normal.txt
179
179
180 (2) pattern not related to largefiles: performance boost
180 (2) pattern not related to largefiles: performance boost
181 $ hg status -A a/b/c/x
181 $ hg status -A a/b/c/x
182 C a/b/c/x/y.normal.txt
182 C a/b/c/x/y.normal.txt
183
183
184 (3) pattern related to largefiles: no performance boost
184 (3) pattern related to largefiles: no performance boost
185 $ hg status -A a/b/c/d
185 $ hg status -A a/b/c/d
186 C a/b/c/d/e.large.txt
186 C a/b/c/d/e.large.txt
187 C a/b/c/d/e.normal.txt
187 C a/b/c/d/e.normal.txt
188
188
189 (4) pattern related to STANDIN (not to largefiles): performance boost
189 (4) pattern related to STANDIN (not to largefiles): performance boost
190 $ hg status -A .hglf/a
190 $ hg status -A .hglf/a
191 C .hglf/a/b/c/d/e.large.txt
191 C .hglf/a/b/c/d/e.large.txt
192
192
193 (5) mixed case: no performance boost
193 (5) mixed case: no performance boost
194 $ hg status -A a/b/c/x a/b/c/d
194 $ hg status -A a/b/c/x a/b/c/d
195 C a/b/c/d/e.large.txt
195 C a/b/c/d/e.large.txt
196 C a/b/c/d/e.normal.txt
196 C a/b/c/d/e.normal.txt
197 C a/b/c/x/y.normal.txt
197 C a/b/c/x/y.normal.txt
198
198
199 verify that largefiles doesn't break filesets
199 verify that largefiles doesn't break filesets
200
200
201 $ hg log --rev . --exclude "set:binary()"
201 $ hg log --rev . --exclude "set:binary()"
202 changeset: 0:41bd42f10efa
202 changeset: 0:41bd42f10efa
203 tag: tip
203 tag: tip
204 user: test
204 user: test
205 date: Thu Jan 01 00:00:00 1970 +0000
205 date: Thu Jan 01 00:00:00 1970 +0000
206 summary: add files
206 summary: add files
207
207
208 verify that large files in subrepos handled properly
208 verify that large files in subrepos handled properly
209 $ hg init subrepo
209 $ hg init subrepo
210 $ echo "subrepo = subrepo" > .hgsub
210 $ echo "subrepo = subrepo" > .hgsub
211 $ hg add .hgsub
211 $ hg add .hgsub
212 $ hg ci -m "add subrepo"
212 $ hg ci -m "add subrepo"
213 Invoking status precommit hook
213 Invoking status precommit hook
214 A .hgsub
214 A .hgsub
215 ? .hgsubstate
215 ? .hgsubstate
216 $ echo "rev 1" > subrepo/large.txt
216 $ echo "rev 1" > subrepo/large.txt
217 $ hg -R subrepo add --large subrepo/large.txt
217 $ hg -R subrepo add --large subrepo/large.txt
218 $ hg sum
218 $ hg sum
219 parent: 1:8ee150ea2e9c tip
219 parent: 1:8ee150ea2e9c tip
220 add subrepo
220 add subrepo
221 branch: default
221 branch: default
222 commit: 1 subrepos
222 commit: 1 subrepos
223 update: (current)
223 update: (current)
224 $ hg st
224 $ hg st
225 $ hg st -S
225 $ hg st -S
226 A subrepo/large.txt
226 A subrepo/large.txt
227 $ hg ci -S -m "commit top repo"
227 $ hg ci -S -m "commit top repo"
228 committing subrepository subrepo
228 committing subrepository subrepo
229 Invoking status precommit hook
229 Invoking status precommit hook
230 A large.txt
230 A large.txt
231 Invoking status precommit hook
231 Invoking status precommit hook
232 M .hgsubstate
232 M .hgsubstate
233 # No differences
233 # No differences
234 $ hg st -S
234 $ hg st -S
235 $ hg sum
235 $ hg sum
236 parent: 2:ce4cd0c527a6 tip
236 parent: 2:ce4cd0c527a6 tip
237 commit top repo
237 commit top repo
238 branch: default
238 branch: default
239 commit: (clean)
239 commit: (clean)
240 update: (current)
240 update: (current)
241 $ echo "rev 2" > subrepo/large.txt
241 $ echo "rev 2" > subrepo/large.txt
242 $ hg st -S
242 $ hg st -S
243 M subrepo/large.txt
243 M subrepo/large.txt
244 $ hg sum
244 $ hg sum
245 parent: 2:ce4cd0c527a6 tip
245 parent: 2:ce4cd0c527a6 tip
246 commit top repo
246 commit top repo
247 branch: default
247 branch: default
248 commit: 1 subrepos
248 commit: 1 subrepos
249 update: (current)
249 update: (current)
250 $ hg ci -m "this commit should fail without -S"
250 $ hg ci -m "this commit should fail without -S"
251 abort: uncommitted changes in subrepo subrepo
251 abort: uncommitted changes in subrepo subrepo
252 (use --subrepos for recursive commit)
252 (use --subrepos for recursive commit)
253 [255]
253 [255]
254
254
255 Add a normal file to the subrepo, then test archiving
255 Add a normal file to the subrepo, then test archiving
256
256
257 $ echo 'normal file' > subrepo/normal.txt
257 $ echo 'normal file' > subrepo/normal.txt
258 $ touch large.dat
258 $ touch large.dat
259 $ mv subrepo/large.txt subrepo/renamed-large.txt
259 $ mv subrepo/large.txt subrepo/renamed-large.txt
260 $ hg -R subrepo addremove --dry-run
260 $ hg -R subrepo addremove --dry-run
261 removing large.txt
261 removing large.txt
262 adding normal.txt
262 adding normal.txt
263 adding renamed-large.txt
263 adding renamed-large.txt
264 $ hg status -S
264 $ hg status -S
265 ! subrepo/large.txt
265 ! subrepo/large.txt
266 ? large.dat
266 ? large.dat
267 ? subrepo/normal.txt
267 ? subrepo/normal.txt
268 ? subrepo/renamed-large.txt
268 ? subrepo/renamed-large.txt
269 $ mv subrepo/renamed-large.txt subrepo/large.txt
269 $ mv subrepo/renamed-large.txt subrepo/large.txt
270 $ hg -R subrepo add subrepo/normal.txt
270 $ hg -R subrepo add subrepo/normal.txt
271
271
272 $ hg addremove
272 $ hg addremove subrepo
273 $ hg addremove -S
273 adding large.dat as a largefile
274 adding large.dat as a largefile
274 $ rm large.dat
275 $ rm large.dat
275
276
276 $ hg addremove
277 $ hg addremove subrepo
278 $ hg addremove -S
277 removing large.dat
279 removing large.dat
278
280
279 Lock in subrepo, otherwise the change isn't archived
281 Lock in subrepo, otherwise the change isn't archived
280
282
281 $ hg ci -S -m "add normal file to top level"
283 $ hg ci -S -m "add normal file to top level"
282 committing subrepository subrepo
284 committing subrepository subrepo
283 Invoking status precommit hook
285 Invoking status precommit hook
284 M large.txt
286 M large.txt
285 A normal.txt
287 A normal.txt
286 Invoking status precommit hook
288 Invoking status precommit hook
287 M .hgsubstate
289 M .hgsubstate
288 $ hg archive -S ../lf_subrepo_archive
290 $ hg archive -S ../lf_subrepo_archive
289 $ find ../lf_subrepo_archive | sort
291 $ find ../lf_subrepo_archive | sort
290 ../lf_subrepo_archive
292 ../lf_subrepo_archive
291 ../lf_subrepo_archive/.hg_archival.txt
293 ../lf_subrepo_archive/.hg_archival.txt
292 ../lf_subrepo_archive/.hgsub
294 ../lf_subrepo_archive/.hgsub
293 ../lf_subrepo_archive/.hgsubstate
295 ../lf_subrepo_archive/.hgsubstate
294 ../lf_subrepo_archive/a
296 ../lf_subrepo_archive/a
295 ../lf_subrepo_archive/a/b
297 ../lf_subrepo_archive/a/b
296 ../lf_subrepo_archive/a/b/c
298 ../lf_subrepo_archive/a/b/c
297 ../lf_subrepo_archive/a/b/c/d
299 ../lf_subrepo_archive/a/b/c/d
298 ../lf_subrepo_archive/a/b/c/d/e.large.txt
300 ../lf_subrepo_archive/a/b/c/d/e.large.txt
299 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
301 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
300 ../lf_subrepo_archive/a/b/c/x
302 ../lf_subrepo_archive/a/b/c/x
301 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
303 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
302 ../lf_subrepo_archive/subrepo
304 ../lf_subrepo_archive/subrepo
303 ../lf_subrepo_archive/subrepo/large.txt
305 ../lf_subrepo_archive/subrepo/large.txt
304 ../lf_subrepo_archive/subrepo/normal.txt
306 ../lf_subrepo_archive/subrepo/normal.txt
305
307
306 Test update with subrepos.
308 Test update with subrepos.
307
309
308 $ hg update 0
310 $ hg update 0
309 getting changed largefiles
311 getting changed largefiles
310 0 largefiles updated, 1 removed
312 0 largefiles updated, 1 removed
311 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
313 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
312 $ hg status -S
314 $ hg status -S
313 $ hg update tip
315 $ hg update tip
314 getting changed largefiles
316 getting changed largefiles
315 1 largefiles updated, 0 removed
317 1 largefiles updated, 0 removed
316 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
318 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
317 $ hg status -S
319 $ hg status -S
318 # modify a large file
320 # modify a large file
319 $ echo "modified" > subrepo/large.txt
321 $ echo "modified" > subrepo/large.txt
320 $ hg st -S
322 $ hg st -S
321 M subrepo/large.txt
323 M subrepo/large.txt
322 # update -C should revert the change.
324 # update -C should revert the change.
323 $ hg update -C
325 $ hg update -C
324 getting changed largefiles
326 getting changed largefiles
325 1 largefiles updated, 0 removed
327 1 largefiles updated, 0 removed
326 getting changed largefiles
328 getting changed largefiles
327 0 largefiles updated, 0 removed
329 0 largefiles updated, 0 removed
328 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 $ hg status -S
331 $ hg status -S
330
332
331 Test archiving a revision that references a subrepo that is not yet
333 Test archiving a revision that references a subrepo that is not yet
332 cloned (see test-subrepo-recursion.t):
334 cloned (see test-subrepo-recursion.t):
333
335
334 $ hg clone -U . ../empty
336 $ hg clone -U . ../empty
335 $ cd ../empty
337 $ cd ../empty
336 $ hg archive --subrepos -r tip ../archive.tar.gz
338 $ hg archive --subrepos -r tip ../archive.tar.gz
337 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
339 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
338 $ cd ..
340 $ cd ..
339
341
340
342
341
343
342
344
343
345
344
346
345 Test addremove, forget and others
347 Test addremove, forget and others
346 ==============================================
348 ==============================================
347
349
348 Test that addremove picks up largefiles prior to the initial commit (issue3541)
350 Test that addremove picks up largefiles prior to the initial commit (issue3541)
349
351
350 $ hg init addrm2
352 $ hg init addrm2
351 $ cd addrm2
353 $ cd addrm2
352 $ touch large.dat
354 $ touch large.dat
353 $ touch large2.dat
355 $ touch large2.dat
354 $ touch normal
356 $ touch normal
355 $ hg add --large large.dat
357 $ hg add --large large.dat
356 $ hg addremove -v
358 $ hg addremove -v
357 adding large2.dat as a largefile
359 adding large2.dat as a largefile
358 adding normal
360 adding normal
359
361
360 Test that forgetting all largefiles reverts to islfilesrepo() == False
362 Test that forgetting all largefiles reverts to islfilesrepo() == False
361 (addremove will add *.dat as normal files now)
363 (addremove will add *.dat as normal files now)
362 $ hg forget large.dat
364 $ hg forget large.dat
363 $ hg forget large2.dat
365 $ hg forget large2.dat
364 $ hg addremove -v
366 $ hg addremove -v
365 adding large.dat
367 adding large.dat
366 adding large2.dat
368 adding large2.dat
367
369
368 Test commit's addremove option prior to the first commit
370 Test commit's addremove option prior to the first commit
369 $ hg forget large.dat
371 $ hg forget large.dat
370 $ hg forget large2.dat
372 $ hg forget large2.dat
371 $ hg add --large large.dat
373 $ hg add --large large.dat
372 $ hg ci -Am "commit"
374 $ hg ci -Am "commit"
373 adding large2.dat as a largefile
375 adding large2.dat as a largefile
374 Invoking status precommit hook
376 Invoking status precommit hook
375 A large.dat
377 A large.dat
376 A large2.dat
378 A large2.dat
377 A normal
379 A normal
378 $ find .hglf | sort
380 $ find .hglf | sort
379 .hglf
381 .hglf
380 .hglf/large.dat
382 .hglf/large.dat
381 .hglf/large2.dat
383 .hglf/large2.dat
382
384
383 Test actions on largefiles using relative paths from subdir
385 Test actions on largefiles using relative paths from subdir
384
386
385 $ mkdir sub
387 $ mkdir sub
386 $ cd sub
388 $ cd sub
387 $ echo anotherlarge > anotherlarge
389 $ echo anotherlarge > anotherlarge
388 $ hg add --large anotherlarge
390 $ hg add --large anotherlarge
389 $ hg st
391 $ hg st
390 A sub/anotherlarge
392 A sub/anotherlarge
391 $ hg st anotherlarge
393 $ hg st anotherlarge
392 A anotherlarge
394 A anotherlarge
393 $ hg commit -m anotherlarge anotherlarge
395 $ hg commit -m anotherlarge anotherlarge
394 Invoking status precommit hook
396 Invoking status precommit hook
395 A sub/anotherlarge
397 A sub/anotherlarge
396 $ hg log anotherlarge
398 $ hg log anotherlarge
397 changeset: 1:9627a577c5e9
399 changeset: 1:9627a577c5e9
398 tag: tip
400 tag: tip
399 user: test
401 user: test
400 date: Thu Jan 01 00:00:00 1970 +0000
402 date: Thu Jan 01 00:00:00 1970 +0000
401 summary: anotherlarge
403 summary: anotherlarge
402
404
403 $ hg log -G anotherlarge
405 $ hg log -G anotherlarge
404 @ changeset: 1:9627a577c5e9
406 @ changeset: 1:9627a577c5e9
405 | tag: tip
407 | tag: tip
406 | user: test
408 | user: test
407 | date: Thu Jan 01 00:00:00 1970 +0000
409 | date: Thu Jan 01 00:00:00 1970 +0000
408 | summary: anotherlarge
410 | summary: anotherlarge
409 |
411 |
410 $ echo more >> anotherlarge
412 $ echo more >> anotherlarge
411 $ hg st .
413 $ hg st .
412 M anotherlarge
414 M anotherlarge
413 $ hg cat anotherlarge
415 $ hg cat anotherlarge
414 anotherlarge
416 anotherlarge
415 $ hg revert anotherlarge
417 $ hg revert anotherlarge
416 $ hg st
418 $ hg st
417 ? sub/anotherlarge.orig
419 ? sub/anotherlarge.orig
418 $ cd ..
420 $ cd ..
419
421
420 $ cd ..
422 $ cd ..
421
423
422 Check error message while exchange
424 Check error message while exchange
423 =========================================================
425 =========================================================
424
426
425 issue3651: summary/outgoing with largefiles shows "no remote repo"
427 issue3651: summary/outgoing with largefiles shows "no remote repo"
426 unexpectedly
428 unexpectedly
427
429
428 $ mkdir issue3651
430 $ mkdir issue3651
429 $ cd issue3651
431 $ cd issue3651
430
432
431 $ hg init src
433 $ hg init src
432 $ echo a > src/a
434 $ echo a > src/a
433 $ hg -R src add --large src/a
435 $ hg -R src add --large src/a
434 $ hg -R src commit -m '#0'
436 $ hg -R src commit -m '#0'
435 Invoking status precommit hook
437 Invoking status precommit hook
436 A a
438 A a
437
439
438 check messages when no remote repository is specified:
440 check messages when no remote repository is specified:
439 "no remote repo" route for "hg outgoing --large" is not tested here,
441 "no remote repo" route for "hg outgoing --large" is not tested here,
440 because it can't be reproduced easily.
442 because it can't be reproduced easily.
441
443
442 $ hg init clone1
444 $ hg init clone1
443 $ hg -R clone1 -q pull src
445 $ hg -R clone1 -q pull src
444 $ hg -R clone1 -q update
446 $ hg -R clone1 -q update
445 $ hg -R clone1 paths | grep default
447 $ hg -R clone1 paths | grep default
446 [1]
448 [1]
447
449
448 $ hg -R clone1 summary --large
450 $ hg -R clone1 summary --large
449 parent: 0:fc0bd45326d3 tip
451 parent: 0:fc0bd45326d3 tip
450 #0
452 #0
451 branch: default
453 branch: default
452 commit: (clean)
454 commit: (clean)
453 update: (current)
455 update: (current)
454 largefiles: (no remote repo)
456 largefiles: (no remote repo)
455
457
456 check messages when there is no files to upload:
458 check messages when there is no files to upload:
457
459
458 $ hg -q clone src clone2
460 $ hg -q clone src clone2
459 $ hg -R clone2 paths | grep default
461 $ hg -R clone2 paths | grep default
460 default = $TESTTMP/issue3651/src (glob)
462 default = $TESTTMP/issue3651/src (glob)
461
463
462 $ hg -R clone2 summary --large
464 $ hg -R clone2 summary --large
463 parent: 0:fc0bd45326d3 tip
465 parent: 0:fc0bd45326d3 tip
464 #0
466 #0
465 branch: default
467 branch: default
466 commit: (clean)
468 commit: (clean)
467 update: (current)
469 update: (current)
468 largefiles: (no files to upload)
470 largefiles: (no files to upload)
469 $ hg -R clone2 outgoing --large
471 $ hg -R clone2 outgoing --large
470 comparing with $TESTTMP/issue3651/src (glob)
472 comparing with $TESTTMP/issue3651/src (glob)
471 searching for changes
473 searching for changes
472 no changes found
474 no changes found
473 largefiles: no files to upload
475 largefiles: no files to upload
474 [1]
476 [1]
475
477
476 $ hg -R clone2 outgoing --large --graph --template "{rev}"
478 $ hg -R clone2 outgoing --large --graph --template "{rev}"
477 comparing with $TESTTMP/issue3651/src (glob)
479 comparing with $TESTTMP/issue3651/src (glob)
478 searching for changes
480 searching for changes
479 no changes found
481 no changes found
480 largefiles: no files to upload
482 largefiles: no files to upload
481
483
482 check messages when there are files to upload:
484 check messages when there are files to upload:
483
485
484 $ echo b > clone2/b
486 $ echo b > clone2/b
485 $ hg -R clone2 add --large clone2/b
487 $ hg -R clone2 add --large clone2/b
486 $ hg -R clone2 commit -m '#1'
488 $ hg -R clone2 commit -m '#1'
487 Invoking status precommit hook
489 Invoking status precommit hook
488 A b
490 A b
489 $ hg -R clone2 summary --large
491 $ hg -R clone2 summary --large
490 parent: 1:1acbe71ce432 tip
492 parent: 1:1acbe71ce432 tip
491 #1
493 #1
492 branch: default
494 branch: default
493 commit: (clean)
495 commit: (clean)
494 update: (current)
496 update: (current)
495 largefiles: 1 entities for 1 files to upload
497 largefiles: 1 entities for 1 files to upload
496 $ hg -R clone2 outgoing --large
498 $ hg -R clone2 outgoing --large
497 comparing with $TESTTMP/issue3651/src (glob)
499 comparing with $TESTTMP/issue3651/src (glob)
498 searching for changes
500 searching for changes
499 changeset: 1:1acbe71ce432
501 changeset: 1:1acbe71ce432
500 tag: tip
502 tag: tip
501 user: test
503 user: test
502 date: Thu Jan 01 00:00:00 1970 +0000
504 date: Thu Jan 01 00:00:00 1970 +0000
503 summary: #1
505 summary: #1
504
506
505 largefiles to upload (1 entities):
507 largefiles to upload (1 entities):
506 b
508 b
507
509
508 $ hg -R clone2 outgoing --large --graph --template "{rev}"
510 $ hg -R clone2 outgoing --large --graph --template "{rev}"
509 comparing with $TESTTMP/issue3651/src (glob)
511 comparing with $TESTTMP/issue3651/src (glob)
510 searching for changes
512 searching for changes
511 @ 1
513 @ 1
512
514
513 largefiles to upload (1 entities):
515 largefiles to upload (1 entities):
514 b
516 b
515
517
516
518
517 $ cp clone2/b clone2/b1
519 $ cp clone2/b clone2/b1
518 $ cp clone2/b clone2/b2
520 $ cp clone2/b clone2/b2
519 $ hg -R clone2 add --large clone2/b1 clone2/b2
521 $ hg -R clone2 add --large clone2/b1 clone2/b2
520 $ hg -R clone2 commit -m '#2: add largefiles referring same entity'
522 $ hg -R clone2 commit -m '#2: add largefiles referring same entity'
521 Invoking status precommit hook
523 Invoking status precommit hook
522 A b1
524 A b1
523 A b2
525 A b2
524 $ hg -R clone2 summary --large
526 $ hg -R clone2 summary --large
525 parent: 2:6095d0695d70 tip
527 parent: 2:6095d0695d70 tip
526 #2: add largefiles referring same entity
528 #2: add largefiles referring same entity
527 branch: default
529 branch: default
528 commit: (clean)
530 commit: (clean)
529 update: (current)
531 update: (current)
530 largefiles: 1 entities for 3 files to upload
532 largefiles: 1 entities for 3 files to upload
531 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
533 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
532 comparing with $TESTTMP/issue3651/src (glob)
534 comparing with $TESTTMP/issue3651/src (glob)
533 searching for changes
535 searching for changes
534 1:1acbe71ce432
536 1:1acbe71ce432
535 2:6095d0695d70
537 2:6095d0695d70
536 largefiles to upload (1 entities):
538 largefiles to upload (1 entities):
537 b
539 b
538 b1
540 b1
539 b2
541 b2
540
542
541 $ hg -R clone2 cat -r 1 clone2/.hglf/b
543 $ hg -R clone2 cat -r 1 clone2/.hglf/b
542 89e6c98d92887913cadf06b2adb97f26cde4849b
544 89e6c98d92887913cadf06b2adb97f26cde4849b
543 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
545 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
544 comparing with $TESTTMP/issue3651/src (glob)
546 comparing with $TESTTMP/issue3651/src (glob)
545 query 1; heads
547 query 1; heads
546 searching for changes
548 searching for changes
547 all remote heads known locally
549 all remote heads known locally
548 1:1acbe71ce432
550 1:1acbe71ce432
549 2:6095d0695d70
551 2:6095d0695d70
550 largefiles to upload (1 entities):
552 largefiles to upload (1 entities):
551 b
553 b
552 89e6c98d92887913cadf06b2adb97f26cde4849b
554 89e6c98d92887913cadf06b2adb97f26cde4849b
553 b1
555 b1
554 89e6c98d92887913cadf06b2adb97f26cde4849b
556 89e6c98d92887913cadf06b2adb97f26cde4849b
555 b2
557 b2
556 89e6c98d92887913cadf06b2adb97f26cde4849b
558 89e6c98d92887913cadf06b2adb97f26cde4849b
557
559
558
560
559 $ echo bbb > clone2/b
561 $ echo bbb > clone2/b
560 $ hg -R clone2 commit -m '#3: add new largefile entity as existing file'
562 $ hg -R clone2 commit -m '#3: add new largefile entity as existing file'
561 Invoking status precommit hook
563 Invoking status precommit hook
562 M b
564 M b
563 $ echo bbbb > clone2/b
565 $ echo bbbb > clone2/b
564 $ hg -R clone2 commit -m '#4: add new largefile entity as existing file'
566 $ hg -R clone2 commit -m '#4: add new largefile entity as existing file'
565 Invoking status precommit hook
567 Invoking status precommit hook
566 M b
568 M b
567 $ cp clone2/b1 clone2/b
569 $ cp clone2/b1 clone2/b
568 $ hg -R clone2 commit -m '#5: refer existing largefile entity again'
570 $ hg -R clone2 commit -m '#5: refer existing largefile entity again'
569 Invoking status precommit hook
571 Invoking status precommit hook
570 M b
572 M b
571 $ hg -R clone2 summary --large
573 $ hg -R clone2 summary --large
572 parent: 5:036794ea641c tip
574 parent: 5:036794ea641c tip
573 #5: refer existing largefile entity again
575 #5: refer existing largefile entity again
574 branch: default
576 branch: default
575 commit: (clean)
577 commit: (clean)
576 update: (current)
578 update: (current)
577 largefiles: 3 entities for 3 files to upload
579 largefiles: 3 entities for 3 files to upload
578 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
580 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
579 comparing with $TESTTMP/issue3651/src (glob)
581 comparing with $TESTTMP/issue3651/src (glob)
580 searching for changes
582 searching for changes
581 1:1acbe71ce432
583 1:1acbe71ce432
582 2:6095d0695d70
584 2:6095d0695d70
583 3:7983dce246cc
585 3:7983dce246cc
584 4:233f12ada4ae
586 4:233f12ada4ae
585 5:036794ea641c
587 5:036794ea641c
586 largefiles to upload (3 entities):
588 largefiles to upload (3 entities):
587 b
589 b
588 b1
590 b1
589 b2
591 b2
590
592
591 $ hg -R clone2 cat -r 3 clone2/.hglf/b
593 $ hg -R clone2 cat -r 3 clone2/.hglf/b
592 c801c9cfe94400963fcb683246217d5db77f9a9a
594 c801c9cfe94400963fcb683246217d5db77f9a9a
593 $ hg -R clone2 cat -r 4 clone2/.hglf/b
595 $ hg -R clone2 cat -r 4 clone2/.hglf/b
594 13f9ed0898e315bf59dc2973fec52037b6f441a2
596 13f9ed0898e315bf59dc2973fec52037b6f441a2
595 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
597 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
596 comparing with $TESTTMP/issue3651/src (glob)
598 comparing with $TESTTMP/issue3651/src (glob)
597 query 1; heads
599 query 1; heads
598 searching for changes
600 searching for changes
599 all remote heads known locally
601 all remote heads known locally
600 1:1acbe71ce432
602 1:1acbe71ce432
601 2:6095d0695d70
603 2:6095d0695d70
602 3:7983dce246cc
604 3:7983dce246cc
603 4:233f12ada4ae
605 4:233f12ada4ae
604 5:036794ea641c
606 5:036794ea641c
605 largefiles to upload (3 entities):
607 largefiles to upload (3 entities):
606 b
608 b
607 13f9ed0898e315bf59dc2973fec52037b6f441a2
609 13f9ed0898e315bf59dc2973fec52037b6f441a2
608 89e6c98d92887913cadf06b2adb97f26cde4849b
610 89e6c98d92887913cadf06b2adb97f26cde4849b
609 c801c9cfe94400963fcb683246217d5db77f9a9a
611 c801c9cfe94400963fcb683246217d5db77f9a9a
610 b1
612 b1
611 89e6c98d92887913cadf06b2adb97f26cde4849b
613 89e6c98d92887913cadf06b2adb97f26cde4849b
612 b2
614 b2
613 89e6c98d92887913cadf06b2adb97f26cde4849b
615 89e6c98d92887913cadf06b2adb97f26cde4849b
614
616
615
617
616 Pushing revision #1 causes uploading entity 89e6c98d9288, which is
618 Pushing revision #1 causes uploading entity 89e6c98d9288, which is
617 shared also by largefiles b1, b2 in revision #2 and b in revision #5.
619 shared also by largefiles b1, b2 in revision #2 and b in revision #5.
618
620
619 Then, entity 89e6c98d9288 is not treated as "outgoing entity" at "hg
621 Then, entity 89e6c98d9288 is not treated as "outgoing entity" at "hg
620 summary" and "hg outgoing", even though files in outgoing revision #2
622 summary" and "hg outgoing", even though files in outgoing revision #2
621 and #5 refer it.
623 and #5 refer it.
622
624
623 $ hg -R clone2 push -r 1 -q
625 $ hg -R clone2 push -r 1 -q
624 $ hg -R clone2 summary --large
626 $ hg -R clone2 summary --large
625 parent: 5:036794ea641c tip
627 parent: 5:036794ea641c tip
626 #5: refer existing largefile entity again
628 #5: refer existing largefile entity again
627 branch: default
629 branch: default
628 commit: (clean)
630 commit: (clean)
629 update: (current)
631 update: (current)
630 largefiles: 2 entities for 1 files to upload
632 largefiles: 2 entities for 1 files to upload
631 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
633 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
632 comparing with $TESTTMP/issue3651/src (glob)
634 comparing with $TESTTMP/issue3651/src (glob)
633 searching for changes
635 searching for changes
634 2:6095d0695d70
636 2:6095d0695d70
635 3:7983dce246cc
637 3:7983dce246cc
636 4:233f12ada4ae
638 4:233f12ada4ae
637 5:036794ea641c
639 5:036794ea641c
638 largefiles to upload (2 entities):
640 largefiles to upload (2 entities):
639 b
641 b
640
642
641 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
643 $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
642 comparing with $TESTTMP/issue3651/src (glob)
644 comparing with $TESTTMP/issue3651/src (glob)
643 query 1; heads
645 query 1; heads
644 searching for changes
646 searching for changes
645 all remote heads known locally
647 all remote heads known locally
646 2:6095d0695d70
648 2:6095d0695d70
647 3:7983dce246cc
649 3:7983dce246cc
648 4:233f12ada4ae
650 4:233f12ada4ae
649 5:036794ea641c
651 5:036794ea641c
650 largefiles to upload (2 entities):
652 largefiles to upload (2 entities):
651 b
653 b
652 13f9ed0898e315bf59dc2973fec52037b6f441a2
654 13f9ed0898e315bf59dc2973fec52037b6f441a2
653 c801c9cfe94400963fcb683246217d5db77f9a9a
655 c801c9cfe94400963fcb683246217d5db77f9a9a
654
656
655
657
656 $ cd ..
658 $ cd ..
657
659
658 merge action 'd' for 'local renamed directory to d2/g' which has no filename
660 merge action 'd' for 'local renamed directory to d2/g' which has no filename
659 ==================================================================================
661 ==================================================================================
660
662
661 $ hg init merge-action
663 $ hg init merge-action
662 $ cd merge-action
664 $ cd merge-action
663 $ touch l
665 $ touch l
664 $ hg add --large l
666 $ hg add --large l
665 $ mkdir d1
667 $ mkdir d1
666 $ touch d1/f
668 $ touch d1/f
667 $ hg ci -Aqm0
669 $ hg ci -Aqm0
668 Invoking status precommit hook
670 Invoking status precommit hook
669 A d1/f
671 A d1/f
670 A l
672 A l
671 $ echo > d1/f
673 $ echo > d1/f
672 $ touch d1/g
674 $ touch d1/g
673 $ hg ci -Aqm1
675 $ hg ci -Aqm1
674 Invoking status precommit hook
676 Invoking status precommit hook
675 M d1/f
677 M d1/f
676 A d1/g
678 A d1/g
677 $ hg up -qr0
679 $ hg up -qr0
678 $ hg mv d1 d2
680 $ hg mv d1 d2
679 moving d1/f to d2/f (glob)
681 moving d1/f to d2/f (glob)
680 $ hg ci -qm2
682 $ hg ci -qm2
681 Invoking status precommit hook
683 Invoking status precommit hook
682 A d2/f
684 A d2/f
683 R d1/f
685 R d1/f
684 $ hg merge
686 $ hg merge
685 merging d2/f and d1/f to d2/f
687 merging d2/f and d1/f to d2/f
686 getting changed largefiles
688 getting changed largefiles
687 0 largefiles updated, 0 removed
689 0 largefiles updated, 0 removed
688 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
690 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
689 (branch merge, don't forget to commit)
691 (branch merge, don't forget to commit)
690 $ cd ..
692 $ cd ..
691
693
692
694
693 Merge conflicts:
695 Merge conflicts:
694 =====================
696 =====================
695
697
696 $ hg init merge
698 $ hg init merge
697 $ cd merge
699 $ cd merge
698 $ echo 0 > f-different
700 $ echo 0 > f-different
699 $ echo 0 > f-same
701 $ echo 0 > f-same
700 $ echo 0 > f-unchanged-1
702 $ echo 0 > f-unchanged-1
701 $ echo 0 > f-unchanged-2
703 $ echo 0 > f-unchanged-2
702 $ hg add --large *
704 $ hg add --large *
703 $ hg ci -m0
705 $ hg ci -m0
704 Invoking status precommit hook
706 Invoking status precommit hook
705 A f-different
707 A f-different
706 A f-same
708 A f-same
707 A f-unchanged-1
709 A f-unchanged-1
708 A f-unchanged-2
710 A f-unchanged-2
709 $ echo tmp1 > f-unchanged-1
711 $ echo tmp1 > f-unchanged-1
710 $ echo tmp1 > f-unchanged-2
712 $ echo tmp1 > f-unchanged-2
711 $ echo tmp1 > f-same
713 $ echo tmp1 > f-same
712 $ hg ci -m1
714 $ hg ci -m1
713 Invoking status precommit hook
715 Invoking status precommit hook
714 M f-same
716 M f-same
715 M f-unchanged-1
717 M f-unchanged-1
716 M f-unchanged-2
718 M f-unchanged-2
717 $ echo 2 > f-different
719 $ echo 2 > f-different
718 $ echo 0 > f-unchanged-1
720 $ echo 0 > f-unchanged-1
719 $ echo 1 > f-unchanged-2
721 $ echo 1 > f-unchanged-2
720 $ echo 1 > f-same
722 $ echo 1 > f-same
721 $ hg ci -m2
723 $ hg ci -m2
722 Invoking status precommit hook
724 Invoking status precommit hook
723 M f-different
725 M f-different
724 M f-same
726 M f-same
725 M f-unchanged-1
727 M f-unchanged-1
726 M f-unchanged-2
728 M f-unchanged-2
727 $ hg up -qr0
729 $ hg up -qr0
728 $ echo tmp2 > f-unchanged-1
730 $ echo tmp2 > f-unchanged-1
729 $ echo tmp2 > f-unchanged-2
731 $ echo tmp2 > f-unchanged-2
730 $ echo tmp2 > f-same
732 $ echo tmp2 > f-same
731 $ hg ci -m3
733 $ hg ci -m3
732 Invoking status precommit hook
734 Invoking status precommit hook
733 M f-same
735 M f-same
734 M f-unchanged-1
736 M f-unchanged-1
735 M f-unchanged-2
737 M f-unchanged-2
736 created new head
738 created new head
737 $ echo 1 > f-different
739 $ echo 1 > f-different
738 $ echo 1 > f-unchanged-1
740 $ echo 1 > f-unchanged-1
739 $ echo 0 > f-unchanged-2
741 $ echo 0 > f-unchanged-2
740 $ echo 1 > f-same
742 $ echo 1 > f-same
741 $ hg ci -m4
743 $ hg ci -m4
742 Invoking status precommit hook
744 Invoking status precommit hook
743 M f-different
745 M f-different
744 M f-same
746 M f-same
745 M f-unchanged-1
747 M f-unchanged-1
746 M f-unchanged-2
748 M f-unchanged-2
747 $ hg merge
749 $ hg merge
748 largefile f-different has a merge conflict
750 largefile f-different has a merge conflict
749 ancestor was 09d2af8dd22201dd8d48e5dcfcaed281ff9422c7
751 ancestor was 09d2af8dd22201dd8d48e5dcfcaed281ff9422c7
750 keep (l)ocal e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e or
752 keep (l)ocal e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e or
751 take (o)ther 7448d8798a4380162d4b56f9b452e2f6f9e24e7a? l
753 take (o)ther 7448d8798a4380162d4b56f9b452e2f6f9e24e7a? l
752 getting changed largefiles
754 getting changed largefiles
753 1 largefiles updated, 0 removed
755 1 largefiles updated, 0 removed
754 0 files updated, 4 files merged, 0 files removed, 0 files unresolved
756 0 files updated, 4 files merged, 0 files removed, 0 files unresolved
755 (branch merge, don't forget to commit)
757 (branch merge, don't forget to commit)
756 $ cat f-different
758 $ cat f-different
757 1
759 1
758 $ cat f-same
760 $ cat f-same
759 1
761 1
760 $ cat f-unchanged-1
762 $ cat f-unchanged-1
761 1
763 1
762 $ cat f-unchanged-2
764 $ cat f-unchanged-2
763 1
765 1
764 $ cd ..
766 $ cd ..
765
767
766 Test largefile insulation (do not enabled a side effect
768 Test largefile insulation (do not enabled a side effect
767 ========================================================
769 ========================================================
768
770
769 Check whether "largefiles" feature is supported only in repositories
771 Check whether "largefiles" feature is supported only in repositories
770 enabling largefiles extension.
772 enabling largefiles extension.
771
773
772 $ mkdir individualenabling
774 $ mkdir individualenabling
773 $ cd individualenabling
775 $ cd individualenabling
774
776
775 $ hg init enabledlocally
777 $ hg init enabledlocally
776 $ echo large > enabledlocally/large
778 $ echo large > enabledlocally/large
777 $ hg -R enabledlocally add --large enabledlocally/large
779 $ hg -R enabledlocally add --large enabledlocally/large
778 $ hg -R enabledlocally commit -m '#0'
780 $ hg -R enabledlocally commit -m '#0'
779 Invoking status precommit hook
781 Invoking status precommit hook
780 A large
782 A large
781
783
782 $ hg init notenabledlocally
784 $ hg init notenabledlocally
783 $ echo large > notenabledlocally/large
785 $ echo large > notenabledlocally/large
784 $ hg -R notenabledlocally add --large notenabledlocally/large
786 $ hg -R notenabledlocally add --large notenabledlocally/large
785 $ hg -R notenabledlocally commit -m '#0'
787 $ hg -R notenabledlocally commit -m '#0'
786 Invoking status precommit hook
788 Invoking status precommit hook
787 A large
789 A large
788
790
789 $ cat >> $HGRCPATH <<EOF
791 $ cat >> $HGRCPATH <<EOF
790 > [extensions]
792 > [extensions]
791 > # disable globally
793 > # disable globally
792 > largefiles=!
794 > largefiles=!
793 > EOF
795 > EOF
794 $ cat >> enabledlocally/.hg/hgrc <<EOF
796 $ cat >> enabledlocally/.hg/hgrc <<EOF
795 > [extensions]
797 > [extensions]
796 > # enable locally
798 > # enable locally
797 > largefiles=
799 > largefiles=
798 > EOF
800 > EOF
799 $ hg -R enabledlocally root
801 $ hg -R enabledlocally root
800 $TESTTMP/individualenabling/enabledlocally (glob)
802 $TESTTMP/individualenabling/enabledlocally (glob)
801 $ hg -R notenabledlocally root
803 $ hg -R notenabledlocally root
802 abort: repository requires features unknown to this Mercurial: largefiles!
804 abort: repository requires features unknown to this Mercurial: largefiles!
803 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
805 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
804 [255]
806 [255]
805
807
806 $ hg init push-dst
808 $ hg init push-dst
807 $ hg -R enabledlocally push push-dst
809 $ hg -R enabledlocally push push-dst
808 pushing to push-dst
810 pushing to push-dst
809 abort: required features are not supported in the destination: largefiles
811 abort: required features are not supported in the destination: largefiles
810 [255]
812 [255]
811
813
812 $ hg init pull-src
814 $ hg init pull-src
813 $ hg -R pull-src pull enabledlocally
815 $ hg -R pull-src pull enabledlocally
814 pulling from enabledlocally
816 pulling from enabledlocally
815 abort: required features are not supported in the destination: largefiles
817 abort: required features are not supported in the destination: largefiles
816 [255]
818 [255]
817
819
818 $ hg clone enabledlocally clone-dst
820 $ hg clone enabledlocally clone-dst
819 abort: repository requires features unknown to this Mercurial: largefiles!
821 abort: repository requires features unknown to this Mercurial: largefiles!
820 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
822 (see http://mercurial.selenic.com/wiki/MissingRequirement for more information)
821 [255]
823 [255]
822 $ test -d clone-dst
824 $ test -d clone-dst
823 [1]
825 [1]
824 $ hg clone --pull enabledlocally clone-pull-dst
826 $ hg clone --pull enabledlocally clone-pull-dst
825 abort: required features are not supported in the destination: largefiles
827 abort: required features are not supported in the destination: largefiles
826 [255]
828 [255]
827 $ test -d clone-pull-dst
829 $ test -d clone-pull-dst
828 [1]
830 [1]
829
831
830 #if serve
832 #if serve
831
833
832 Test largefiles specific peer setup, when largefiles is enabled
834 Test largefiles specific peer setup, when largefiles is enabled
833 locally (issue4109)
835 locally (issue4109)
834
836
835 $ hg showconfig extensions | grep largefiles
837 $ hg showconfig extensions | grep largefiles
836 extensions.largefiles=!
838 extensions.largefiles=!
837 $ mkdir -p $TESTTMP/individualenabling/usercache
839 $ mkdir -p $TESTTMP/individualenabling/usercache
838
840
839 $ hg serve -R enabledlocally -d -p $HGPORT --pid-file hg.pid
841 $ hg serve -R enabledlocally -d -p $HGPORT --pid-file hg.pid
840 $ cat hg.pid >> $DAEMON_PIDS
842 $ cat hg.pid >> $DAEMON_PIDS
841
843
842 $ hg init pull-dst
844 $ hg init pull-dst
843 $ cat > pull-dst/.hg/hgrc <<EOF
845 $ cat > pull-dst/.hg/hgrc <<EOF
844 > [extensions]
846 > [extensions]
845 > # enable locally
847 > # enable locally
846 > largefiles=
848 > largefiles=
847 > [largefiles]
849 > [largefiles]
848 > # ignore system cache to force largefiles specific wire proto access
850 > # ignore system cache to force largefiles specific wire proto access
849 > usercache=$TESTTMP/individualenabling/usercache
851 > usercache=$TESTTMP/individualenabling/usercache
850 > EOF
852 > EOF
851 $ hg -R pull-dst -q pull -u http://localhost:$HGPORT
853 $ hg -R pull-dst -q pull -u http://localhost:$HGPORT
852
854
853 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
855 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
854 #endif
856 #endif
855
857
856 $ cd ..
858 $ cd ..
857
859
858
860
859 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
861 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
860 =========================================================================
862 =========================================================================
861
863
862 $ hg showconfig extensions | grep largefiles
864 $ hg showconfig extensions | grep largefiles
863 extensions.largefiles=!
865 extensions.largefiles=!
864
866
865 $ mkdir issue3861
867 $ mkdir issue3861
866 $ cd issue3861
868 $ cd issue3861
867 $ hg init src
869 $ hg init src
868 $ hg clone -q src dst
870 $ hg clone -q src dst
869 $ echo a > src/a
871 $ echo a > src/a
870 $ hg -R src commit -Aqm "#0"
872 $ hg -R src commit -Aqm "#0"
871 Invoking status precommit hook
873 Invoking status precommit hook
872 A a
874 A a
873
875
874 $ cat >> dst/.hg/hgrc <<EOF
876 $ cat >> dst/.hg/hgrc <<EOF
875 > [extensions]
877 > [extensions]
876 > largefiles=
878 > largefiles=
877 > EOF
879 > EOF
878 $ hg -R dst pull --rebase
880 $ hg -R dst pull --rebase
879 pulling from $TESTTMP/issue3861/src (glob)
881 pulling from $TESTTMP/issue3861/src (glob)
880 requesting all changes
882 requesting all changes
881 adding changesets
883 adding changesets
882 adding manifests
884 adding manifests
883 adding file changes
885 adding file changes
884 added 1 changesets with 1 changes to 1 files
886 added 1 changesets with 1 changes to 1 files
885 nothing to rebase - working directory parent is already an ancestor of destination bf5e395ced2c
887 nothing to rebase - working directory parent is already an ancestor of destination bf5e395ced2c
886 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
888 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
887
889
888 $ cd ..
890 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now