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