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