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