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