##// END OF EJS Templates
largefiles: take lock before writing requirements...
marmoute -
r49510:497c2655 default
parent child Browse files
Show More
@@ -1,467 +1,468 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 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 import copy
12 import copy
13
13
14 from mercurial.i18n import _
14 from mercurial.i18n import _
15
15
16 from mercurial import (
16 from mercurial import (
17 error,
17 error,
18 extensions,
18 extensions,
19 localrepo,
19 localrepo,
20 match as matchmod,
20 match as matchmod,
21 scmutil,
21 scmutil,
22 util,
22 util,
23 )
23 )
24
24
25 from mercurial.dirstateutils import timestamp
25 from mercurial.dirstateutils import timestamp
26
26
27 from . import (
27 from . import (
28 lfcommands,
28 lfcommands,
29 lfutil,
29 lfutil,
30 )
30 )
31
31
32
32
33 def reposetup(ui, repo):
33 def reposetup(ui, repo):
34 # wire repositories should be given new wireproto functions
34 # wire repositories should be given new wireproto functions
35 # by "proto.wirereposetup()" via "hg.wirepeersetupfuncs"
35 # by "proto.wirereposetup()" via "hg.wirepeersetupfuncs"
36 if not repo.local():
36 if not repo.local():
37 return
37 return
38
38
39 class lfilesrepo(repo.__class__):
39 class lfilesrepo(repo.__class__):
40 # the mark to examine whether "repo" object enables largefiles or not
40 # the mark to examine whether "repo" object enables largefiles or not
41 _largefilesenabled = True
41 _largefilesenabled = True
42
42
43 lfstatus = False
43 lfstatus = False
44
44
45 # When lfstatus is set, return a context that gives the names
45 # When lfstatus is set, return a context that gives the names
46 # of largefiles instead of their corresponding standins and
46 # of largefiles instead of their corresponding standins and
47 # identifies the largefiles as always binary, regardless of
47 # identifies the largefiles as always binary, regardless of
48 # their actual contents.
48 # their actual contents.
49 def __getitem__(self, changeid):
49 def __getitem__(self, changeid):
50 ctx = super(lfilesrepo, self).__getitem__(changeid)
50 ctx = super(lfilesrepo, self).__getitem__(changeid)
51 if self.lfstatus:
51 if self.lfstatus:
52
52
53 def files(orig):
53 def files(orig):
54 filenames = orig()
54 filenames = orig()
55 return [lfutil.splitstandin(f) or f for f in filenames]
55 return [lfutil.splitstandin(f) or f for f in filenames]
56
56
57 extensions.wrapfunction(ctx, 'files', files)
57 extensions.wrapfunction(ctx, 'files', files)
58
58
59 def manifest(orig):
59 def manifest(orig):
60 man1 = orig()
60 man1 = orig()
61
61
62 class lfilesmanifest(man1.__class__):
62 class lfilesmanifest(man1.__class__):
63 def __contains__(self, filename):
63 def __contains__(self, filename):
64 orig = super(lfilesmanifest, self).__contains__
64 orig = super(lfilesmanifest, self).__contains__
65 return orig(filename) or orig(
65 return orig(filename) or orig(
66 lfutil.standin(filename)
66 lfutil.standin(filename)
67 )
67 )
68
68
69 man1.__class__ = lfilesmanifest
69 man1.__class__ = lfilesmanifest
70 return man1
70 return man1
71
71
72 extensions.wrapfunction(ctx, 'manifest', manifest)
72 extensions.wrapfunction(ctx, 'manifest', manifest)
73
73
74 def filectx(orig, path, fileid=None, filelog=None):
74 def filectx(orig, path, fileid=None, filelog=None):
75 try:
75 try:
76 if filelog is not None:
76 if filelog is not None:
77 result = orig(path, fileid, filelog)
77 result = orig(path, fileid, filelog)
78 else:
78 else:
79 result = orig(path, fileid)
79 result = orig(path, fileid)
80 except error.LookupError:
80 except error.LookupError:
81 # Adding a null character will cause Mercurial to
81 # Adding a null character will cause Mercurial to
82 # identify this as a binary file.
82 # identify this as a binary file.
83 if filelog is not None:
83 if filelog is not None:
84 result = orig(lfutil.standin(path), fileid, filelog)
84 result = orig(lfutil.standin(path), fileid, filelog)
85 else:
85 else:
86 result = orig(lfutil.standin(path), fileid)
86 result = orig(lfutil.standin(path), fileid)
87 olddata = result.data
87 olddata = result.data
88 result.data = lambda: olddata() + b'\0'
88 result.data = lambda: olddata() + b'\0'
89 return result
89 return result
90
90
91 extensions.wrapfunction(ctx, 'filectx', filectx)
91 extensions.wrapfunction(ctx, 'filectx', filectx)
92
92
93 return ctx
93 return ctx
94
94
95 # Figure out the status of big files and insert them into the
95 # Figure out the status of big files and insert them into the
96 # appropriate list in the result. Also removes standin files
96 # appropriate list in the result. Also removes standin files
97 # from the listing. Revert to the original status if
97 # from the listing. Revert to the original status if
98 # self.lfstatus is False.
98 # self.lfstatus is False.
99 # XXX large file status is buggy when used on repo proxy.
99 # XXX large file status is buggy when used on repo proxy.
100 # XXX this needs to be investigated.
100 # XXX this needs to be investigated.
101 @localrepo.unfilteredmethod
101 @localrepo.unfilteredmethod
102 def status(
102 def status(
103 self,
103 self,
104 node1=b'.',
104 node1=b'.',
105 node2=None,
105 node2=None,
106 match=None,
106 match=None,
107 ignored=False,
107 ignored=False,
108 clean=False,
108 clean=False,
109 unknown=False,
109 unknown=False,
110 listsubrepos=False,
110 listsubrepos=False,
111 ):
111 ):
112 listignored, listclean, listunknown = ignored, clean, unknown
112 listignored, listclean, listunknown = ignored, clean, unknown
113 orig = super(lfilesrepo, self).status
113 orig = super(lfilesrepo, self).status
114 if not self.lfstatus:
114 if not self.lfstatus:
115 return orig(
115 return orig(
116 node1,
116 node1,
117 node2,
117 node2,
118 match,
118 match,
119 listignored,
119 listignored,
120 listclean,
120 listclean,
121 listunknown,
121 listunknown,
122 listsubrepos,
122 listsubrepos,
123 )
123 )
124
124
125 # some calls in this function rely on the old version of status
125 # some calls in this function rely on the old version of status
126 self.lfstatus = False
126 self.lfstatus = False
127 ctx1 = self[node1]
127 ctx1 = self[node1]
128 ctx2 = self[node2]
128 ctx2 = self[node2]
129 working = ctx2.rev() is None
129 working = ctx2.rev() is None
130 parentworking = working and ctx1 == self[b'.']
130 parentworking = working and ctx1 == self[b'.']
131
131
132 if match is None:
132 if match is None:
133 match = matchmod.always()
133 match = matchmod.always()
134
134
135 try:
135 try:
136 # updating the dirstate is optional
136 # updating the dirstate is optional
137 # so we don't wait on the lock
137 # so we don't wait on the lock
138 wlock = self.wlock(False)
138 wlock = self.wlock(False)
139 gotlock = True
139 gotlock = True
140 except error.LockError:
140 except error.LockError:
141 wlock = util.nullcontextmanager()
141 wlock = util.nullcontextmanager()
142 gotlock = False
142 gotlock = False
143 with wlock:
143 with wlock:
144
144
145 # First check if paths or patterns were specified on the
145 # First check if paths or patterns were specified on the
146 # command line. If there were, and they don't match any
146 # command line. If there were, and they don't match any
147 # largefiles, we should just bail here and let super
147 # largefiles, we should just bail here and let super
148 # handle it -- thus gaining a big performance boost.
148 # handle it -- thus gaining a big performance boost.
149 lfdirstate = lfutil.openlfdirstate(ui, self)
149 lfdirstate = lfutil.openlfdirstate(ui, self)
150 if not match.always():
150 if not match.always():
151 for f in lfdirstate:
151 for f in lfdirstate:
152 if match(f):
152 if match(f):
153 break
153 break
154 else:
154 else:
155 return orig(
155 return orig(
156 node1,
156 node1,
157 node2,
157 node2,
158 match,
158 match,
159 listignored,
159 listignored,
160 listclean,
160 listclean,
161 listunknown,
161 listunknown,
162 listsubrepos,
162 listsubrepos,
163 )
163 )
164
164
165 # Create a copy of match that matches standins instead
165 # Create a copy of match that matches standins instead
166 # of largefiles.
166 # of largefiles.
167 def tostandins(files):
167 def tostandins(files):
168 if not working:
168 if not working:
169 return files
169 return files
170 newfiles = []
170 newfiles = []
171 dirstate = self.dirstate
171 dirstate = self.dirstate
172 for f in files:
172 for f in files:
173 sf = lfutil.standin(f)
173 sf = lfutil.standin(f)
174 if sf in dirstate:
174 if sf in dirstate:
175 newfiles.append(sf)
175 newfiles.append(sf)
176 elif dirstate.hasdir(sf):
176 elif dirstate.hasdir(sf):
177 # Directory entries could be regular or
177 # Directory entries could be regular or
178 # standin, check both
178 # standin, check both
179 newfiles.extend((f, sf))
179 newfiles.extend((f, sf))
180 else:
180 else:
181 newfiles.append(f)
181 newfiles.append(f)
182 return newfiles
182 return newfiles
183
183
184 m = copy.copy(match)
184 m = copy.copy(match)
185 m._files = tostandins(m._files)
185 m._files = tostandins(m._files)
186
186
187 result = orig(
187 result = orig(
188 node1, node2, m, ignored, clean, unknown, listsubrepos
188 node1, node2, m, ignored, clean, unknown, listsubrepos
189 )
189 )
190 if working:
190 if working:
191
191
192 def sfindirstate(f):
192 def sfindirstate(f):
193 sf = lfutil.standin(f)
193 sf = lfutil.standin(f)
194 dirstate = self.dirstate
194 dirstate = self.dirstate
195 return sf in dirstate or dirstate.hasdir(sf)
195 return sf in dirstate or dirstate.hasdir(sf)
196
196
197 match._files = [f for f in match._files if sfindirstate(f)]
197 match._files = [f for f in match._files if sfindirstate(f)]
198 # Don't waste time getting the ignored and unknown
198 # Don't waste time getting the ignored and unknown
199 # files from lfdirstate
199 # files from lfdirstate
200 unsure, s, mtime_boundary = lfdirstate.status(
200 unsure, s, mtime_boundary = lfdirstate.status(
201 match,
201 match,
202 subrepos=[],
202 subrepos=[],
203 ignored=False,
203 ignored=False,
204 clean=listclean,
204 clean=listclean,
205 unknown=False,
205 unknown=False,
206 )
206 )
207 (modified, added, removed, deleted, clean) = (
207 (modified, added, removed, deleted, clean) = (
208 s.modified,
208 s.modified,
209 s.added,
209 s.added,
210 s.removed,
210 s.removed,
211 s.deleted,
211 s.deleted,
212 s.clean,
212 s.clean,
213 )
213 )
214 if parentworking:
214 if parentworking:
215 wctx = repo[None]
215 wctx = repo[None]
216 for lfile in unsure:
216 for lfile in unsure:
217 standin = lfutil.standin(lfile)
217 standin = lfutil.standin(lfile)
218 if standin not in ctx1:
218 if standin not in ctx1:
219 # from second parent
219 # from second parent
220 modified.append(lfile)
220 modified.append(lfile)
221 elif lfutil.readasstandin(
221 elif lfutil.readasstandin(
222 ctx1[standin]
222 ctx1[standin]
223 ) != lfutil.hashfile(self.wjoin(lfile)):
223 ) != lfutil.hashfile(self.wjoin(lfile)):
224 modified.append(lfile)
224 modified.append(lfile)
225 else:
225 else:
226 if listclean:
226 if listclean:
227 clean.append(lfile)
227 clean.append(lfile)
228 s = wctx[lfile].lstat()
228 s = wctx[lfile].lstat()
229 mode = s.st_mode
229 mode = s.st_mode
230 size = s.st_size
230 size = s.st_size
231 mtime = timestamp.reliable_mtime_of(
231 mtime = timestamp.reliable_mtime_of(
232 s, mtime_boundary
232 s, mtime_boundary
233 )
233 )
234 if mtime is not None:
234 if mtime is not None:
235 cache_data = (mode, size, mtime)
235 cache_data = (mode, size, mtime)
236 lfdirstate.set_clean(lfile, cache_data)
236 lfdirstate.set_clean(lfile, cache_data)
237 else:
237 else:
238 tocheck = unsure + modified + added + clean
238 tocheck = unsure + modified + added + clean
239 modified, added, clean = [], [], []
239 modified, added, clean = [], [], []
240 checkexec = self.dirstate._checkexec
240 checkexec = self.dirstate._checkexec
241
241
242 for lfile in tocheck:
242 for lfile in tocheck:
243 standin = lfutil.standin(lfile)
243 standin = lfutil.standin(lfile)
244 if standin in ctx1:
244 if standin in ctx1:
245 abslfile = self.wjoin(lfile)
245 abslfile = self.wjoin(lfile)
246 if (
246 if (
247 lfutil.readasstandin(ctx1[standin])
247 lfutil.readasstandin(ctx1[standin])
248 != lfutil.hashfile(abslfile)
248 != lfutil.hashfile(abslfile)
249 ) or (
249 ) or (
250 checkexec
250 checkexec
251 and (b'x' in ctx1.flags(standin))
251 and (b'x' in ctx1.flags(standin))
252 != bool(lfutil.getexecutable(abslfile))
252 != bool(lfutil.getexecutable(abslfile))
253 ):
253 ):
254 modified.append(lfile)
254 modified.append(lfile)
255 elif listclean:
255 elif listclean:
256 clean.append(lfile)
256 clean.append(lfile)
257 else:
257 else:
258 added.append(lfile)
258 added.append(lfile)
259
259
260 # at this point, 'removed' contains largefiles
260 # at this point, 'removed' contains largefiles
261 # marked as 'R' in the working context.
261 # marked as 'R' in the working context.
262 # then, largefiles not managed also in the target
262 # then, largefiles not managed also in the target
263 # context should be excluded from 'removed'.
263 # context should be excluded from 'removed'.
264 removed = [
264 removed = [
265 lfile
265 lfile
266 for lfile in removed
266 for lfile in removed
267 if lfutil.standin(lfile) in ctx1
267 if lfutil.standin(lfile) in ctx1
268 ]
268 ]
269
269
270 # Standins no longer found in lfdirstate have been deleted
270 # Standins no longer found in lfdirstate have been deleted
271 for standin in ctx1.walk(lfutil.getstandinmatcher(self)):
271 for standin in ctx1.walk(lfutil.getstandinmatcher(self)):
272 lfile = lfutil.splitstandin(standin)
272 lfile = lfutil.splitstandin(standin)
273 if not match(lfile):
273 if not match(lfile):
274 continue
274 continue
275 if lfile not in lfdirstate:
275 if lfile not in lfdirstate:
276 deleted.append(lfile)
276 deleted.append(lfile)
277 # Sync "largefile has been removed" back to the
277 # Sync "largefile has been removed" back to the
278 # standin. Removing a file as a side effect of
278 # standin. Removing a file as a side effect of
279 # running status is gross, but the alternatives (if
279 # running status is gross, but the alternatives (if
280 # any) are worse.
280 # any) are worse.
281 self.wvfs.unlinkpath(standin, ignoremissing=True)
281 self.wvfs.unlinkpath(standin, ignoremissing=True)
282
282
283 # Filter result lists
283 # Filter result lists
284 result = list(result)
284 result = list(result)
285
285
286 # Largefiles are not really removed when they're
286 # Largefiles are not really removed when they're
287 # still in the normal dirstate. Likewise, normal
287 # still in the normal dirstate. Likewise, normal
288 # files are not really removed if they are still in
288 # files are not really removed if they are still in
289 # lfdirstate. This happens in merges where files
289 # lfdirstate. This happens in merges where files
290 # change type.
290 # change type.
291 removed = [f for f in removed if f not in self.dirstate]
291 removed = [f for f in removed if f not in self.dirstate]
292 result[2] = [f for f in result[2] if f not in lfdirstate]
292 result[2] = [f for f in result[2] if f not in lfdirstate]
293
293
294 lfiles = set(lfdirstate)
294 lfiles = set(lfdirstate)
295 # Unknown files
295 # Unknown files
296 result[4] = set(result[4]).difference(lfiles)
296 result[4] = set(result[4]).difference(lfiles)
297 # Ignored files
297 # Ignored files
298 result[5] = set(result[5]).difference(lfiles)
298 result[5] = set(result[5]).difference(lfiles)
299 # combine normal files and largefiles
299 # combine normal files and largefiles
300 normals = [
300 normals = [
301 [fn for fn in filelist if not lfutil.isstandin(fn)]
301 [fn for fn in filelist if not lfutil.isstandin(fn)]
302 for filelist in result
302 for filelist in result
303 ]
303 ]
304 lfstatus = (
304 lfstatus = (
305 modified,
305 modified,
306 added,
306 added,
307 removed,
307 removed,
308 deleted,
308 deleted,
309 [],
309 [],
310 [],
310 [],
311 clean,
311 clean,
312 )
312 )
313 result = [
313 result = [
314 sorted(list1 + list2)
314 sorted(list1 + list2)
315 for (list1, list2) in zip(normals, lfstatus)
315 for (list1, list2) in zip(normals, lfstatus)
316 ]
316 ]
317 else: # not against working directory
317 else: # not against working directory
318 result = [
318 result = [
319 [lfutil.splitstandin(f) or f for f in items]
319 [lfutil.splitstandin(f) or f for f in items]
320 for items in result
320 for items in result
321 ]
321 ]
322
322
323 if gotlock:
323 if gotlock:
324 lfdirstate.write(self.currenttransaction())
324 lfdirstate.write(self.currenttransaction())
325
325
326 self.lfstatus = True
326 self.lfstatus = True
327 return scmutil.status(*result)
327 return scmutil.status(*result)
328
328
329 def commitctx(self, ctx, *args, **kwargs):
329 def commitctx(self, ctx, *args, **kwargs):
330 node = super(lfilesrepo, self).commitctx(ctx, *args, **kwargs)
330 node = super(lfilesrepo, self).commitctx(ctx, *args, **kwargs)
331
331
332 class lfilesctx(ctx.__class__):
332 class lfilesctx(ctx.__class__):
333 def markcommitted(self, node):
333 def markcommitted(self, node):
334 orig = super(lfilesctx, self).markcommitted
334 orig = super(lfilesctx, self).markcommitted
335 return lfutil.markcommitted(orig, self, node)
335 return lfutil.markcommitted(orig, self, node)
336
336
337 ctx.__class__ = lfilesctx
337 ctx.__class__ = lfilesctx
338 return node
338 return node
339
339
340 # Before commit, largefile standins have not had their
340 # Before commit, largefile standins have not had their
341 # contents updated to reflect the hash of their largefile.
341 # contents updated to reflect the hash of their largefile.
342 # Do that here.
342 # Do that here.
343 def commit(
343 def commit(
344 self,
344 self,
345 text=b"",
345 text=b"",
346 user=None,
346 user=None,
347 date=None,
347 date=None,
348 match=None,
348 match=None,
349 force=False,
349 force=False,
350 editor=False,
350 editor=False,
351 extra=None,
351 extra=None,
352 ):
352 ):
353 if extra is None:
353 if extra is None:
354 extra = {}
354 extra = {}
355 orig = super(lfilesrepo, self).commit
355 orig = super(lfilesrepo, self).commit
356
356
357 with self.wlock():
357 with self.wlock():
358 lfcommithook = self._lfcommithooks[-1]
358 lfcommithook = self._lfcommithooks[-1]
359 match = lfcommithook(self, match)
359 match = lfcommithook(self, match)
360 result = orig(
360 result = orig(
361 text=text,
361 text=text,
362 user=user,
362 user=user,
363 date=date,
363 date=date,
364 match=match,
364 match=match,
365 force=force,
365 force=force,
366 editor=editor,
366 editor=editor,
367 extra=extra,
367 extra=extra,
368 )
368 )
369 return result
369 return result
370
370
371 # TODO: _subdirlfs should be moved into "lfutil.py", because
371 # TODO: _subdirlfs should be moved into "lfutil.py", because
372 # it is referred only from "lfutil.updatestandinsbymatch"
372 # it is referred only from "lfutil.updatestandinsbymatch"
373 def _subdirlfs(self, files, lfiles):
373 def _subdirlfs(self, files, lfiles):
374 """
374 """
375 Adjust matched file list
375 Adjust matched file list
376 If we pass a directory to commit whose only committable files
376 If we pass a directory to commit whose only committable files
377 are largefiles, the core commit code aborts before finding
377 are largefiles, the core commit code aborts before finding
378 the largefiles.
378 the largefiles.
379 So we do the following:
379 So we do the following:
380 For directories that only have largefiles as matches,
380 For directories that only have largefiles as matches,
381 we explicitly add the largefiles to the match list and remove
381 we explicitly add the largefiles to the match list and remove
382 the directory.
382 the directory.
383 In other cases, we leave the match list unmodified.
383 In other cases, we leave the match list unmodified.
384 """
384 """
385 actualfiles = []
385 actualfiles = []
386 dirs = []
386 dirs = []
387 regulars = []
387 regulars = []
388
388
389 for f in files:
389 for f in files:
390 if lfutil.isstandin(f + b'/'):
390 if lfutil.isstandin(f + b'/'):
391 raise error.Abort(
391 raise error.Abort(
392 _(b'file "%s" is a largefile standin') % f,
392 _(b'file "%s" is a largefile standin') % f,
393 hint=b'commit the largefile itself instead',
393 hint=b'commit the largefile itself instead',
394 )
394 )
395 # Scan directories
395 # Scan directories
396 if self.wvfs.isdir(f):
396 if self.wvfs.isdir(f):
397 dirs.append(f)
397 dirs.append(f)
398 else:
398 else:
399 regulars.append(f)
399 regulars.append(f)
400
400
401 for f in dirs:
401 for f in dirs:
402 matcheddir = False
402 matcheddir = False
403 d = self.dirstate.normalize(f) + b'/'
403 d = self.dirstate.normalize(f) + b'/'
404 # Check for matched normal files
404 # Check for matched normal files
405 for mf in regulars:
405 for mf in regulars:
406 if self.dirstate.normalize(mf).startswith(d):
406 if self.dirstate.normalize(mf).startswith(d):
407 actualfiles.append(f)
407 actualfiles.append(f)
408 matcheddir = True
408 matcheddir = True
409 break
409 break
410 if not matcheddir:
410 if not matcheddir:
411 # If no normal match, manually append
411 # If no normal match, manually append
412 # any matching largefiles
412 # any matching largefiles
413 for lf in lfiles:
413 for lf in lfiles:
414 if self.dirstate.normalize(lf).startswith(d):
414 if self.dirstate.normalize(lf).startswith(d):
415 actualfiles.append(lf)
415 actualfiles.append(lf)
416 if not matcheddir:
416 if not matcheddir:
417 # There may still be normal files in the dir, so
417 # There may still be normal files in the dir, so
418 # add a directory to the list, which
418 # add a directory to the list, which
419 # forces status/dirstate to walk all files and
419 # forces status/dirstate to walk all files and
420 # call the match function on the matcher, even
420 # call the match function on the matcher, even
421 # on case sensitive filesystems.
421 # on case sensitive filesystems.
422 actualfiles.append(b'.')
422 actualfiles.append(b'.')
423 matcheddir = True
423 matcheddir = True
424 # Nothing in dir, so readd it
424 # Nothing in dir, so readd it
425 # and let commit reject it
425 # and let commit reject it
426 if not matcheddir:
426 if not matcheddir:
427 actualfiles.append(f)
427 actualfiles.append(f)
428
428
429 # Always add normal files
429 # Always add normal files
430 actualfiles += regulars
430 actualfiles += regulars
431 return actualfiles
431 return actualfiles
432
432
433 repo.__class__ = lfilesrepo
433 repo.__class__ = lfilesrepo
434
434
435 # stack of hooks being executed before committing.
435 # stack of hooks being executed before committing.
436 # only last element ("_lfcommithooks[-1]") is used for each committing.
436 # only last element ("_lfcommithooks[-1]") is used for each committing.
437 repo._lfcommithooks = [lfutil.updatestandinsbymatch]
437 repo._lfcommithooks = [lfutil.updatestandinsbymatch]
438
438
439 # Stack of status writer functions taking "*msg, **opts" arguments
439 # Stack of status writer functions taking "*msg, **opts" arguments
440 # like "ui.status()". Only last element ("_lfstatuswriters[-1]")
440 # like "ui.status()". Only last element ("_lfstatuswriters[-1]")
441 # is used to write status out.
441 # is used to write status out.
442 repo._lfstatuswriters = [ui.status]
442 repo._lfstatuswriters = [ui.status]
443
443
444 def prepushoutgoinghook(pushop):
444 def prepushoutgoinghook(pushop):
445 """Push largefiles for pushop before pushing revisions."""
445 """Push largefiles for pushop before pushing revisions."""
446 lfrevs = pushop.lfrevs
446 lfrevs = pushop.lfrevs
447 if lfrevs is None:
447 if lfrevs is None:
448 lfrevs = pushop.outgoing.missing
448 lfrevs = pushop.outgoing.missing
449 if lfrevs:
449 if lfrevs:
450 toupload = set()
450 toupload = set()
451 addfunc = lambda fn, lfhash: toupload.add(lfhash)
451 addfunc = lambda fn, lfhash: toupload.add(lfhash)
452 lfutil.getlfilestoupload(pushop.repo, lfrevs, addfunc)
452 lfutil.getlfilestoupload(pushop.repo, lfrevs, addfunc)
453 lfcommands.uploadlfiles(ui, pushop.repo, pushop.remote, toupload)
453 lfcommands.uploadlfiles(ui, pushop.repo, pushop.remote, toupload)
454
454
455 repo.prepushoutgoinghooks.add(b"largefiles", prepushoutgoinghook)
455 repo.prepushoutgoinghooks.add(b"largefiles", prepushoutgoinghook)
456
456
457 def checkrequireslfiles(ui, repo, **kwargs):
457 def checkrequireslfiles(ui, repo, **kwargs):
458 if b'largefiles' not in repo.requirements and any(
458 with repo.lock():
459 lfutil.shortname + b'/' in f[1] for f in repo.store.datafiles()
459 if b'largefiles' not in repo.requirements and any(
460 ):
460 lfutil.shortname + b'/' in f[1] for f in repo.store.datafiles()
461 repo.requirements.add(b'largefiles')
461 ):
462 scmutil.writereporequirements(repo)
462 repo.requirements.add(b'largefiles')
463 scmutil.writereporequirements(repo)
463
464
464 ui.setconfig(
465 ui.setconfig(
465 b'hooks', b'changegroup.lfiles', checkrequireslfiles, b'largefiles'
466 b'hooks', b'changegroup.lfiles', checkrequireslfiles, b'largefiles'
466 )
467 )
467 ui.setconfig(b'hooks', b'commit.lfiles', checkrequireslfiles, b'largefiles')
468 ui.setconfig(b'hooks', b'commit.lfiles', checkrequireslfiles, b'largefiles')
General Comments 0
You need to be logged in to leave comments. Login now