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