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