##// END OF EJS Templates
largefiles: call super class method with proper kwargs to respect API...
Long Vu -
r20177:c5f05740 default
parent child Browse files
Show More
@@ -1,514 +1,514 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 repositories: reposetup'''
9 '''setup for largefiles repositories: reposetup'''
10 import copy
10 import copy
11 import os
11 import os
12
12
13 from mercurial import error, manifest, match as match_, util, discovery
13 from mercurial import error, manifest, match as match_, util, discovery
14 from mercurial import node as node_
14 from mercurial import node as node_
15 from mercurial.i18n import _
15 from mercurial.i18n import _
16 from mercurial import localrepo
16 from mercurial import localrepo
17
17
18 import lfcommands
18 import lfcommands
19 import proto
19 import proto
20 import lfutil
20 import lfutil
21
21
22 def reposetup(ui, repo):
22 def reposetup(ui, repo):
23 # wire repositories should be given new wireproto functions but not the
23 # wire repositories should be given new wireproto functions but not the
24 # other largefiles modifications
24 # other largefiles modifications
25 if not repo.local():
25 if not repo.local():
26 return proto.wirereposetup(ui, repo)
26 return proto.wirereposetup(ui, repo)
27
27
28 class lfilesrepo(repo.__class__):
28 class lfilesrepo(repo.__class__):
29 lfstatus = False
29 lfstatus = False
30 def status_nolfiles(self, *args, **kwargs):
30 def status_nolfiles(self, *args, **kwargs):
31 return super(lfilesrepo, self).status(*args, **kwargs)
31 return super(lfilesrepo, self).status(*args, **kwargs)
32
32
33 # When lfstatus is set, return a context that gives the names
33 # When lfstatus is set, return a context that gives the names
34 # of largefiles instead of their corresponding standins and
34 # of largefiles instead of their corresponding standins and
35 # identifies the largefiles as always binary, regardless of
35 # identifies the largefiles as always binary, regardless of
36 # their actual contents.
36 # their actual contents.
37 def __getitem__(self, changeid):
37 def __getitem__(self, changeid):
38 ctx = super(lfilesrepo, self).__getitem__(changeid)
38 ctx = super(lfilesrepo, self).__getitem__(changeid)
39 if self.lfstatus:
39 if self.lfstatus:
40 class lfilesmanifestdict(manifest.manifestdict):
40 class lfilesmanifestdict(manifest.manifestdict):
41 def __contains__(self, filename):
41 def __contains__(self, filename):
42 if super(lfilesmanifestdict,
42 if super(lfilesmanifestdict,
43 self).__contains__(filename):
43 self).__contains__(filename):
44 return True
44 return True
45 return super(lfilesmanifestdict,
45 return super(lfilesmanifestdict,
46 self).__contains__(lfutil.standin(filename))
46 self).__contains__(lfutil.standin(filename))
47 class lfilesctx(ctx.__class__):
47 class lfilesctx(ctx.__class__):
48 def files(self):
48 def files(self):
49 filenames = super(lfilesctx, self).files()
49 filenames = super(lfilesctx, self).files()
50 return [lfutil.splitstandin(f) or f for f in filenames]
50 return [lfutil.splitstandin(f) or f for f in filenames]
51 def manifest(self):
51 def manifest(self):
52 man1 = super(lfilesctx, self).manifest()
52 man1 = super(lfilesctx, self).manifest()
53 man1.__class__ = lfilesmanifestdict
53 man1.__class__ = lfilesmanifestdict
54 return man1
54 return man1
55 def filectx(self, path, fileid=None, filelog=None):
55 def filectx(self, path, fileid=None, filelog=None):
56 try:
56 try:
57 if filelog is not None:
57 if filelog is not None:
58 result = super(lfilesctx, self).filectx(
58 result = super(lfilesctx, self).filectx(
59 path, fileid, filelog)
59 path, fileid, filelog)
60 else:
60 else:
61 result = super(lfilesctx, self).filectx(
61 result = super(lfilesctx, self).filectx(
62 path, fileid)
62 path, fileid)
63 except error.LookupError:
63 except error.LookupError:
64 # Adding a null character will cause Mercurial to
64 # Adding a null character will cause Mercurial to
65 # identify this as a binary file.
65 # identify this as a binary file.
66 if filelog is not None:
66 if filelog is not None:
67 result = super(lfilesctx, self).filectx(
67 result = super(lfilesctx, self).filectx(
68 lfutil.standin(path), fileid, filelog)
68 lfutil.standin(path), fileid, filelog)
69 else:
69 else:
70 result = super(lfilesctx, self).filectx(
70 result = super(lfilesctx, self).filectx(
71 lfutil.standin(path), fileid)
71 lfutil.standin(path), fileid)
72 olddata = result.data
72 olddata = result.data
73 result.data = lambda: olddata() + '\0'
73 result.data = lambda: olddata() + '\0'
74 return result
74 return result
75 ctx.__class__ = lfilesctx
75 ctx.__class__ = lfilesctx
76 return ctx
76 return ctx
77
77
78 # Figure out the status of big files and insert them into the
78 # Figure out the status of big files and insert them into the
79 # appropriate list in the result. Also removes standin files
79 # appropriate list in the result. Also removes standin files
80 # from the listing. Revert to the original status if
80 # from the listing. Revert to the original status if
81 # self.lfstatus is False.
81 # self.lfstatus is False.
82 # XXX large file status is buggy when used on repo proxy.
82 # XXX large file status is buggy when used on repo proxy.
83 # XXX this needs to be investigated.
83 # XXX this needs to be investigated.
84 @localrepo.unfilteredmethod
84 @localrepo.unfilteredmethod
85 def status(self, node1='.', node2=None, match=None, ignored=False,
85 def status(self, node1='.', node2=None, match=None, ignored=False,
86 clean=False, unknown=False, listsubrepos=False):
86 clean=False, unknown=False, listsubrepos=False):
87 listignored, listclean, listunknown = ignored, clean, unknown
87 listignored, listclean, listunknown = ignored, clean, unknown
88 if not self.lfstatus:
88 if not self.lfstatus:
89 return super(lfilesrepo, self).status(node1, node2, match,
89 return super(lfilesrepo, self).status(node1, node2, match,
90 listignored, listclean, listunknown, listsubrepos)
90 listignored, listclean, listunknown, listsubrepos)
91 else:
91 else:
92 # some calls in this function rely on the old version of status
92 # some calls in this function rely on the old version of status
93 self.lfstatus = False
93 self.lfstatus = False
94 ctx1 = self[node1]
94 ctx1 = self[node1]
95 ctx2 = self[node2]
95 ctx2 = self[node2]
96 working = ctx2.rev() is None
96 working = ctx2.rev() is None
97 parentworking = working and ctx1 == self['.']
97 parentworking = working and ctx1 == self['.']
98
98
99 def inctx(file, ctx):
99 def inctx(file, ctx):
100 try:
100 try:
101 if ctx.rev() is None:
101 if ctx.rev() is None:
102 return file in ctx.manifest()
102 return file in ctx.manifest()
103 ctx[file]
103 ctx[file]
104 return True
104 return True
105 except KeyError:
105 except KeyError:
106 return False
106 return False
107
107
108 if match is None:
108 if match is None:
109 match = match_.always(self.root, self.getcwd())
109 match = match_.always(self.root, self.getcwd())
110
110
111 wlock = None
111 wlock = None
112 try:
112 try:
113 try:
113 try:
114 # updating the dirstate is optional
114 # updating the dirstate is optional
115 # so we don't wait on the lock
115 # so we don't wait on the lock
116 wlock = self.wlock(False)
116 wlock = self.wlock(False)
117 except error.LockError:
117 except error.LockError:
118 pass
118 pass
119
119
120 # First check if there were files specified on the
120 # First check if there were files specified on the
121 # command line. If there were, and none of them were
121 # command line. If there were, and none of them were
122 # largefiles, we should just bail here and let super
122 # largefiles, we should just bail here and let super
123 # handle it -- thus gaining a big performance boost.
123 # handle it -- thus gaining a big performance boost.
124 lfdirstate = lfutil.openlfdirstate(ui, self)
124 lfdirstate = lfutil.openlfdirstate(ui, self)
125 if match.files() and not match.anypats():
125 if match.files() and not match.anypats():
126 for f in lfdirstate:
126 for f in lfdirstate:
127 if match(f):
127 if match(f):
128 break
128 break
129 else:
129 else:
130 return super(lfilesrepo, self).status(node1, node2,
130 return super(lfilesrepo, self).status(node1, node2,
131 match, listignored, listclean,
131 match, listignored, listclean,
132 listunknown, listsubrepos)
132 listunknown, listsubrepos)
133
133
134 # Create a copy of match that matches standins instead
134 # Create a copy of match that matches standins instead
135 # of largefiles.
135 # of largefiles.
136 def tostandins(files):
136 def tostandins(files):
137 if not working:
137 if not working:
138 return files
138 return files
139 newfiles = []
139 newfiles = []
140 dirstate = self.dirstate
140 dirstate = self.dirstate
141 for f in files:
141 for f in files:
142 sf = lfutil.standin(f)
142 sf = lfutil.standin(f)
143 if sf in dirstate:
143 if sf in dirstate:
144 newfiles.append(sf)
144 newfiles.append(sf)
145 elif sf in dirstate.dirs():
145 elif sf in dirstate.dirs():
146 # Directory entries could be regular or
146 # Directory entries could be regular or
147 # standin, check both
147 # standin, check both
148 newfiles.extend((f, sf))
148 newfiles.extend((f, sf))
149 else:
149 else:
150 newfiles.append(f)
150 newfiles.append(f)
151 return newfiles
151 return newfiles
152
152
153 m = copy.copy(match)
153 m = copy.copy(match)
154 m._files = tostandins(m._files)
154 m._files = tostandins(m._files)
155
155
156 result = super(lfilesrepo, self).status(node1, node2, m,
156 result = super(lfilesrepo, self).status(node1, node2, m,
157 ignored, clean, unknown, listsubrepos)
157 ignored, clean, unknown, listsubrepos)
158 if working:
158 if working:
159
159
160 def sfindirstate(f):
160 def sfindirstate(f):
161 sf = lfutil.standin(f)
161 sf = lfutil.standin(f)
162 dirstate = self.dirstate
162 dirstate = self.dirstate
163 return sf in dirstate or sf in dirstate.dirs()
163 return sf in dirstate or sf in dirstate.dirs()
164
164
165 match._files = [f for f in match._files
165 match._files = [f for f in match._files
166 if sfindirstate(f)]
166 if sfindirstate(f)]
167 # Don't waste time getting the ignored and unknown
167 # Don't waste time getting the ignored and unknown
168 # files from lfdirstate
168 # files from lfdirstate
169 s = lfdirstate.status(match, [], False,
169 s = lfdirstate.status(match, [], False,
170 listclean, False)
170 listclean, False)
171 (unsure, modified, added, removed, missing, _unknown,
171 (unsure, modified, added, removed, missing, _unknown,
172 _ignored, clean) = s
172 _ignored, clean) = s
173 if parentworking:
173 if parentworking:
174 for lfile in unsure:
174 for lfile in unsure:
175 standin = lfutil.standin(lfile)
175 standin = lfutil.standin(lfile)
176 if standin not in ctx1:
176 if standin not in ctx1:
177 # from second parent
177 # from second parent
178 modified.append(lfile)
178 modified.append(lfile)
179 elif ctx1[standin].data().strip() \
179 elif ctx1[standin].data().strip() \
180 != lfutil.hashfile(self.wjoin(lfile)):
180 != lfutil.hashfile(self.wjoin(lfile)):
181 modified.append(lfile)
181 modified.append(lfile)
182 else:
182 else:
183 clean.append(lfile)
183 clean.append(lfile)
184 lfdirstate.normal(lfile)
184 lfdirstate.normal(lfile)
185 else:
185 else:
186 tocheck = unsure + modified + added + clean
186 tocheck = unsure + modified + added + clean
187 modified, added, clean = [], [], []
187 modified, added, clean = [], [], []
188
188
189 for lfile in tocheck:
189 for lfile in tocheck:
190 standin = lfutil.standin(lfile)
190 standin = lfutil.standin(lfile)
191 if inctx(standin, ctx1):
191 if inctx(standin, ctx1):
192 if ctx1[standin].data().strip() != \
192 if ctx1[standin].data().strip() != \
193 lfutil.hashfile(self.wjoin(lfile)):
193 lfutil.hashfile(self.wjoin(lfile)):
194 modified.append(lfile)
194 modified.append(lfile)
195 else:
195 else:
196 clean.append(lfile)
196 clean.append(lfile)
197 else:
197 else:
198 added.append(lfile)
198 added.append(lfile)
199
199
200 # Standins no longer found in lfdirstate has been
200 # Standins no longer found in lfdirstate has been
201 # removed
201 # removed
202 for standin in ctx1.manifest():
202 for standin in ctx1.manifest():
203 if not lfutil.isstandin(standin):
203 if not lfutil.isstandin(standin):
204 continue
204 continue
205 lfile = lfutil.splitstandin(standin)
205 lfile = lfutil.splitstandin(standin)
206 if not match(lfile):
206 if not match(lfile):
207 continue
207 continue
208 if lfile not in lfdirstate:
208 if lfile not in lfdirstate:
209 removed.append(lfile)
209 removed.append(lfile)
210
210
211 # Filter result lists
211 # Filter result lists
212 result = list(result)
212 result = list(result)
213
213
214 # Largefiles are not really removed when they're
214 # Largefiles are not really removed when they're
215 # still in the normal dirstate. Likewise, normal
215 # still in the normal dirstate. Likewise, normal
216 # files are not really removed if they are still in
216 # files are not really removed if they are still in
217 # lfdirstate. This happens in merges where files
217 # lfdirstate. This happens in merges where files
218 # change type.
218 # change type.
219 removed = [f for f in removed
219 removed = [f for f in removed
220 if f not in self.dirstate]
220 if f not in self.dirstate]
221 result[2] = [f for f in result[2]
221 result[2] = [f for f in result[2]
222 if f not in lfdirstate]
222 if f not in lfdirstate]
223
223
224 lfiles = set(lfdirstate._map)
224 lfiles = set(lfdirstate._map)
225 # Unknown files
225 # Unknown files
226 result[4] = set(result[4]).difference(lfiles)
226 result[4] = set(result[4]).difference(lfiles)
227 # Ignored files
227 # Ignored files
228 result[5] = set(result[5]).difference(lfiles)
228 result[5] = set(result[5]).difference(lfiles)
229 # combine normal files and largefiles
229 # combine normal files and largefiles
230 normals = [[fn for fn in filelist
230 normals = [[fn for fn in filelist
231 if not lfutil.isstandin(fn)]
231 if not lfutil.isstandin(fn)]
232 for filelist in result]
232 for filelist in result]
233 lfiles = (modified, added, removed, missing, [], [],
233 lfiles = (modified, added, removed, missing, [], [],
234 clean)
234 clean)
235 result = [sorted(list1 + list2)
235 result = [sorted(list1 + list2)
236 for (list1, list2) in zip(normals, lfiles)]
236 for (list1, list2) in zip(normals, lfiles)]
237 else:
237 else:
238 def toname(f):
238 def toname(f):
239 if lfutil.isstandin(f):
239 if lfutil.isstandin(f):
240 return lfutil.splitstandin(f)
240 return lfutil.splitstandin(f)
241 return f
241 return f
242 result = [[toname(f) for f in items]
242 result = [[toname(f) for f in items]
243 for items in result]
243 for items in result]
244
244
245 if wlock:
245 if wlock:
246 lfdirstate.write()
246 lfdirstate.write()
247
247
248 finally:
248 finally:
249 if wlock:
249 if wlock:
250 wlock.release()
250 wlock.release()
251
251
252 if not listunknown:
252 if not listunknown:
253 result[4] = []
253 result[4] = []
254 if not listignored:
254 if not listignored:
255 result[5] = []
255 result[5] = []
256 if not listclean:
256 if not listclean:
257 result[6] = []
257 result[6] = []
258 self.lfstatus = True
258 self.lfstatus = True
259 return result
259 return result
260
260
261 # As part of committing, copy all of the largefiles into the
261 # As part of committing, copy all of the largefiles into the
262 # cache.
262 # cache.
263 def commitctx(self, *args, **kwargs):
263 def commitctx(self, *args, **kwargs):
264 node = super(lfilesrepo, self).commitctx(*args, **kwargs)
264 node = super(lfilesrepo, self).commitctx(*args, **kwargs)
265 lfutil.copyalltostore(self, node)
265 lfutil.copyalltostore(self, node)
266 return node
266 return node
267
267
268 # Before commit, largefile standins have not had their
268 # Before commit, largefile standins have not had their
269 # contents updated to reflect the hash of their largefile.
269 # contents updated to reflect the hash of their largefile.
270 # Do that here.
270 # Do that here.
271 def commit(self, text="", user=None, date=None, match=None,
271 def commit(self, text="", user=None, date=None, match=None,
272 force=False, editor=False, extra={}):
272 force=False, editor=False, extra={}):
273 orig = super(lfilesrepo, self).commit
273 orig = super(lfilesrepo, self).commit
274
274
275 wlock = self.wlock()
275 wlock = self.wlock()
276 try:
276 try:
277 # Case 0: Rebase or Transplant
277 # Case 0: Rebase or Transplant
278 # We have to take the time to pull down the new largefiles now.
278 # We have to take the time to pull down the new largefiles now.
279 # Otherwise, any largefiles that were modified in the
279 # Otherwise, any largefiles that were modified in the
280 # destination changesets get overwritten, either by the rebase
280 # destination changesets get overwritten, either by the rebase
281 # or in the first commit after the rebase or transplant.
281 # or in the first commit after the rebase or transplant.
282 # updatelfiles will update the dirstate to mark any pulled
282 # updatelfiles will update the dirstate to mark any pulled
283 # largefiles as modified
283 # largefiles as modified
284 if getattr(self, "_isrebasing", False) or \
284 if getattr(self, "_isrebasing", False) or \
285 getattr(self, "_istransplanting", False):
285 getattr(self, "_istransplanting", False):
286 lfcommands.updatelfiles(self.ui, self, filelist=None,
286 lfcommands.updatelfiles(self.ui, self, filelist=None,
287 printmessage=False)
287 printmessage=False)
288 result = orig(text=text, user=user, date=date, match=match,
288 result = orig(text=text, user=user, date=date, match=match,
289 force=force, editor=editor, extra=extra)
289 force=force, editor=editor, extra=extra)
290 return result
290 return result
291 # Case 1: user calls commit with no specific files or
291 # Case 1: user calls commit with no specific files or
292 # include/exclude patterns: refresh and commit all files that
292 # include/exclude patterns: refresh and commit all files that
293 # are "dirty".
293 # are "dirty".
294 if ((match is None) or
294 if ((match is None) or
295 (not match.anypats() and not match.files())):
295 (not match.anypats() and not match.files())):
296 # Spend a bit of time here to get a list of files we know
296 # Spend a bit of time here to get a list of files we know
297 # are modified so we can compare only against those.
297 # are modified so we can compare only against those.
298 # It can cost a lot of time (several seconds)
298 # It can cost a lot of time (several seconds)
299 # otherwise to update all standins if the largefiles are
299 # otherwise to update all standins if the largefiles are
300 # large.
300 # large.
301 lfdirstate = lfutil.openlfdirstate(ui, self)
301 lfdirstate = lfutil.openlfdirstate(ui, self)
302 dirtymatch = match_.always(self.root, self.getcwd())
302 dirtymatch = match_.always(self.root, self.getcwd())
303 s = lfdirstate.status(dirtymatch, [], False, False, False)
303 s = lfdirstate.status(dirtymatch, [], False, False, False)
304 (unsure, modified, added, removed, _missing, _unknown,
304 (unsure, modified, added, removed, _missing, _unknown,
305 _ignored, _clean) = s
305 _ignored, _clean) = s
306 modifiedfiles = unsure + modified + added + removed
306 modifiedfiles = unsure + modified + added + removed
307 lfiles = lfutil.listlfiles(self)
307 lfiles = lfutil.listlfiles(self)
308 # this only loops through largefiles that exist (not
308 # this only loops through largefiles that exist (not
309 # removed/renamed)
309 # removed/renamed)
310 for lfile in lfiles:
310 for lfile in lfiles:
311 if lfile in modifiedfiles:
311 if lfile in modifiedfiles:
312 if os.path.exists(
312 if os.path.exists(
313 self.wjoin(lfutil.standin(lfile))):
313 self.wjoin(lfutil.standin(lfile))):
314 # this handles the case where a rebase is being
314 # this handles the case where a rebase is being
315 # performed and the working copy is not updated
315 # performed and the working copy is not updated
316 # yet.
316 # yet.
317 if os.path.exists(self.wjoin(lfile)):
317 if os.path.exists(self.wjoin(lfile)):
318 lfutil.updatestandin(self,
318 lfutil.updatestandin(self,
319 lfutil.standin(lfile))
319 lfutil.standin(lfile))
320 lfdirstate.normal(lfile)
320 lfdirstate.normal(lfile)
321
321
322 result = orig(text=text, user=user, date=date, match=match,
322 result = orig(text=text, user=user, date=date, match=match,
323 force=force, editor=editor, extra=extra)
323 force=force, editor=editor, extra=extra)
324
324
325 if result is not None:
325 if result is not None:
326 for lfile in lfdirstate:
326 for lfile in lfdirstate:
327 if lfile in modifiedfiles:
327 if lfile in modifiedfiles:
328 if (not os.path.exists(self.wjoin(
328 if (not os.path.exists(self.wjoin(
329 lfutil.standin(lfile)))) or \
329 lfutil.standin(lfile)))) or \
330 (not os.path.exists(self.wjoin(lfile))):
330 (not os.path.exists(self.wjoin(lfile))):
331 lfdirstate.drop(lfile)
331 lfdirstate.drop(lfile)
332
332
333 # This needs to be after commit; otherwise precommit hooks
333 # This needs to be after commit; otherwise precommit hooks
334 # get the wrong status
334 # get the wrong status
335 lfdirstate.write()
335 lfdirstate.write()
336 return result
336 return result
337
337
338 lfiles = lfutil.listlfiles(self)
338 lfiles = lfutil.listlfiles(self)
339 match._files = self._subdirlfs(match.files(), lfiles)
339 match._files = self._subdirlfs(match.files(), lfiles)
340
340
341 # Case 2: user calls commit with specified patterns: refresh
341 # Case 2: user calls commit with specified patterns: refresh
342 # any matching big files.
342 # any matching big files.
343 smatcher = lfutil.composestandinmatcher(self, match)
343 smatcher = lfutil.composestandinmatcher(self, match)
344 standins = self.dirstate.walk(smatcher, [], False, False)
344 standins = self.dirstate.walk(smatcher, [], False, False)
345
345
346 # No matching big files: get out of the way and pass control to
346 # No matching big files: get out of the way and pass control to
347 # the usual commit() method.
347 # the usual commit() method.
348 if not standins:
348 if not standins:
349 return orig(text=text, user=user, date=date, match=match,
349 return orig(text=text, user=user, date=date, match=match,
350 force=force, editor=editor, extra=extra)
350 force=force, editor=editor, extra=extra)
351
351
352 # Refresh all matching big files. It's possible that the
352 # Refresh all matching big files. It's possible that the
353 # commit will end up failing, in which case the big files will
353 # commit will end up failing, in which case the big files will
354 # stay refreshed. No harm done: the user modified them and
354 # stay refreshed. No harm done: the user modified them and
355 # asked to commit them, so sooner or later we're going to
355 # asked to commit them, so sooner or later we're going to
356 # refresh the standins. Might as well leave them refreshed.
356 # refresh the standins. Might as well leave them refreshed.
357 lfdirstate = lfutil.openlfdirstate(ui, self)
357 lfdirstate = lfutil.openlfdirstate(ui, self)
358 for standin in standins:
358 for standin in standins:
359 lfile = lfutil.splitstandin(standin)
359 lfile = lfutil.splitstandin(standin)
360 if lfdirstate[lfile] != 'r':
360 if lfdirstate[lfile] != 'r':
361 lfutil.updatestandin(self, standin)
361 lfutil.updatestandin(self, standin)
362 lfdirstate.normal(lfile)
362 lfdirstate.normal(lfile)
363 else:
363 else:
364 lfdirstate.drop(lfile)
364 lfdirstate.drop(lfile)
365
365
366 # Cook up a new matcher that only matches regular files or
366 # Cook up a new matcher that only matches regular files or
367 # standins corresponding to the big files requested by the
367 # standins corresponding to the big files requested by the
368 # user. Have to modify _files to prevent commit() from
368 # user. Have to modify _files to prevent commit() from
369 # complaining "not tracked" for big files.
369 # complaining "not tracked" for big files.
370 match = copy.copy(match)
370 match = copy.copy(match)
371 origmatchfn = match.matchfn
371 origmatchfn = match.matchfn
372
372
373 # Check both the list of largefiles and the list of
373 # Check both the list of largefiles and the list of
374 # standins because if a largefile was removed, it
374 # standins because if a largefile was removed, it
375 # won't be in the list of largefiles at this point
375 # won't be in the list of largefiles at this point
376 match._files += sorted(standins)
376 match._files += sorted(standins)
377
377
378 actualfiles = []
378 actualfiles = []
379 for f in match._files:
379 for f in match._files:
380 fstandin = lfutil.standin(f)
380 fstandin = lfutil.standin(f)
381
381
382 # ignore known largefiles and standins
382 # ignore known largefiles and standins
383 if f in lfiles or fstandin in standins:
383 if f in lfiles or fstandin in standins:
384 continue
384 continue
385
385
386 # append directory separator to avoid collisions
386 # append directory separator to avoid collisions
387 if not fstandin.endswith(os.sep):
387 if not fstandin.endswith(os.sep):
388 fstandin += os.sep
388 fstandin += os.sep
389
389
390 actualfiles.append(f)
390 actualfiles.append(f)
391 match._files = actualfiles
391 match._files = actualfiles
392
392
393 def matchfn(f):
393 def matchfn(f):
394 if origmatchfn(f):
394 if origmatchfn(f):
395 return f not in lfiles
395 return f not in lfiles
396 else:
396 else:
397 return f in standins
397 return f in standins
398
398
399 match.matchfn = matchfn
399 match.matchfn = matchfn
400 result = orig(text=text, user=user, date=date, match=match,
400 result = orig(text=text, user=user, date=date, match=match,
401 force=force, editor=editor, extra=extra)
401 force=force, editor=editor, extra=extra)
402 # This needs to be after commit; otherwise precommit hooks
402 # This needs to be after commit; otherwise precommit hooks
403 # get the wrong status
403 # get the wrong status
404 lfdirstate.write()
404 lfdirstate.write()
405 return result
405 return result
406 finally:
406 finally:
407 wlock.release()
407 wlock.release()
408
408
409 def push(self, remote, force=False, revs=None, newbranch=False):
409 def push(self, remote, force=False, revs=None, newbranch=False):
410 if remote.local():
410 if remote.local():
411 missing = set(self.requirements) - remote.local().supported
411 missing = set(self.requirements) - remote.local().supported
412 if missing:
412 if missing:
413 msg = _("required features are not"
413 msg = _("required features are not"
414 " supported in the destination:"
414 " supported in the destination:"
415 " %s") % (', '.join(sorted(missing)))
415 " %s") % (', '.join(sorted(missing)))
416 raise util.Abort(msg)
416 raise util.Abort(msg)
417
417
418 outgoing = discovery.findcommonoutgoing(repo, remote.peer(),
418 outgoing = discovery.findcommonoutgoing(repo, remote.peer(),
419 force=force)
419 force=force)
420 if outgoing.missing:
420 if outgoing.missing:
421 toupload = set()
421 toupload = set()
422 o = self.changelog.nodesbetween(outgoing.missing, revs)[0]
422 o = self.changelog.nodesbetween(outgoing.missing, revs)[0]
423 for n in o:
423 for n in o:
424 parents = [p for p in self.changelog.parents(n)
424 parents = [p for p in self.changelog.parents(n)
425 if p != node_.nullid]
425 if p != node_.nullid]
426 ctx = self[n]
426 ctx = self[n]
427 files = set(ctx.files())
427 files = set(ctx.files())
428 if len(parents) == 2:
428 if len(parents) == 2:
429 mc = ctx.manifest()
429 mc = ctx.manifest()
430 mp1 = ctx.parents()[0].manifest()
430 mp1 = ctx.parents()[0].manifest()
431 mp2 = ctx.parents()[1].manifest()
431 mp2 = ctx.parents()[1].manifest()
432 for f in mp1:
432 for f in mp1:
433 if f not in mc:
433 if f not in mc:
434 files.add(f)
434 files.add(f)
435 for f in mp2:
435 for f in mp2:
436 if f not in mc:
436 if f not in mc:
437 files.add(f)
437 files.add(f)
438 for f in mc:
438 for f in mc:
439 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f,
439 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f,
440 None):
440 None):
441 files.add(f)
441 files.add(f)
442
442
443 toupload = toupload.union(
443 toupload = toupload.union(
444 set([ctx[f].data().strip()
444 set([ctx[f].data().strip()
445 for f in files
445 for f in files
446 if lfutil.isstandin(f) and f in ctx]))
446 if lfutil.isstandin(f) and f in ctx]))
447 lfcommands.uploadlfiles(ui, self, remote, toupload)
447 lfcommands.uploadlfiles(ui, self, remote, toupload)
448 return super(lfilesrepo, self).push(remote, force, revs,
448 return super(lfilesrepo, self).push(remote, force=force, revs=revs,
449 newbranch)
449 newbranch=newbranch)
450
450
451 def _subdirlfs(self, files, lfiles):
451 def _subdirlfs(self, files, lfiles):
452 '''
452 '''
453 Adjust matched file list
453 Adjust matched file list
454 If we pass a directory to commit whose only commitable files
454 If we pass a directory to commit whose only commitable files
455 are largefiles, the core commit code aborts before finding
455 are largefiles, the core commit code aborts before finding
456 the largefiles.
456 the largefiles.
457 So we do the following:
457 So we do the following:
458 For directories that only have largefiles as matches,
458 For directories that only have largefiles as matches,
459 we explicitly add the largefiles to the match list and remove
459 we explicitly add the largefiles to the match list and remove
460 the directory.
460 the directory.
461 In other cases, we leave the match list unmodified.
461 In other cases, we leave the match list unmodified.
462 '''
462 '''
463 actualfiles = []
463 actualfiles = []
464 dirs = []
464 dirs = []
465 regulars = []
465 regulars = []
466
466
467 for f in files:
467 for f in files:
468 if lfutil.isstandin(f + '/'):
468 if lfutil.isstandin(f + '/'):
469 raise util.Abort(
469 raise util.Abort(
470 _('file "%s" is a largefile standin') % f,
470 _('file "%s" is a largefile standin') % f,
471 hint=('commit the largefile itself instead'))
471 hint=('commit the largefile itself instead'))
472 # Scan directories
472 # Scan directories
473 if os.path.isdir(self.wjoin(f)):
473 if os.path.isdir(self.wjoin(f)):
474 dirs.append(f)
474 dirs.append(f)
475 else:
475 else:
476 regulars.append(f)
476 regulars.append(f)
477
477
478 for f in dirs:
478 for f in dirs:
479 matcheddir = False
479 matcheddir = False
480 d = self.dirstate.normalize(f) + '/'
480 d = self.dirstate.normalize(f) + '/'
481 # Check for matched normal files
481 # Check for matched normal files
482 for mf in regulars:
482 for mf in regulars:
483 if self.dirstate.normalize(mf).startswith(d):
483 if self.dirstate.normalize(mf).startswith(d):
484 actualfiles.append(f)
484 actualfiles.append(f)
485 matcheddir = True
485 matcheddir = True
486 break
486 break
487 if not matcheddir:
487 if not matcheddir:
488 # If no normal match, manually append
488 # If no normal match, manually append
489 # any matching largefiles
489 # any matching largefiles
490 for lf in lfiles:
490 for lf in lfiles:
491 if self.dirstate.normalize(lf).startswith(d):
491 if self.dirstate.normalize(lf).startswith(d):
492 actualfiles.append(lf)
492 actualfiles.append(lf)
493 if not matcheddir:
493 if not matcheddir:
494 actualfiles.append(lfutil.standin(f))
494 actualfiles.append(lfutil.standin(f))
495 matcheddir = True
495 matcheddir = True
496 # Nothing in dir, so readd it
496 # Nothing in dir, so readd it
497 # and let commit reject it
497 # and let commit reject it
498 if not matcheddir:
498 if not matcheddir:
499 actualfiles.append(f)
499 actualfiles.append(f)
500
500
501 # Always add normal files
501 # Always add normal files
502 actualfiles += regulars
502 actualfiles += regulars
503 return actualfiles
503 return actualfiles
504
504
505 repo.__class__ = lfilesrepo
505 repo.__class__ = lfilesrepo
506
506
507 def checkrequireslfiles(ui, repo, **kwargs):
507 def checkrequireslfiles(ui, repo, **kwargs):
508 if 'largefiles' not in repo.requirements and util.any(
508 if 'largefiles' not in repo.requirements and util.any(
509 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
509 lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
510 repo.requirements.add('largefiles')
510 repo.requirements.add('largefiles')
511 repo._writerequirements()
511 repo._writerequirements()
512
512
513 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles)
513 ui.setconfig('hooks', 'changegroup.lfiles', checkrequireslfiles)
514 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles)
514 ui.setconfig('hooks', 'commit.lfiles', checkrequireslfiles)
General Comments 0
You need to be logged in to leave comments. Login now