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