Show More
@@ -6,7 +6,7 b'' | |||||
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 |
''' |
|
9 | '''base class for store implementations and store-related utility code''' | |
10 |
|
10 | |||
11 | import os |
|
11 | import os | |
12 | import tempfile |
|
12 | import tempfile | |
@@ -168,9 +168,10 b' def _openstore(repo, remote=None, put=Fa' | |||||
168 | if not remote: |
|
168 | if not remote: | |
169 | path = getattr(repo, 'lfpullsource', None) or \ |
|
169 | path = getattr(repo, 'lfpullsource', None) or \ | |
170 | ui.expandpath('default-push', 'default') |
|
170 | ui.expandpath('default-push', 'default') | |
171 | # If 'default-push' and 'default' can't be expanded |
|
171 | ||
172 | # they are just returned. In that case use the empty string which |
|
172 | # ui.expandpath() leaves 'default-push' and 'default' alone if | |
173 | # use the filescheme. |
|
173 | # they cannot be expanded: fallback to the empty string, | |
|
174 | # meaning the current directory. | |||
174 | if path == 'default-push' or path == 'default': |
|
175 | if path == 'default-push' or path == 'default': | |
175 | path = '' |
|
176 | path = '' | |
176 | remote = repo |
|
177 | remote = repo |
@@ -6,7 +6,7 b'' | |||||
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 |
'''High-level command function |
|
9 | '''High-level command function for lfconvert, plus the cmdtable.''' | |
10 |
|
10 | |||
11 | import os |
|
11 | import os | |
12 | import shutil |
|
12 | import shutil | |
@@ -316,11 +316,9 b' def _lfconvert_addchangeset(rsrc, rdst, ' | |||||
316 | revmap[ctx.node()] = rdst.changelog.tip() |
|
316 | revmap[ctx.node()] = rdst.changelog.tip() | |
317 |
|
317 | |||
318 | def _islfile(file, ctx, matcher, size): |
|
318 | def _islfile(file, ctx, matcher, size): | |
319 | ''' |
|
319 | '''Return true if file should be considered a largefile, i.e. | |
320 | A file is a lfile if it matches a pattern or is over |
|
320 | matcher matches it or it is larger than size.''' | |
321 | the given size. |
|
321 | # never store special .hg* files as largefiles | |
322 | ''' |
|
|||
323 | # Never store hgtags or hgignore as lfiles |
|
|||
324 | if file == '.hgtags' or file == '.hgignore' or file == '.hgsigs': |
|
322 | if file == '.hgtags' or file == '.hgignore' or file == '.hgsigs': | |
325 | return False |
|
323 | return False | |
326 | if matcher and matcher(file): |
|
324 | if matcher and matcher(file): |
@@ -76,7 +76,7 b' def link(src, dest):' | |||||
76 | try: |
|
76 | try: | |
77 | util.oslink(src, dest) |
|
77 | util.oslink(src, dest) | |
78 | except OSError: |
|
78 | except OSError: | |
79 |
# |
|
79 | # if hardlinks fail, fallback on copy | |
80 | shutil.copyfile(src, dest) |
|
80 | shutil.copyfile(src, dest) | |
81 | os.chmod(dest, os.stat(src).st_mode) |
|
81 | os.chmod(dest, os.stat(src).st_mode) | |
82 |
|
82 | |||
@@ -122,8 +122,8 b' class largefiles_dirstate(dirstate.dirst' | |||||
122 |
|
122 | |||
123 | def openlfdirstate(ui, repo): |
|
123 | def openlfdirstate(ui, repo): | |
124 | ''' |
|
124 | ''' | |
125 |
Return a dirstate object that tracks |
|
125 | Return a dirstate object that tracks largefiles: i.e. its root is | |
126 | repo root, but it is saved in .hg/largefiles/dirstate. |
|
126 | the repo root, but it is saved in .hg/largefiles/dirstate. | |
127 | ''' |
|
127 | ''' | |
128 | admin = repo.join(longname) |
|
128 | admin = repo.join(longname) | |
129 | opener = scmutil.opener(admin) |
|
129 | opener = scmutil.opener(admin) | |
@@ -133,10 +133,10 b' def openlfdirstate(ui, repo):' | |||||
133 | else: |
|
133 | else: | |
134 | lfdirstate = largefiles_dirstate(opener, ui, repo.root) |
|
134 | lfdirstate = largefiles_dirstate(opener, ui, repo.root) | |
135 |
|
135 | |||
136 |
# If the largefiles dirstate does not exist, populate and create |
|
136 | # If the largefiles dirstate does not exist, populate and create | |
137 |
# ensures that we create it on the first meaningful |
|
137 | # it. This ensures that we create it on the first meaningful | |
138 | # a new clone. It also gives us an easy way to forcibly rebuild largefiles |
|
138 | # largefiles operation in a new clone. It also gives us an easy | |
139 | # state: |
|
139 | # way to forcibly rebuild largefiles state: | |
140 | # rm .hg/largefiles/dirstate && hg status |
|
140 | # rm .hg/largefiles/dirstate && hg status | |
141 | # Or even, if things are really messed up: |
|
141 | # Or even, if things are really messed up: | |
142 | # rm -rf .hg/largefiles && hg status |
|
142 | # rm -rf .hg/largefiles && hg status | |
@@ -177,7 +177,8 b' def lfdirstate_status(lfdirstate, repo, ' | |||||
177 | return (modified, added, removed, missing, unknown, ignored, clean) |
|
177 | return (modified, added, removed, missing, unknown, ignored, clean) | |
178 |
|
178 | |||
179 | def listlfiles(repo, rev=None, matcher=None): |
|
179 | def listlfiles(repo, rev=None, matcher=None): | |
180 |
'''list largefiles in the working copy or |
|
180 | '''return a list of largefiles in the working copy or the | |
|
181 | specified changeset''' | |||
181 |
|
182 | |||
182 | if matcher is None: |
|
183 | if matcher is None: | |
183 | matcher = getstandinmatcher(repo) |
|
184 | matcher = getstandinmatcher(repo) | |
@@ -197,10 +198,11 b' def cachepath(repo, hash):' | |||||
197 | return repo.join(os.path.join(longname, hash)) |
|
198 | return repo.join(os.path.join(longname, hash)) | |
198 |
|
199 | |||
199 | def copyfromcache(repo, hash, filename): |
|
200 | def copyfromcache(repo, hash, filename): | |
200 |
''' |
|
201 | '''Copy the specified largefile from the repo or system cache to | |
201 | cache to the specified location in the repository. It will not throw an |
|
202 | filename in the repository. Return true on success or false if the | |
202 | exception on failure, as it is meant to be called only after ensuring that |
|
203 | file was not found in either cache (which should not happened: | |
203 | the needed largefile exists in the cache.''' |
|
204 | this is meant to be called only after ensuring that the needed | |
|
205 | largefile exists in the cache).''' | |||
204 | path = findfile(repo, hash) |
|
206 | path = findfile(repo, hash) | |
205 | if path is None: |
|
207 | if path is None: | |
206 | return False |
|
208 | return False | |
@@ -249,9 +251,9 b' def getstandinmatcher(repo, pats=[], opt' | |||||
249 | return getmatcher(repo, pats, opts, showbad=False) |
|
251 | return getmatcher(repo, pats, opts, showbad=False) | |
250 |
|
252 | |||
251 | def getmatcher(repo, pats=[], opts={}, showbad=True): |
|
253 | def getmatcher(repo, pats=[], opts={}, showbad=True): | |
252 |
'''Wrapper around scmutil.match() that adds showbad: if false, |
|
254 | '''Wrapper around scmutil.match() that adds showbad: if false, | |
253 |
the match object |
|
255 | neuter the match object's bad() method so it does not print any | |
254 | about missing files or directories.''' |
|
256 | warnings about missing files or directories.''' | |
255 | match = scmutil.match(repo[None], pats, opts) |
|
257 | match = scmutil.match(repo[None], pats, opts) | |
256 |
|
258 | |||
257 | if not showbad: |
|
259 | if not showbad: | |
@@ -259,9 +261,9 b' def getmatcher(repo, pats=[], opts={}, s' | |||||
259 | return match |
|
261 | return match | |
260 |
|
262 | |||
261 | def composestandinmatcher(repo, rmatcher): |
|
263 | def composestandinmatcher(repo, rmatcher): | |
262 |
'''Return a matcher that accepts standins corresponding to the |
|
264 | '''Return a matcher that accepts standins corresponding to the | |
263 |
accepted by rmatcher. Pass the list of files in the matcher |
|
265 | files accepted by rmatcher. Pass the list of files in the matcher | |
264 | paths specified by the user.''' |
|
266 | as the paths specified by the user.''' | |
265 | smatcher = getstandinmatcher(repo, rmatcher.files()) |
|
267 | smatcher = getstandinmatcher(repo, rmatcher.files()) | |
266 | isstandin = smatcher.matchfn |
|
268 | isstandin = smatcher.matchfn | |
267 | def composed_matchfn(f): |
|
269 | def composed_matchfn(f): | |
@@ -283,8 +285,8 b' def standin(filename):' | |||||
283 | return shortname + '/' + filename.replace(os.sep, '/') |
|
285 | return shortname + '/' + filename.replace(os.sep, '/') | |
284 |
|
286 | |||
285 | def isstandin(filename): |
|
287 | def isstandin(filename): | |
286 |
'''Return true if filename is a big file standin. |
|
288 | '''Return true if filename is a big file standin. filename must be | |
287 |
|
|
289 | in Mercurial's internal form (slash-separated).''' | |
288 | return filename.startswith(shortname + '/') |
|
290 | return filename.startswith(shortname + '/') | |
289 |
|
291 | |||
290 | def splitstandin(filename): |
|
292 | def splitstandin(filename): | |
@@ -310,7 +312,7 b' def readstandin(repo, filename, node=Non' | |||||
310 | return repo[node][standin(filename)].data().strip() |
|
312 | return repo[node][standin(filename)].data().strip() | |
311 |
|
313 | |||
312 | def writestandin(repo, standin, hash, executable): |
|
314 | def writestandin(repo, standin, hash, executable): | |
313 |
'''write h |
|
315 | '''write hash to <repo.root>/<standin>''' | |
314 | writehash(hash, repo.wjoin(standin), executable) |
|
316 | writehash(hash, repo.wjoin(standin), executable) | |
315 |
|
317 | |||
316 | def copyandhash(instream, outfile): |
|
318 | def copyandhash(instream, outfile): | |
@@ -323,7 +325,7 b' def copyandhash(instream, outfile):' | |||||
323 | outfile.write(data) |
|
325 | outfile.write(data) | |
324 |
|
326 | |||
325 | # Blecch: closing a file that somebody else opened is rude and |
|
327 | # Blecch: closing a file that somebody else opened is rude and | |
326 |
# wrong. |
|
328 | # wrong. But it's so darn convenient and practical! After all, | |
327 | # outfile was opened just to copy and hash. |
|
329 | # outfile was opened just to copy and hash. | |
328 | outfile.close() |
|
330 | outfile.close() | |
329 |
|
331 | |||
@@ -364,7 +366,7 b' def blockstream(infile, blocksize=128 * ' | |||||
364 | if not data: |
|
366 | if not data: | |
365 | break |
|
367 | break | |
366 | yield data |
|
368 | yield data | |
367 |
# |
|
369 | # same blecch as copyandhash() above | |
368 | infile.close() |
|
370 | infile.close() | |
369 |
|
371 | |||
370 | def readhash(filename): |
|
372 | def readhash(filename): | |
@@ -425,9 +427,8 b' def hexsha1(data):' | |||||
425 | def httpsendfile(ui, filename): |
|
427 | def httpsendfile(ui, filename): | |
426 | return httpconnection.httpsendfile(ui, filename, 'rb') |
|
428 | return httpconnection.httpsendfile(ui, filename, 'rb') | |
427 |
|
429 | |||
428 | # Convert a path to a unix style path. This is used to give a |
|
|||
429 | # canonical path to the lfdirstate. |
|
|||
430 | def unixpath(path): |
|
430 | def unixpath(path): | |
|
431 | '''Return a version of path normalized for use with the lfdirstate.''' | |||
431 | return os.path.normpath(path).replace(os.sep, '/') |
|
432 | return os.path.normpath(path).replace(os.sep, '/') | |
432 |
|
433 | |||
433 | def islfilesrepo(repo): |
|
434 | def islfilesrepo(repo): |
@@ -6,7 +6,7 b'' | |||||
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 |
''' |
|
9 | '''store class for local filesystem''' | |
10 |
|
10 | |||
11 | import os |
|
11 | import os | |
12 |
|
12 | |||
@@ -17,17 +17,17 b' import lfutil' | |||||
17 | import basestore |
|
17 | import basestore | |
18 |
|
18 | |||
19 | class localstore(basestore.basestore): |
|
19 | class localstore(basestore.basestore): | |
20 |
'''Because there is a system |
|
20 | '''Because there is a system-wide cache, the local store always | |
21 |
cache. |
|
21 | uses that cache. Since the cache is updated elsewhere, we can | |
22 | as if it were the store.''' |
|
22 | just read from it here as if it were the store.''' | |
23 |
|
23 | |||
24 | def __init__(self, ui, repo, remote): |
|
24 | def __init__(self, ui, repo, remote): | |
25 | url = os.path.join(remote.path, '.hg', lfutil.longname) |
|
25 | url = os.path.join(remote.path, '.hg', lfutil.longname) | |
26 | super(localstore, self).__init__(ui, repo, util.expandpath(url)) |
|
26 | super(localstore, self).__init__(ui, repo, util.expandpath(url)) | |
27 |
|
27 | |||
28 | def put(self, source, filename, hash): |
|
28 | def put(self, source, filename, hash): | |
29 |
'''Any file that is put must already be in the system |
|
29 | '''Any file that is put must already be in the system-wide | |
30 | nothing.''' |
|
30 | cache so do nothing.''' | |
31 | return |
|
31 | return | |
32 |
|
32 | |||
33 | def exists(self, hash): |
|
33 | def exists(self, hash): |
@@ -59,9 +59,9 b' def restorematchfn():' | |||||
59 |
|
59 | |||
60 | # -- Wrappers: modify existing commands -------------------------------- |
|
60 | # -- Wrappers: modify existing commands -------------------------------- | |
61 |
|
61 | |||
62 | # Add works by going through the files that the user wanted to add |
|
62 | # Add works by going through the files that the user wanted to add and | |
63 |
# |
|
63 | # checking if they should be added as largefiles. Then it makes a new | |
64 |
# matcher which matches only the normal files and run |
|
64 | # matcher which matches only the normal files and runs the original | |
65 | # version of add. |
|
65 | # version of add. | |
66 | def override_add(orig, ui, repo, *pats, **opts): |
|
66 | def override_add(orig, ui, repo, *pats, **opts): | |
67 | large = opts.pop('large', None) |
|
67 | large = opts.pop('large', None) | |
@@ -101,8 +101,8 b' def override_add(orig, ui, repo, *pats, ' | |||||
101 | bad = [] |
|
101 | bad = [] | |
102 | standins = [] |
|
102 | standins = [] | |
103 |
|
103 | |||
104 |
# Need to lock otherwise there could be a race condition |
|
104 | # Need to lock, otherwise there could be a race condition between | |
105 | # standins are created and added to the repo |
|
105 | # when standins are created and added to the repo. | |
106 | wlock = repo.wlock() |
|
106 | wlock = repo.wlock() | |
107 | try: |
|
107 | try: | |
108 | if not opts.get('dry_run'): |
|
108 | if not opts.get('dry_run'): | |
@@ -221,8 +221,8 b' def override_update(orig, ui, repo, *pat' | |||||
221 | False, False) |
|
221 | False, False) | |
222 | (unsure, modified, added, removed, missing, unknown, ignored, clean) = s |
|
222 | (unsure, modified, added, removed, missing, unknown, ignored, clean) = s | |
223 |
|
223 | |||
224 |
# Need to lock between the standins getting updated and their |
|
224 | # Need to lock between the standins getting updated and their | |
225 | # getting updated |
|
225 | # largefiles getting updated | |
226 | wlock = repo.wlock() |
|
226 | wlock = repo.wlock() | |
227 | try: |
|
227 | try: | |
228 | if opts['check']: |
|
228 | if opts['check']: | |
@@ -245,9 +245,9 b' def override_update(orig, ui, repo, *pat' | |||||
245 | wlock.release() |
|
245 | wlock.release() | |
246 | return orig(ui, repo, *pats, **opts) |
|
246 | return orig(ui, repo, *pats, **opts) | |
247 |
|
247 | |||
248 |
# Override filemerge to prompt the user about how they wish to merge |
|
248 | # Override filemerge to prompt the user about how they wish to merge | |
249 |
# This will handle identical edits, and copy/rename + |
|
249 | # largefiles. This will handle identical edits, and copy/rename + | |
250 | # the user. |
|
250 | # edit without prompting the user. | |
251 | def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca): |
|
251 | def override_filemerge(origfn, repo, mynode, orig, fcd, fco, fca): | |
252 | # Use better variable names here. Because this is a wrapper we cannot |
|
252 | # Use better variable names here. Because this is a wrapper we cannot | |
253 | # change the variable names in the function declaration. |
|
253 | # change the variable names in the function declaration. | |
@@ -288,12 +288,13 b' def override_filemerge(origfn, repo, myn' | |||||
288 | repo.wwrite(fcdest.path(), fcother.data(), fcother.flags()) |
|
288 | repo.wwrite(fcdest.path(), fcother.data(), fcother.flags()) | |
289 | return 0 |
|
289 | return 0 | |
290 |
|
290 | |||
291 |
# Copy first changes the matchers to match standins instead of |
|
291 | # Copy first changes the matchers to match standins instead of | |
292 |
# Then it overrides util.copyfile in that function it |
|
292 | # largefiles. Then it overrides util.copyfile in that function it | |
293 | # lfile already exists. It also keeps a list of copied files so that the lfiles |
|
293 | # checks if the destination largefile already exists. It also keeps a | |
294 | # can be copied and the dirstate updated. |
|
294 | # list of copied files so that the largefiles can be copied and the | |
|
295 | # dirstate updated. | |||
295 | def override_copy(orig, ui, repo, pats, opts, rename=False): |
|
296 | def override_copy(orig, ui, repo, pats, opts, rename=False): | |
296 | # doesn't remove lfile on rename |
|
297 | # doesn't remove largefile on rename | |
297 | if len(pats) < 2: |
|
298 | if len(pats) < 2: | |
298 | # this isn't legal, let the original function deal with it |
|
299 | # this isn't legal, let the original function deal with it | |
299 | return orig(ui, repo, pats, opts, rename) |
|
300 | return orig(ui, repo, pats, opts, rename) | |
@@ -309,9 +310,10 b' def override_copy(orig, ui, repo, pats, ' | |||||
309 | if os.path.isdir(dest): |
|
310 | if os.path.isdir(dest): | |
310 | if not os.path.isdir(makestandin(dest)): |
|
311 | if not os.path.isdir(makestandin(dest)): | |
311 | os.makedirs(makestandin(dest)) |
|
312 | os.makedirs(makestandin(dest)) | |
312 |
# This could copy both lfiles and normal files in one command, |
|
313 | # This could copy both largefiles and normal files in one command, | |
313 |
# want to do that first replace their matcher to only |
|
314 | # but we don't want to do that first replace their matcher to only | |
314 |
# and run it then replace it to just match |
|
315 | # match normal files and run it then replace it to just match | |
|
316 | # lfiles and run it again | |||
315 | nonormalfiles = False |
|
317 | nonormalfiles = False | |
316 | nolfiles = False |
|
318 | nolfiles = False | |
317 | try: |
|
319 | try: |
@@ -17,8 +17,8 b" LARGEFILES_REQUIRED_MSG = '\\nThis reposi" | |||||
17 | 'file.\n' |
|
17 | 'file.\n' | |
18 |
|
18 | |||
19 | def putlfile(repo, proto, sha): |
|
19 | def putlfile(repo, proto, sha): | |
20 |
|
|
20 | '''Put a largefile into a repository's local cache and into the | |
21 |
system cache. |
|
21 | system cache.''' | |
22 | f = None |
|
22 | f = None | |
23 | proto.redirect() |
|
23 | proto.redirect() | |
24 | try: |
|
24 | try: | |
@@ -40,17 +40,19 b' def putlfile(repo, proto, sha):' | |||||
40 | return wireproto.pushres(0) |
|
40 | return wireproto.pushres(0) | |
41 |
|
41 | |||
42 | def getlfile(repo, proto, sha): |
|
42 | def getlfile(repo, proto, sha): | |
43 |
|
|
43 | '''Retrieve a largefile from the repository-local cache or system | |
44 |
cache. |
|
44 | cache.''' | |
45 | filename = lfutil.findfile(repo, sha) |
|
45 | filename = lfutil.findfile(repo, sha) | |
46 | if not filename: |
|
46 | if not filename: | |
47 | raise util.Abort(_('requested largefile %s not present in cache') % sha) |
|
47 | raise util.Abort(_('requested largefile %s not present in cache') % sha) | |
48 | f = open(filename, 'rb') |
|
48 | f = open(filename, 'rb') | |
49 | length = os.fstat(f.fileno())[6] |
|
49 | length = os.fstat(f.fileno())[6] | |
50 | # since we can't set an HTTP content-length header here, and mercurial core |
|
50 | ||
51 | # provides no way to give the length of a streamres (and reading the entire |
|
51 | # Since we can't set an HTTP content-length header here, and | |
52 | # file into RAM would be ill-advised), we just send the length on the first |
|
52 | # Mercurial core provides no way to give the length of a streamres | |
53 | # line of the response, like the ssh proto does for string responses. |
|
53 | # (and reading the entire file into RAM would be ill-advised), we | |
|
54 | # just send the length on the first line of the response, like the | |||
|
55 | # ssh proto does for string responses. | |||
54 | def generator(): |
|
56 | def generator(): | |
55 | yield '%d\n' % length |
|
57 | yield '%d\n' % length | |
56 | for chunk in f: |
|
58 | for chunk in f: | |
@@ -58,8 +60,8 b' def getlfile(repo, proto, sha):' | |||||
58 | return wireproto.streamres(generator()) |
|
60 | return wireproto.streamres(generator()) | |
59 |
|
61 | |||
60 | def statlfile(repo, proto, sha): |
|
62 | def statlfile(repo, proto, sha): | |
61 |
|
|
63 | '''Return '2\n' if the largefile is missing, '1\n' if it has a | |
62 |
mismatched checksum, or '0\n' if it is in good condition |
|
64 | mismatched checksum, or '0\n' if it is in good condition''' | |
63 | filename = lfutil.findfile(repo, sha) |
|
65 | filename = lfutil.findfile(repo, sha) | |
64 | if not filename: |
|
66 | if not filename: | |
65 | return '2\n' |
|
67 | return '2\n' | |
@@ -113,10 +115,10 b' def wirereposetup(ui, repo):' | |||||
113 | try: |
|
115 | try: | |
114 | return int(self._call("statlfile", sha=sha)) |
|
116 | return int(self._call("statlfile", sha=sha)) | |
115 | except (ValueError, urllib2.HTTPError): |
|
117 | except (ValueError, urllib2.HTTPError): | |
116 |
# |
|
118 | # If the server returns anything but an integer followed by a | |
117 | # newline, newline, it's not speaking our language; if we get |
|
119 | # newline, newline, it's not speaking our language; if we get | |
118 | # an HTTP error, we can't be sure the largefile is present; |
|
120 | # an HTTP error, we can't be sure the largefile is present; | |
119 | # either way, consider it missing |
|
121 | # either way, consider it missing. | |
120 | return 2 |
|
122 | return 2 | |
121 |
|
123 | |||
122 | repo.__class__ = lfileswirerepository |
|
124 | repo.__class__ = lfileswirerepository |
@@ -4,7 +4,7 b'' | |||||
4 | # This software may be used and distributed according to the terms of the |
|
4 | # This software may be used and distributed according to the terms of the | |
5 | # GNU General Public License version 2 or any later version. |
|
5 | # GNU General Public License version 2 or any later version. | |
6 |
|
6 | |||
7 |
''' |
|
7 | '''remote largefile store; the base class for servestore''' | |
8 |
|
8 | |||
9 | import urllib2 |
|
9 | import urllib2 | |
10 |
|
10 | |||
@@ -15,7 +15,7 b' import lfutil' | |||||
15 | import basestore |
|
15 | import basestore | |
16 |
|
16 | |||
17 | class remotestore(basestore.basestore): |
|
17 | class remotestore(basestore.basestore): | |
18 |
|
|
18 | '''a largefile store accessed over a network''' | |
19 | def __init__(self, ui, repo, url): |
|
19 | def __init__(self, ui, repo, url): | |
20 | super(remotestore, self).__init__(ui, repo, url) |
|
20 | super(remotestore, self).__init__(ui, repo, url) | |
21 |
|
21 |
@@ -42,9 +42,10 b' def reposetup(ui, repo):' | |||||
42 | def status_nolfiles(self, *args, **kwargs): |
|
42 | def status_nolfiles(self, *args, **kwargs): | |
43 | return super(lfiles_repo, self).status(*args, **kwargs) |
|
43 | return super(lfiles_repo, self).status(*args, **kwargs) | |
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 |
# instead of their corresponding standins and |
|
46 | # of largefiles instead of their corresponding standins and | |
47 | # always binary, regardless of their actual contents. |
|
47 | # identifies the largefiles as always binary, regardless of | |
|
48 | # their actual contents. | |||
48 | def __getitem__(self, changeid): |
|
49 | def __getitem__(self, changeid): | |
49 | ctx = super(lfiles_repo, self).__getitem__(changeid) |
|
50 | ctx = super(lfiles_repo, self).__getitem__(changeid) | |
50 | if self.lfstatus: |
|
51 | if self.lfstatus: | |
@@ -81,9 +82,9 b' def reposetup(ui, repo):' | |||||
81 | return ctx |
|
82 | return ctx | |
82 |
|
83 | |||
83 | # Figure out the status of big files and insert them into the |
|
84 | # Figure out the status of big files and insert them into the | |
84 |
# appropriate list in the result. Also removes standin files |
|
85 | # appropriate list in the result. Also removes standin files | |
85 |
# the listing. |
|
86 | # from the listing. Revert to the original status if | |
86 | # self.lfstatus is False |
|
87 | # self.lfstatus is False. | |
87 | def status(self, node1='.', node2=None, match=None, ignored=False, |
|
88 | def status(self, node1='.', node2=None, match=None, ignored=False, | |
88 | clean=False, unknown=False, listsubrepos=False): |
|
89 | clean=False, unknown=False, listsubrepos=False): | |
89 | listignored, listclean, listunknown = ignored, clean, unknown |
|
90 | listignored, listclean, listunknown = ignored, clean, unknown | |
@@ -131,8 +132,8 b' def reposetup(ui, repo):' | |||||
131 | m = copy.copy(match) |
|
132 | m = copy.copy(match) | |
132 | m._files = [tostandin(f) for f in m._files] |
|
133 | m._files = [tostandin(f) for f in m._files] | |
133 |
|
134 | |||
134 |
# get ignored clean and unknown but remove them |
|
135 | # get ignored, clean, and unknown but remove them | |
135 | # were not asked for |
|
136 | # later if they were not asked for | |
136 | try: |
|
137 | try: | |
137 | result = super(lfiles_repo, self).status(node1, node2, m, |
|
138 | result = super(lfiles_repo, self).status(node1, node2, m, | |
138 | True, True, True, listsubrepos) |
|
139 | True, True, True, listsubrepos) | |
@@ -140,11 +141,11 b' def reposetup(ui, repo):' | |||||
140 | result = super(lfiles_repo, self).status(node1, node2, m, |
|
141 | result = super(lfiles_repo, self).status(node1, node2, m, | |
141 | True, True, True) |
|
142 | True, True, True) | |
142 | if working: |
|
143 | if working: | |
143 |
# |
|
144 | # hold the wlock while we read largefiles and | |
144 | # lfdirstate |
|
145 | # update the lfdirstate | |
145 | wlock = repo.wlock() |
|
146 | wlock = repo.wlock() | |
146 | try: |
|
147 | try: | |
147 |
# Any non |
|
148 | # Any non-largefiles that were explicitly listed must be | |
148 | # taken out or lfdirstate.status will report an error. |
|
149 | # taken out or lfdirstate.status will report an error. | |
149 | # The status of these files was already computed using |
|
150 | # The status of these files was already computed using | |
150 | # super's status. |
|
151 | # super's status. | |
@@ -334,15 +335,15 b' def reposetup(ui, repo):' | |||||
334 | for f in match._files: |
|
335 | for f in match._files: | |
335 | fstandin = lfutil.standin(f) |
|
336 | fstandin = lfutil.standin(f) | |
336 |
|
337 | |||
337 |
# |
|
338 | # ignore known largefiles and standins | |
338 | if f in lfiles or fstandin in standins: |
|
339 | if f in lfiles or fstandin in standins: | |
339 | continue |
|
340 | continue | |
340 |
|
341 | |||
341 |
# |
|
342 | # append directory separator to avoid collisions | |
342 | if not fstandin.endswith(os.sep): |
|
343 | if not fstandin.endswith(os.sep): | |
343 | fstandin += os.sep |
|
344 | fstandin += os.sep | |
344 |
|
345 | |||
345 |
# |
|
346 | # prevalidate matching standin directories | |
346 | if lfutil.any_(st for st in match._files if \ |
|
347 | if lfutil.any_(st for st in match._files if \ | |
347 | st.startswith(fstandin)): |
|
348 | st.startswith(fstandin)): | |
348 | continue |
|
349 | continue | |
@@ -397,8 +398,8 b' def reposetup(ui, repo):' | |||||
397 | def checkrequireslfiles(ui, repo, **kwargs): |
|
398 | def checkrequireslfiles(ui, repo, **kwargs): | |
398 | if 'largefiles' not in repo.requirements and lfutil.any_( |
|
399 | if 'largefiles' not in repo.requirements and lfutil.any_( | |
399 | lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()): |
|
400 | lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()): | |
400 |
# work |
|
401 | # workaround bug in Mercurial 1.9 whereby requirements is | |
401 | # on newly-cloned repos |
|
402 | # a list on newly-cloned repos | |
402 | repo.requirements = set(repo.requirements) |
|
403 | repo.requirements = set(repo.requirements) | |
403 |
|
404 | |||
404 | repo.requirements |= set(['largefiles']) |
|
405 | repo.requirements |= set(['largefiles']) |
@@ -110,8 +110,8 b' def uisetup(ui):' | |||||
110 | proto.capabilities_orig = wireproto.capabilities |
|
110 | proto.capabilities_orig = wireproto.capabilities | |
111 | wireproto.capabilities = proto.capabilities |
|
111 | wireproto.capabilities = proto.capabilities | |
112 |
|
112 | |||
113 |
# these let us reject non-lfiles clients and make them display |
|
113 | # these let us reject non-largefiles clients and make them display | |
114 | # messages |
|
114 | # our error messages | |
115 | protocol.webproto.refuseclient = proto.webproto_refuseclient |
|
115 | protocol.webproto.refuseclient = proto.webproto_refuseclient | |
116 | sshserver.sshserver.refuseclient = proto.sshproto_refuseclient |
|
116 | sshserver.sshserver.refuseclient = proto.sshproto_refuseclient | |
117 |
|
117 |
@@ -3,7 +3,7 b'' | |||||
3 | # This software may be used and distributed according to the terms of the |
|
3 | # This software may be used and distributed according to the terms of the | |
4 | # GNU General Public License version 2 or any later version. |
|
4 | # GNU General Public License version 2 or any later version. | |
5 |
|
5 | |||
6 |
'''largefile store working over |
|
6 | '''largefile store working over Mercurial's wire protocol''' | |
7 |
|
7 | |||
8 | import lfutil |
|
8 | import lfutil | |
9 | import remotestore |
|
9 | import remotestore |
General Comments 0
You need to be logged in to leave comments.
Login now