##// END OF EJS Templates
largefiles: don't mute and obfuscate http errors when putlfile fails...
Mads Kiilerich -
r26825:78539633 stable
parent child Browse files
Show More
@@ -1,176 +1,175
1 # Copyright 2011 Fog Creek Software
1 # Copyright 2011 Fog Creek Software
2 #
2 #
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 import os
6 import os
7 import urllib2
7 import urllib2
8 import re
8 import re
9
9
10 from mercurial import error, httppeer, util, wireproto
10 from mercurial import error, httppeer, util, wireproto
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12
12
13 import lfutil
13 import lfutil
14
14
15 LARGEFILES_REQUIRED_MSG = ('\nThis repository uses the largefiles extension.'
15 LARGEFILES_REQUIRED_MSG = ('\nThis repository uses the largefiles extension.'
16 '\n\nPlease enable it in your Mercurial config '
16 '\n\nPlease enable it in your Mercurial config '
17 'file.\n')
17 'file.\n')
18
18
19 # these will all be replaced by largefiles.uisetup
19 # these will all be replaced by largefiles.uisetup
20 capabilitiesorig = None
20 capabilitiesorig = None
21 ssholdcallstream = None
21 ssholdcallstream = None
22 httpoldcallstream = None
22 httpoldcallstream = None
23
23
24 def putlfile(repo, proto, sha):
24 def putlfile(repo, proto, sha):
25 '''Put a largefile into a repository's local store and into the
25 '''Put a largefile into a repository's local store and into the
26 user cache.'''
26 user cache.'''
27 proto.redirect()
27 proto.redirect()
28
28
29 path = lfutil.storepath(repo, sha)
29 path = lfutil.storepath(repo, sha)
30 util.makedirs(os.path.dirname(path))
30 util.makedirs(os.path.dirname(path))
31 tmpfp = util.atomictempfile(path, createmode=repo.store.createmode)
31 tmpfp = util.atomictempfile(path, createmode=repo.store.createmode)
32
32
33 try:
33 try:
34 proto.getfile(tmpfp)
34 proto.getfile(tmpfp)
35 tmpfp._fp.seek(0)
35 tmpfp._fp.seek(0)
36 if sha != lfutil.hexsha1(tmpfp._fp):
36 if sha != lfutil.hexsha1(tmpfp._fp):
37 raise IOError(0, _('largefile contents do not match hash'))
37 raise IOError(0, _('largefile contents do not match hash'))
38 tmpfp.close()
38 tmpfp.close()
39 lfutil.linktousercache(repo, sha)
39 lfutil.linktousercache(repo, sha)
40 except IOError as e:
40 except IOError as e:
41 repo.ui.warn(_('largefiles: failed to put %s into store: %s\n') %
41 repo.ui.warn(_('largefiles: failed to put %s into store: %s\n') %
42 (sha, e.strerror))
42 (sha, e.strerror))
43 return wireproto.pushres(1)
43 return wireproto.pushres(1)
44 finally:
44 finally:
45 tmpfp.discard()
45 tmpfp.discard()
46
46
47 return wireproto.pushres(0)
47 return wireproto.pushres(0)
48
48
49 def getlfile(repo, proto, sha):
49 def getlfile(repo, proto, sha):
50 '''Retrieve a largefile from the repository-local cache or system
50 '''Retrieve a largefile from the repository-local cache or system
51 cache.'''
51 cache.'''
52 filename = lfutil.findfile(repo, sha)
52 filename = lfutil.findfile(repo, sha)
53 if not filename:
53 if not filename:
54 raise error.Abort(_('requested largefile %s not present in cache')
54 raise error.Abort(_('requested largefile %s not present in cache')
55 % sha)
55 % sha)
56 f = open(filename, 'rb')
56 f = open(filename, 'rb')
57 length = os.fstat(f.fileno())[6]
57 length = os.fstat(f.fileno())[6]
58
58
59 # Since we can't set an HTTP content-length header here, and
59 # Since we can't set an HTTP content-length header here, and
60 # Mercurial core provides no way to give the length of a streamres
60 # Mercurial core provides no way to give the length of a streamres
61 # (and reading the entire file into RAM would be ill-advised), we
61 # (and reading the entire file into RAM would be ill-advised), we
62 # just send the length on the first line of the response, like the
62 # just send the length on the first line of the response, like the
63 # ssh proto does for string responses.
63 # ssh proto does for string responses.
64 def generator():
64 def generator():
65 yield '%d\n' % length
65 yield '%d\n' % length
66 for chunk in util.filechunkiter(f):
66 for chunk in util.filechunkiter(f):
67 yield chunk
67 yield chunk
68 return wireproto.streamres(generator())
68 return wireproto.streamres(generator())
69
69
70 def statlfile(repo, proto, sha):
70 def statlfile(repo, proto, sha):
71 '''Return '2\n' if the largefile is missing, '0\n' if it seems to be in
71 '''Return '2\n' if the largefile is missing, '0\n' if it seems to be in
72 good condition.
72 good condition.
73
73
74 The value 1 is reserved for mismatched checksum, but that is too expensive
74 The value 1 is reserved for mismatched checksum, but that is too expensive
75 to be verified on every stat and must be caught be running 'hg verify'
75 to be verified on every stat and must be caught be running 'hg verify'
76 server side.'''
76 server side.'''
77 filename = lfutil.findfile(repo, sha)
77 filename = lfutil.findfile(repo, sha)
78 if not filename:
78 if not filename:
79 return '2\n'
79 return '2\n'
80 return '0\n'
80 return '0\n'
81
81
82 def wirereposetup(ui, repo):
82 def wirereposetup(ui, repo):
83 class lfileswirerepository(repo.__class__):
83 class lfileswirerepository(repo.__class__):
84 def putlfile(self, sha, fd):
84 def putlfile(self, sha, fd):
85 # unfortunately, httprepository._callpush tries to convert its
85 # unfortunately, httprepository._callpush tries to convert its
86 # input file-like into a bundle before sending it, so we can't use
86 # input file-like into a bundle before sending it, so we can't use
87 # it ...
87 # it ...
88 if issubclass(self.__class__, httppeer.httppeer):
88 if issubclass(self.__class__, httppeer.httppeer):
89 res = None
89 res = self._call('putlfile', data=fd, sha=sha,
90 headers={'content-type':'application/mercurial-0.1'})
90 try:
91 try:
91 res = self._call('putlfile', data=fd, sha=sha,
92 headers={'content-type':'application/mercurial-0.1'})
93 d, output = res.split('\n', 1)
92 d, output = res.split('\n', 1)
94 for l in output.splitlines(True):
93 for l in output.splitlines(True):
95 self.ui.warn(_('remote: '), l) # assume l ends with \n
94 self.ui.warn(_('remote: '), l) # assume l ends with \n
96 return int(d)
95 return int(d)
97 except (ValueError, urllib2.HTTPError):
96 except ValueError:
98 self.ui.warn(_('unexpected putlfile response: %r\n') % res)
97 self.ui.warn(_('unexpected putlfile response: %r\n') % res)
99 return 1
98 return 1
100 # ... but we can't use sshrepository._call because the data=
99 # ... but we can't use sshrepository._call because the data=
101 # argument won't get sent, and _callpush does exactly what we want
100 # argument won't get sent, and _callpush does exactly what we want
102 # in this case: send the data straight through
101 # in this case: send the data straight through
103 else:
102 else:
104 try:
103 try:
105 ret, output = self._callpush("putlfile", fd, sha=sha)
104 ret, output = self._callpush("putlfile", fd, sha=sha)
106 if ret == "":
105 if ret == "":
107 raise error.ResponseError(_('putlfile failed:'),
106 raise error.ResponseError(_('putlfile failed:'),
108 output)
107 output)
109 return int(ret)
108 return int(ret)
110 except IOError:
109 except IOError:
111 return 1
110 return 1
112 except ValueError:
111 except ValueError:
113 raise error.ResponseError(
112 raise error.ResponseError(
114 _('putlfile failed (unexpected response):'), ret)
113 _('putlfile failed (unexpected response):'), ret)
115
114
116 def getlfile(self, sha):
115 def getlfile(self, sha):
117 """returns an iterable with the chunks of the file with sha sha"""
116 """returns an iterable with the chunks of the file with sha sha"""
118 stream = self._callstream("getlfile", sha=sha)
117 stream = self._callstream("getlfile", sha=sha)
119 length = stream.readline()
118 length = stream.readline()
120 try:
119 try:
121 length = int(length)
120 length = int(length)
122 except ValueError:
121 except ValueError:
123 self._abort(error.ResponseError(_("unexpected response:"),
122 self._abort(error.ResponseError(_("unexpected response:"),
124 length))
123 length))
125
124
126 # SSH streams will block if reading more than length
125 # SSH streams will block if reading more than length
127 for chunk in util.filechunkiter(stream, 128 * 1024, length):
126 for chunk in util.filechunkiter(stream, 128 * 1024, length):
128 yield chunk
127 yield chunk
129 # HTTP streams must hit the end to process the last empty
128 # HTTP streams must hit the end to process the last empty
130 # chunk of Chunked-Encoding so the connection can be reused.
129 # chunk of Chunked-Encoding so the connection can be reused.
131 if issubclass(self.__class__, httppeer.httppeer):
130 if issubclass(self.__class__, httppeer.httppeer):
132 chunk = stream.read(1)
131 chunk = stream.read(1)
133 if chunk:
132 if chunk:
134 self._abort(error.ResponseError(_("unexpected response:"),
133 self._abort(error.ResponseError(_("unexpected response:"),
135 chunk))
134 chunk))
136
135
137 @wireproto.batchable
136 @wireproto.batchable
138 def statlfile(self, sha):
137 def statlfile(self, sha):
139 f = wireproto.future()
138 f = wireproto.future()
140 result = {'sha': sha}
139 result = {'sha': sha}
141 yield result, f
140 yield result, f
142 try:
141 try:
143 yield int(f.value)
142 yield int(f.value)
144 except (ValueError, urllib2.HTTPError):
143 except (ValueError, urllib2.HTTPError):
145 # If the server returns anything but an integer followed by a
144 # If the server returns anything but an integer followed by a
146 # newline, newline, it's not speaking our language; if we get
145 # newline, newline, it's not speaking our language; if we get
147 # an HTTP error, we can't be sure the largefile is present;
146 # an HTTP error, we can't be sure the largefile is present;
148 # either way, consider it missing.
147 # either way, consider it missing.
149 yield 2
148 yield 2
150
149
151 repo.__class__ = lfileswirerepository
150 repo.__class__ = lfileswirerepository
152
151
153 # advertise the largefiles=serve capability
152 # advertise the largefiles=serve capability
154 def capabilities(repo, proto):
153 def capabilities(repo, proto):
155 return capabilitiesorig(repo, proto) + ' largefiles=serve'
154 return capabilitiesorig(repo, proto) + ' largefiles=serve'
156
155
157 def heads(repo, proto):
156 def heads(repo, proto):
158 if lfutil.islfilesrepo(repo):
157 if lfutil.islfilesrepo(repo):
159 return wireproto.ooberror(LARGEFILES_REQUIRED_MSG)
158 return wireproto.ooberror(LARGEFILES_REQUIRED_MSG)
160 return wireproto.heads(repo, proto)
159 return wireproto.heads(repo, proto)
161
160
162 def sshrepocallstream(self, cmd, **args):
161 def sshrepocallstream(self, cmd, **args):
163 if cmd == 'heads' and self.capable('largefiles'):
162 if cmd == 'heads' and self.capable('largefiles'):
164 cmd = 'lheads'
163 cmd = 'lheads'
165 if cmd == 'batch' and self.capable('largefiles'):
164 if cmd == 'batch' and self.capable('largefiles'):
166 args['cmds'] = args['cmds'].replace('heads ', 'lheads ')
165 args['cmds'] = args['cmds'].replace('heads ', 'lheads ')
167 return ssholdcallstream(self, cmd, **args)
166 return ssholdcallstream(self, cmd, **args)
168
167
169 headsre = re.compile(r'(^|;)heads\b')
168 headsre = re.compile(r'(^|;)heads\b')
170
169
171 def httprepocallstream(self, cmd, **args):
170 def httprepocallstream(self, cmd, **args):
172 if cmd == 'heads' and self.capable('largefiles'):
171 if cmd == 'heads' and self.capable('largefiles'):
173 cmd = 'lheads'
172 cmd = 'lheads'
174 if cmd == 'batch' and self.capable('largefiles'):
173 if cmd == 'batch' and self.capable('largefiles'):
175 args['cmds'] = headsre.sub('lheads', args['cmds'])
174 args['cmds'] = headsre.sub('lheads', args['cmds'])
176 return httpoldcallstream(self, cmd, **args)
175 return httpoldcallstream(self, cmd, **args)
@@ -1,233 +1,231
1 Create user cache directory
1 Create user cache directory
2
2
3 $ USERCACHE=`pwd`/cache; export USERCACHE
3 $ USERCACHE=`pwd`/cache; export USERCACHE
4 $ cat <<EOF >> ${HGRCPATH}
4 $ cat <<EOF >> ${HGRCPATH}
5 > [extensions]
5 > [extensions]
6 > hgext.largefiles=
6 > hgext.largefiles=
7 > [largefiles]
7 > [largefiles]
8 > usercache=${USERCACHE}
8 > usercache=${USERCACHE}
9 > EOF
9 > EOF
10 $ mkdir -p ${USERCACHE}
10 $ mkdir -p ${USERCACHE}
11
11
12 Create source repo, and commit adding largefile.
12 Create source repo, and commit adding largefile.
13
13
14 $ hg init src
14 $ hg init src
15 $ cd src
15 $ cd src
16 $ echo large > large
16 $ echo large > large
17 $ hg add --large large
17 $ hg add --large large
18 $ hg commit -m 'add largefile'
18 $ hg commit -m 'add largefile'
19 $ hg rm large
19 $ hg rm large
20 $ hg commit -m 'branchhead without largefile'
20 $ hg commit -m 'branchhead without largefile'
21 $ hg up -qr 0
21 $ hg up -qr 0
22 $ cd ..
22 $ cd ..
23
23
24 Discard all cached largefiles in USERCACHE
24 Discard all cached largefiles in USERCACHE
25
25
26 $ rm -rf ${USERCACHE}
26 $ rm -rf ${USERCACHE}
27
27
28 Create mirror repo, and pull from source without largefile:
28 Create mirror repo, and pull from source without largefile:
29 "pull" is used instead of "clone" for suppression of (1) updating to
29 "pull" is used instead of "clone" for suppression of (1) updating to
30 tip (= caching largefile from source repo), and (2) recording source
30 tip (= caching largefile from source repo), and (2) recording source
31 repo as "default" path in .hg/hgrc.
31 repo as "default" path in .hg/hgrc.
32
32
33 $ hg init mirror
33 $ hg init mirror
34 $ cd mirror
34 $ cd mirror
35 $ hg pull ../src
35 $ hg pull ../src
36 pulling from ../src
36 pulling from ../src
37 requesting all changes
37 requesting all changes
38 adding changesets
38 adding changesets
39 adding manifests
39 adding manifests
40 adding file changes
40 adding file changes
41 added 2 changesets with 1 changes to 1 files
41 added 2 changesets with 1 changes to 1 files
42 (run 'hg update' to get a working copy)
42 (run 'hg update' to get a working copy)
43
43
44 Update working directory to "tip", which requires largefile("large"),
44 Update working directory to "tip", which requires largefile("large"),
45 but there is no cache file for it. So, hg must treat it as
45 but there is no cache file for it. So, hg must treat it as
46 "missing"(!) file.
46 "missing"(!) file.
47
47
48 $ hg update -r0
48 $ hg update -r0
49 getting changed largefiles
49 getting changed largefiles
50 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
50 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
51 0 largefiles updated, 0 removed
51 0 largefiles updated, 0 removed
52 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
53 $ hg status
53 $ hg status
54 ! large
54 ! large
55
55
56 Update working directory to null: this cleanup .hg/largefiles/dirstate
56 Update working directory to null: this cleanup .hg/largefiles/dirstate
57
57
58 $ hg update null
58 $ hg update null
59 getting changed largefiles
59 getting changed largefiles
60 0 largefiles updated, 0 removed
60 0 largefiles updated, 0 removed
61 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
61 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
62
62
63 Update working directory to tip, again.
63 Update working directory to tip, again.
64
64
65 $ hg update -r0
65 $ hg update -r0
66 getting changed largefiles
66 getting changed largefiles
67 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
67 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
68 0 largefiles updated, 0 removed
68 0 largefiles updated, 0 removed
69 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 $ hg status
70 $ hg status
71 ! large
71 ! large
72 $ cd ..
72 $ cd ..
73
73
74 Verify that largefiles from pulled branchheads are fetched, also to an empty repo
74 Verify that largefiles from pulled branchheads are fetched, also to an empty repo
75
75
76 $ hg init mirror2
76 $ hg init mirror2
77 $ hg -R mirror2 pull src -r0
77 $ hg -R mirror2 pull src -r0
78 pulling from src
78 pulling from src
79 adding changesets
79 adding changesets
80 adding manifests
80 adding manifests
81 adding file changes
81 adding file changes
82 added 1 changesets with 1 changes to 1 files
82 added 1 changesets with 1 changes to 1 files
83 (run 'hg update' to get a working copy)
83 (run 'hg update' to get a working copy)
84
84
85 #if unix-permissions
85 #if unix-permissions
86
86
87 Portable way to print file permissions:
87 Portable way to print file permissions:
88
88
89 $ cat > ls-l.py <<EOF
89 $ cat > ls-l.py <<EOF
90 > #!/usr/bin/env python
90 > #!/usr/bin/env python
91 > import sys, os
91 > import sys, os
92 > path = sys.argv[1]
92 > path = sys.argv[1]
93 > print '%03o' % (os.lstat(path).st_mode & 0777)
93 > print '%03o' % (os.lstat(path).st_mode & 0777)
94 > EOF
94 > EOF
95 $ chmod +x ls-l.py
95 $ chmod +x ls-l.py
96
96
97 Test that files in .hg/largefiles inherit mode from .hg/store, not
97 Test that files in .hg/largefiles inherit mode from .hg/store, not
98 from file in working copy:
98 from file in working copy:
99
99
100 $ cd src
100 $ cd src
101 $ chmod 750 .hg/store
101 $ chmod 750 .hg/store
102 $ chmod 660 large
102 $ chmod 660 large
103 $ echo change >> large
103 $ echo change >> large
104 $ hg commit -m change
104 $ hg commit -m change
105 created new head
105 created new head
106 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
106 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
107 640
107 640
108
108
109 Test permission of with files in .hg/largefiles created by update:
109 Test permission of with files in .hg/largefiles created by update:
110
110
111 $ cd ../mirror
111 $ cd ../mirror
112 $ rm -r "$USERCACHE" .hg/largefiles # avoid links
112 $ rm -r "$USERCACHE" .hg/largefiles # avoid links
113 $ chmod 750 .hg/store
113 $ chmod 750 .hg/store
114 $ hg pull ../src --update -q
114 $ hg pull ../src --update -q
115 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
115 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
116 640
116 640
117
117
118 Test permission of files created by push:
118 Test permission of files created by push:
119
119
120 $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
120 $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
121 > --config "web.allow_push=*" --config web.push_ssl=no
121 > --config "web.allow_push=*" --config web.push_ssl=no
122 $ cat hg.pid >> $DAEMON_PIDS
122 $ cat hg.pid >> $DAEMON_PIDS
123
123
124 $ echo change >> large
124 $ echo change >> large
125 $ hg commit -m change
125 $ hg commit -m change
126
126
127 $ rm -r "$USERCACHE"
127 $ rm -r "$USERCACHE"
128
128
129 $ hg push -q http://localhost:$HGPORT/
129 $ hg push -q http://localhost:$HGPORT/
130
130
131 $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
131 $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
132 640
132 640
133
133
134 $ cd ..
134 $ cd ..
135
135
136 #endif
136 #endif
137
137
138 Test issue 4053 (remove --after on a deleted, uncommitted file shouldn't say
138 Test issue 4053 (remove --after on a deleted, uncommitted file shouldn't say
139 it is missing, but a remove on a nonexistent unknown file still should. Same
139 it is missing, but a remove on a nonexistent unknown file still should. Same
140 for a forget.)
140 for a forget.)
141
141
142 $ cd src
142 $ cd src
143 $ touch x
143 $ touch x
144 $ hg add x
144 $ hg add x
145 $ mv x y
145 $ mv x y
146 $ hg remove -A x y ENOENT
146 $ hg remove -A x y ENOENT
147 ENOENT: * (glob)
147 ENOENT: * (glob)
148 not removing y: file is untracked
148 not removing y: file is untracked
149 [1]
149 [1]
150 $ hg add y
150 $ hg add y
151 $ mv y z
151 $ mv y z
152 $ hg forget y z ENOENT
152 $ hg forget y z ENOENT
153 ENOENT: * (glob)
153 ENOENT: * (glob)
154 not removing z: file is already untracked
154 not removing z: file is already untracked
155 [1]
155 [1]
156
156
157 Largefiles are accessible from the share's store
157 Largefiles are accessible from the share's store
158 $ cd ..
158 $ cd ..
159 $ hg share -q src share_dst --config extensions.share=
159 $ hg share -q src share_dst --config extensions.share=
160 $ hg -R share_dst update -r0
160 $ hg -R share_dst update -r0
161 getting changed largefiles
161 getting changed largefiles
162 1 largefiles updated, 0 removed
162 1 largefiles updated, 0 removed
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
164
164
165 $ echo modified > share_dst/large
165 $ echo modified > share_dst/large
166 $ hg -R share_dst ci -m modified
166 $ hg -R share_dst ci -m modified
167 created new head
167 created new head
168
168
169 Only dirstate is in the local store for the share, and the largefile is in the
169 Only dirstate is in the local store for the share, and the largefile is in the
170 share source's local store. Avoid the extra largefiles added in the unix
170 share source's local store. Avoid the extra largefiles added in the unix
171 conditional above.
171 conditional above.
172 $ hash=`hg -R share_dst cat share_dst/.hglf/large`
172 $ hash=`hg -R share_dst cat share_dst/.hglf/large`
173 $ echo $hash
173 $ echo $hash
174 e2fb5f2139d086ded2cb600d5a91a196e76bf020
174 e2fb5f2139d086ded2cb600d5a91a196e76bf020
175
175
176 $ find share_dst/.hg/largefiles/* | sort
176 $ find share_dst/.hg/largefiles/* | sort
177 share_dst/.hg/largefiles/dirstate
177 share_dst/.hg/largefiles/dirstate
178
178
179 $ find src/.hg/largefiles/* | egrep "(dirstate|$hash)" | sort
179 $ find src/.hg/largefiles/* | egrep "(dirstate|$hash)" | sort
180 src/.hg/largefiles/dirstate
180 src/.hg/largefiles/dirstate
181 src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
181 src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
182
182
183 Inject corruption into the largefiles store and see how update handles that:
183 Inject corruption into the largefiles store and see how update handles that:
184
184
185 $ cd src
185 $ cd src
186 $ hg up -qC
186 $ hg up -qC
187 $ cat large
187 $ cat large
188 modified
188 modified
189 $ rm large
189 $ rm large
190 $ cat .hglf/large
190 $ cat .hglf/large
191 e2fb5f2139d086ded2cb600d5a91a196e76bf020
191 e2fb5f2139d086ded2cb600d5a91a196e76bf020
192 $ mv .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 ..
192 $ mv .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 ..
193 $ echo corruption > .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
193 $ echo corruption > .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
194 $ hg up -C
194 $ hg up -C
195 getting changed largefiles
195 getting changed largefiles
196 large: data corruption in $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 with hash 6a7bb2556144babe3899b25e5428123735bb1e27
196 large: data corruption in $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 with hash 6a7bb2556144babe3899b25e5428123735bb1e27
197 0 largefiles updated, 0 removed
197 0 largefiles updated, 0 removed
198 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 $ hg st
199 $ hg st
200 ! large
200 ! large
201 ? z
201 ? z
202 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
202 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
203
203
204 #if serve
204 #if serve
205
205
206 Test coverage of error handling from putlfile:
206 Test coverage of error handling from putlfile:
207
207
208 $ mkdir $TESTTMP/mirrorcache
208 $ mkdir $TESTTMP/mirrorcache
209 $ hg serve -R ../mirror -d -p $HGPORT1 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache
209 $ hg serve -R ../mirror -d -p $HGPORT1 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache
210 $ cat hg.pid >> $DAEMON_PIDS
210 $ cat hg.pid >> $DAEMON_PIDS
211
211
212 (the following push fails but doesn't show why)
213 $ hg push http://localhost:$HGPORT1 -f --config files.usercache=nocache
212 $ hg push http://localhost:$HGPORT1 -f --config files.usercache=nocache
214 pushing to http://localhost:$HGPORT1/
213 pushing to http://localhost:$HGPORT1/
215 searching for changes
214 searching for changes
216 unexpected putlfile response: None
215 abort: remotestore: could not open file $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020: HTTP Error 403: ssl required
217 abort: remotestore: could not put $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 to remote store http://localhost:$HGPORT1/
218 [255]
216 [255]
219
217
220 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
218 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
221
219
222 Test coverage of 'missing from store':
220 Test coverage of 'missing from store':
223
221
224 $ hg serve -R ../mirror -d -p $HGPORT2 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache --config "web.allow_push=*" --config web.push_ssl=no
222 $ hg serve -R ../mirror -d -p $HGPORT2 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache --config "web.allow_push=*" --config web.push_ssl=no
225 $ cat hg.pid >> $DAEMON_PIDS
223 $ cat hg.pid >> $DAEMON_PIDS
226
224
227 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache
225 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache
228 pushing to http://localhost:$HGPORT2/
226 pushing to http://localhost:$HGPORT2/
229 searching for changes
227 searching for changes
230 abort: largefile e2fb5f2139d086ded2cb600d5a91a196e76bf020 missing from store (needs to be uploaded)
228 abort: largefile e2fb5f2139d086ded2cb600d5a91a196e76bf020 missing from store (needs to be uploaded)
231 [255]
229 [255]
232
230
233 #endif
231 #endif
General Comments 0
You need to be logged in to leave comments. Login now