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