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