##// END OF EJS Templates
lfs: use the localstore download method to transfer from remote stores...
Matt Harbison -
r35566:fd610bef default
parent child Browse files
Show More
@@ -1,468 +1,470 b''
1 # blobstore.py - local and remote (speaking Git-LFS protocol) blob storages
1 # blobstore.py - local and remote (speaking Git-LFS protocol) blob storages
2 #
2 #
3 # Copyright 2017 Facebook, Inc.
3 # Copyright 2017 Facebook, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import hashlib
10 import hashlib
11 import json
11 import json
12 import os
12 import os
13 import re
13 import re
14 import socket
14 import socket
15
15
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17
17
18 from mercurial import (
18 from mercurial import (
19 error,
19 error,
20 pathutil,
20 pathutil,
21 url as urlmod,
21 url as urlmod,
22 util,
22 util,
23 vfs as vfsmod,
23 vfs as vfsmod,
24 worker,
24 worker,
25 )
25 )
26
26
27 from ..largefiles import lfutil
27 from ..largefiles import lfutil
28
28
29 # 64 bytes for SHA256
29 # 64 bytes for SHA256
30 _lfsre = re.compile(r'\A[a-f0-9]{64}\Z')
30 _lfsre = re.compile(r'\A[a-f0-9]{64}\Z')
31
31
32 class lfsvfs(vfsmod.vfs):
32 class lfsvfs(vfsmod.vfs):
33 def join(self, path):
33 def join(self, path):
34 """split the path at first two characters, like: XX/XXXXX..."""
34 """split the path at first two characters, like: XX/XXXXX..."""
35 if not _lfsre.match(path):
35 if not _lfsre.match(path):
36 raise error.ProgrammingError('unexpected lfs path: %s' % path)
36 raise error.ProgrammingError('unexpected lfs path: %s' % path)
37 return super(lfsvfs, self).join(path[0:2], path[2:])
37 return super(lfsvfs, self).join(path[0:2], path[2:])
38
38
39 def walk(self, path=None, onerror=None):
39 def walk(self, path=None, onerror=None):
40 """Yield (dirpath, [], oids) tuple for blobs under path
40 """Yield (dirpath, [], oids) tuple for blobs under path
41
41
42 Oids only exist in the root of this vfs, so dirpath is always ''.
42 Oids only exist in the root of this vfs, so dirpath is always ''.
43 """
43 """
44 root = os.path.normpath(self.base)
44 root = os.path.normpath(self.base)
45 # when dirpath == root, dirpath[prefixlen:] becomes empty
45 # when dirpath == root, dirpath[prefixlen:] becomes empty
46 # because len(dirpath) < prefixlen.
46 # because len(dirpath) < prefixlen.
47 prefixlen = len(pathutil.normasprefix(root))
47 prefixlen = len(pathutil.normasprefix(root))
48 oids = []
48 oids = []
49
49
50 for dirpath, dirs, files in os.walk(self.reljoin(self.base, path or ''),
50 for dirpath, dirs, files in os.walk(self.reljoin(self.base, path or ''),
51 onerror=onerror):
51 onerror=onerror):
52 dirpath = dirpath[prefixlen:]
52 dirpath = dirpath[prefixlen:]
53
53
54 # Silently skip unexpected files and directories
54 # Silently skip unexpected files and directories
55 if len(dirpath) == 2:
55 if len(dirpath) == 2:
56 oids.extend([dirpath + f for f in files
56 oids.extend([dirpath + f for f in files
57 if _lfsre.match(dirpath + f)])
57 if _lfsre.match(dirpath + f)])
58
58
59 yield ('', [], oids)
59 yield ('', [], oids)
60
60
61 class filewithprogress(object):
61 class filewithprogress(object):
62 """a file-like object that supports __len__ and read.
62 """a file-like object that supports __len__ and read.
63
63
64 Useful to provide progress information for how many bytes are read.
64 Useful to provide progress information for how many bytes are read.
65 """
65 """
66
66
67 def __init__(self, fp, callback):
67 def __init__(self, fp, callback):
68 self._fp = fp
68 self._fp = fp
69 self._callback = callback # func(readsize)
69 self._callback = callback # func(readsize)
70 fp.seek(0, os.SEEK_END)
70 fp.seek(0, os.SEEK_END)
71 self._len = fp.tell()
71 self._len = fp.tell()
72 fp.seek(0)
72 fp.seek(0)
73
73
74 def __len__(self):
74 def __len__(self):
75 return self._len
75 return self._len
76
76
77 def read(self, size):
77 def read(self, size):
78 if self._fp is None:
78 if self._fp is None:
79 return b''
79 return b''
80 data = self._fp.read(size)
80 data = self._fp.read(size)
81 if data:
81 if data:
82 if self._callback:
82 if self._callback:
83 self._callback(len(data))
83 self._callback(len(data))
84 else:
84 else:
85 self._fp.close()
85 self._fp.close()
86 self._fp = None
86 self._fp = None
87 return data
87 return data
88
88
89 class local(object):
89 class local(object):
90 """Local blobstore for large file contents.
90 """Local blobstore for large file contents.
91
91
92 This blobstore is used both as a cache and as a staging area for large blobs
92 This blobstore is used both as a cache and as a staging area for large blobs
93 to be uploaded to the remote blobstore.
93 to be uploaded to the remote blobstore.
94 """
94 """
95
95
96 def __init__(self, repo):
96 def __init__(self, repo):
97 fullpath = repo.svfs.join('lfs/objects')
97 fullpath = repo.svfs.join('lfs/objects')
98 self.vfs = lfsvfs(fullpath)
98 self.vfs = lfsvfs(fullpath)
99 usercache = lfutil._usercachedir(repo.ui, 'lfs')
99 usercache = lfutil._usercachedir(repo.ui, 'lfs')
100 self.cachevfs = lfsvfs(usercache)
100 self.cachevfs = lfsvfs(usercache)
101 self.ui = repo.ui
101 self.ui = repo.ui
102
102
103 def open(self, oid):
103 def open(self, oid):
104 """Open a read-only file descriptor to the named blob, in either the
104 """Open a read-only file descriptor to the named blob, in either the
105 usercache or the local store."""
105 usercache or the local store."""
106 # The usercache is the most likely place to hold the file. Commit will
106 # The usercache is the most likely place to hold the file. Commit will
107 # write to both it and the local store, as will anything that downloads
107 # write to both it and the local store, as will anything that downloads
108 # the blobs. However, things like clone without an update won't
108 # the blobs. However, things like clone without an update won't
109 # populate the local store. For an init + push of a local clone,
109 # populate the local store. For an init + push of a local clone,
110 # the usercache is the only place it _could_ be. If not present, the
110 # the usercache is the only place it _could_ be. If not present, the
111 # missing file msg here will indicate the local repo, not the usercache.
111 # missing file msg here will indicate the local repo, not the usercache.
112 if self.cachevfs.exists(oid):
112 if self.cachevfs.exists(oid):
113 return self.cachevfs(oid, 'rb')
113 return self.cachevfs(oid, 'rb')
114
114
115 return self.vfs(oid, 'rb')
115 return self.vfs(oid, 'rb')
116
116
117 def download(self, oid, src):
117 def download(self, oid, src):
118 """Read the blob from the remote source in chunks, verify the content,
118 """Read the blob from the remote source in chunks, verify the content,
119 and write to this local blobstore."""
119 and write to this local blobstore."""
120 sha256 = hashlib.sha256()
120 sha256 = hashlib.sha256()
121
121
122 with self.vfs(oid, 'wb', atomictemp=True) as fp:
122 with self.vfs(oid, 'wb', atomictemp=True) as fp:
123 for chunk in util.filechunkiter(src, size=1048576):
123 for chunk in util.filechunkiter(src, size=1048576):
124 fp.write(chunk)
124 fp.write(chunk)
125 sha256.update(chunk)
125 sha256.update(chunk)
126
126
127 realoid = sha256.hexdigest()
127 realoid = sha256.hexdigest()
128 if realoid != oid:
128 if realoid != oid:
129 raise error.Abort(_('corrupt remote lfs object: %s') % oid)
129 raise error.Abort(_('corrupt remote lfs object: %s') % oid)
130
130
131 # XXX: should we verify the content of the cache, and hardlink back to
131 # XXX: should we verify the content of the cache, and hardlink back to
132 # the local store on success, but truncate, write and link on failure?
132 # the local store on success, but truncate, write and link on failure?
133 if not self.cachevfs.exists(oid):
133 if not self.cachevfs.exists(oid):
134 self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
134 self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
135 lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))
135 lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))
136
136
137 def write(self, oid, data, verify=True):
137 def write(self, oid, data, verify=True):
138 """Write blob to local blobstore."""
138 """Write blob to local blobstore."""
139 if verify:
139 if verify:
140 _verify(oid, data)
140 _verify(oid, data)
141
141
142 with self.vfs(oid, 'wb', atomictemp=True) as fp:
142 with self.vfs(oid, 'wb', atomictemp=True) as fp:
143 fp.write(data)
143 fp.write(data)
144
144
145 # XXX: should we verify the content of the cache, and hardlink back to
145 # XXX: should we verify the content of the cache, and hardlink back to
146 # the local store on success, but truncate, write and link on failure?
146 # the local store on success, but truncate, write and link on failure?
147 if not self.cachevfs.exists(oid):
147 if not self.cachevfs.exists(oid):
148 if verify or hashlib.sha256(data).hexdigest() == oid:
148 if verify or hashlib.sha256(data).hexdigest() == oid:
149 self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
149 self.ui.note(_('lfs: adding %s to the usercache\n') % oid)
150 lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))
150 lfutil.link(self.vfs.join(oid), self.cachevfs.join(oid))
151
151
152 def read(self, oid, verify=True):
152 def read(self, oid, verify=True):
153 """Read blob from local blobstore."""
153 """Read blob from local blobstore."""
154 if not self.vfs.exists(oid):
154 if not self.vfs.exists(oid):
155 blob = self._read(self.cachevfs, oid, verify)
155 blob = self._read(self.cachevfs, oid, verify)
156
156
157 # Even if revlog will verify the content, it needs to be verified
157 # Even if revlog will verify the content, it needs to be verified
158 # now before making the hardlink to avoid propagating corrupt blobs.
158 # now before making the hardlink to avoid propagating corrupt blobs.
159 # Don't abort if corruption is detected, because `hg verify` will
159 # Don't abort if corruption is detected, because `hg verify` will
160 # give more useful info about the corruption- simply don't add the
160 # give more useful info about the corruption- simply don't add the
161 # hardlink.
161 # hardlink.
162 if verify or hashlib.sha256(blob).hexdigest() == oid:
162 if verify or hashlib.sha256(blob).hexdigest() == oid:
163 self.ui.note(_('lfs: found %s in the usercache\n') % oid)
163 self.ui.note(_('lfs: found %s in the usercache\n') % oid)
164 lfutil.link(self.cachevfs.join(oid), self.vfs.join(oid))
164 lfutil.link(self.cachevfs.join(oid), self.vfs.join(oid))
165 else:
165 else:
166 self.ui.note(_('lfs: found %s in the local lfs store\n') % oid)
166 self.ui.note(_('lfs: found %s in the local lfs store\n') % oid)
167 blob = self._read(self.vfs, oid, verify)
167 blob = self._read(self.vfs, oid, verify)
168 return blob
168 return blob
169
169
170 def _read(self, vfs, oid, verify):
170 def _read(self, vfs, oid, verify):
171 """Read blob (after verifying) from the given store"""
171 """Read blob (after verifying) from the given store"""
172 blob = vfs.read(oid)
172 blob = vfs.read(oid)
173 if verify:
173 if verify:
174 _verify(oid, blob)
174 _verify(oid, blob)
175 return blob
175 return blob
176
176
177 def has(self, oid):
177 def has(self, oid):
178 """Returns True if the local blobstore contains the requested blob,
178 """Returns True if the local blobstore contains the requested blob,
179 False otherwise."""
179 False otherwise."""
180 return self.cachevfs.exists(oid) or self.vfs.exists(oid)
180 return self.cachevfs.exists(oid) or self.vfs.exists(oid)
181
181
182 class _gitlfsremote(object):
182 class _gitlfsremote(object):
183
183
184 def __init__(self, repo, url):
184 def __init__(self, repo, url):
185 ui = repo.ui
185 ui = repo.ui
186 self.ui = ui
186 self.ui = ui
187 baseurl, authinfo = url.authinfo()
187 baseurl, authinfo = url.authinfo()
188 self.baseurl = baseurl.rstrip('/')
188 self.baseurl = baseurl.rstrip('/')
189 useragent = repo.ui.config('experimental', 'lfs.user-agent')
189 useragent = repo.ui.config('experimental', 'lfs.user-agent')
190 if not useragent:
190 if not useragent:
191 useragent = 'mercurial/%s git/2.15.1' % util.version()
191 useragent = 'mercurial/%s git/2.15.1' % util.version()
192 self.urlopener = urlmod.opener(ui, authinfo, useragent)
192 self.urlopener = urlmod.opener(ui, authinfo, useragent)
193 self.retry = ui.configint('lfs', 'retry')
193 self.retry = ui.configint('lfs', 'retry')
194
194
195 def writebatch(self, pointers, fromstore):
195 def writebatch(self, pointers, fromstore):
196 """Batch upload from local to remote blobstore."""
196 """Batch upload from local to remote blobstore."""
197 self._batch(pointers, fromstore, 'upload')
197 self._batch(pointers, fromstore, 'upload')
198
198
199 def readbatch(self, pointers, tostore):
199 def readbatch(self, pointers, tostore):
200 """Batch download from remote to local blostore."""
200 """Batch download from remote to local blostore."""
201 self._batch(pointers, tostore, 'download')
201 self._batch(pointers, tostore, 'download')
202
202
203 def _batchrequest(self, pointers, action):
203 def _batchrequest(self, pointers, action):
204 """Get metadata about objects pointed by pointers for given action
204 """Get metadata about objects pointed by pointers for given action
205
205
206 Return decoded JSON object like {'objects': [{'oid': '', 'size': 1}]}
206 Return decoded JSON object like {'objects': [{'oid': '', 'size': 1}]}
207 See https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md
207 See https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md
208 """
208 """
209 objects = [{'oid': p.oid(), 'size': p.size()} for p in pointers]
209 objects = [{'oid': p.oid(), 'size': p.size()} for p in pointers]
210 requestdata = json.dumps({
210 requestdata = json.dumps({
211 'objects': objects,
211 'objects': objects,
212 'operation': action,
212 'operation': action,
213 })
213 })
214 batchreq = util.urlreq.request('%s/objects/batch' % self.baseurl,
214 batchreq = util.urlreq.request('%s/objects/batch' % self.baseurl,
215 data=requestdata)
215 data=requestdata)
216 batchreq.add_header('Accept', 'application/vnd.git-lfs+json')
216 batchreq.add_header('Accept', 'application/vnd.git-lfs+json')
217 batchreq.add_header('Content-Type', 'application/vnd.git-lfs+json')
217 batchreq.add_header('Content-Type', 'application/vnd.git-lfs+json')
218 try:
218 try:
219 rawjson = self.urlopener.open(batchreq).read()
219 rawjson = self.urlopener.open(batchreq).read()
220 except util.urlerr.httperror as ex:
220 except util.urlerr.httperror as ex:
221 raise LfsRemoteError(_('LFS HTTP error: %s (action=%s)')
221 raise LfsRemoteError(_('LFS HTTP error: %s (action=%s)')
222 % (ex, action))
222 % (ex, action))
223 try:
223 try:
224 response = json.loads(rawjson)
224 response = json.loads(rawjson)
225 except ValueError:
225 except ValueError:
226 raise LfsRemoteError(_('LFS server returns invalid JSON: %s')
226 raise LfsRemoteError(_('LFS server returns invalid JSON: %s')
227 % rawjson)
227 % rawjson)
228 return response
228 return response
229
229
230 def _checkforservererror(self, pointers, responses):
230 def _checkforservererror(self, pointers, responses):
231 """Scans errors from objects
231 """Scans errors from objects
232
232
233 Returns LfsRemoteError if any objects has an error"""
233 Returns LfsRemoteError if any objects has an error"""
234 for response in responses:
234 for response in responses:
235 error = response.get('error')
235 error = response.get('error')
236 if error:
236 if error:
237 ptrmap = {p.oid(): p for p in pointers}
237 ptrmap = {p.oid(): p for p in pointers}
238 p = ptrmap.get(response['oid'], None)
238 p = ptrmap.get(response['oid'], None)
239 if error['code'] == 404 and p:
239 if error['code'] == 404 and p:
240 filename = getattr(p, 'filename', 'unknown')
240 filename = getattr(p, 'filename', 'unknown')
241 raise LfsRemoteError(
241 raise LfsRemoteError(
242 _(('LFS server error. Remote object '
242 _(('LFS server error. Remote object '
243 'for file %s not found: %r')) % (filename, response))
243 'for file %s not found: %r')) % (filename, response))
244 raise LfsRemoteError(_('LFS server error: %r') % response)
244 raise LfsRemoteError(_('LFS server error: %r') % response)
245
245
246 def _extractobjects(self, response, pointers, action):
246 def _extractobjects(self, response, pointers, action):
247 """extract objects from response of the batch API
247 """extract objects from response of the batch API
248
248
249 response: parsed JSON object returned by batch API
249 response: parsed JSON object returned by batch API
250 return response['objects'] filtered by action
250 return response['objects'] filtered by action
251 raise if any object has an error
251 raise if any object has an error
252 """
252 """
253 # Scan errors from objects - fail early
253 # Scan errors from objects - fail early
254 objects = response.get('objects', [])
254 objects = response.get('objects', [])
255 self._checkforservererror(pointers, objects)
255 self._checkforservererror(pointers, objects)
256
256
257 # Filter objects with given action. Practically, this skips uploading
257 # Filter objects with given action. Practically, this skips uploading
258 # objects which exist in the server.
258 # objects which exist in the server.
259 filteredobjects = [o for o in objects if action in o.get('actions', [])]
259 filteredobjects = [o for o in objects if action in o.get('actions', [])]
260 # But for downloading, we want all objects. Therefore missing objects
260 # But for downloading, we want all objects. Therefore missing objects
261 # should be considered an error.
261 # should be considered an error.
262 if action == 'download':
262 if action == 'download':
263 if len(filteredobjects) < len(objects):
263 if len(filteredobjects) < len(objects):
264 missing = [o.get('oid', '?')
264 missing = [o.get('oid', '?')
265 for o in objects
265 for o in objects
266 if action not in o.get('actions', [])]
266 if action not in o.get('actions', [])]
267 raise LfsRemoteError(
267 raise LfsRemoteError(
268 _('LFS server claims required objects do not exist:\n%s')
268 _('LFS server claims required objects do not exist:\n%s')
269 % '\n'.join(missing))
269 % '\n'.join(missing))
270
270
271 return filteredobjects
271 return filteredobjects
272
272
273 def _basictransfer(self, obj, action, localstore):
273 def _basictransfer(self, obj, action, localstore):
274 """Download or upload a single object using basic transfer protocol
274 """Download or upload a single object using basic transfer protocol
275
275
276 obj: dict, an object description returned by batch API
276 obj: dict, an object description returned by batch API
277 action: string, one of ['upload', 'download']
277 action: string, one of ['upload', 'download']
278 localstore: blobstore.local
278 localstore: blobstore.local
279
279
280 See https://github.com/git-lfs/git-lfs/blob/master/docs/api/\
280 See https://github.com/git-lfs/git-lfs/blob/master/docs/api/\
281 basic-transfers.md
281 basic-transfers.md
282 """
282 """
283 oid = str(obj['oid'])
283 oid = str(obj['oid'])
284
284
285 href = str(obj['actions'][action].get('href'))
285 href = str(obj['actions'][action].get('href'))
286 headers = obj['actions'][action].get('header', {}).items()
286 headers = obj['actions'][action].get('header', {}).items()
287
287
288 request = util.urlreq.request(href)
288 request = util.urlreq.request(href)
289 if action == 'upload':
289 if action == 'upload':
290 # If uploading blobs, read data from local blobstore.
290 # If uploading blobs, read data from local blobstore.
291 with localstore.open(oid) as fp:
291 with localstore.open(oid) as fp:
292 _verifyfile(oid, fp)
292 _verifyfile(oid, fp)
293 request.data = filewithprogress(localstore.open(oid), None)
293 request.data = filewithprogress(localstore.open(oid), None)
294 request.get_method = lambda: 'PUT'
294 request.get_method = lambda: 'PUT'
295
295
296 for k, v in headers:
296 for k, v in headers:
297 request.add_header(k, v)
297 request.add_header(k, v)
298
298
299 response = b''
299 response = b''
300 try:
300 try:
301 req = self.urlopener.open(request)
301 req = self.urlopener.open(request)
302 while True:
302 if action == 'download':
303 data = req.read(1048576)
303 # If downloading blobs, store downloaded data to local blobstore
304 if not data:
304 localstore.download(oid, req)
305 break
305 else:
306 response += data
306 while True:
307 data = req.read(1048576)
308 if not data:
309 break
310 response += data
311 if response:
312 self.ui.debug('lfs %s response: %s' % (action, response))
307 except util.urlerr.httperror as ex:
313 except util.urlerr.httperror as ex:
308 raise LfsRemoteError(_('HTTP error: %s (oid=%s, action=%s)')
314 raise LfsRemoteError(_('HTTP error: %s (oid=%s, action=%s)')
309 % (ex, oid, action))
315 % (ex, oid, action))
310
316
311 if action == 'download':
312 # If downloading blobs, store downloaded data to local blobstore
313 localstore.write(oid, response, verify=True)
314
315 def _batch(self, pointers, localstore, action):
317 def _batch(self, pointers, localstore, action):
316 if action not in ['upload', 'download']:
318 if action not in ['upload', 'download']:
317 raise error.ProgrammingError('invalid Git-LFS action: %s' % action)
319 raise error.ProgrammingError('invalid Git-LFS action: %s' % action)
318
320
319 response = self._batchrequest(pointers, action)
321 response = self._batchrequest(pointers, action)
320 objects = self._extractobjects(response, pointers, action)
322 objects = self._extractobjects(response, pointers, action)
321 total = sum(x.get('size', 0) for x in objects)
323 total = sum(x.get('size', 0) for x in objects)
322 sizes = {}
324 sizes = {}
323 for obj in objects:
325 for obj in objects:
324 sizes[obj.get('oid')] = obj.get('size', 0)
326 sizes[obj.get('oid')] = obj.get('size', 0)
325 topic = {'upload': _('lfs uploading'),
327 topic = {'upload': _('lfs uploading'),
326 'download': _('lfs downloading')}[action]
328 'download': _('lfs downloading')}[action]
327 if len(objects) > 1:
329 if len(objects) > 1:
328 self.ui.note(_('lfs: need to transfer %d objects (%s)\n')
330 self.ui.note(_('lfs: need to transfer %d objects (%s)\n')
329 % (len(objects), util.bytecount(total)))
331 % (len(objects), util.bytecount(total)))
330 self.ui.progress(topic, 0, total=total)
332 self.ui.progress(topic, 0, total=total)
331 def transfer(chunk):
333 def transfer(chunk):
332 for obj in chunk:
334 for obj in chunk:
333 objsize = obj.get('size', 0)
335 objsize = obj.get('size', 0)
334 if self.ui.verbose:
336 if self.ui.verbose:
335 if action == 'download':
337 if action == 'download':
336 msg = _('lfs: downloading %s (%s)\n')
338 msg = _('lfs: downloading %s (%s)\n')
337 elif action == 'upload':
339 elif action == 'upload':
338 msg = _('lfs: uploading %s (%s)\n')
340 msg = _('lfs: uploading %s (%s)\n')
339 self.ui.note(msg % (obj.get('oid'),
341 self.ui.note(msg % (obj.get('oid'),
340 util.bytecount(objsize)))
342 util.bytecount(objsize)))
341 retry = self.retry
343 retry = self.retry
342 while True:
344 while True:
343 try:
345 try:
344 self._basictransfer(obj, action, localstore)
346 self._basictransfer(obj, action, localstore)
345 yield 1, obj.get('oid')
347 yield 1, obj.get('oid')
346 break
348 break
347 except socket.error as ex:
349 except socket.error as ex:
348 if retry > 0:
350 if retry > 0:
349 self.ui.note(
351 self.ui.note(
350 _('lfs: failed: %r (remaining retry %d)\n')
352 _('lfs: failed: %r (remaining retry %d)\n')
351 % (ex, retry))
353 % (ex, retry))
352 retry -= 1
354 retry -= 1
353 continue
355 continue
354 raise
356 raise
355
357
356 oids = worker.worker(self.ui, 0.1, transfer, (),
358 oids = worker.worker(self.ui, 0.1, transfer, (),
357 sorted(objects, key=lambda o: o.get('oid')))
359 sorted(objects, key=lambda o: o.get('oid')))
358 processed = 0
360 processed = 0
359 for _one, oid in oids:
361 for _one, oid in oids:
360 processed += sizes[oid]
362 processed += sizes[oid]
361 self.ui.progress(topic, processed, total=total)
363 self.ui.progress(topic, processed, total=total)
362 self.ui.note(_('lfs: processed: %s\n') % oid)
364 self.ui.note(_('lfs: processed: %s\n') % oid)
363 self.ui.progress(topic, pos=None, total=total)
365 self.ui.progress(topic, pos=None, total=total)
364
366
365 def __del__(self):
367 def __del__(self):
366 # copied from mercurial/httppeer.py
368 # copied from mercurial/httppeer.py
367 urlopener = getattr(self, 'urlopener', None)
369 urlopener = getattr(self, 'urlopener', None)
368 if urlopener:
370 if urlopener:
369 for h in urlopener.handlers:
371 for h in urlopener.handlers:
370 h.close()
372 h.close()
371 getattr(h, "close_all", lambda : None)()
373 getattr(h, "close_all", lambda : None)()
372
374
373 class _dummyremote(object):
375 class _dummyremote(object):
374 """Dummy store storing blobs to temp directory."""
376 """Dummy store storing blobs to temp directory."""
375
377
376 def __init__(self, repo, url):
378 def __init__(self, repo, url):
377 fullpath = repo.vfs.join('lfs', url.path)
379 fullpath = repo.vfs.join('lfs', url.path)
378 self.vfs = lfsvfs(fullpath)
380 self.vfs = lfsvfs(fullpath)
379
381
380 def writebatch(self, pointers, fromstore):
382 def writebatch(self, pointers, fromstore):
381 for p in pointers:
383 for p in pointers:
382 content = fromstore.read(p.oid(), verify=True)
384 content = fromstore.read(p.oid(), verify=True)
383 with self.vfs(p.oid(), 'wb', atomictemp=True) as fp:
385 with self.vfs(p.oid(), 'wb', atomictemp=True) as fp:
384 fp.write(content)
386 fp.write(content)
385
387
386 def readbatch(self, pointers, tostore):
388 def readbatch(self, pointers, tostore):
387 for p in pointers:
389 for p in pointers:
388 content = self.vfs.read(p.oid())
390 with self.vfs(p.oid(), 'rb') as fp:
389 tostore.write(p.oid(), content, verify=True)
391 tostore.download(p.oid(), fp)
390
392
391 class _nullremote(object):
393 class _nullremote(object):
392 """Null store storing blobs to /dev/null."""
394 """Null store storing blobs to /dev/null."""
393
395
394 def __init__(self, repo, url):
396 def __init__(self, repo, url):
395 pass
397 pass
396
398
397 def writebatch(self, pointers, fromstore):
399 def writebatch(self, pointers, fromstore):
398 pass
400 pass
399
401
400 def readbatch(self, pointers, tostore):
402 def readbatch(self, pointers, tostore):
401 pass
403 pass
402
404
403 class _promptremote(object):
405 class _promptremote(object):
404 """Prompt user to set lfs.url when accessed."""
406 """Prompt user to set lfs.url when accessed."""
405
407
406 def __init__(self, repo, url):
408 def __init__(self, repo, url):
407 pass
409 pass
408
410
409 def writebatch(self, pointers, fromstore, ui=None):
411 def writebatch(self, pointers, fromstore, ui=None):
410 self._prompt()
412 self._prompt()
411
413
412 def readbatch(self, pointers, tostore, ui=None):
414 def readbatch(self, pointers, tostore, ui=None):
413 self._prompt()
415 self._prompt()
414
416
415 def _prompt(self):
417 def _prompt(self):
416 raise error.Abort(_('lfs.url needs to be configured'))
418 raise error.Abort(_('lfs.url needs to be configured'))
417
419
418 _storemap = {
420 _storemap = {
419 'https': _gitlfsremote,
421 'https': _gitlfsremote,
420 'http': _gitlfsremote,
422 'http': _gitlfsremote,
421 'file': _dummyremote,
423 'file': _dummyremote,
422 'null': _nullremote,
424 'null': _nullremote,
423 None: _promptremote,
425 None: _promptremote,
424 }
426 }
425
427
426 def _verify(oid, content):
428 def _verify(oid, content):
427 realoid = hashlib.sha256(content).hexdigest()
429 realoid = hashlib.sha256(content).hexdigest()
428 if realoid != oid:
430 if realoid != oid:
429 raise error.Abort(_('detected corrupt lfs object: %s') % oid,
431 raise error.Abort(_('detected corrupt lfs object: %s') % oid,
430 hint=_('run hg verify'))
432 hint=_('run hg verify'))
431
433
432 def _verifyfile(oid, fp):
434 def _verifyfile(oid, fp):
433 sha256 = hashlib.sha256()
435 sha256 = hashlib.sha256()
434 while True:
436 while True:
435 data = fp.read(1024 * 1024)
437 data = fp.read(1024 * 1024)
436 if not data:
438 if not data:
437 break
439 break
438 sha256.update(data)
440 sha256.update(data)
439 realoid = sha256.hexdigest()
441 realoid = sha256.hexdigest()
440 if realoid != oid:
442 if realoid != oid:
441 raise error.Abort(_('detected corrupt lfs object: %s') % oid,
443 raise error.Abort(_('detected corrupt lfs object: %s') % oid,
442 hint=_('run hg verify'))
444 hint=_('run hg verify'))
443
445
444 def remote(repo):
446 def remote(repo):
445 """remotestore factory. return a store in _storemap depending on config"""
447 """remotestore factory. return a store in _storemap depending on config"""
446 defaulturl = ''
448 defaulturl = ''
447
449
448 # convert deprecated configs to the new url. TODO: remove this if other
450 # convert deprecated configs to the new url. TODO: remove this if other
449 # places are migrated to the new url config.
451 # places are migrated to the new url config.
450 # deprecated config: lfs.remotestore
452 # deprecated config: lfs.remotestore
451 deprecatedstore = repo.ui.config('lfs', 'remotestore')
453 deprecatedstore = repo.ui.config('lfs', 'remotestore')
452 if deprecatedstore == 'dummy':
454 if deprecatedstore == 'dummy':
453 # deprecated config: lfs.remotepath
455 # deprecated config: lfs.remotepath
454 defaulturl = 'file://' + repo.ui.config('lfs', 'remotepath')
456 defaulturl = 'file://' + repo.ui.config('lfs', 'remotepath')
455 elif deprecatedstore == 'git-lfs':
457 elif deprecatedstore == 'git-lfs':
456 # deprecated config: lfs.remoteurl
458 # deprecated config: lfs.remoteurl
457 defaulturl = repo.ui.config('lfs', 'remoteurl')
459 defaulturl = repo.ui.config('lfs', 'remoteurl')
458 elif deprecatedstore == 'null':
460 elif deprecatedstore == 'null':
459 defaulturl = 'null://'
461 defaulturl = 'null://'
460
462
461 url = util.url(repo.ui.config('lfs', 'url', defaulturl))
463 url = util.url(repo.ui.config('lfs', 'url', defaulturl))
462 scheme = url.scheme
464 scheme = url.scheme
463 if scheme not in _storemap:
465 if scheme not in _storemap:
464 raise error.Abort(_('lfs: unknown url scheme: %s') % scheme)
466 raise error.Abort(_('lfs: unknown url scheme: %s') % scheme)
465 return _storemap[scheme](repo, url)
467 return _storemap[scheme](repo, url)
466
468
467 class LfsRemoteError(error.RevlogError):
469 class LfsRemoteError(error.RevlogError):
468 pass
470 pass
@@ -1,193 +1,191 b''
1 #require lfs-test-server
1 #require lfs-test-server
2
2
3 $ LFS_LISTEN="tcp://:$HGPORT"
3 $ LFS_LISTEN="tcp://:$HGPORT"
4 $ LFS_HOST="localhost:$HGPORT"
4 $ LFS_HOST="localhost:$HGPORT"
5 $ LFS_PUBLIC=1
5 $ LFS_PUBLIC=1
6 $ export LFS_LISTEN LFS_HOST LFS_PUBLIC
6 $ export LFS_LISTEN LFS_HOST LFS_PUBLIC
7 #if no-windows
7 #if no-windows
8 $ lfs-test-server &> lfs-server.log &
8 $ lfs-test-server &> lfs-server.log &
9 $ echo $! >> $DAEMON_PIDS
9 $ echo $! >> $DAEMON_PIDS
10 #else
10 #else
11 $ cat >> $TESTTMP/spawn.py <<EOF
11 $ cat >> $TESTTMP/spawn.py <<EOF
12 > import os
12 > import os
13 > import subprocess
13 > import subprocess
14 > import sys
14 > import sys
15 >
15 >
16 > for path in os.environ["PATH"].split(os.pathsep):
16 > for path in os.environ["PATH"].split(os.pathsep):
17 > exe = os.path.join(path, 'lfs-test-server.exe')
17 > exe = os.path.join(path, 'lfs-test-server.exe')
18 > if os.path.exists(exe):
18 > if os.path.exists(exe):
19 > with open('lfs-server.log', 'wb') as out:
19 > with open('lfs-server.log', 'wb') as out:
20 > p = subprocess.Popen(exe, stdout=out, stderr=out)
20 > p = subprocess.Popen(exe, stdout=out, stderr=out)
21 > sys.stdout.write('%s\n' % p.pid)
21 > sys.stdout.write('%s\n' % p.pid)
22 > sys.exit(0)
22 > sys.exit(0)
23 > sys.exit(1)
23 > sys.exit(1)
24 > EOF
24 > EOF
25 $ $PYTHON $TESTTMP/spawn.py >> $DAEMON_PIDS
25 $ $PYTHON $TESTTMP/spawn.py >> $DAEMON_PIDS
26 #endif
26 #endif
27
27
28 $ cat >> $HGRCPATH <<EOF
28 $ cat >> $HGRCPATH <<EOF
29 > [extensions]
29 > [extensions]
30 > lfs=
30 > lfs=
31 > [lfs]
31 > [lfs]
32 > url=http://foo:bar@$LFS_HOST/
32 > url=http://foo:bar@$LFS_HOST/
33 > threshold=1
33 > threshold=1
34 > EOF
34 > EOF
35
35
36 $ hg init repo1
36 $ hg init repo1
37 $ cd repo1
37 $ cd repo1
38 $ echo THIS-IS-LFS > a
38 $ echo THIS-IS-LFS > a
39 $ hg commit -m a -A a
39 $ hg commit -m a -A a
40
40
41 A push can be serviced directly from the usercache if it isn't in the local
41 A push can be serviced directly from the usercache if it isn't in the local
42 store.
42 store.
43
43
44 $ hg init ../repo2
44 $ hg init ../repo2
45 $ mv .hg/store/lfs .hg/store/lfs_
45 $ mv .hg/store/lfs .hg/store/lfs_
46 $ hg push ../repo2 -v
46 $ hg push ../repo2 -v
47 pushing to ../repo2
47 pushing to ../repo2
48 searching for changes
48 searching for changes
49 lfs: uploading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
49 lfs: uploading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
50 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
50 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
51 1 changesets found
51 1 changesets found
52 uncompressed size of bundle content:
52 uncompressed size of bundle content:
53 * (changelog) (glob)
53 * (changelog) (glob)
54 * (manifests) (glob)
54 * (manifests) (glob)
55 * a (glob)
55 * a (glob)
56 adding changesets
56 adding changesets
57 adding manifests
57 adding manifests
58 adding file changes
58 adding file changes
59 added 1 changesets with 1 changes to 1 files
59 added 1 changesets with 1 changes to 1 files
60 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
60 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
61 $ mv .hg/store/lfs_ .hg/store/lfs
61 $ mv .hg/store/lfs_ .hg/store/lfs
62
62
63 Clear the cache to force a download
63 Clear the cache to force a download
64 $ rm -rf `hg config lfs.usercache`
64 $ rm -rf `hg config lfs.usercache`
65 $ cd ../repo2
65 $ cd ../repo2
66 $ hg update tip -v
66 $ hg update tip -v
67 resolving manifests
67 resolving manifests
68 getting a
68 getting a
69 lfs: downloading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
69 lfs: downloading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
70 lfs: adding 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b to the usercache
70 lfs: adding 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b to the usercache
71 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
71 lfs: processed: 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b
72 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
72 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
73 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
73 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
74
74
75 When the server has some blobs already
75 When the server has some blobs already
76
76
77 $ hg mv a b
77 $ hg mv a b
78 $ echo ANOTHER-LARGE-FILE > c
78 $ echo ANOTHER-LARGE-FILE > c
79 $ echo ANOTHER-LARGE-FILE2 > d
79 $ echo ANOTHER-LARGE-FILE2 > d
80 $ hg commit -m b-and-c -A b c d
80 $ hg commit -m b-and-c -A b c d
81 $ hg push ../repo1 -v | grep -v '^ '
81 $ hg push ../repo1 -v | grep -v '^ '
82 pushing to ../repo1
82 pushing to ../repo1
83 searching for changes
83 searching for changes
84 lfs: need to transfer 2 objects (39 bytes)
84 lfs: need to transfer 2 objects (39 bytes)
85 lfs: uploading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
85 lfs: uploading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
86 lfs: processed: 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
86 lfs: processed: 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
87 lfs: uploading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
87 lfs: uploading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
88 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
88 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
89 1 changesets found
89 1 changesets found
90 uncompressed size of bundle content:
90 uncompressed size of bundle content:
91 adding changesets
91 adding changesets
92 adding manifests
92 adding manifests
93 adding file changes
93 adding file changes
94 added 1 changesets with 3 changes to 3 files
94 added 1 changesets with 3 changes to 3 files
95
95
96 Clear the cache to force a download
96 Clear the cache to force a download
97 $ rm -rf `hg config lfs.usercache`
97 $ rm -rf `hg config lfs.usercache`
98 $ hg --repo ../repo1 update tip -v
98 $ hg --repo ../repo1 update tip -v
99 resolving manifests
99 resolving manifests
100 getting b
100 getting b
101 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
101 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
102 getting c
102 getting c
103 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
103 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
104 lfs: adding d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 to the usercache
104 lfs: adding d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 to the usercache
105 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
105 lfs: processed: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
106 lfs: found d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 in the local lfs store
106 lfs: found d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 in the local lfs store
107 getting d
107 getting d
108 lfs: downloading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
108 lfs: downloading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
109 lfs: adding 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 to the usercache
109 lfs: adding 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 to the usercache
110 lfs: processed: 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
110 lfs: processed: 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19
111 lfs: found 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 in the local lfs store
111 lfs: found 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 in the local lfs store
112 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
112 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
113
113
114 Test a corrupt file download, but clear the cache first to force a download.
114 Test a corrupt file download, but clear the cache first to force a download.
115
115
116 $ rm -rf `hg config lfs.usercache`
116 $ rm -rf `hg config lfs.usercache`
117 $ cp $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 blob
117 $ cp $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 blob
118 $ echo 'damage' > $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
118 $ echo 'damage' > $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
119 $ rm ../repo1/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
119 $ rm ../repo1/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
120 $ rm ../repo1/*
120 $ rm ../repo1/*
121
121
122 XXX: suggesting `hg verify` won't help with a corrupt file on the lfs server.
123 $ hg --repo ../repo1 update -C tip -v
122 $ hg --repo ../repo1 update -C tip -v
124 resolving manifests
123 resolving manifests
125 getting a
124 getting a
126 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
125 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
127 getting b
126 getting b
128 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
127 lfs: found 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b in the local lfs store
129 getting c
128 getting c
130 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
129 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
131 abort: detected corrupt lfs object: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
130 abort: corrupt remote lfs object: d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
132 (run hg verify)
133 [255]
131 [255]
134
132
135 The corrupted blob is not added to the usercache or local store
133 The corrupted blob is not added to the usercache or local store
136
134
137 $ test -f ../repo1/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
135 $ test -f ../repo1/.hg/store/lfs/objects/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
138 [1]
136 [1]
139 $ test -f `hg config lfs.usercache`/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
137 $ test -f `hg config lfs.usercache`/d1/1e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
140 [1]
138 [1]
141 $ cp blob $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
139 $ cp blob $TESTTMP/lfs-content/d1/1e/1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998
142
140
143 Test a corrupted file upload
141 Test a corrupted file upload
144
142
145 $ echo 'another lfs blob' > b
143 $ echo 'another lfs blob' > b
146 $ hg ci -m 'another blob'
144 $ hg ci -m 'another blob'
147 $ echo 'damage' > .hg/store/lfs/objects/e6/59058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0
145 $ echo 'damage' > .hg/store/lfs/objects/e6/59058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0
148 $ hg push -v ../repo1
146 $ hg push -v ../repo1
149 pushing to ../repo1
147 pushing to ../repo1
150 searching for changes
148 searching for changes
151 lfs: uploading e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0 (17 bytes)
149 lfs: uploading e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0 (17 bytes)
152 abort: detected corrupt lfs object: e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0
150 abort: detected corrupt lfs object: e659058e26b07b39d2a9c7145b3f99b41f797b6621c8076600e9cb7ee88291f0
153 (run hg verify)
151 (run hg verify)
154 [255]
152 [255]
155
153
156 Check error message when the remote missed a blob:
154 Check error message when the remote missed a blob:
157
155
158 $ echo FFFFF > b
156 $ echo FFFFF > b
159 $ hg commit -m b -A b
157 $ hg commit -m b -A b
160 $ echo FFFFF >> b
158 $ echo FFFFF >> b
161 $ hg commit -m b b
159 $ hg commit -m b b
162 $ rm -rf .hg/store/lfs
160 $ rm -rf .hg/store/lfs
163 $ rm -rf `hg config lfs.usercache`
161 $ rm -rf `hg config lfs.usercache`
164 $ hg update -C '.^'
162 $ hg update -C '.^'
165 abort: LFS server claims required objects do not exist:
163 abort: LFS server claims required objects do not exist:
166 8e6ea5f6c066b44a0efa43bcce86aea73f17e6e23f0663df0251e7524e140a13!
164 8e6ea5f6c066b44a0efa43bcce86aea73f17e6e23f0663df0251e7524e140a13!
167 [255]
165 [255]
168
166
169 Check error message when object does not exist:
167 Check error message when object does not exist:
170
168
171 $ hg init test && cd test
169 $ hg init test && cd test
172 $ echo "[extensions]" >> .hg/hgrc
170 $ echo "[extensions]" >> .hg/hgrc
173 $ echo "lfs=" >> .hg/hgrc
171 $ echo "lfs=" >> .hg/hgrc
174 $ echo "[lfs]" >> .hg/hgrc
172 $ echo "[lfs]" >> .hg/hgrc
175 $ echo "threshold=1" >> .hg/hgrc
173 $ echo "threshold=1" >> .hg/hgrc
176 $ echo a > a
174 $ echo a > a
177 $ hg add a
175 $ hg add a
178 $ hg commit -m 'test'
176 $ hg commit -m 'test'
179 $ echo aaaaa > a
177 $ echo aaaaa > a
180 $ hg commit -m 'largefile'
178 $ hg commit -m 'largefile'
181 $ hg debugdata .hg/store/data/a.i 1 # verify this is no the file content but includes "oid", the LFS "pointer".
179 $ hg debugdata .hg/store/data/a.i 1 # verify this is no the file content but includes "oid", the LFS "pointer".
182 version https://git-lfs.github.com/spec/v1
180 version https://git-lfs.github.com/spec/v1
183 oid sha256:bdc26931acfb734b142a8d675f205becf27560dc461f501822de13274fe6fc8a
181 oid sha256:bdc26931acfb734b142a8d675f205becf27560dc461f501822de13274fe6fc8a
184 size 6
182 size 6
185 x-is-binary 0
183 x-is-binary 0
186 $ cd ..
184 $ cd ..
187 $ rm -rf `hg config lfs.usercache`
185 $ rm -rf `hg config lfs.usercache`
188 $ hg --config 'lfs.url=https://dewey-lfs.vip.facebook.com/lfs' clone test test2
186 $ hg --config 'lfs.url=https://dewey-lfs.vip.facebook.com/lfs' clone test test2
189 updating to branch default
187 updating to branch default
190 abort: LFS server error. Remote object for file data/a.i not found:(.*)! (re)
188 abort: LFS server error. Remote object for file data/a.i not found:(.*)! (re)
191 [255]
189 [255]
192
190
193 $ $PYTHON $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
191 $ $PYTHON $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
@@ -1,916 +1,915 b''
1 # Initial setup
1 # Initial setup
2
2
3 $ cat >> $HGRCPATH << EOF
3 $ cat >> $HGRCPATH << EOF
4 > [extensions]
4 > [extensions]
5 > lfs=
5 > lfs=
6 > [lfs]
6 > [lfs]
7 > threshold=1000B
7 > threshold=1000B
8 > EOF
8 > EOF
9
9
10 $ LONG=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
10 $ LONG=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
11
11
12 # Prepare server and enable extension
12 # Prepare server and enable extension
13 $ hg init server
13 $ hg init server
14 $ hg clone -q server client
14 $ hg clone -q server client
15 $ cd client
15 $ cd client
16
16
17 # Commit small file
17 # Commit small file
18 $ echo s > smallfile
18 $ echo s > smallfile
19 $ hg commit -Aqm "add small file"
19 $ hg commit -Aqm "add small file"
20
20
21 # Commit large file
21 # Commit large file
22 $ echo $LONG > largefile
22 $ echo $LONG > largefile
23 $ grep lfs .hg/requires
23 $ grep lfs .hg/requires
24 [1]
24 [1]
25 $ hg commit --traceback -Aqm "add large file"
25 $ hg commit --traceback -Aqm "add large file"
26 $ grep lfs .hg/requires
26 $ grep lfs .hg/requires
27 lfs
27 lfs
28
28
29 # Ensure metadata is stored
29 # Ensure metadata is stored
30 $ hg debugdata largefile 0
30 $ hg debugdata largefile 0
31 version https://git-lfs.github.com/spec/v1
31 version https://git-lfs.github.com/spec/v1
32 oid sha256:f11e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
32 oid sha256:f11e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
33 size 1501
33 size 1501
34 x-is-binary 0
34 x-is-binary 0
35
35
36 # Check the blobstore is populated
36 # Check the blobstore is populated
37 $ find .hg/store/lfs/objects | sort
37 $ find .hg/store/lfs/objects | sort
38 .hg/store/lfs/objects
38 .hg/store/lfs/objects
39 .hg/store/lfs/objects/f1
39 .hg/store/lfs/objects/f1
40 .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
40 .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
41
41
42 # Check the blob stored contains the actual contents of the file
42 # Check the blob stored contains the actual contents of the file
43 $ cat .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
43 $ cat .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
44 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
44 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
45
45
46 # Push changes to the server
46 # Push changes to the server
47
47
48 $ hg push
48 $ hg push
49 pushing to $TESTTMP/server
49 pushing to $TESTTMP/server
50 searching for changes
50 searching for changes
51 abort: lfs.url needs to be configured
51 abort: lfs.url needs to be configured
52 [255]
52 [255]
53
53
54 $ cat >> $HGRCPATH << EOF
54 $ cat >> $HGRCPATH << EOF
55 > [lfs]
55 > [lfs]
56 > url=file:$TESTTMP/dummy-remote/
56 > url=file:$TESTTMP/dummy-remote/
57 > EOF
57 > EOF
58
58
59 Push to a local non-lfs repo with the extension enabled will add the
59 Push to a local non-lfs repo with the extension enabled will add the
60 lfs requirement
60 lfs requirement
61
61
62 $ grep lfs $TESTTMP/server/.hg/requires
62 $ grep lfs $TESTTMP/server/.hg/requires
63 [1]
63 [1]
64 $ hg push -v | egrep -v '^(uncompressed| )'
64 $ hg push -v | egrep -v '^(uncompressed| )'
65 pushing to $TESTTMP/server
65 pushing to $TESTTMP/server
66 searching for changes
66 searching for changes
67 lfs: found f11e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b in the local lfs store
67 lfs: found f11e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b in the local lfs store
68 2 changesets found
68 2 changesets found
69 adding changesets
69 adding changesets
70 adding manifests
70 adding manifests
71 adding file changes
71 adding file changes
72 added 2 changesets with 2 changes to 2 files
72 added 2 changesets with 2 changes to 2 files
73 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
73 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
74 $ grep lfs $TESTTMP/server/.hg/requires
74 $ grep lfs $TESTTMP/server/.hg/requires
75 lfs
75 lfs
76
76
77 # Unknown URL scheme
77 # Unknown URL scheme
78
78
79 $ hg push --config lfs.url=ftp://foobar
79 $ hg push --config lfs.url=ftp://foobar
80 abort: lfs: unknown url scheme: ftp
80 abort: lfs: unknown url scheme: ftp
81 [255]
81 [255]
82
82
83 $ cd ../
83 $ cd ../
84
84
85 # Initialize new client (not cloning) and setup extension
85 # Initialize new client (not cloning) and setup extension
86 $ hg init client2
86 $ hg init client2
87 $ cd client2
87 $ cd client2
88 $ cat >> .hg/hgrc <<EOF
88 $ cat >> .hg/hgrc <<EOF
89 > [paths]
89 > [paths]
90 > default = $TESTTMP/server
90 > default = $TESTTMP/server
91 > EOF
91 > EOF
92
92
93 # Pull from server
93 # Pull from server
94
94
95 Pulling a local lfs repo into a local non-lfs repo with the extension
95 Pulling a local lfs repo into a local non-lfs repo with the extension
96 enabled adds the lfs requirement
96 enabled adds the lfs requirement
97
97
98 $ grep lfs .hg/requires $TESTTMP/server/.hg/requires
98 $ grep lfs .hg/requires $TESTTMP/server/.hg/requires
99 $TESTTMP/server/.hg/requires:lfs
99 $TESTTMP/server/.hg/requires:lfs
100 $ hg pull default
100 $ hg pull default
101 pulling from $TESTTMP/server
101 pulling from $TESTTMP/server
102 requesting all changes
102 requesting all changes
103 adding changesets
103 adding changesets
104 adding manifests
104 adding manifests
105 adding file changes
105 adding file changes
106 added 2 changesets with 2 changes to 2 files
106 added 2 changesets with 2 changes to 2 files
107 new changesets b29ba743f89d:00c137947d30
107 new changesets b29ba743f89d:00c137947d30
108 (run 'hg update' to get a working copy)
108 (run 'hg update' to get a working copy)
109 $ grep lfs .hg/requires $TESTTMP/server/.hg/requires
109 $ grep lfs .hg/requires $TESTTMP/server/.hg/requires
110 .hg/requires:lfs
110 .hg/requires:lfs
111 $TESTTMP/server/.hg/requires:lfs
111 $TESTTMP/server/.hg/requires:lfs
112
112
113 # Check the blobstore is not yet populated
113 # Check the blobstore is not yet populated
114 $ [ -d .hg/store/lfs/objects ]
114 $ [ -d .hg/store/lfs/objects ]
115 [1]
115 [1]
116
116
117 # Update to the last revision containing the large file
117 # Update to the last revision containing the large file
118 $ hg update
118 $ hg update
119 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
120
120
121 # Check the blobstore has been populated on update
121 # Check the blobstore has been populated on update
122 $ find .hg/store/lfs/objects | sort
122 $ find .hg/store/lfs/objects | sort
123 .hg/store/lfs/objects
123 .hg/store/lfs/objects
124 .hg/store/lfs/objects/f1
124 .hg/store/lfs/objects/f1
125 .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
125 .hg/store/lfs/objects/f1/1e77c257047a398492d8d6cb9f6acf3aa7c4384bb23080b43546053e183e4b
126
126
127 # Check the contents of the file are fetched from blobstore when requested
127 # Check the contents of the file are fetched from blobstore when requested
128 $ hg cat -r . largefile
128 $ hg cat -r . largefile
129 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
129 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
130
130
131 # Check the file has been copied in the working copy
131 # Check the file has been copied in the working copy
132 $ cat largefile
132 $ cat largefile
133 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
133 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
134
134
135 $ cd ..
135 $ cd ..
136
136
137 # Check rename, and switch between large and small files
137 # Check rename, and switch between large and small files
138
138
139 $ hg init repo3
139 $ hg init repo3
140 $ cd repo3
140 $ cd repo3
141 $ cat >> .hg/hgrc << EOF
141 $ cat >> .hg/hgrc << EOF
142 > [lfs]
142 > [lfs]
143 > threshold=10B
143 > threshold=10B
144 > EOF
144 > EOF
145
145
146 $ echo LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS > large
146 $ echo LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS > large
147 $ echo SHORTER > small
147 $ echo SHORTER > small
148 $ hg add . -q
148 $ hg add . -q
149 $ hg commit -m 'commit with lfs content'
149 $ hg commit -m 'commit with lfs content'
150
150
151 $ hg mv large l
151 $ hg mv large l
152 $ hg mv small s
152 $ hg mv small s
153 $ hg commit -m 'renames'
153 $ hg commit -m 'renames'
154
154
155 $ echo SHORT > l
155 $ echo SHORT > l
156 $ echo BECOME-LARGER-FROM-SHORTER > s
156 $ echo BECOME-LARGER-FROM-SHORTER > s
157 $ hg commit -m 'large to small, small to large'
157 $ hg commit -m 'large to small, small to large'
158
158
159 $ echo 1 >> l
159 $ echo 1 >> l
160 $ echo 2 >> s
160 $ echo 2 >> s
161 $ hg commit -m 'random modifications'
161 $ hg commit -m 'random modifications'
162
162
163 $ echo RESTORE-TO-BE-LARGE > l
163 $ echo RESTORE-TO-BE-LARGE > l
164 $ echo SHORTER > s
164 $ echo SHORTER > s
165 $ hg commit -m 'switch large and small again'
165 $ hg commit -m 'switch large and small again'
166
166
167 # Test lfs_files template
167 # Test lfs_files template
168
168
169 $ hg log -r 'all()' -T '{rev} {join(lfs_files, ", ")}\n'
169 $ hg log -r 'all()' -T '{rev} {join(lfs_files, ", ")}\n'
170 0 large
170 0 large
171 1 l
171 1 l
172 2 s
172 2 s
173 3 s
173 3 s
174 4 l
174 4 l
175
175
176 # Push and pull the above repo
176 # Push and pull the above repo
177
177
178 $ hg --cwd .. init repo4
178 $ hg --cwd .. init repo4
179 $ hg push ../repo4
179 $ hg push ../repo4
180 pushing to ../repo4
180 pushing to ../repo4
181 searching for changes
181 searching for changes
182 adding changesets
182 adding changesets
183 adding manifests
183 adding manifests
184 adding file changes
184 adding file changes
185 added 5 changesets with 10 changes to 4 files
185 added 5 changesets with 10 changes to 4 files
186
186
187 $ hg --cwd .. init repo5
187 $ hg --cwd .. init repo5
188 $ hg --cwd ../repo5 pull ../repo3
188 $ hg --cwd ../repo5 pull ../repo3
189 pulling from ../repo3
189 pulling from ../repo3
190 requesting all changes
190 requesting all changes
191 adding changesets
191 adding changesets
192 adding manifests
192 adding manifests
193 adding file changes
193 adding file changes
194 added 5 changesets with 10 changes to 4 files
194 added 5 changesets with 10 changes to 4 files
195 new changesets fd47a419c4f7:5adf850972b9
195 new changesets fd47a419c4f7:5adf850972b9
196 (run 'hg update' to get a working copy)
196 (run 'hg update' to get a working copy)
197
197
198 $ cd ..
198 $ cd ..
199
199
200 # Test clone
200 # Test clone
201
201
202 $ hg init repo6
202 $ hg init repo6
203 $ cd repo6
203 $ cd repo6
204 $ cat >> .hg/hgrc << EOF
204 $ cat >> .hg/hgrc << EOF
205 > [lfs]
205 > [lfs]
206 > threshold=30B
206 > threshold=30B
207 > EOF
207 > EOF
208
208
209 $ echo LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES > large
209 $ echo LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES > large
210 $ echo SMALL > small
210 $ echo SMALL > small
211 $ hg commit -Aqm 'create a lfs file' large small
211 $ hg commit -Aqm 'create a lfs file' large small
212 $ hg debuglfsupload -r 'all()' -v
212 $ hg debuglfsupload -r 'all()' -v
213 lfs: found 8e92251415339ae9b148c8da89ed5ec665905166a1ab11b09dca8fad83344738 in the local lfs store
213 lfs: found 8e92251415339ae9b148c8da89ed5ec665905166a1ab11b09dca8fad83344738 in the local lfs store
214
214
215 $ cd ..
215 $ cd ..
216
216
217 $ hg clone repo6 repo7
217 $ hg clone repo6 repo7
218 updating to branch default
218 updating to branch default
219 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 $ cd repo7
220 $ cd repo7
221 $ hg config extensions --debug | grep lfs
221 $ hg config extensions --debug | grep lfs
222 $TESTTMP/repo7/.hg/hgrc:*: extensions.lfs= (glob)
222 $TESTTMP/repo7/.hg/hgrc:*: extensions.lfs= (glob)
223 $ cat large
223 $ cat large
224 LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES
224 LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES
225 $ cat small
225 $ cat small
226 SMALL
226 SMALL
227
227
228 $ cd ..
228 $ cd ..
229
229
230 $ hg --config extensions.share= share repo7 sharedrepo
230 $ hg --config extensions.share= share repo7 sharedrepo
231 updating working directory
231 updating working directory
232 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 $ hg -R sharedrepo config extensions --debug | grep lfs
233 $ hg -R sharedrepo config extensions --debug | grep lfs
234 $TESTTMP/sharedrepo/.hg/hgrc:*: extensions.lfs= (glob)
234 $TESTTMP/sharedrepo/.hg/hgrc:*: extensions.lfs= (glob)
235
235
236 # Test rename and status
236 # Test rename and status
237
237
238 $ hg init repo8
238 $ hg init repo8
239 $ cd repo8
239 $ cd repo8
240 $ cat >> .hg/hgrc << EOF
240 $ cat >> .hg/hgrc << EOF
241 > [lfs]
241 > [lfs]
242 > threshold=10B
242 > threshold=10B
243 > EOF
243 > EOF
244
244
245 $ echo THIS-IS-LFS-BECAUSE-10-BYTES > a1
245 $ echo THIS-IS-LFS-BECAUSE-10-BYTES > a1
246 $ echo SMALL > a2
246 $ echo SMALL > a2
247 $ hg commit -m a -A a1 a2
247 $ hg commit -m a -A a1 a2
248 $ hg status
248 $ hg status
249 $ hg mv a1 b1
249 $ hg mv a1 b1
250 $ hg mv a2 a1
250 $ hg mv a2 a1
251 $ hg mv b1 a2
251 $ hg mv b1 a2
252 $ hg commit -m b
252 $ hg commit -m b
253 $ hg status
253 $ hg status
254 >>> with open('a2', 'wb') as f:
254 >>> with open('a2', 'wb') as f:
255 ... f.write(b'\1\nSTART-WITH-HG-FILELOG-METADATA')
255 ... f.write(b'\1\nSTART-WITH-HG-FILELOG-METADATA')
256 >>> with open('a1', 'wb') as f:
256 >>> with open('a1', 'wb') as f:
257 ... f.write(b'\1\nMETA\n')
257 ... f.write(b'\1\nMETA\n')
258 $ hg commit -m meta
258 $ hg commit -m meta
259 $ hg status
259 $ hg status
260 $ hg log -T '{rev}: {file_copies} | {file_dels} | {file_adds}\n'
260 $ hg log -T '{rev}: {file_copies} | {file_dels} | {file_adds}\n'
261 2: | |
261 2: | |
262 1: a1 (a2)a2 (a1) | |
262 1: a1 (a2)a2 (a1) | |
263 0: | | a1 a2
263 0: | | a1 a2
264
264
265 $ for n in a1 a2; do
265 $ for n in a1 a2; do
266 > for r in 0 1 2; do
266 > for r in 0 1 2; do
267 > printf '\n%s @ %s\n' $n $r
267 > printf '\n%s @ %s\n' $n $r
268 > hg debugdata $n $r
268 > hg debugdata $n $r
269 > done
269 > done
270 > done
270 > done
271
271
272 a1 @ 0
272 a1 @ 0
273 version https://git-lfs.github.com/spec/v1
273 version https://git-lfs.github.com/spec/v1
274 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
274 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
275 size 29
275 size 29
276 x-is-binary 0
276 x-is-binary 0
277
277
278 a1 @ 1
278 a1 @ 1
279 \x01 (esc)
279 \x01 (esc)
280 copy: a2
280 copy: a2
281 copyrev: 50470ad23cf937b1f4b9f80bfe54df38e65b50d9
281 copyrev: 50470ad23cf937b1f4b9f80bfe54df38e65b50d9
282 \x01 (esc)
282 \x01 (esc)
283 SMALL
283 SMALL
284
284
285 a1 @ 2
285 a1 @ 2
286 \x01 (esc)
286 \x01 (esc)
287 \x01 (esc)
287 \x01 (esc)
288 \x01 (esc)
288 \x01 (esc)
289 META
289 META
290
290
291 a2 @ 0
291 a2 @ 0
292 SMALL
292 SMALL
293
293
294 a2 @ 1
294 a2 @ 1
295 version https://git-lfs.github.com/spec/v1
295 version https://git-lfs.github.com/spec/v1
296 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
296 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
297 size 29
297 size 29
298 x-hg-copy a1
298 x-hg-copy a1
299 x-hg-copyrev be23af27908a582af43e5cda209a5a9b319de8d4
299 x-hg-copyrev be23af27908a582af43e5cda209a5a9b319de8d4
300 x-is-binary 0
300 x-is-binary 0
301
301
302 a2 @ 2
302 a2 @ 2
303 version https://git-lfs.github.com/spec/v1
303 version https://git-lfs.github.com/spec/v1
304 oid sha256:876dadc86a8542f9798048f2c47f51dbf8e4359aed883e8ec80c5db825f0d943
304 oid sha256:876dadc86a8542f9798048f2c47f51dbf8e4359aed883e8ec80c5db825f0d943
305 size 32
305 size 32
306 x-is-binary 0
306 x-is-binary 0
307
307
308 # Verify commit hashes include rename metadata
308 # Verify commit hashes include rename metadata
309
309
310 $ hg log -T '{rev}:{node|short} {desc}\n'
310 $ hg log -T '{rev}:{node|short} {desc}\n'
311 2:0fae949de7fa meta
311 2:0fae949de7fa meta
312 1:9cd6bdffdac0 b
312 1:9cd6bdffdac0 b
313 0:7f96794915f7 a
313 0:7f96794915f7 a
314
314
315 $ cd ..
315 $ cd ..
316
316
317 # Test bundle
317 # Test bundle
318
318
319 $ hg init repo9
319 $ hg init repo9
320 $ cd repo9
320 $ cd repo9
321 $ cat >> .hg/hgrc << EOF
321 $ cat >> .hg/hgrc << EOF
322 > [lfs]
322 > [lfs]
323 > threshold=10B
323 > threshold=10B
324 > [diff]
324 > [diff]
325 > git=1
325 > git=1
326 > EOF
326 > EOF
327
327
328 $ for i in 0 single two three 4; do
328 $ for i in 0 single two three 4; do
329 > echo 'THIS-IS-LFS-'$i > a
329 > echo 'THIS-IS-LFS-'$i > a
330 > hg commit -m a-$i -A a
330 > hg commit -m a-$i -A a
331 > done
331 > done
332
332
333 $ hg update 2 -q
333 $ hg update 2 -q
334 $ echo 'THIS-IS-LFS-2-CHILD' > a
334 $ echo 'THIS-IS-LFS-2-CHILD' > a
335 $ hg commit -m branching -q
335 $ hg commit -m branching -q
336
336
337 $ hg bundle --base 1 bundle.hg -v
337 $ hg bundle --base 1 bundle.hg -v
338 lfs: found 5ab7a3739a5feec94a562d070a14f36dba7cad17e5484a4a89eea8e5f3166888 in the local lfs store
338 lfs: found 5ab7a3739a5feec94a562d070a14f36dba7cad17e5484a4a89eea8e5f3166888 in the local lfs store
339 lfs: found a9c7d1cd6ce2b9bbdf46ed9a862845228717b921c089d0d42e3bcaed29eb612e in the local lfs store
339 lfs: found a9c7d1cd6ce2b9bbdf46ed9a862845228717b921c089d0d42e3bcaed29eb612e in the local lfs store
340 lfs: found f693890c49c409ec33673b71e53f297681f76c1166daf33b2ad7ebf8b1d3237e in the local lfs store
340 lfs: found f693890c49c409ec33673b71e53f297681f76c1166daf33b2ad7ebf8b1d3237e in the local lfs store
341 lfs: found fda198fea753eb66a252e9856915e1f5cddbe41723bd4b695ece2604ad3c9f75 in the local lfs store
341 lfs: found fda198fea753eb66a252e9856915e1f5cddbe41723bd4b695ece2604ad3c9f75 in the local lfs store
342 4 changesets found
342 4 changesets found
343 uncompressed size of bundle content:
343 uncompressed size of bundle content:
344 * (changelog) (glob)
344 * (changelog) (glob)
345 * (manifests) (glob)
345 * (manifests) (glob)
346 * a (glob)
346 * a (glob)
347 $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
347 $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
348 $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
348 $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
349 5 branching
349 5 branching
350 diff --git a/a b/a
350 diff --git a/a b/a
351 --- a/a
351 --- a/a
352 +++ b/a
352 +++ b/a
353 @@ -1,1 +1,1 @@
353 @@ -1,1 +1,1 @@
354 -THIS-IS-LFS-two
354 -THIS-IS-LFS-two
355 +THIS-IS-LFS-2-CHILD
355 +THIS-IS-LFS-2-CHILD
356
356
357 4 a-4
357 4 a-4
358 diff --git a/a b/a
358 diff --git a/a b/a
359 --- a/a
359 --- a/a
360 +++ b/a
360 +++ b/a
361 @@ -1,1 +1,1 @@
361 @@ -1,1 +1,1 @@
362 -THIS-IS-LFS-three
362 -THIS-IS-LFS-three
363 +THIS-IS-LFS-4
363 +THIS-IS-LFS-4
364
364
365 3 a-three
365 3 a-three
366 diff --git a/a b/a
366 diff --git a/a b/a
367 --- a/a
367 --- a/a
368 +++ b/a
368 +++ b/a
369 @@ -1,1 +1,1 @@
369 @@ -1,1 +1,1 @@
370 -THIS-IS-LFS-two
370 -THIS-IS-LFS-two
371 +THIS-IS-LFS-three
371 +THIS-IS-LFS-three
372
372
373 2 a-two
373 2 a-two
374 diff --git a/a b/a
374 diff --git a/a b/a
375 --- a/a
375 --- a/a
376 +++ b/a
376 +++ b/a
377 @@ -1,1 +1,1 @@
377 @@ -1,1 +1,1 @@
378 -THIS-IS-LFS-single
378 -THIS-IS-LFS-single
379 +THIS-IS-LFS-two
379 +THIS-IS-LFS-two
380
380
381 1 a-single
381 1 a-single
382 diff --git a/a b/a
382 diff --git a/a b/a
383 --- a/a
383 --- a/a
384 +++ b/a
384 +++ b/a
385 @@ -1,1 +1,1 @@
385 @@ -1,1 +1,1 @@
386 -THIS-IS-LFS-0
386 -THIS-IS-LFS-0
387 +THIS-IS-LFS-single
387 +THIS-IS-LFS-single
388
388
389 0 a-0
389 0 a-0
390 diff --git a/a b/a
390 diff --git a/a b/a
391 new file mode 100644
391 new file mode 100644
392 --- /dev/null
392 --- /dev/null
393 +++ b/a
393 +++ b/a
394 @@ -0,0 +1,1 @@
394 @@ -0,0 +1,1 @@
395 +THIS-IS-LFS-0
395 +THIS-IS-LFS-0
396
396
397 $ hg bundle -R bundle.hg --base 1 bundle-again.hg -q
397 $ hg bundle -R bundle.hg --base 1 bundle-again.hg -q
398 $ hg -R bundle-again.hg log -p -T '{rev} {desc}\n' a
398 $ hg -R bundle-again.hg log -p -T '{rev} {desc}\n' a
399 5 branching
399 5 branching
400 diff --git a/a b/a
400 diff --git a/a b/a
401 --- a/a
401 --- a/a
402 +++ b/a
402 +++ b/a
403 @@ -1,1 +1,1 @@
403 @@ -1,1 +1,1 @@
404 -THIS-IS-LFS-two
404 -THIS-IS-LFS-two
405 +THIS-IS-LFS-2-CHILD
405 +THIS-IS-LFS-2-CHILD
406
406
407 4 a-4
407 4 a-4
408 diff --git a/a b/a
408 diff --git a/a b/a
409 --- a/a
409 --- a/a
410 +++ b/a
410 +++ b/a
411 @@ -1,1 +1,1 @@
411 @@ -1,1 +1,1 @@
412 -THIS-IS-LFS-three
412 -THIS-IS-LFS-three
413 +THIS-IS-LFS-4
413 +THIS-IS-LFS-4
414
414
415 3 a-three
415 3 a-three
416 diff --git a/a b/a
416 diff --git a/a b/a
417 --- a/a
417 --- a/a
418 +++ b/a
418 +++ b/a
419 @@ -1,1 +1,1 @@
419 @@ -1,1 +1,1 @@
420 -THIS-IS-LFS-two
420 -THIS-IS-LFS-two
421 +THIS-IS-LFS-three
421 +THIS-IS-LFS-three
422
422
423 2 a-two
423 2 a-two
424 diff --git a/a b/a
424 diff --git a/a b/a
425 --- a/a
425 --- a/a
426 +++ b/a
426 +++ b/a
427 @@ -1,1 +1,1 @@
427 @@ -1,1 +1,1 @@
428 -THIS-IS-LFS-single
428 -THIS-IS-LFS-single
429 +THIS-IS-LFS-two
429 +THIS-IS-LFS-two
430
430
431 1 a-single
431 1 a-single
432 diff --git a/a b/a
432 diff --git a/a b/a
433 --- a/a
433 --- a/a
434 +++ b/a
434 +++ b/a
435 @@ -1,1 +1,1 @@
435 @@ -1,1 +1,1 @@
436 -THIS-IS-LFS-0
436 -THIS-IS-LFS-0
437 +THIS-IS-LFS-single
437 +THIS-IS-LFS-single
438
438
439 0 a-0
439 0 a-0
440 diff --git a/a b/a
440 diff --git a/a b/a
441 new file mode 100644
441 new file mode 100644
442 --- /dev/null
442 --- /dev/null
443 +++ b/a
443 +++ b/a
444 @@ -0,0 +1,1 @@
444 @@ -0,0 +1,1 @@
445 +THIS-IS-LFS-0
445 +THIS-IS-LFS-0
446
446
447 $ cd ..
447 $ cd ..
448
448
449 # Test isbinary
449 # Test isbinary
450
450
451 $ hg init repo10
451 $ hg init repo10
452 $ cd repo10
452 $ cd repo10
453 $ cat >> .hg/hgrc << EOF
453 $ cat >> .hg/hgrc << EOF
454 > [extensions]
454 > [extensions]
455 > lfs=
455 > lfs=
456 > [lfs]
456 > [lfs]
457 > threshold=1
457 > threshold=1
458 > EOF
458 > EOF
459 $ $PYTHON <<'EOF'
459 $ $PYTHON <<'EOF'
460 > def write(path, content):
460 > def write(path, content):
461 > with open(path, 'wb') as f:
461 > with open(path, 'wb') as f:
462 > f.write(content)
462 > f.write(content)
463 > write('a', b'\0\0')
463 > write('a', b'\0\0')
464 > write('b', b'\1\n')
464 > write('b', b'\1\n')
465 > write('c', b'\1\n\0')
465 > write('c', b'\1\n\0')
466 > write('d', b'xx')
466 > write('d', b'xx')
467 > EOF
467 > EOF
468 $ hg add a b c d
468 $ hg add a b c d
469 $ hg diff --stat
469 $ hg diff --stat
470 a | Bin
470 a | Bin
471 b | 1 +
471 b | 1 +
472 c | Bin
472 c | Bin
473 d | 1 +
473 d | 1 +
474 4 files changed, 2 insertions(+), 0 deletions(-)
474 4 files changed, 2 insertions(+), 0 deletions(-)
475 $ hg commit -m binarytest
475 $ hg commit -m binarytest
476 $ cat > $TESTTMP/dumpbinary.py << EOF
476 $ cat > $TESTTMP/dumpbinary.py << EOF
477 > def reposetup(ui, repo):
477 > def reposetup(ui, repo):
478 > for n in 'abcd':
478 > for n in 'abcd':
479 > ui.write(('%s: binary=%s\n') % (n, repo['.'][n].isbinary()))
479 > ui.write(('%s: binary=%s\n') % (n, repo['.'][n].isbinary()))
480 > EOF
480 > EOF
481 $ hg --config extensions.dumpbinary=$TESTTMP/dumpbinary.py id --trace
481 $ hg --config extensions.dumpbinary=$TESTTMP/dumpbinary.py id --trace
482 a: binary=True
482 a: binary=True
483 b: binary=False
483 b: binary=False
484 c: binary=True
484 c: binary=True
485 d: binary=False
485 d: binary=False
486 b55353847f02 tip
486 b55353847f02 tip
487
487
488 $ cd ..
488 $ cd ..
489
489
490 # Test fctx.cmp fastpath - diff without LFS blobs
490 # Test fctx.cmp fastpath - diff without LFS blobs
491
491
492 $ hg init repo11
492 $ hg init repo11
493 $ cd repo11
493 $ cd repo11
494 $ cat >> .hg/hgrc <<EOF
494 $ cat >> .hg/hgrc <<EOF
495 > [lfs]
495 > [lfs]
496 > threshold=1
496 > threshold=1
497 > EOF
497 > EOF
498 $ cat > ../patch.diff <<EOF
498 $ cat > ../patch.diff <<EOF
499 > # HG changeset patch
499 > # HG changeset patch
500 > 2
500 > 2
501 >
501 >
502 > diff --git a/a b/a
502 > diff --git a/a b/a
503 > old mode 100644
503 > old mode 100644
504 > new mode 100755
504 > new mode 100755
505 > EOF
505 > EOF
506
506
507 $ for i in 1 2 3; do
507 $ for i in 1 2 3; do
508 > cp ../repo10/a a
508 > cp ../repo10/a a
509 > if [ $i = 3 ]; then
509 > if [ $i = 3 ]; then
510 > # make a content-only change
510 > # make a content-only change
511 > hg import -q --bypass ../patch.diff
511 > hg import -q --bypass ../patch.diff
512 > hg update -q
512 > hg update -q
513 > rm ../patch.diff
513 > rm ../patch.diff
514 > else
514 > else
515 > echo $i >> a
515 > echo $i >> a
516 > hg commit -m $i -A a
516 > hg commit -m $i -A a
517 > fi
517 > fi
518 > done
518 > done
519 $ [ -d .hg/store/lfs/objects ]
519 $ [ -d .hg/store/lfs/objects ]
520
520
521 $ cd ..
521 $ cd ..
522
522
523 $ hg clone repo11 repo12 --noupdate
523 $ hg clone repo11 repo12 --noupdate
524 $ cd repo12
524 $ cd repo12
525 $ hg log --removed -p a -T '{desc}\n' --config diff.nobinary=1 --git
525 $ hg log --removed -p a -T '{desc}\n' --config diff.nobinary=1 --git
526 2
526 2
527 diff --git a/a b/a
527 diff --git a/a b/a
528 old mode 100644
528 old mode 100644
529 new mode 100755
529 new mode 100755
530
530
531 2
531 2
532 diff --git a/a b/a
532 diff --git a/a b/a
533 Binary file a has changed
533 Binary file a has changed
534
534
535 1
535 1
536 diff --git a/a b/a
536 diff --git a/a b/a
537 new file mode 100644
537 new file mode 100644
538 Binary file a has changed
538 Binary file a has changed
539
539
540 $ [ -d .hg/store/lfs/objects ]
540 $ [ -d .hg/store/lfs/objects ]
541 [1]
541 [1]
542
542
543 $ cd ..
543 $ cd ..
544
544
545 # Verify the repos
545 # Verify the repos
546
546
547 $ cat > $TESTTMP/dumpflog.py << EOF
547 $ cat > $TESTTMP/dumpflog.py << EOF
548 > # print raw revision sizes, flags, and hashes for certain files
548 > # print raw revision sizes, flags, and hashes for certain files
549 > import hashlib
549 > import hashlib
550 > from mercurial import revlog
550 > from mercurial import revlog
551 > from mercurial.node import short
551 > from mercurial.node import short
552 > def hash(rawtext):
552 > def hash(rawtext):
553 > h = hashlib.sha512()
553 > h = hashlib.sha512()
554 > h.update(rawtext)
554 > h.update(rawtext)
555 > return h.hexdigest()[:4]
555 > return h.hexdigest()[:4]
556 > def reposetup(ui, repo):
556 > def reposetup(ui, repo):
557 > # these 2 files are interesting
557 > # these 2 files are interesting
558 > for name in ['l', 's']:
558 > for name in ['l', 's']:
559 > fl = repo.file(name)
559 > fl = repo.file(name)
560 > if len(fl) == 0:
560 > if len(fl) == 0:
561 > continue
561 > continue
562 > sizes = [revlog.revlog.rawsize(fl, i) for i in fl]
562 > sizes = [revlog.revlog.rawsize(fl, i) for i in fl]
563 > texts = [fl.revision(i, raw=True) for i in fl]
563 > texts = [fl.revision(i, raw=True) for i in fl]
564 > flags = [int(fl.flags(i)) for i in fl]
564 > flags = [int(fl.flags(i)) for i in fl]
565 > hashes = [hash(t) for t in texts]
565 > hashes = [hash(t) for t in texts]
566 > print(' %s: rawsizes=%r flags=%r hashes=%r'
566 > print(' %s: rawsizes=%r flags=%r hashes=%r'
567 > % (name, sizes, flags, hashes))
567 > % (name, sizes, flags, hashes))
568 > EOF
568 > EOF
569
569
570 $ for i in client client2 server repo3 repo4 repo5 repo6 repo7 repo8 repo9 \
570 $ for i in client client2 server repo3 repo4 repo5 repo6 repo7 repo8 repo9 \
571 > repo10; do
571 > repo10; do
572 > echo 'repo:' $i
572 > echo 'repo:' $i
573 > hg --cwd $i verify --config extensions.dumpflog=$TESTTMP/dumpflog.py -q
573 > hg --cwd $i verify --config extensions.dumpflog=$TESTTMP/dumpflog.py -q
574 > done
574 > done
575 repo: client
575 repo: client
576 repo: client2
576 repo: client2
577 repo: server
577 repo: server
578 repo: repo3
578 repo: repo3
579 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
579 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
580 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
580 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
581 repo: repo4
581 repo: repo4
582 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
582 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
583 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
583 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
584 repo: repo5
584 repo: repo5
585 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
585 l: rawsizes=[211, 6, 8, 141] flags=[8192, 0, 0, 8192] hashes=['d2b8', '948c', 'cc88', '724d']
586 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
586 s: rawsizes=[74, 141, 141, 8] flags=[0, 8192, 8192, 0] hashes=['3c80', 'fce0', '874a', '826b']
587 repo: repo6
587 repo: repo6
588 repo: repo7
588 repo: repo7
589 repo: repo8
589 repo: repo8
590 repo: repo9
590 repo: repo9
591 repo: repo10
591 repo: repo10
592
592
593 repo12 doesn't have any cached lfs files and its source never pushed its
593 repo12 doesn't have any cached lfs files and its source never pushed its
594 files. Therefore, the files don't exist in the remote store. Use the files in
594 files. Therefore, the files don't exist in the remote store. Use the files in
595 the user cache.
595 the user cache.
596
596
597 $ test -d $TESTTMP/repo12/.hg/store/lfs/objects
597 $ test -d $TESTTMP/repo12/.hg/store/lfs/objects
598 [1]
598 [1]
599
599
600 $ hg --config extensions.share= share repo12 repo13
600 $ hg --config extensions.share= share repo12 repo13
601 updating working directory
601 updating working directory
602 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
602 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
603 $ hg -R repo13 -q verify
603 $ hg -R repo13 -q verify
604
604
605 $ hg clone repo12 repo14
605 $ hg clone repo12 repo14
606 updating to branch default
606 updating to branch default
607 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
607 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
608 $ hg -R repo14 -q verify
608 $ hg -R repo14 -q verify
609
609
610 If the source repo doesn't have the blob (maybe it was pulled or cloned with
610 If the source repo doesn't have the blob (maybe it was pulled or cloned with
611 --noupdate), the blob is still accessible via the global cache to send to the
611 --noupdate), the blob is still accessible via the global cache to send to the
612 remote store.
612 remote store.
613
613
614 $ rm -rf $TESTTMP/repo14/.hg/store/lfs
614 $ rm -rf $TESTTMP/repo14/.hg/store/lfs
615 $ hg init repo15
615 $ hg init repo15
616 $ hg -R repo14 push repo15
616 $ hg -R repo14 push repo15
617 pushing to repo15
617 pushing to repo15
618 searching for changes
618 searching for changes
619 adding changesets
619 adding changesets
620 adding manifests
620 adding manifests
621 adding file changes
621 adding file changes
622 added 3 changesets with 2 changes to 1 files
622 added 3 changesets with 2 changes to 1 files
623 $ hg -R repo14 -q verify
623 $ hg -R repo14 -q verify
624
624
625 Test damaged file scenarios. (This also damages the usercache because of the
625 Test damaged file scenarios. (This also damages the usercache because of the
626 hardlinks.)
626 hardlinks.)
627
627
628 $ echo 'damage' >> repo5/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
628 $ echo 'damage' >> repo5/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
629
629
630 Repo with damaged lfs objects in any revision will fail verification.
630 Repo with damaged lfs objects in any revision will fail verification.
631
631
632 $ hg -R repo5 verify
632 $ hg -R repo5 verify
633 checking changesets
633 checking changesets
634 checking manifests
634 checking manifests
635 crosschecking files in changesets and manifests
635 crosschecking files in changesets and manifests
636 checking files
636 checking files
637 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
637 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
638 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
638 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
639 4 files, 5 changesets, 10 total revisions
639 4 files, 5 changesets, 10 total revisions
640 2 integrity errors encountered!
640 2 integrity errors encountered!
641 (first damaged changeset appears to be 0)
641 (first damaged changeset appears to be 0)
642 [1]
642 [1]
643
643
644 Updates work after cloning a damaged repo, if the damaged lfs objects aren't in
644 Updates work after cloning a damaged repo, if the damaged lfs objects aren't in
645 the update destination. Those objects won't be added to the new repo's store
645 the update destination. Those objects won't be added to the new repo's store
646 because they aren't accessed.
646 because they aren't accessed.
647
647
648 $ hg clone -v repo5 fromcorrupt
648 $ hg clone -v repo5 fromcorrupt
649 updating to branch default
649 updating to branch default
650 resolving manifests
650 resolving manifests
651 getting l
651 getting l
652 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the usercache
652 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the usercache
653 getting s
653 getting s
654 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
654 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
655 $ test -f fromcorrupt/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
655 $ test -f fromcorrupt/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
656 [1]
656 [1]
657
657
658 Verify will copy/link all lfs objects into the local store that aren't already
658 Verify will copy/link all lfs objects into the local store that aren't already
659 present. Bypass the corrupted usercache to show that verify works when fed by
659 present. Bypass the corrupted usercache to show that verify works when fed by
660 the (uncorrupted) remote store.
660 the (uncorrupted) remote store.
661
661
662 $ hg -R fromcorrupt --config lfs.usercache=emptycache verify -v
662 $ hg -R fromcorrupt --config lfs.usercache=emptycache verify -v
663 repository uses revlog format 1
663 repository uses revlog format 1
664 checking changesets
664 checking changesets
665 checking manifests
665 checking manifests
666 crosschecking files in changesets and manifests
666 crosschecking files in changesets and manifests
667 checking files
667 checking files
668 lfs: adding 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e to the usercache
668 lfs: adding 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e to the usercache
669 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
669 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
670 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
670 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
671 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
671 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
672 lfs: adding 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 to the usercache
672 lfs: adding 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 to the usercache
673 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
673 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
674 lfs: adding b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c to the usercache
674 lfs: adding b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c to the usercache
675 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
675 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
676 4 files, 5 changesets, 10 total revisions
676 4 files, 5 changesets, 10 total revisions
677
677
678 Verify will not copy/link a corrupted file from the usercache into the local
678 Verify will not copy/link a corrupted file from the usercache into the local
679 store, and poison it. (The verify with a good remote now works.)
679 store, and poison it. (The verify with a good remote now works.)
680
680
681 $ rm -r fromcorrupt/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
681 $ rm -r fromcorrupt/.hg/store/lfs/objects/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
682 $ hg -R fromcorrupt verify -v
682 $ hg -R fromcorrupt verify -v
683 repository uses revlog format 1
683 repository uses revlog format 1
684 checking changesets
684 checking changesets
685 checking manifests
685 checking manifests
686 crosschecking files in changesets and manifests
686 crosschecking files in changesets and manifests
687 checking files
687 checking files
688 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
688 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
689 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
689 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
690 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
690 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
691 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
691 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
692 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
692 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
693 4 files, 5 changesets, 10 total revisions
693 4 files, 5 changesets, 10 total revisions
694 2 integrity errors encountered!
694 2 integrity errors encountered!
695 (first damaged changeset appears to be 0)
695 (first damaged changeset appears to be 0)
696 [1]
696 [1]
697 $ hg -R fromcorrupt --config lfs.usercache=emptycache verify -v
697 $ hg -R fromcorrupt --config lfs.usercache=emptycache verify -v
698 repository uses revlog format 1
698 repository uses revlog format 1
699 checking changesets
699 checking changesets
700 checking manifests
700 checking manifests
701 crosschecking files in changesets and manifests
701 crosschecking files in changesets and manifests
702 checking files
702 checking files
703 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the usercache
703 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the usercache
704 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
704 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
705 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
705 lfs: found 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e in the local lfs store
706 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
706 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
707 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
707 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
708 4 files, 5 changesets, 10 total revisions
708 4 files, 5 changesets, 10 total revisions
709
709
710 Damaging a file required by the update destination fails the update.
710 Damaging a file required by the update destination fails the update.
711
711
712 $ echo 'damage' >> $TESTTMP/dummy-remote/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
712 $ echo 'damage' >> $TESTTMP/dummy-remote/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
713 $ hg --config lfs.usercache=emptycache clone -v repo5 fromcorrupt2
713 $ hg --config lfs.usercache=emptycache clone -v repo5 fromcorrupt2
714 updating to branch default
714 updating to branch default
715 resolving manifests
715 resolving manifests
716 getting l
716 getting l
717 abort: detected corrupt lfs object: 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
717 abort: corrupt remote lfs object: 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
718 (run hg verify)
719 [255]
718 [255]
720
719
721 A corrupted lfs blob is not transferred from a file://remotestore to the
720 A corrupted lfs blob is not transferred from a file://remotestore to the
722 usercache or local store.
721 usercache or local store.
723
722
724 $ test -f emptycache/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
723 $ test -f emptycache/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
725 [1]
724 [1]
726 $ test -f fromcorrupt2/.hg/store/lfs/objects/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
725 $ test -f fromcorrupt2/.hg/store/lfs/objects/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
727 [1]
726 [1]
728
727
729 $ hg -R fromcorrupt2 verify
728 $ hg -R fromcorrupt2 verify
730 checking changesets
729 checking changesets
731 checking manifests
730 checking manifests
732 crosschecking files in changesets and manifests
731 crosschecking files in changesets and manifests
733 checking files
732 checking files
734 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
733 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
735 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
734 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
736 4 files, 5 changesets, 10 total revisions
735 4 files, 5 changesets, 10 total revisions
737 2 integrity errors encountered!
736 2 integrity errors encountered!
738 (first damaged changeset appears to be 0)
737 (first damaged changeset appears to be 0)
739 [1]
738 [1]
740
739
741 Corrupt local files are not sent upstream. (The alternate dummy remote
740 Corrupt local files are not sent upstream. (The alternate dummy remote
742 avoids the corrupt lfs object in the original remote.)
741 avoids the corrupt lfs object in the original remote.)
743
742
744 $ mkdir $TESTTMP/dummy-remote2
743 $ mkdir $TESTTMP/dummy-remote2
745 $ hg init dest
744 $ hg init dest
746 $ hg -R fromcorrupt2 --config lfs.url=file:///$TESTTMP/dummy-remote2 push -v dest
745 $ hg -R fromcorrupt2 --config lfs.url=file:///$TESTTMP/dummy-remote2 push -v dest
747 pushing to dest
746 pushing to dest
748 searching for changes
747 searching for changes
749 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
748 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
750 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
749 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
751 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
750 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
752 abort: detected corrupt lfs object: 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
751 abort: detected corrupt lfs object: 66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
753 (run hg verify)
752 (run hg verify)
754 [255]
753 [255]
755
754
756 $ hg -R fromcorrupt2 --config lfs.url=file:///$TESTTMP/dummy-remote2 verify -v
755 $ hg -R fromcorrupt2 --config lfs.url=file:///$TESTTMP/dummy-remote2 verify -v
757 repository uses revlog format 1
756 repository uses revlog format 1
758 checking changesets
757 checking changesets
759 checking manifests
758 checking manifests
760 crosschecking files in changesets and manifests
759 crosschecking files in changesets and manifests
761 checking files
760 checking files
762 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
761 l@1: unpacking 46a2f24864bc: integrity check failed on data/l.i:0
763 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
762 lfs: found 22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b in the local lfs store
764 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
763 large@0: unpacking 2c531e0992ff: integrity check failed on data/large.i:0
765 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
764 lfs: found 89b6070915a3d573ff3599d1cda305bc5e38549b15c4847ab034169da66e1ca8 in the local lfs store
766 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
765 lfs: found b1a6ea88da0017a0e77db139a54618986e9a2489bee24af9fe596de9daac498c in the local lfs store
767 4 files, 5 changesets, 10 total revisions
766 4 files, 5 changesets, 10 total revisions
768 2 integrity errors encountered!
767 2 integrity errors encountered!
769 (first damaged changeset appears to be 0)
768 (first damaged changeset appears to be 0)
770 [1]
769 [1]
771
770
772 $ cat $TESTTMP/dummy-remote2/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b | $TESTDIR/f --sha256
771 $ cat $TESTTMP/dummy-remote2/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b | $TESTDIR/f --sha256
773 sha256=22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
772 sha256=22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
774 $ cat fromcorrupt2/.hg/store/lfs/objects/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b | $TESTDIR/f --sha256
773 $ cat fromcorrupt2/.hg/store/lfs/objects/22/f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b | $TESTDIR/f --sha256
775 sha256=22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
774 sha256=22f66a3fc0b9bf3f012c814303995ec07099b3a9ce02a7af84b5970811074a3b
776 $ test -f $TESTTMP/dummy-remote2/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
775 $ test -f $TESTTMP/dummy-remote2/66/100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
777 [1]
776 [1]
778
777
779 Accessing a corrupt file will complain
778 Accessing a corrupt file will complain
780
779
781 $ hg --cwd fromcorrupt2 cat -r 0 large
780 $ hg --cwd fromcorrupt2 cat -r 0 large
782 abort: integrity check failed on data/large.i:0!
781 abort: integrity check failed on data/large.i:0!
783 [255]
782 [255]
784
783
785 lfs -> normal -> lfs round trip conversions are possible. The threshold for the
784 lfs -> normal -> lfs round trip conversions are possible. The threshold for the
786 lfs destination is specified here because it was originally listed in the local
785 lfs destination is specified here because it was originally listed in the local
787 .hgrc, and the global one is too high to trigger lfs usage. For lfs -> normal,
786 .hgrc, and the global one is too high to trigger lfs usage. For lfs -> normal,
788 there's no 'lfs' destination repo requirement. For normal -> lfs, there is.
787 there's no 'lfs' destination repo requirement. For normal -> lfs, there is.
789
788
790 XXX: There's not a great way to ensure that the conversion to normal files
789 XXX: There's not a great way to ensure that the conversion to normal files
791 actually converts _everything_ to normal. The extension needs to be loaded for
790 actually converts _everything_ to normal. The extension needs to be loaded for
792 the source, but there's no way to disable it for the destination. The best that
791 the source, but there's no way to disable it for the destination. The best that
793 can be done is to raise the threshold so that lfs isn't used on the destination.
792 can be done is to raise the threshold so that lfs isn't used on the destination.
794 It doesn't like using '!' to unset the value on the command line.
793 It doesn't like using '!' to unset the value on the command line.
795
794
796 $ hg --config extensions.convert= --config lfs.threshold=1000M \
795 $ hg --config extensions.convert= --config lfs.threshold=1000M \
797 > convert repo8 convert_normal
796 > convert repo8 convert_normal
798 initializing destination convert_normal repository
797 initializing destination convert_normal repository
799 scanning source...
798 scanning source...
800 sorting...
799 sorting...
801 converting...
800 converting...
802 2 a
801 2 a
803 1 b
802 1 b
804 0 meta
803 0 meta
805 $ grep 'lfs' convert_normal/.hg/requires
804 $ grep 'lfs' convert_normal/.hg/requires
806 [1]
805 [1]
807 $ hg --cwd convert_normal debugdata a1 0
806 $ hg --cwd convert_normal debugdata a1 0
808 THIS-IS-LFS-BECAUSE-10-BYTES
807 THIS-IS-LFS-BECAUSE-10-BYTES
809
808
810 $ hg --config extensions.convert= --config lfs.threshold=10B \
809 $ hg --config extensions.convert= --config lfs.threshold=10B \
811 > convert convert_normal convert_lfs
810 > convert convert_normal convert_lfs
812 initializing destination convert_lfs repository
811 initializing destination convert_lfs repository
813 scanning source...
812 scanning source...
814 sorting...
813 sorting...
815 converting...
814 converting...
816 2 a
815 2 a
817 1 b
816 1 b
818 0 meta
817 0 meta
819 $ hg --cwd convert_lfs debugdata a1 0
818 $ hg --cwd convert_lfs debugdata a1 0
820 version https://git-lfs.github.com/spec/v1
819 version https://git-lfs.github.com/spec/v1
821 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
820 oid sha256:5bb8341bee63b3649f222b2215bde37322bea075a30575aa685d8f8d21c77024
822 size 29
821 size 29
823 x-is-binary 0
822 x-is-binary 0
824 $ grep 'lfs' convert_lfs/.hg/requires
823 $ grep 'lfs' convert_lfs/.hg/requires
825 lfs
824 lfs
826
825
827 This convert is trickier, because it contains deleted files (via `hg mv`)
826 This convert is trickier, because it contains deleted files (via `hg mv`)
828
827
829 $ hg --config extensions.convert= --config lfs.threshold=1000M \
828 $ hg --config extensions.convert= --config lfs.threshold=1000M \
830 > convert repo3 convert_normal2
829 > convert repo3 convert_normal2
831 initializing destination convert_normal2 repository
830 initializing destination convert_normal2 repository
832 scanning source...
831 scanning source...
833 sorting...
832 sorting...
834 converting...
833 converting...
835 4 commit with lfs content
834 4 commit with lfs content
836 3 renames
835 3 renames
837 2 large to small, small to large
836 2 large to small, small to large
838 1 random modifications
837 1 random modifications
839 0 switch large and small again
838 0 switch large and small again
840 $ grep 'lfs' convert_normal2/.hg/requires
839 $ grep 'lfs' convert_normal2/.hg/requires
841 [1]
840 [1]
842 $ hg --cwd convert_normal2 debugdata large 0
841 $ hg --cwd convert_normal2 debugdata large 0
843 LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS
842 LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS
844
843
845 $ hg --config extensions.convert= --config lfs.threshold=10B \
844 $ hg --config extensions.convert= --config lfs.threshold=10B \
846 > convert convert_normal2 convert_lfs2
845 > convert convert_normal2 convert_lfs2
847 initializing destination convert_lfs2 repository
846 initializing destination convert_lfs2 repository
848 scanning source...
847 scanning source...
849 sorting...
848 sorting...
850 converting...
849 converting...
851 4 commit with lfs content
850 4 commit with lfs content
852 3 renames
851 3 renames
853 2 large to small, small to large
852 2 large to small, small to large
854 1 random modifications
853 1 random modifications
855 0 switch large and small again
854 0 switch large and small again
856 $ grep 'lfs' convert_lfs2/.hg/requires
855 $ grep 'lfs' convert_lfs2/.hg/requires
857 lfs
856 lfs
858 $ hg --cwd convert_lfs2 debugdata large 0
857 $ hg --cwd convert_lfs2 debugdata large 0
859 version https://git-lfs.github.com/spec/v1
858 version https://git-lfs.github.com/spec/v1
860 oid sha256:66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
859 oid sha256:66100b384bf761271b407d79fc30cdd0554f3b2c5d944836e936d584b88ce88e
861 size 39
860 size 39
862 x-is-binary 0
861 x-is-binary 0
863
862
864 $ hg -R convert_lfs2 config --debug extensions | grep lfs
863 $ hg -R convert_lfs2 config --debug extensions | grep lfs
865 $TESTTMP/convert_lfs2/.hg/hgrc:*: extensions.lfs= (glob)
864 $TESTTMP/convert_lfs2/.hg/hgrc:*: extensions.lfs= (glob)
866
865
867 Committing deleted files works:
866 Committing deleted files works:
868
867
869 $ hg init $TESTTMP/repo-del
868 $ hg init $TESTTMP/repo-del
870 $ cd $TESTTMP/repo-del
869 $ cd $TESTTMP/repo-del
871 $ echo 1 > A
870 $ echo 1 > A
872 $ hg commit -m 'add A' -A A
871 $ hg commit -m 'add A' -A A
873 $ hg rm A
872 $ hg rm A
874 $ hg commit -m 'rm A'
873 $ hg commit -m 'rm A'
875 $ cd ..
874 $ cd ..
876
875
877 Unbundling adds a requirement to a non-lfs repo, if necessary.
876 Unbundling adds a requirement to a non-lfs repo, if necessary.
878
877
879 $ hg bundle -R $TESTTMP/repo-del -qr 0 --base null nolfs.hg
878 $ hg bundle -R $TESTTMP/repo-del -qr 0 --base null nolfs.hg
880 $ hg bundle -R convert_lfs2 -qr tip --base null lfs.hg
879 $ hg bundle -R convert_lfs2 -qr tip --base null lfs.hg
881 $ hg init unbundle
880 $ hg init unbundle
882 $ hg pull -R unbundle -q nolfs.hg
881 $ hg pull -R unbundle -q nolfs.hg
883 $ grep lfs unbundle/.hg/requires
882 $ grep lfs unbundle/.hg/requires
884 [1]
883 [1]
885 $ hg pull -R unbundle -q lfs.hg
884 $ hg pull -R unbundle -q lfs.hg
886 $ grep lfs unbundle/.hg/requires
885 $ grep lfs unbundle/.hg/requires
887 lfs
886 lfs
888
887
889 $ hg init no_lfs
888 $ hg init no_lfs
890 $ cat >> no_lfs/.hg/hgrc <<EOF
889 $ cat >> no_lfs/.hg/hgrc <<EOF
891 > [experimental]
890 > [experimental]
892 > changegroup3 = True
891 > changegroup3 = True
893 > [extensions]
892 > [extensions]
894 > lfs=!
893 > lfs=!
895 > EOF
894 > EOF
896 $ cp -R no_lfs no_lfs2
895 $ cp -R no_lfs no_lfs2
897
896
898 Pushing from a local lfs repo to a local repo without an lfs requirement and
897 Pushing from a local lfs repo to a local repo without an lfs requirement and
899 with lfs disabled, fails.
898 with lfs disabled, fails.
900
899
901 $ hg push -R convert_lfs2 no_lfs
900 $ hg push -R convert_lfs2 no_lfs
902 pushing to no_lfs
901 pushing to no_lfs
903 abort: required features are not supported in the destination: lfs
902 abort: required features are not supported in the destination: lfs
904 [255]
903 [255]
905 $ grep lfs no_lfs/.hg/requires
904 $ grep lfs no_lfs/.hg/requires
906 [1]
905 [1]
907
906
908 Pulling from a local lfs repo to a local repo without an lfs requirement and
907 Pulling from a local lfs repo to a local repo without an lfs requirement and
909 with lfs disabled, fails.
908 with lfs disabled, fails.
910
909
911 $ hg pull -R no_lfs2 convert_lfs2
910 $ hg pull -R no_lfs2 convert_lfs2
912 pulling from convert_lfs2
911 pulling from convert_lfs2
913 abort: required features are not supported in the destination: lfs
912 abort: required features are not supported in the destination: lfs
914 [255]
913 [255]
915 $ grep lfs no_lfs2/.hg/requires
914 $ grep lfs no_lfs2/.hg/requires
916 [1]
915 [1]
General Comments 0
You need to be logged in to leave comments. Login now