##// END OF EJS Templates
largefiles: use separate try/except and try/finally as needed for python2.4...
Thomas Arendsen Hein -
r15279:01860816 stable
parent child Browse files
Show More
@@ -1,830 +1,832
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''Overridden Mercurial commands and functions for the largefiles extension'''
9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10
10
11 import os
11 import os
12 import copy
12 import copy
13
13
14 from mercurial import hg, commands, util, cmdutil, match as match_, node, \
14 from mercurial import hg, commands, util, cmdutil, match as match_, node, \
15 archival, error, merge
15 archival, error, merge
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial.node import hex
17 from mercurial.node import hex
18 from hgext import rebase
18 from hgext import rebase
19 import lfutil
19 import lfutil
20
20
21 try:
21 try:
22 from mercurial import scmutil
22 from mercurial import scmutil
23 except ImportError:
23 except ImportError:
24 pass
24 pass
25
25
26 import lfutil
26 import lfutil
27 import lfcommands
27 import lfcommands
28
28
29 def installnormalfilesmatchfn(manifest):
29 def installnormalfilesmatchfn(manifest):
30 '''overrides scmutil.match so that the matcher it returns will ignore all
30 '''overrides scmutil.match so that the matcher it returns will ignore all
31 largefiles'''
31 largefiles'''
32 oldmatch = None # for the closure
32 oldmatch = None # for the closure
33 def override_match(repo, pats=[], opts={}, globbed=False,
33 def override_match(repo, pats=[], opts={}, globbed=False,
34 default='relpath'):
34 default='relpath'):
35 match = oldmatch(repo, pats, opts, globbed, default)
35 match = oldmatch(repo, pats, opts, globbed, default)
36 m = copy.copy(match)
36 m = copy.copy(match)
37 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
37 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
38 manifest)
38 manifest)
39 m._files = filter(notlfile, m._files)
39 m._files = filter(notlfile, m._files)
40 m._fmap = set(m._files)
40 m._fmap = set(m._files)
41 orig_matchfn = m.matchfn
41 orig_matchfn = m.matchfn
42 m.matchfn = lambda f: notlfile(f) and orig_matchfn(f) or None
42 m.matchfn = lambda f: notlfile(f) and orig_matchfn(f) or None
43 return m
43 return m
44 oldmatch = installmatchfn(override_match)
44 oldmatch = installmatchfn(override_match)
45
45
46 def installmatchfn(f):
46 def installmatchfn(f):
47 oldmatch = scmutil.match
47 oldmatch = scmutil.match
48 setattr(f, 'oldmatch', oldmatch)
48 setattr(f, 'oldmatch', oldmatch)
49 scmutil.match = f
49 scmutil.match = f
50 return oldmatch
50 return oldmatch
51
51
52 def restorematchfn():
52 def restorematchfn():
53 '''restores scmutil.match to what it was before installnormalfilesmatchfn
53 '''restores scmutil.match to what it was before installnormalfilesmatchfn
54 was called. no-op if scmutil.match is its original function.
54 was called. no-op if scmutil.match is its original function.
55
55
56 Note that n calls to installnormalfilesmatchfn will require n calls to
56 Note that n calls to installnormalfilesmatchfn will require n calls to
57 restore matchfn to reverse'''
57 restore matchfn to reverse'''
58 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
58 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
59
59
60 # -- Wrappers: modify existing commands --------------------------------
60 # -- Wrappers: modify existing commands --------------------------------
61
61
62 # Add works by going through the files that the user wanted to add and
62 # Add works by going through the files that the user wanted to add and
63 # checking if they should be added as largefiles. Then it makes a new
63 # checking if they should be added as largefiles. Then it makes a new
64 # matcher which matches only the normal files and runs the original
64 # matcher which matches only the normal files and runs the original
65 # version of add.
65 # version of add.
66 def override_add(orig, ui, repo, *pats, **opts):
66 def override_add(orig, ui, repo, *pats, **opts):
67 large = opts.pop('large', None)
67 large = opts.pop('large', None)
68 lfsize = lfutil.getminsize(
68 lfsize = lfutil.getminsize(
69 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
69 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
70
70
71 lfmatcher = None
71 lfmatcher = None
72 if os.path.exists(repo.wjoin(lfutil.shortname)):
72 if os.path.exists(repo.wjoin(lfutil.shortname)):
73 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
73 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
74 if lfpats:
74 if lfpats:
75 lfmatcher = match_.match(repo.root, '', list(lfpats))
75 lfmatcher = match_.match(repo.root, '', list(lfpats))
76
76
77 lfnames = []
77 lfnames = []
78 m = scmutil.match(repo[None], pats, opts)
78 m = scmutil.match(repo[None], pats, opts)
79 m.bad = lambda x, y: None
79 m.bad = lambda x, y: None
80 wctx = repo[None]
80 wctx = repo[None]
81 for f in repo.walk(m):
81 for f in repo.walk(m):
82 exact = m.exact(f)
82 exact = m.exact(f)
83 lfile = lfutil.standin(f) in wctx
83 lfile = lfutil.standin(f) in wctx
84 nfile = f in wctx
84 nfile = f in wctx
85 exists = lfile or nfile
85 exists = lfile or nfile
86
86
87 # Don't warn the user when they attempt to add a normal tracked file.
87 # Don't warn the user when they attempt to add a normal tracked file.
88 # The normal add code will do that for us.
88 # The normal add code will do that for us.
89 if exact and exists:
89 if exact and exists:
90 if lfile:
90 if lfile:
91 ui.warn(_('%s already a largefile\n') % f)
91 ui.warn(_('%s already a largefile\n') % f)
92 continue
92 continue
93
93
94 if exact or not exists:
94 if exact or not exists:
95 abovemin = (lfsize and
95 abovemin = (lfsize and
96 os.path.getsize(repo.wjoin(f)) >= lfsize * 1024 * 1024)
96 os.path.getsize(repo.wjoin(f)) >= lfsize * 1024 * 1024)
97 if large or abovemin or (lfmatcher and lfmatcher(f)):
97 if large or abovemin or (lfmatcher and lfmatcher(f)):
98 lfnames.append(f)
98 lfnames.append(f)
99 if ui.verbose or not exact:
99 if ui.verbose or not exact:
100 ui.status(_('adding %s as a largefile\n') % m.rel(f))
100 ui.status(_('adding %s as a largefile\n') % m.rel(f))
101
101
102 bad = []
102 bad = []
103 standins = []
103 standins = []
104
104
105 # Need to lock, otherwise there could be a race condition between
105 # Need to lock, otherwise there could be a race condition between
106 # when standins are created and added to the repo.
106 # when standins are created and added to the repo.
107 wlock = repo.wlock()
107 wlock = repo.wlock()
108 try:
108 try:
109 if not opts.get('dry_run'):
109 if not opts.get('dry_run'):
110 lfdirstate = lfutil.openlfdirstate(ui, repo)
110 lfdirstate = lfutil.openlfdirstate(ui, repo)
111 for f in lfnames:
111 for f in lfnames:
112 standinname = lfutil.standin(f)
112 standinname = lfutil.standin(f)
113 lfutil.writestandin(repo, standinname, hash='',
113 lfutil.writestandin(repo, standinname, hash='',
114 executable=lfutil.getexecutable(repo.wjoin(f)))
114 executable=lfutil.getexecutable(repo.wjoin(f)))
115 standins.append(standinname)
115 standins.append(standinname)
116 if lfdirstate[f] == 'r':
116 if lfdirstate[f] == 'r':
117 lfdirstate.normallookup(f)
117 lfdirstate.normallookup(f)
118 else:
118 else:
119 lfdirstate.add(f)
119 lfdirstate.add(f)
120 lfdirstate.write()
120 lfdirstate.write()
121 bad += [lfutil.splitstandin(f)
121 bad += [lfutil.splitstandin(f)
122 for f in lfutil.repo_add(repo, standins)
122 for f in lfutil.repo_add(repo, standins)
123 if f in m.files()]
123 if f in m.files()]
124 finally:
124 finally:
125 wlock.release()
125 wlock.release()
126
126
127 installnormalfilesmatchfn(repo[None].manifest())
127 installnormalfilesmatchfn(repo[None].manifest())
128 result = orig(ui, repo, *pats, **opts)
128 result = orig(ui, repo, *pats, **opts)
129 restorematchfn()
129 restorematchfn()
130
130
131 return (result == 1 or bad) and 1 or 0
131 return (result == 1 or bad) and 1 or 0
132
132
133 def override_remove(orig, ui, repo, *pats, **opts):
133 def override_remove(orig, ui, repo, *pats, **opts):
134 manifest = repo[None].manifest()
134 manifest = repo[None].manifest()
135 installnormalfilesmatchfn(manifest)
135 installnormalfilesmatchfn(manifest)
136 orig(ui, repo, *pats, **opts)
136 orig(ui, repo, *pats, **opts)
137 restorematchfn()
137 restorematchfn()
138
138
139 after, force = opts.get('after'), opts.get('force')
139 after, force = opts.get('after'), opts.get('force')
140 if not pats and not after:
140 if not pats and not after:
141 raise util.Abort(_('no files specified'))
141 raise util.Abort(_('no files specified'))
142 m = scmutil.match(repo[None], pats, opts)
142 m = scmutil.match(repo[None], pats, opts)
143 try:
143 try:
144 repo.lfstatus = True
144 repo.lfstatus = True
145 s = repo.status(match=m, clean=True)
145 s = repo.status(match=m, clean=True)
146 finally:
146 finally:
147 repo.lfstatus = False
147 repo.lfstatus = False
148 modified, added, deleted, clean = [[f for f in list
148 modified, added, deleted, clean = [[f for f in list
149 if lfutil.standin(f) in manifest]
149 if lfutil.standin(f) in manifest]
150 for list in [s[0], s[1], s[3], s[6]]]
150 for list in [s[0], s[1], s[3], s[6]]]
151
151
152 def warn(files, reason):
152 def warn(files, reason):
153 for f in files:
153 for f in files:
154 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
154 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
155 % (m.rel(f), reason))
155 % (m.rel(f), reason))
156
156
157 if force:
157 if force:
158 remove, forget = modified + deleted + clean, added
158 remove, forget = modified + deleted + clean, added
159 elif after:
159 elif after:
160 remove, forget = deleted, []
160 remove, forget = deleted, []
161 warn(modified + added + clean, _('still exists'))
161 warn(modified + added + clean, _('still exists'))
162 else:
162 else:
163 remove, forget = deleted + clean, []
163 remove, forget = deleted + clean, []
164 warn(modified, _('is modified'))
164 warn(modified, _('is modified'))
165 warn(added, _('has been marked for add'))
165 warn(added, _('has been marked for add'))
166
166
167 for f in sorted(remove + forget):
167 for f in sorted(remove + forget):
168 if ui.verbose or not m.exact(f):
168 if ui.verbose or not m.exact(f):
169 ui.status(_('removing %s\n') % m.rel(f))
169 ui.status(_('removing %s\n') % m.rel(f))
170
170
171 # Need to lock because standin files are deleted then removed from the
171 # Need to lock because standin files are deleted then removed from the
172 # repository and we could race inbetween.
172 # repository and we could race inbetween.
173 wlock = repo.wlock()
173 wlock = repo.wlock()
174 try:
174 try:
175 lfdirstate = lfutil.openlfdirstate(ui, repo)
175 lfdirstate = lfutil.openlfdirstate(ui, repo)
176 for f in remove:
176 for f in remove:
177 if not after:
177 if not after:
178 os.unlink(repo.wjoin(f))
178 os.unlink(repo.wjoin(f))
179 currentdir = os.path.split(f)[0]
179 currentdir = os.path.split(f)[0]
180 while currentdir and not os.listdir(repo.wjoin(currentdir)):
180 while currentdir and not os.listdir(repo.wjoin(currentdir)):
181 os.rmdir(repo.wjoin(currentdir))
181 os.rmdir(repo.wjoin(currentdir))
182 currentdir = os.path.split(currentdir)[0]
182 currentdir = os.path.split(currentdir)[0]
183 lfdirstate.remove(f)
183 lfdirstate.remove(f)
184 lfdirstate.write()
184 lfdirstate.write()
185
185
186 forget = [lfutil.standin(f) for f in forget]
186 forget = [lfutil.standin(f) for f in forget]
187 remove = [lfutil.standin(f) for f in remove]
187 remove = [lfutil.standin(f) for f in remove]
188 lfutil.repo_forget(repo, forget)
188 lfutil.repo_forget(repo, forget)
189 lfutil.repo_remove(repo, remove, unlink=True)
189 lfutil.repo_remove(repo, remove, unlink=True)
190 finally:
190 finally:
191 wlock.release()
191 wlock.release()
192
192
193 def override_status(orig, ui, repo, *pats, **opts):
193 def override_status(orig, ui, repo, *pats, **opts):
194 try:
194 try:
195 repo.lfstatus = True
195 repo.lfstatus = True
196 return orig(ui, repo, *pats, **opts)
196 return orig(ui, repo, *pats, **opts)
197 finally:
197 finally:
198 repo.lfstatus = False
198 repo.lfstatus = False
199
199
200 def override_log(orig, ui, repo, *pats, **opts):
200 def override_log(orig, ui, repo, *pats, **opts):
201 try:
201 try:
202 repo.lfstatus = True
202 repo.lfstatus = True
203 orig(ui, repo, *pats, **opts)
203 orig(ui, repo, *pats, **opts)
204 finally:
204 finally:
205 repo.lfstatus = False
205 repo.lfstatus = False
206
206
207 def override_verify(orig, ui, repo, *pats, **opts):
207 def override_verify(orig, ui, repo, *pats, **opts):
208 large = opts.pop('large', False)
208 large = opts.pop('large', False)
209 all = opts.pop('lfa', False)
209 all = opts.pop('lfa', False)
210 contents = opts.pop('lfc', False)
210 contents = opts.pop('lfc', False)
211
211
212 result = orig(ui, repo, *pats, **opts)
212 result = orig(ui, repo, *pats, **opts)
213 if large:
213 if large:
214 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
214 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
215 return result
215 return result
216
216
217 # Override needs to refresh standins so that update's normal merge
217 # Override needs to refresh standins so that update's normal merge
218 # will go through properly. Then the other update hook (overriding repo.update)
218 # will go through properly. Then the other update hook (overriding repo.update)
219 # will get the new files. Filemerge is also overriden so that the merge
219 # will get the new files. Filemerge is also overriden so that the merge
220 # will merge standins correctly.
220 # will merge standins correctly.
221 def override_update(orig, ui, repo, *pats, **opts):
221 def override_update(orig, ui, repo, *pats, **opts):
222 lfdirstate = lfutil.openlfdirstate(ui, repo)
222 lfdirstate = lfutil.openlfdirstate(ui, repo)
223 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
223 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
224 False, False)
224 False, False)
225 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
225 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
226
226
227 # Need to lock between the standins getting updated and their
227 # Need to lock between the standins getting updated and their
228 # largefiles getting updated
228 # largefiles getting updated
229 wlock = repo.wlock()
229 wlock = repo.wlock()
230 try:
230 try:
231 if opts['check']:
231 if opts['check']:
232 mod = len(modified) > 0
232 mod = len(modified) > 0
233 for lfile in unsure:
233 for lfile in unsure:
234 standin = lfutil.standin(lfile)
234 standin = lfutil.standin(lfile)
235 if repo['.'][standin].data().strip() != \
235 if repo['.'][standin].data().strip() != \
236 lfutil.hashfile(repo.wjoin(lfile)):
236 lfutil.hashfile(repo.wjoin(lfile)):
237 mod = True
237 mod = True
238 else:
238 else:
239 lfdirstate.normal(lfile)
239 lfdirstate.normal(lfile)
240 lfdirstate.write()
240 lfdirstate.write()
241 if mod:
241 if mod:
242 raise util.Abort(_('uncommitted local changes'))
242 raise util.Abort(_('uncommitted local changes'))
243 # XXX handle removed differently
243 # XXX handle removed differently
244 if not opts['clean']:
244 if not opts['clean']:
245 for lfile in unsure + modified + added:
245 for lfile in unsure + modified + added:
246 lfutil.updatestandin(repo, lfutil.standin(lfile))
246 lfutil.updatestandin(repo, lfutil.standin(lfile))
247 finally:
247 finally:
248 wlock.release()
248 wlock.release()
249 return orig(ui, repo, *pats, **opts)
249 return orig(ui, repo, *pats, **opts)
250
250
251 # Override filemerge to prompt the user about how they wish to merge
251 # Override filemerge to prompt the user about how they wish to merge
252 # largefiles. This will handle identical edits, and copy/rename +
252 # largefiles. This will handle identical edits, and copy/rename +
253 # edit without prompting the user.
253 # edit without prompting the user.
254 def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca):
254 def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca):
255 # Use better variable names here. Because this is a wrapper we cannot
255 # Use better variable names here. Because this is a wrapper we cannot
256 # change the variable names in the function declaration.
256 # change the variable names in the function declaration.
257 fcdest, fcother, fcancestor = fcd, fco, fca
257 fcdest, fcother, fcancestor = fcd, fco, fca
258 if not lfutil.isstandin(orig):
258 if not lfutil.isstandin(orig):
259 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
259 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
260 else:
260 else:
261 if not fcother.cmp(fcdest): # files identical?
261 if not fcother.cmp(fcdest): # files identical?
262 return None
262 return None
263
263
264 # backwards, use working dir parent as ancestor
264 # backwards, use working dir parent as ancestor
265 if fcancestor == fcother:
265 if fcancestor == fcother:
266 fcancestor = fcdest.parents()[0]
266 fcancestor = fcdest.parents()[0]
267
267
268 if orig != fcother.path():
268 if orig != fcother.path():
269 repo.ui.status(_('merging %s and %s to %s\n')
269 repo.ui.status(_('merging %s and %s to %s\n')
270 % (lfutil.splitstandin(orig),
270 % (lfutil.splitstandin(orig),
271 lfutil.splitstandin(fcother.path()),
271 lfutil.splitstandin(fcother.path()),
272 lfutil.splitstandin(fcdest.path())))
272 lfutil.splitstandin(fcdest.path())))
273 else:
273 else:
274 repo.ui.status(_('merging %s\n')
274 repo.ui.status(_('merging %s\n')
275 % lfutil.splitstandin(fcdest.path()))
275 % lfutil.splitstandin(fcdest.path()))
276
276
277 if fcancestor.path() != fcother.path() and fcother.data() == \
277 if fcancestor.path() != fcother.path() and fcother.data() == \
278 fcancestor.data():
278 fcancestor.data():
279 return 0
279 return 0
280 if fcancestor.path() != fcdest.path() and fcdest.data() == \
280 if fcancestor.path() != fcdest.path() and fcdest.data() == \
281 fcancestor.data():
281 fcancestor.data():
282 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
282 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
283 return 0
283 return 0
284
284
285 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
285 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
286 'keep (l)ocal or take (o)ther?') %
286 'keep (l)ocal or take (o)ther?') %
287 lfutil.splitstandin(orig),
287 lfutil.splitstandin(orig),
288 (_('&Local'), _('&Other')), 0) == 0:
288 (_('&Local'), _('&Other')), 0) == 0:
289 return 0
289 return 0
290 else:
290 else:
291 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
291 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
292 return 0
292 return 0
293
293
294 # Copy first changes the matchers to match standins instead of
294 # Copy first changes the matchers to match standins instead of
295 # largefiles. Then it overrides util.copyfile in that function it
295 # largefiles. Then it overrides util.copyfile in that function it
296 # checks if the destination largefile already exists. It also keeps a
296 # checks if the destination largefile already exists. It also keeps a
297 # list of copied files so that the largefiles can be copied and the
297 # list of copied files so that the largefiles can be copied and the
298 # dirstate updated.
298 # dirstate updated.
299 def override_copy(orig, ui, repo, pats, opts, rename=False):
299 def override_copy(orig, ui, repo, pats, opts, rename=False):
300 # doesn't remove largefile on rename
300 # doesn't remove largefile on rename
301 if len(pats) < 2:
301 if len(pats) < 2:
302 # this isn't legal, let the original function deal with it
302 # this isn't legal, let the original function deal with it
303 return orig(ui, repo, pats, opts, rename)
303 return orig(ui, repo, pats, opts, rename)
304
304
305 def makestandin(relpath):
305 def makestandin(relpath):
306 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
306 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
307 return os.path.join(os.path.relpath('.', repo.getcwd()),
307 return os.path.join(os.path.relpath('.', repo.getcwd()),
308 lfutil.standin(path))
308 lfutil.standin(path))
309
309
310 fullpats = scmutil.expandpats(pats)
310 fullpats = scmutil.expandpats(pats)
311 dest = fullpats[-1]
311 dest = fullpats[-1]
312
312
313 if os.path.isdir(dest):
313 if os.path.isdir(dest):
314 if not os.path.isdir(makestandin(dest)):
314 if not os.path.isdir(makestandin(dest)):
315 os.makedirs(makestandin(dest))
315 os.makedirs(makestandin(dest))
316 # This could copy both lfiles and normal files in one command,
316 # This could copy both lfiles and normal files in one command,
317 # but we don't want to do that. First replace their matcher to
317 # but we don't want to do that. First replace their matcher to
318 # only match normal files and run it, then replace it to just
318 # only match normal files and run it, then replace it to just
319 # match largefiles and run it again.
319 # match largefiles and run it again.
320 nonormalfiles = False
320 nonormalfiles = False
321 nolfiles = False
321 nolfiles = False
322 try:
322 try:
323 installnormalfilesmatchfn(repo[None].manifest())
323 try:
324 result = orig(ui, repo, pats, opts, rename)
324 installnormalfilesmatchfn(repo[None].manifest())
325 except util.Abort, e:
325 result = orig(ui, repo, pats, opts, rename)
326 if str(e) != 'no files to copy':
326 except util.Abort, e:
327 raise e
327 if str(e) != 'no files to copy':
328 else:
328 raise e
329 nonormalfiles = True
329 else:
330 result = 0
330 nonormalfiles = True
331 result = 0
331 finally:
332 finally:
332 restorematchfn()
333 restorematchfn()
333
334
334 # The first rename can cause our current working directory to be removed.
335 # The first rename can cause our current working directory to be removed.
335 # In that case there is nothing left to copy/rename so just quit.
336 # In that case there is nothing left to copy/rename so just quit.
336 try:
337 try:
337 repo.getcwd()
338 repo.getcwd()
338 except OSError:
339 except OSError:
339 return result
340 return result
340
341
341 try:
342 try:
342 # When we call orig below it creates the standins but we don't add them
343 try:
343 # to the dir state until later so lock during that time.
344 # When we call orig below it creates the standins but we don't add them
344 wlock = repo.wlock()
345 # to the dir state until later so lock during that time.
346 wlock = repo.wlock()
345
347
346 manifest = repo[None].manifest()
348 manifest = repo[None].manifest()
347 oldmatch = None # for the closure
349 oldmatch = None # for the closure
348 def override_match(repo, pats=[], opts={}, globbed=False,
350 def override_match(repo, pats=[], opts={}, globbed=False,
349 default='relpath'):
351 default='relpath'):
350 newpats = []
352 newpats = []
351 # The patterns were previously mangled to add the standin
353 # The patterns were previously mangled to add the standin
352 # directory; we need to remove that now
354 # directory; we need to remove that now
355 for pat in pats:
356 if match_.patkind(pat) is None and lfutil.shortname in pat:
357 newpats.append(pat.replace(lfutil.shortname, ''))
358 else:
359 newpats.append(pat)
360 match = oldmatch(repo, newpats, opts, globbed, default)
361 m = copy.copy(match)
362 lfile = lambda f: lfutil.standin(f) in manifest
363 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
364 m._fmap = set(m._files)
365 orig_matchfn = m.matchfn
366 m.matchfn = lambda f: (lfutil.isstandin(f) and
367 lfile(lfutil.splitstandin(f)) and
368 orig_matchfn(lfutil.splitstandin(f)) or
369 None)
370 return m
371 oldmatch = installmatchfn(override_match)
372 listpats = []
353 for pat in pats:
373 for pat in pats:
354 if match_.patkind(pat) is None and lfutil.shortname in pat:
374 if match_.patkind(pat) is not None:
355 newpats.append(pat.replace(lfutil.shortname, ''))
375 listpats.append(pat)
356 else:
376 else:
357 newpats.append(pat)
377 listpats.append(makestandin(pat))
358 match = oldmatch(repo, newpats, opts, globbed, default)
359 m = copy.copy(match)
360 lfile = lambda f: lfutil.standin(f) in manifest
361 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
362 m._fmap = set(m._files)
363 orig_matchfn = m.matchfn
364 m.matchfn = lambda f: (lfutil.isstandin(f) and
365 lfile(lfutil.splitstandin(f)) and
366 orig_matchfn(lfutil.splitstandin(f)) or
367 None)
368 return m
369 oldmatch = installmatchfn(override_match)
370 listpats = []
371 for pat in pats:
372 if match_.patkind(pat) is not None:
373 listpats.append(pat)
374 else:
375 listpats.append(makestandin(pat))
376
378
377 try:
379 try:
378 origcopyfile = util.copyfile
380 origcopyfile = util.copyfile
379 copiedfiles = []
381 copiedfiles = []
380 def override_copyfile(src, dest):
382 def override_copyfile(src, dest):
381 if lfutil.shortname in src and lfutil.shortname in dest:
383 if lfutil.shortname in src and lfutil.shortname in dest:
382 destlfile = dest.replace(lfutil.shortname, '')
384 destlfile = dest.replace(lfutil.shortname, '')
383 if not opts['force'] and os.path.exists(destlfile):
385 if not opts['force'] and os.path.exists(destlfile):
384 raise IOError('',
386 raise IOError('',
385 _('destination largefile already exists'))
387 _('destination largefile already exists'))
386 copiedfiles.append((src, dest))
388 copiedfiles.append((src, dest))
387 origcopyfile(src, dest)
389 origcopyfile(src, dest)
388
390
389 util.copyfile = override_copyfile
391 util.copyfile = override_copyfile
390 result += orig(ui, repo, listpats, opts, rename)
392 result += orig(ui, repo, listpats, opts, rename)
391 finally:
393 finally:
392 util.copyfile = origcopyfile
394 util.copyfile = origcopyfile
393
395
394 lfdirstate = lfutil.openlfdirstate(ui, repo)
396 lfdirstate = lfutil.openlfdirstate(ui, repo)
395 for (src, dest) in copiedfiles:
397 for (src, dest) in copiedfiles:
396 if lfutil.shortname in src and lfutil.shortname in dest:
398 if lfutil.shortname in src and lfutil.shortname in dest:
397 srclfile = src.replace(lfutil.shortname, '')
399 srclfile = src.replace(lfutil.shortname, '')
398 destlfile = dest.replace(lfutil.shortname, '')
400 destlfile = dest.replace(lfutil.shortname, '')
399 destlfiledir = os.path.dirname(destlfile) or '.'
401 destlfiledir = os.path.dirname(destlfile) or '.'
400 if not os.path.isdir(destlfiledir):
402 if not os.path.isdir(destlfiledir):
401 os.makedirs(destlfiledir)
403 os.makedirs(destlfiledir)
402 if rename:
404 if rename:
403 os.rename(srclfile, destlfile)
405 os.rename(srclfile, destlfile)
404 lfdirstate.remove(os.path.relpath(srclfile,
406 lfdirstate.remove(os.path.relpath(srclfile,
407 repo.root))
408 else:
409 util.copyfile(srclfile, destlfile)
410 lfdirstate.add(os.path.relpath(destlfile,
405 repo.root))
411 repo.root))
406 else:
412 lfdirstate.write()
407 util.copyfile(srclfile, destlfile)
413 except util.Abort, e:
408 lfdirstate.add(os.path.relpath(destlfile,
414 if str(e) != 'no files to copy':
409 repo.root))
415 raise e
410 lfdirstate.write()
416 else:
411 except util.Abort, e:
417 nolfiles = True
412 if str(e) != 'no files to copy':
413 raise e
414 else:
415 nolfiles = True
416 finally:
418 finally:
417 restorematchfn()
419 restorematchfn()
418 wlock.release()
420 wlock.release()
419
421
420 if nolfiles and nonormalfiles:
422 if nolfiles and nonormalfiles:
421 raise util.Abort(_('no files to copy'))
423 raise util.Abort(_('no files to copy'))
422
424
423 return result
425 return result
424
426
425 # When the user calls revert, we have to be careful to not revert any
427 # When the user calls revert, we have to be careful to not revert any
426 # changes to other largefiles accidentally. This means we have to keep
428 # changes to other largefiles accidentally. This means we have to keep
427 # track of the largefiles that are being reverted so we only pull down
429 # track of the largefiles that are being reverted so we only pull down
428 # the necessary largefiles.
430 # the necessary largefiles.
429 #
431 #
430 # Standins are only updated (to match the hash of largefiles) before
432 # Standins are only updated (to match the hash of largefiles) before
431 # commits. Update the standins then run the original revert, changing
433 # commits. Update the standins then run the original revert, changing
432 # the matcher to hit standins instead of largefiles. Based on the
434 # the matcher to hit standins instead of largefiles. Based on the
433 # resulting standins update the largefiles. Then return the standins
435 # resulting standins update the largefiles. Then return the standins
434 # to their proper state
436 # to their proper state
435 def override_revert(orig, ui, repo, *pats, **opts):
437 def override_revert(orig, ui, repo, *pats, **opts):
436 # Because we put the standins in a bad state (by updating them)
438 # Because we put the standins in a bad state (by updating them)
437 # and then return them to a correct state we need to lock to
439 # and then return them to a correct state we need to lock to
438 # prevent others from changing them in their incorrect state.
440 # prevent others from changing them in their incorrect state.
439 wlock = repo.wlock()
441 wlock = repo.wlock()
440 try:
442 try:
441 lfdirstate = lfutil.openlfdirstate(ui, repo)
443 lfdirstate = lfutil.openlfdirstate(ui, repo)
442 (modified, added, removed, missing, unknown, ignored, clean) = \
444 (modified, added, removed, missing, unknown, ignored, clean) = \
443 lfutil.lfdirstate_status(lfdirstate, repo, repo['.'].rev())
445 lfutil.lfdirstate_status(lfdirstate, repo, repo['.'].rev())
444 for lfile in modified:
446 for lfile in modified:
445 lfutil.updatestandin(repo, lfutil.standin(lfile))
447 lfutil.updatestandin(repo, lfutil.standin(lfile))
446
448
447 try:
449 try:
448 ctx = repo[opts.get('rev')]
450 ctx = repo[opts.get('rev')]
449 oldmatch = None # for the closure
451 oldmatch = None # for the closure
450 def override_match(ctxorrepo, pats=[], opts={}, globbed=False,
452 def override_match(ctxorrepo, pats=[], opts={}, globbed=False,
451 default='relpath'):
453 default='relpath'):
452 if util.safehasattr(ctxorrepo, 'match'):
454 if util.safehasattr(ctxorrepo, 'match'):
453 ctx0 = ctxorrepo
455 ctx0 = ctxorrepo
454 else:
456 else:
455 ctx0 = ctxorrepo[None]
457 ctx0 = ctxorrepo[None]
456 match = oldmatch(ctxorrepo, pats, opts, globbed, default)
458 match = oldmatch(ctxorrepo, pats, opts, globbed, default)
457 m = copy.copy(match)
459 m = copy.copy(match)
458 def tostandin(f):
460 def tostandin(f):
459 if lfutil.standin(f) in ctx0 or lfutil.standin(f) in ctx:
461 if lfutil.standin(f) in ctx0 or lfutil.standin(f) in ctx:
460 return lfutil.standin(f)
462 return lfutil.standin(f)
461 elif lfutil.standin(f) in repo[None]:
463 elif lfutil.standin(f) in repo[None]:
462 return None
464 return None
463 return f
465 return f
464 m._files = [tostandin(f) for f in m._files]
466 m._files = [tostandin(f) for f in m._files]
465 m._files = [f for f in m._files if f is not None]
467 m._files = [f for f in m._files if f is not None]
466 m._fmap = set(m._files)
468 m._fmap = set(m._files)
467 orig_matchfn = m.matchfn
469 orig_matchfn = m.matchfn
468 def matchfn(f):
470 def matchfn(f):
469 if lfutil.isstandin(f):
471 if lfutil.isstandin(f):
470 # We need to keep track of what largefiles are being
472 # We need to keep track of what largefiles are being
471 # matched so we know which ones to update later --
473 # matched so we know which ones to update later --
472 # otherwise we accidentally revert changes to other
474 # otherwise we accidentally revert changes to other
473 # largefiles. This is repo-specific, so duckpunch the
475 # largefiles. This is repo-specific, so duckpunch the
474 # repo object to keep the list of largefiles for us
476 # repo object to keep the list of largefiles for us
475 # later.
477 # later.
476 if orig_matchfn(lfutil.splitstandin(f)) and \
478 if orig_matchfn(lfutil.splitstandin(f)) and \
477 (f in repo[None] or f in ctx):
479 (f in repo[None] or f in ctx):
478 lfileslist = getattr(repo, '_lfilestoupdate', [])
480 lfileslist = getattr(repo, '_lfilestoupdate', [])
479 lfileslist.append(lfutil.splitstandin(f))
481 lfileslist.append(lfutil.splitstandin(f))
480 repo._lfilestoupdate = lfileslist
482 repo._lfilestoupdate = lfileslist
481 return True
483 return True
482 else:
484 else:
483 return False
485 return False
484 return orig_matchfn(f)
486 return orig_matchfn(f)
485 m.matchfn = matchfn
487 m.matchfn = matchfn
486 return m
488 return m
487 oldmatch = installmatchfn(override_match)
489 oldmatch = installmatchfn(override_match)
488 scmutil.match
490 scmutil.match
489 matches = override_match(repo[None], pats, opts)
491 matches = override_match(repo[None], pats, opts)
490 orig(ui, repo, *pats, **opts)
492 orig(ui, repo, *pats, **opts)
491 finally:
493 finally:
492 restorematchfn()
494 restorematchfn()
493 lfileslist = getattr(repo, '_lfilestoupdate', [])
495 lfileslist = getattr(repo, '_lfilestoupdate', [])
494 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
496 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
495 printmessage=False)
497 printmessage=False)
496
498
497 # empty out the largefiles list so we start fresh next time
499 # empty out the largefiles list so we start fresh next time
498 repo._lfilestoupdate = []
500 repo._lfilestoupdate = []
499 for lfile in modified:
501 for lfile in modified:
500 if lfile in lfileslist:
502 if lfile in lfileslist:
501 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
503 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
502 in repo['.']:
504 in repo['.']:
503 lfutil.writestandin(repo, lfutil.standin(lfile),
505 lfutil.writestandin(repo, lfutil.standin(lfile),
504 repo['.'][lfile].data().strip(),
506 repo['.'][lfile].data().strip(),
505 'x' in repo['.'][lfile].flags())
507 'x' in repo['.'][lfile].flags())
506 lfdirstate = lfutil.openlfdirstate(ui, repo)
508 lfdirstate = lfutil.openlfdirstate(ui, repo)
507 for lfile in added:
509 for lfile in added:
508 standin = lfutil.standin(lfile)
510 standin = lfutil.standin(lfile)
509 if standin not in ctx and (standin in matches or opts.get('all')):
511 if standin not in ctx and (standin in matches or opts.get('all')):
510 if lfile in lfdirstate:
512 if lfile in lfdirstate:
511 lfdirstate.drop(lfile)
513 lfdirstate.drop(lfile)
512 util.unlinkpath(repo.wjoin(standin))
514 util.unlinkpath(repo.wjoin(standin))
513 lfdirstate.write()
515 lfdirstate.write()
514 finally:
516 finally:
515 wlock.release()
517 wlock.release()
516
518
517 def hg_update(orig, repo, node):
519 def hg_update(orig, repo, node):
518 result = orig(repo, node)
520 result = orig(repo, node)
519 # XXX check if it worked first
521 # XXX check if it worked first
520 lfcommands.updatelfiles(repo.ui, repo)
522 lfcommands.updatelfiles(repo.ui, repo)
521 return result
523 return result
522
524
523 def hg_clean(orig, repo, node, show_stats=True):
525 def hg_clean(orig, repo, node, show_stats=True):
524 result = orig(repo, node, show_stats)
526 result = orig(repo, node, show_stats)
525 lfcommands.updatelfiles(repo.ui, repo)
527 lfcommands.updatelfiles(repo.ui, repo)
526 return result
528 return result
527
529
528 def hg_merge(orig, repo, node, force=None, remind=True):
530 def hg_merge(orig, repo, node, force=None, remind=True):
529 result = orig(repo, node, force, remind)
531 result = orig(repo, node, force, remind)
530 lfcommands.updatelfiles(repo.ui, repo)
532 lfcommands.updatelfiles(repo.ui, repo)
531 return result
533 return result
532
534
533 # When we rebase a repository with remotely changed largefiles, we need to
535 # When we rebase a repository with remotely changed largefiles, we need to
534 # take some extra care so that the largefiles are correctly updated in the
536 # take some extra care so that the largefiles are correctly updated in the
535 # working copy
537 # working copy
536 def override_pull(orig, ui, repo, source=None, **opts):
538 def override_pull(orig, ui, repo, source=None, **opts):
537 if opts.get('rebase', False):
539 if opts.get('rebase', False):
538 repo._isrebasing = True
540 repo._isrebasing = True
539 try:
541 try:
540 if opts.get('update'):
542 if opts.get('update'):
541 del opts['update']
543 del opts['update']
542 ui.debug('--update and --rebase are not compatible, ignoring '
544 ui.debug('--update and --rebase are not compatible, ignoring '
543 'the update flag\n')
545 'the update flag\n')
544 del opts['rebase']
546 del opts['rebase']
545 cmdutil.bailifchanged(repo)
547 cmdutil.bailifchanged(repo)
546 revsprepull = len(repo)
548 revsprepull = len(repo)
547 origpostincoming = commands.postincoming
549 origpostincoming = commands.postincoming
548 def _dummy(*args, **kwargs):
550 def _dummy(*args, **kwargs):
549 pass
551 pass
550 commands.postincoming = _dummy
552 commands.postincoming = _dummy
551 repo.lfpullsource = source
553 repo.lfpullsource = source
552 if not source:
554 if not source:
553 source = 'default'
555 source = 'default'
554 try:
556 try:
555 result = commands.pull(ui, repo, source, **opts)
557 result = commands.pull(ui, repo, source, **opts)
556 finally:
558 finally:
557 commands.postincoming = origpostincoming
559 commands.postincoming = origpostincoming
558 revspostpull = len(repo)
560 revspostpull = len(repo)
559 if revspostpull > revsprepull:
561 if revspostpull > revsprepull:
560 result = result or rebase.rebase(ui, repo)
562 result = result or rebase.rebase(ui, repo)
561 finally:
563 finally:
562 repo._isrebasing = False
564 repo._isrebasing = False
563 else:
565 else:
564 repo.lfpullsource = source
566 repo.lfpullsource = source
565 if not source:
567 if not source:
566 source = 'default'
568 source = 'default'
567 result = orig(ui, repo, source, **opts)
569 result = orig(ui, repo, source, **opts)
568 return result
570 return result
569
571
570 def override_rebase(orig, ui, repo, **opts):
572 def override_rebase(orig, ui, repo, **opts):
571 repo._isrebasing = True
573 repo._isrebasing = True
572 try:
574 try:
573 orig(ui, repo, **opts)
575 orig(ui, repo, **opts)
574 finally:
576 finally:
575 repo._isrebasing = False
577 repo._isrebasing = False
576
578
577 def override_archive(orig, repo, dest, node, kind, decode=True, matchfn=None,
579 def override_archive(orig, repo, dest, node, kind, decode=True, matchfn=None,
578 prefix=None, mtime=None, subrepos=None):
580 prefix=None, mtime=None, subrepos=None):
579 # No need to lock because we are only reading history and
581 # No need to lock because we are only reading history and
580 # largefile caches, neither of which are modified.
582 # largefile caches, neither of which are modified.
581 lfcommands.cachelfiles(repo.ui, repo, node)
583 lfcommands.cachelfiles(repo.ui, repo, node)
582
584
583 if kind not in archival.archivers:
585 if kind not in archival.archivers:
584 raise util.Abort(_("unknown archive type '%s'") % kind)
586 raise util.Abort(_("unknown archive type '%s'") % kind)
585
587
586 ctx = repo[node]
588 ctx = repo[node]
587
589
588 if kind == 'files':
590 if kind == 'files':
589 if prefix:
591 if prefix:
590 raise util.Abort(
592 raise util.Abort(
591 _('cannot give prefix when archiving to files'))
593 _('cannot give prefix when archiving to files'))
592 else:
594 else:
593 prefix = archival.tidyprefix(dest, kind, prefix)
595 prefix = archival.tidyprefix(dest, kind, prefix)
594
596
595 def write(name, mode, islink, getdata):
597 def write(name, mode, islink, getdata):
596 if matchfn and not matchfn(name):
598 if matchfn and not matchfn(name):
597 return
599 return
598 data = getdata()
600 data = getdata()
599 if decode:
601 if decode:
600 data = repo.wwritedata(name, data)
602 data = repo.wwritedata(name, data)
601 archiver.addfile(prefix + name, mode, islink, data)
603 archiver.addfile(prefix + name, mode, islink, data)
602
604
603 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
605 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
604
606
605 if repo.ui.configbool("ui", "archivemeta", True):
607 if repo.ui.configbool("ui", "archivemeta", True):
606 def metadata():
608 def metadata():
607 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
609 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
608 hex(repo.changelog.node(0)), hex(node), ctx.branch())
610 hex(repo.changelog.node(0)), hex(node), ctx.branch())
609
611
610 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
612 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
611 if repo.tagtype(t) == 'global')
613 if repo.tagtype(t) == 'global')
612 if not tags:
614 if not tags:
613 repo.ui.pushbuffer()
615 repo.ui.pushbuffer()
614 opts = {'template': '{latesttag}\n{latesttagdistance}',
616 opts = {'template': '{latesttag}\n{latesttagdistance}',
615 'style': '', 'patch': None, 'git': None}
617 'style': '', 'patch': None, 'git': None}
616 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
618 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
617 ltags, dist = repo.ui.popbuffer().split('\n')
619 ltags, dist = repo.ui.popbuffer().split('\n')
618 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
620 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
619 tags += 'latesttagdistance: %s\n' % dist
621 tags += 'latesttagdistance: %s\n' % dist
620
622
621 return base + tags
623 return base + tags
622
624
623 write('.hg_archival.txt', 0644, False, metadata)
625 write('.hg_archival.txt', 0644, False, metadata)
624
626
625 for f in ctx:
627 for f in ctx:
626 ff = ctx.flags(f)
628 ff = ctx.flags(f)
627 getdata = ctx[f].data
629 getdata = ctx[f].data
628 if lfutil.isstandin(f):
630 if lfutil.isstandin(f):
629 path = lfutil.findfile(repo, getdata().strip())
631 path = lfutil.findfile(repo, getdata().strip())
630 f = lfutil.splitstandin(f)
632 f = lfutil.splitstandin(f)
631
633
632 def getdatafn():
634 def getdatafn():
633 try:
635 try:
634 fd = open(path, 'rb')
636 fd = open(path, 'rb')
635 return fd.read()
637 return fd.read()
636 finally:
638 finally:
637 fd.close()
639 fd.close()
638
640
639 getdata = getdatafn
641 getdata = getdatafn
640 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
642 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
641
643
642 if subrepos:
644 if subrepos:
643 for subpath in ctx.substate:
645 for subpath in ctx.substate:
644 sub = ctx.sub(subpath)
646 sub = ctx.sub(subpath)
645 try:
647 try:
646 sub.archive(repo.ui, archiver, prefix)
648 sub.archive(repo.ui, archiver, prefix)
647 except TypeError:
649 except TypeError:
648 sub.archive(archiver, prefix)
650 sub.archive(archiver, prefix)
649
651
650 archiver.done()
652 archiver.done()
651
653
652 # If a largefile is modified, the change is not reflected in its
654 # If a largefile is modified, the change is not reflected in its
653 # standin until a commit. cmdutil.bailifchanged() raises an exception
655 # standin until a commit. cmdutil.bailifchanged() raises an exception
654 # if the repo has uncommitted changes. Wrap it to also check if
656 # if the repo has uncommitted changes. Wrap it to also check if
655 # largefiles were changed. This is used by bisect and backout.
657 # largefiles were changed. This is used by bisect and backout.
656 def override_bailifchanged(orig, repo):
658 def override_bailifchanged(orig, repo):
657 orig(repo)
659 orig(repo)
658 repo.lfstatus = True
660 repo.lfstatus = True
659 modified, added, removed, deleted = repo.status()[:4]
661 modified, added, removed, deleted = repo.status()[:4]
660 repo.lfstatus = False
662 repo.lfstatus = False
661 if modified or added or removed or deleted:
663 if modified or added or removed or deleted:
662 raise util.Abort(_('outstanding uncommitted changes'))
664 raise util.Abort(_('outstanding uncommitted changes'))
663
665
664 # Fetch doesn't use cmdutil.bail_if_changed so override it to add the check
666 # Fetch doesn't use cmdutil.bail_if_changed so override it to add the check
665 def override_fetch(orig, ui, repo, *pats, **opts):
667 def override_fetch(orig, ui, repo, *pats, **opts):
666 repo.lfstatus = True
668 repo.lfstatus = True
667 modified, added, removed, deleted = repo.status()[:4]
669 modified, added, removed, deleted = repo.status()[:4]
668 repo.lfstatus = False
670 repo.lfstatus = False
669 if modified or added or removed or deleted:
671 if modified or added or removed or deleted:
670 raise util.Abort(_('outstanding uncommitted changes'))
672 raise util.Abort(_('outstanding uncommitted changes'))
671 return orig(ui, repo, *pats, **opts)
673 return orig(ui, repo, *pats, **opts)
672
674
673 def override_forget(orig, ui, repo, *pats, **opts):
675 def override_forget(orig, ui, repo, *pats, **opts):
674 installnormalfilesmatchfn(repo[None].manifest())
676 installnormalfilesmatchfn(repo[None].manifest())
675 orig(ui, repo, *pats, **opts)
677 orig(ui, repo, *pats, **opts)
676 restorematchfn()
678 restorematchfn()
677 m = scmutil.match(repo[None], pats, opts)
679 m = scmutil.match(repo[None], pats, opts)
678
680
679 try:
681 try:
680 repo.lfstatus = True
682 repo.lfstatus = True
681 s = repo.status(match=m, clean=True)
683 s = repo.status(match=m, clean=True)
682 finally:
684 finally:
683 repo.lfstatus = False
685 repo.lfstatus = False
684 forget = sorted(s[0] + s[1] + s[3] + s[6])
686 forget = sorted(s[0] + s[1] + s[3] + s[6])
685 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
687 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
686
688
687 for f in forget:
689 for f in forget:
688 if lfutil.standin(f) not in repo.dirstate and not \
690 if lfutil.standin(f) not in repo.dirstate and not \
689 os.path.isdir(m.rel(lfutil.standin(f))):
691 os.path.isdir(m.rel(lfutil.standin(f))):
690 ui.warn(_('not removing %s: file is already untracked\n')
692 ui.warn(_('not removing %s: file is already untracked\n')
691 % m.rel(f))
693 % m.rel(f))
692
694
693 for f in forget:
695 for f in forget:
694 if ui.verbose or not m.exact(f):
696 if ui.verbose or not m.exact(f):
695 ui.status(_('removing %s\n') % m.rel(f))
697 ui.status(_('removing %s\n') % m.rel(f))
696
698
697 # Need to lock because standin files are deleted then removed from the
699 # Need to lock because standin files are deleted then removed from the
698 # repository and we could race inbetween.
700 # repository and we could race inbetween.
699 wlock = repo.wlock()
701 wlock = repo.wlock()
700 try:
702 try:
701 lfdirstate = lfutil.openlfdirstate(ui, repo)
703 lfdirstate = lfutil.openlfdirstate(ui, repo)
702 for f in forget:
704 for f in forget:
703 if lfdirstate[f] == 'a':
705 if lfdirstate[f] == 'a':
704 lfdirstate.drop(f)
706 lfdirstate.drop(f)
705 else:
707 else:
706 lfdirstate.remove(f)
708 lfdirstate.remove(f)
707 lfdirstate.write()
709 lfdirstate.write()
708 lfutil.repo_remove(repo, [lfutil.standin(f) for f in forget],
710 lfutil.repo_remove(repo, [lfutil.standin(f) for f in forget],
709 unlink=True)
711 unlink=True)
710 finally:
712 finally:
711 wlock.release()
713 wlock.release()
712
714
713 def getoutgoinglfiles(ui, repo, dest=None, **opts):
715 def getoutgoinglfiles(ui, repo, dest=None, **opts):
714 dest = ui.expandpath(dest or 'default-push', dest or 'default')
716 dest = ui.expandpath(dest or 'default-push', dest or 'default')
715 dest, branches = hg.parseurl(dest, opts.get('branch'))
717 dest, branches = hg.parseurl(dest, opts.get('branch'))
716 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
718 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
717 if revs:
719 if revs:
718 revs = [repo.lookup(rev) for rev in revs]
720 revs = [repo.lookup(rev) for rev in revs]
719
721
720 remoteui = hg.remoteui
722 remoteui = hg.remoteui
721
723
722 try:
724 try:
723 remote = hg.repository(remoteui(repo, opts), dest)
725 remote = hg.repository(remoteui(repo, opts), dest)
724 except error.RepoError:
726 except error.RepoError:
725 return None
727 return None
726 o = lfutil.findoutgoing(repo, remote, False)
728 o = lfutil.findoutgoing(repo, remote, False)
727 if not o:
729 if not o:
728 return None
730 return None
729 o = repo.changelog.nodesbetween(o, revs)[0]
731 o = repo.changelog.nodesbetween(o, revs)[0]
730 if opts.get('newest_first'):
732 if opts.get('newest_first'):
731 o.reverse()
733 o.reverse()
732
734
733 toupload = set()
735 toupload = set()
734 for n in o:
736 for n in o:
735 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
737 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
736 ctx = repo[n]
738 ctx = repo[n]
737 files = set(ctx.files())
739 files = set(ctx.files())
738 if len(parents) == 2:
740 if len(parents) == 2:
739 mc = ctx.manifest()
741 mc = ctx.manifest()
740 mp1 = ctx.parents()[0].manifest()
742 mp1 = ctx.parents()[0].manifest()
741 mp2 = ctx.parents()[1].manifest()
743 mp2 = ctx.parents()[1].manifest()
742 for f in mp1:
744 for f in mp1:
743 if f not in mc:
745 if f not in mc:
744 files.add(f)
746 files.add(f)
745 for f in mp2:
747 for f in mp2:
746 if f not in mc:
748 if f not in mc:
747 files.add(f)
749 files.add(f)
748 for f in mc:
750 for f in mc:
749 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
751 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
750 files.add(f)
752 files.add(f)
751 toupload = toupload.union(
753 toupload = toupload.union(
752 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
754 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
753 return toupload
755 return toupload
754
756
755 def override_outgoing(orig, ui, repo, dest=None, **opts):
757 def override_outgoing(orig, ui, repo, dest=None, **opts):
756 orig(ui, repo, dest, **opts)
758 orig(ui, repo, dest, **opts)
757
759
758 if opts.pop('large', None):
760 if opts.pop('large', None):
759 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
761 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
760 if toupload is None:
762 if toupload is None:
761 ui.status(_('largefiles: No remote repo\n'))
763 ui.status(_('largefiles: No remote repo\n'))
762 else:
764 else:
763 ui.status(_('largefiles to upload:\n'))
765 ui.status(_('largefiles to upload:\n'))
764 for file in toupload:
766 for file in toupload:
765 ui.status(lfutil.splitstandin(file) + '\n')
767 ui.status(lfutil.splitstandin(file) + '\n')
766 ui.status('\n')
768 ui.status('\n')
767
769
768 def override_summary(orig, ui, repo, *pats, **opts):
770 def override_summary(orig, ui, repo, *pats, **opts):
769 orig(ui, repo, *pats, **opts)
771 orig(ui, repo, *pats, **opts)
770
772
771 if opts.pop('large', None):
773 if opts.pop('large', None):
772 toupload = getoutgoinglfiles(ui, repo, None, **opts)
774 toupload = getoutgoinglfiles(ui, repo, None, **opts)
773 if toupload is None:
775 if toupload is None:
774 ui.status(_('largefiles: No remote repo\n'))
776 ui.status(_('largefiles: No remote repo\n'))
775 else:
777 else:
776 ui.status(_('largefiles: %d to upload\n') % len(toupload))
778 ui.status(_('largefiles: %d to upload\n') % len(toupload))
777
779
778 def override_addremove(orig, ui, repo, *pats, **opts):
780 def override_addremove(orig, ui, repo, *pats, **opts):
779 # Check if the parent or child has largefiles; if so, disallow
781 # Check if the parent or child has largefiles; if so, disallow
780 # addremove. If there is a symlink in the manifest then getting
782 # addremove. If there is a symlink in the manifest then getting
781 # the manifest throws an exception: catch it and let addremove
783 # the manifest throws an exception: catch it and let addremove
782 # deal with it.
784 # deal with it.
783 try:
785 try:
784 manifesttip = set(repo['tip'].manifest())
786 manifesttip = set(repo['tip'].manifest())
785 except util.Abort:
787 except util.Abort:
786 manifesttip = set()
788 manifesttip = set()
787 try:
789 try:
788 manifestworking = set(repo[None].manifest())
790 manifestworking = set(repo[None].manifest())
789 except util.Abort:
791 except util.Abort:
790 manifestworking = set()
792 manifestworking = set()
791
793
792 # Manifests are only iterable so turn them into sets then union
794 # Manifests are only iterable so turn them into sets then union
793 for file in manifesttip.union(manifestworking):
795 for file in manifesttip.union(manifestworking):
794 if file.startswith(lfutil.shortname):
796 if file.startswith(lfutil.shortname):
795 raise util.Abort(
797 raise util.Abort(
796 _('addremove cannot be run on a repo with largefiles'))
798 _('addremove cannot be run on a repo with largefiles'))
797
799
798 return orig(ui, repo, *pats, **opts)
800 return orig(ui, repo, *pats, **opts)
799
801
800 # Calling purge with --all will cause the largefiles to be deleted.
802 # Calling purge with --all will cause the largefiles to be deleted.
801 # Override repo.status to prevent this from happening.
803 # Override repo.status to prevent this from happening.
802 def override_purge(orig, ui, repo, *dirs, **opts):
804 def override_purge(orig, ui, repo, *dirs, **opts):
803 oldstatus = repo.status
805 oldstatus = repo.status
804 def override_status(node1='.', node2=None, match=None, ignored=False,
806 def override_status(node1='.', node2=None, match=None, ignored=False,
805 clean=False, unknown=False, listsubrepos=False):
807 clean=False, unknown=False, listsubrepos=False):
806 r = oldstatus(node1, node2, match, ignored, clean, unknown,
808 r = oldstatus(node1, node2, match, ignored, clean, unknown,
807 listsubrepos)
809 listsubrepos)
808 lfdirstate = lfutil.openlfdirstate(ui, repo)
810 lfdirstate = lfutil.openlfdirstate(ui, repo)
809 modified, added, removed, deleted, unknown, ignored, clean = r
811 modified, added, removed, deleted, unknown, ignored, clean = r
810 unknown = [f for f in unknown if lfdirstate[f] == '?']
812 unknown = [f for f in unknown if lfdirstate[f] == '?']
811 ignored = [f for f in ignored if lfdirstate[f] == '?']
813 ignored = [f for f in ignored if lfdirstate[f] == '?']
812 return modified, added, removed, deleted, unknown, ignored, clean
814 return modified, added, removed, deleted, unknown, ignored, clean
813 repo.status = override_status
815 repo.status = override_status
814 orig(ui, repo, *dirs, **opts)
816 orig(ui, repo, *dirs, **opts)
815 repo.status = oldstatus
817 repo.status = oldstatus
816
818
817 def override_rollback(orig, ui, repo, **opts):
819 def override_rollback(orig, ui, repo, **opts):
818 result = orig(ui, repo, **opts)
820 result = orig(ui, repo, **opts)
819 merge.update(repo, node=None, branchmerge=False, force=True,
821 merge.update(repo, node=None, branchmerge=False, force=True,
820 partial=lfutil.isstandin)
822 partial=lfutil.isstandin)
821 lfdirstate = lfutil.openlfdirstate(ui, repo)
823 lfdirstate = lfutil.openlfdirstate(ui, repo)
822 lfiles = lfutil.listlfiles(repo)
824 lfiles = lfutil.listlfiles(repo)
823 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
825 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
824 for file in lfiles:
826 for file in lfiles:
825 if file in oldlfiles:
827 if file in oldlfiles:
826 lfdirstate.normallookup(file)
828 lfdirstate.normallookup(file)
827 else:
829 else:
828 lfdirstate.add(file)
830 lfdirstate.add(file)
829 lfdirstate.write()
831 lfdirstate.write()
830 return result
832 return result
General Comments 0
You need to be logged in to leave comments. Login now