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