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