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