##// END OF EJS Templates
hghave: add a check for lfs-test-server...
Matt Harbison -
r35137:a2e927de default
parent child Browse files
Show More
@@ -1,691 +1,702
1 from __future__ import absolute_import
1 from __future__ import absolute_import
2
2
3 import errno
3 import errno
4 import os
4 import os
5 import re
5 import re
6 import socket
6 import socket
7 import stat
7 import stat
8 import subprocess
8 import subprocess
9 import sys
9 import sys
10 import tempfile
10 import tempfile
11
11
12 tempprefix = 'hg-hghave-'
12 tempprefix = 'hg-hghave-'
13
13
14 checks = {
14 checks = {
15 "true": (lambda: True, "yak shaving"),
15 "true": (lambda: True, "yak shaving"),
16 "false": (lambda: False, "nail clipper"),
16 "false": (lambda: False, "nail clipper"),
17 }
17 }
18
18
19 def check(name, desc):
19 def check(name, desc):
20 """Registers a check function for a feature."""
20 """Registers a check function for a feature."""
21 def decorator(func):
21 def decorator(func):
22 checks[name] = (func, desc)
22 checks[name] = (func, desc)
23 return func
23 return func
24 return decorator
24 return decorator
25
25
26 def checkvers(name, desc, vers):
26 def checkvers(name, desc, vers):
27 """Registers a check function for each of a series of versions.
27 """Registers a check function for each of a series of versions.
28
28
29 vers can be a list or an iterator"""
29 vers can be a list or an iterator"""
30 def decorator(func):
30 def decorator(func):
31 def funcv(v):
31 def funcv(v):
32 def f():
32 def f():
33 return func(v)
33 return func(v)
34 return f
34 return f
35 for v in vers:
35 for v in vers:
36 v = str(v)
36 v = str(v)
37 f = funcv(v)
37 f = funcv(v)
38 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
38 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v)
39 return func
39 return func
40 return decorator
40 return decorator
41
41
42 def checkfeatures(features):
42 def checkfeatures(features):
43 result = {
43 result = {
44 'error': [],
44 'error': [],
45 'missing': [],
45 'missing': [],
46 'skipped': [],
46 'skipped': [],
47 }
47 }
48
48
49 for feature in features:
49 for feature in features:
50 negate = feature.startswith('no-')
50 negate = feature.startswith('no-')
51 if negate:
51 if negate:
52 feature = feature[3:]
52 feature = feature[3:]
53
53
54 if feature not in checks:
54 if feature not in checks:
55 result['missing'].append(feature)
55 result['missing'].append(feature)
56 continue
56 continue
57
57
58 check, desc = checks[feature]
58 check, desc = checks[feature]
59 try:
59 try:
60 available = check()
60 available = check()
61 except Exception:
61 except Exception:
62 result['error'].append('hghave check failed: %s' % feature)
62 result['error'].append('hghave check failed: %s' % feature)
63 continue
63 continue
64
64
65 if not negate and not available:
65 if not negate and not available:
66 result['skipped'].append('missing feature: %s' % desc)
66 result['skipped'].append('missing feature: %s' % desc)
67 elif negate and available:
67 elif negate and available:
68 result['skipped'].append('system supports %s' % desc)
68 result['skipped'].append('system supports %s' % desc)
69
69
70 return result
70 return result
71
71
72 def require(features):
72 def require(features):
73 """Require that features are available, exiting if not."""
73 """Require that features are available, exiting if not."""
74 result = checkfeatures(features)
74 result = checkfeatures(features)
75
75
76 for missing in result['missing']:
76 for missing in result['missing']:
77 sys.stderr.write('skipped: unknown feature: %s\n' % missing)
77 sys.stderr.write('skipped: unknown feature: %s\n' % missing)
78 for msg in result['skipped']:
78 for msg in result['skipped']:
79 sys.stderr.write('skipped: %s\n' % msg)
79 sys.stderr.write('skipped: %s\n' % msg)
80 for msg in result['error']:
80 for msg in result['error']:
81 sys.stderr.write('%s\n' % msg)
81 sys.stderr.write('%s\n' % msg)
82
82
83 if result['missing']:
83 if result['missing']:
84 sys.exit(2)
84 sys.exit(2)
85
85
86 if result['skipped'] or result['error']:
86 if result['skipped'] or result['error']:
87 sys.exit(1)
87 sys.exit(1)
88
88
89 def matchoutput(cmd, regexp, ignorestatus=False):
89 def matchoutput(cmd, regexp, ignorestatus=False):
90 """Return the match object if cmd executes successfully and its output
90 """Return the match object if cmd executes successfully and its output
91 is matched by the supplied regular expression.
91 is matched by the supplied regular expression.
92 """
92 """
93 r = re.compile(regexp)
93 r = re.compile(regexp)
94 try:
94 try:
95 p = subprocess.Popen(
95 p = subprocess.Popen(
96 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
96 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
97 except OSError as e:
97 except OSError as e:
98 if e.errno != errno.ENOENT:
98 if e.errno != errno.ENOENT:
99 raise
99 raise
100 ret = -1
100 ret = -1
101 ret = p.wait()
101 ret = p.wait()
102 s = p.stdout.read()
102 s = p.stdout.read()
103 return (ignorestatus or not ret) and r.search(s)
103 return (ignorestatus or not ret) and r.search(s)
104
104
105 @check("baz", "GNU Arch baz client")
105 @check("baz", "GNU Arch baz client")
106 def has_baz():
106 def has_baz():
107 return matchoutput('baz --version 2>&1', br'baz Bazaar version')
107 return matchoutput('baz --version 2>&1', br'baz Bazaar version')
108
108
109 @check("bzr", "Canonical's Bazaar client")
109 @check("bzr", "Canonical's Bazaar client")
110 def has_bzr():
110 def has_bzr():
111 try:
111 try:
112 import bzrlib
112 import bzrlib
113 import bzrlib.bzrdir
113 import bzrlib.bzrdir
114 import bzrlib.errors
114 import bzrlib.errors
115 import bzrlib.revision
115 import bzrlib.revision
116 import bzrlib.revisionspec
116 import bzrlib.revisionspec
117 bzrlib.revisionspec.RevisionSpec
117 bzrlib.revisionspec.RevisionSpec
118 return bzrlib.__doc__ is not None
118 return bzrlib.__doc__ is not None
119 except (AttributeError, ImportError):
119 except (AttributeError, ImportError):
120 return False
120 return False
121
121
122 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
122 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,))
123 def has_bzr_range(v):
123 def has_bzr_range(v):
124 major, minor = v.split('.')[0:2]
124 major, minor = v.split('.')[0:2]
125 try:
125 try:
126 import bzrlib
126 import bzrlib
127 return (bzrlib.__doc__ is not None
127 return (bzrlib.__doc__ is not None
128 and bzrlib.version_info[:2] >= (int(major), int(minor)))
128 and bzrlib.version_info[:2] >= (int(major), int(minor)))
129 except ImportError:
129 except ImportError:
130 return False
130 return False
131
131
132 @check("chg", "running with chg")
132 @check("chg", "running with chg")
133 def has_chg():
133 def has_chg():
134 return 'CHGHG' in os.environ
134 return 'CHGHG' in os.environ
135
135
136 @check("cvs", "cvs client/server")
136 @check("cvs", "cvs client/server")
137 def has_cvs():
137 def has_cvs():
138 re = br'Concurrent Versions System.*?server'
138 re = br'Concurrent Versions System.*?server'
139 return matchoutput('cvs --version 2>&1', re) and not has_msys()
139 return matchoutput('cvs --version 2>&1', re) and not has_msys()
140
140
141 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
141 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)")
142 def has_cvs112():
142 def has_cvs112():
143 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
143 re = br'Concurrent Versions System \(CVS\) 1.12.*?server'
144 return matchoutput('cvs --version 2>&1', re) and not has_msys()
144 return matchoutput('cvs --version 2>&1', re) and not has_msys()
145
145
146 @check("cvsnt", "cvsnt client/server")
146 @check("cvsnt", "cvsnt client/server")
147 def has_cvsnt():
147 def has_cvsnt():
148 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
148 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)'
149 return matchoutput('cvsnt --version 2>&1', re)
149 return matchoutput('cvsnt --version 2>&1', re)
150
150
151 @check("darcs", "darcs client")
151 @check("darcs", "darcs client")
152 def has_darcs():
152 def has_darcs():
153 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True)
153 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True)
154
154
155 @check("mtn", "monotone client (>= 1.0)")
155 @check("mtn", "monotone client (>= 1.0)")
156 def has_mtn():
156 def has_mtn():
157 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
157 return matchoutput('mtn --version', br'monotone', True) and not matchoutput(
158 'mtn --version', br'monotone 0\.', True)
158 'mtn --version', br'monotone 0\.', True)
159
159
160 @check("eol-in-paths", "end-of-lines in paths")
160 @check("eol-in-paths", "end-of-lines in paths")
161 def has_eol_in_paths():
161 def has_eol_in_paths():
162 try:
162 try:
163 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
163 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
164 os.close(fd)
164 os.close(fd)
165 os.remove(path)
165 os.remove(path)
166 return True
166 return True
167 except (IOError, OSError):
167 except (IOError, OSError):
168 return False
168 return False
169
169
170 @check("execbit", "executable bit")
170 @check("execbit", "executable bit")
171 def has_executablebit():
171 def has_executablebit():
172 try:
172 try:
173 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
173 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
174 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
174 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
175 try:
175 try:
176 os.close(fh)
176 os.close(fh)
177 m = os.stat(fn).st_mode & 0o777
177 m = os.stat(fn).st_mode & 0o777
178 new_file_has_exec = m & EXECFLAGS
178 new_file_has_exec = m & EXECFLAGS
179 os.chmod(fn, m ^ EXECFLAGS)
179 os.chmod(fn, m ^ EXECFLAGS)
180 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
180 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
181 finally:
181 finally:
182 os.unlink(fn)
182 os.unlink(fn)
183 except (IOError, OSError):
183 except (IOError, OSError):
184 # we don't care, the user probably won't be able to commit anyway
184 # we don't care, the user probably won't be able to commit anyway
185 return False
185 return False
186 return not (new_file_has_exec or exec_flags_cannot_flip)
186 return not (new_file_has_exec or exec_flags_cannot_flip)
187
187
188 @check("icasefs", "case insensitive file system")
188 @check("icasefs", "case insensitive file system")
189 def has_icasefs():
189 def has_icasefs():
190 # Stolen from mercurial.util
190 # Stolen from mercurial.util
191 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
191 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
192 os.close(fd)
192 os.close(fd)
193 try:
193 try:
194 s1 = os.stat(path)
194 s1 = os.stat(path)
195 d, b = os.path.split(path)
195 d, b = os.path.split(path)
196 p2 = os.path.join(d, b.upper())
196 p2 = os.path.join(d, b.upper())
197 if path == p2:
197 if path == p2:
198 p2 = os.path.join(d, b.lower())
198 p2 = os.path.join(d, b.lower())
199 try:
199 try:
200 s2 = os.stat(p2)
200 s2 = os.stat(p2)
201 return s2 == s1
201 return s2 == s1
202 except OSError:
202 except OSError:
203 return False
203 return False
204 finally:
204 finally:
205 os.remove(path)
205 os.remove(path)
206
206
207 @check("fifo", "named pipes")
207 @check("fifo", "named pipes")
208 def has_fifo():
208 def has_fifo():
209 if getattr(os, "mkfifo", None) is None:
209 if getattr(os, "mkfifo", None) is None:
210 return False
210 return False
211 name = tempfile.mktemp(dir='.', prefix=tempprefix)
211 name = tempfile.mktemp(dir='.', prefix=tempprefix)
212 try:
212 try:
213 os.mkfifo(name)
213 os.mkfifo(name)
214 os.unlink(name)
214 os.unlink(name)
215 return True
215 return True
216 except OSError:
216 except OSError:
217 return False
217 return False
218
218
219 @check("killdaemons", 'killdaemons.py support')
219 @check("killdaemons", 'killdaemons.py support')
220 def has_killdaemons():
220 def has_killdaemons():
221 return True
221 return True
222
222
223 @check("cacheable", "cacheable filesystem")
223 @check("cacheable", "cacheable filesystem")
224 def has_cacheable_fs():
224 def has_cacheable_fs():
225 from mercurial import util
225 from mercurial import util
226
226
227 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
227 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
228 os.close(fd)
228 os.close(fd)
229 try:
229 try:
230 return util.cachestat(path).cacheable()
230 return util.cachestat(path).cacheable()
231 finally:
231 finally:
232 os.remove(path)
232 os.remove(path)
233
233
234 @check("lsprof", "python lsprof module")
234 @check("lsprof", "python lsprof module")
235 def has_lsprof():
235 def has_lsprof():
236 try:
236 try:
237 import _lsprof
237 import _lsprof
238 _lsprof.Profiler # silence unused import warning
238 _lsprof.Profiler # silence unused import warning
239 return True
239 return True
240 except ImportError:
240 except ImportError:
241 return False
241 return False
242
242
243 def gethgversion():
243 def gethgversion():
244 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
244 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)')
245 if not m:
245 if not m:
246 return (0, 0)
246 return (0, 0)
247 return (int(m.group(1)), int(m.group(2)))
247 return (int(m.group(1)), int(m.group(2)))
248
248
249 @checkvers("hg", "Mercurial >= %s",
249 @checkvers("hg", "Mercurial >= %s",
250 list([(1.0 * x) / 10 for x in range(9, 99)]))
250 list([(1.0 * x) / 10 for x in range(9, 99)]))
251 def has_hg_range(v):
251 def has_hg_range(v):
252 major, minor = v.split('.')[0:2]
252 major, minor = v.split('.')[0:2]
253 return gethgversion() >= (int(major), int(minor))
253 return gethgversion() >= (int(major), int(minor))
254
254
255 @check("hg08", "Mercurial >= 0.8")
255 @check("hg08", "Mercurial >= 0.8")
256 def has_hg08():
256 def has_hg08():
257 if checks["hg09"][0]():
257 if checks["hg09"][0]():
258 return True
258 return True
259 return matchoutput('hg help annotate 2>&1', '--date')
259 return matchoutput('hg help annotate 2>&1', '--date')
260
260
261 @check("hg07", "Mercurial >= 0.7")
261 @check("hg07", "Mercurial >= 0.7")
262 def has_hg07():
262 def has_hg07():
263 if checks["hg08"][0]():
263 if checks["hg08"][0]():
264 return True
264 return True
265 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
265 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM')
266
266
267 @check("hg06", "Mercurial >= 0.6")
267 @check("hg06", "Mercurial >= 0.6")
268 def has_hg06():
268 def has_hg06():
269 if checks["hg07"][0]():
269 if checks["hg07"][0]():
270 return True
270 return True
271 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
271 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version')
272
272
273 @check("gettext", "GNU Gettext (msgfmt)")
273 @check("gettext", "GNU Gettext (msgfmt)")
274 def has_gettext():
274 def has_gettext():
275 return matchoutput('msgfmt --version', br'GNU gettext-tools')
275 return matchoutput('msgfmt --version', br'GNU gettext-tools')
276
276
277 @check("git", "git command line client")
277 @check("git", "git command line client")
278 def has_git():
278 def has_git():
279 return matchoutput('git --version 2>&1', br'^git version')
279 return matchoutput('git --version 2>&1', br'^git version')
280
280
281 def getgitversion():
281 def getgitversion():
282 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)')
282 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)')
283 if not m:
283 if not m:
284 return (0, 0)
284 return (0, 0)
285 return (int(m.group(1)), int(m.group(2)))
285 return (int(m.group(1)), int(m.group(2)))
286
286
287 # https://github.com/git-lfs/lfs-test-server
288 @check("lfs-test-server", "git-lfs test server")
289 def has_lfsserver():
290 exe = 'lfs-test-server'
291 if has_windows():
292 exe = 'lfs-test-server.exe'
293 return any(
294 os.access(os.path.join(path, exe), os.X_OK)
295 for path in os.environ["PATH"].split(os.pathsep)
296 )
297
287 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,))
298 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,))
288 def has_git_range(v):
299 def has_git_range(v):
289 major, minor = v.split('.')[0:2]
300 major, minor = v.split('.')[0:2]
290 return getgitversion() >= (int(major), int(minor))
301 return getgitversion() >= (int(major), int(minor))
291
302
292 @check("docutils", "Docutils text processing library")
303 @check("docutils", "Docutils text processing library")
293 def has_docutils():
304 def has_docutils():
294 try:
305 try:
295 import docutils.core
306 import docutils.core
296 docutils.core.publish_cmdline # silence unused import
307 docutils.core.publish_cmdline # silence unused import
297 return True
308 return True
298 except ImportError:
309 except ImportError:
299 return False
310 return False
300
311
301 def getsvnversion():
312 def getsvnversion():
302 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
313 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)')
303 if not m:
314 if not m:
304 return (0, 0)
315 return (0, 0)
305 return (int(m.group(1)), int(m.group(2)))
316 return (int(m.group(1)), int(m.group(2)))
306
317
307 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
318 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5))
308 def has_svn_range(v):
319 def has_svn_range(v):
309 major, minor = v.split('.')[0:2]
320 major, minor = v.split('.')[0:2]
310 return getsvnversion() >= (int(major), int(minor))
321 return getsvnversion() >= (int(major), int(minor))
311
322
312 @check("svn", "subversion client and admin tools")
323 @check("svn", "subversion client and admin tools")
313 def has_svn():
324 def has_svn():
314 return matchoutput('svn --version 2>&1', br'^svn, version') and \
325 return matchoutput('svn --version 2>&1', br'^svn, version') and \
315 matchoutput('svnadmin --version 2>&1', br'^svnadmin, version')
326 matchoutput('svnadmin --version 2>&1', br'^svnadmin, version')
316
327
317 @check("svn-bindings", "subversion python bindings")
328 @check("svn-bindings", "subversion python bindings")
318 def has_svn_bindings():
329 def has_svn_bindings():
319 try:
330 try:
320 import svn.core
331 import svn.core
321 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
332 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
322 if version < (1, 4):
333 if version < (1, 4):
323 return False
334 return False
324 return True
335 return True
325 except ImportError:
336 except ImportError:
326 return False
337 return False
327
338
328 @check("p4", "Perforce server and client")
339 @check("p4", "Perforce server and client")
329 def has_p4():
340 def has_p4():
330 return (matchoutput('p4 -V', br'Rev\. P4/') and
341 return (matchoutput('p4 -V', br'Rev\. P4/') and
331 matchoutput('p4d -V', br'Rev\. P4D/'))
342 matchoutput('p4d -V', br'Rev\. P4D/'))
332
343
333 @check("symlink", "symbolic links")
344 @check("symlink", "symbolic links")
334 def has_symlink():
345 def has_symlink():
335 if getattr(os, "symlink", None) is None:
346 if getattr(os, "symlink", None) is None:
336 return False
347 return False
337 name = tempfile.mktemp(dir='.', prefix=tempprefix)
348 name = tempfile.mktemp(dir='.', prefix=tempprefix)
338 try:
349 try:
339 os.symlink(".", name)
350 os.symlink(".", name)
340 os.unlink(name)
351 os.unlink(name)
341 return True
352 return True
342 except (OSError, AttributeError):
353 except (OSError, AttributeError):
343 return False
354 return False
344
355
345 @check("hardlink", "hardlinks")
356 @check("hardlink", "hardlinks")
346 def has_hardlink():
357 def has_hardlink():
347 from mercurial import util
358 from mercurial import util
348 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
359 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
349 os.close(fh)
360 os.close(fh)
350 name = tempfile.mktemp(dir='.', prefix=tempprefix)
361 name = tempfile.mktemp(dir='.', prefix=tempprefix)
351 try:
362 try:
352 util.oslink(fn, name)
363 util.oslink(fn, name)
353 os.unlink(name)
364 os.unlink(name)
354 return True
365 return True
355 except OSError:
366 except OSError:
356 return False
367 return False
357 finally:
368 finally:
358 os.unlink(fn)
369 os.unlink(fn)
359
370
360 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems")
371 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems")
361 def has_hardlink_whitelisted():
372 def has_hardlink_whitelisted():
362 from mercurial import util
373 from mercurial import util
363 try:
374 try:
364 fstype = util.getfstype('.')
375 fstype = util.getfstype('.')
365 except OSError:
376 except OSError:
366 return False
377 return False
367 return fstype in util._hardlinkfswhitelist
378 return fstype in util._hardlinkfswhitelist
368
379
369 @check("rmcwd", "can remove current working directory")
380 @check("rmcwd", "can remove current working directory")
370 def has_rmcwd():
381 def has_rmcwd():
371 ocwd = os.getcwd()
382 ocwd = os.getcwd()
372 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix)
383 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix)
373 try:
384 try:
374 os.chdir(temp)
385 os.chdir(temp)
375 # On Linux, 'rmdir .' isn't allowed, but the other names are okay.
386 # On Linux, 'rmdir .' isn't allowed, but the other names are okay.
376 # On Solaris and Windows, the cwd can't be removed by any names.
387 # On Solaris and Windows, the cwd can't be removed by any names.
377 os.rmdir(os.getcwd())
388 os.rmdir(os.getcwd())
378 return True
389 return True
379 except OSError:
390 except OSError:
380 return False
391 return False
381 finally:
392 finally:
382 os.chdir(ocwd)
393 os.chdir(ocwd)
383 # clean up temp dir on platforms where cwd can't be removed
394 # clean up temp dir on platforms where cwd can't be removed
384 try:
395 try:
385 os.rmdir(temp)
396 os.rmdir(temp)
386 except OSError:
397 except OSError:
387 pass
398 pass
388
399
389 @check("tla", "GNU Arch tla client")
400 @check("tla", "GNU Arch tla client")
390 def has_tla():
401 def has_tla():
391 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
402 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision')
392
403
393 @check("gpg", "gpg client")
404 @check("gpg", "gpg client")
394 def has_gpg():
405 def has_gpg():
395 return matchoutput('gpg --version 2>&1', br'GnuPG')
406 return matchoutput('gpg --version 2>&1', br'GnuPG')
396
407
397 @check("gpg2", "gpg client v2")
408 @check("gpg2", "gpg client v2")
398 def has_gpg2():
409 def has_gpg2():
399 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
410 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.')
400
411
401 @check("gpg21", "gpg client v2.1+")
412 @check("gpg21", "gpg client v2.1+")
402 def has_gpg21():
413 def has_gpg21():
403 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)')
414 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)')
404
415
405 @check("unix-permissions", "unix-style permissions")
416 @check("unix-permissions", "unix-style permissions")
406 def has_unix_permissions():
417 def has_unix_permissions():
407 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
418 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
408 try:
419 try:
409 fname = os.path.join(d, 'foo')
420 fname = os.path.join(d, 'foo')
410 for umask in (0o77, 0o07, 0o22):
421 for umask in (0o77, 0o07, 0o22):
411 os.umask(umask)
422 os.umask(umask)
412 f = open(fname, 'w')
423 f = open(fname, 'w')
413 f.close()
424 f.close()
414 mode = os.stat(fname).st_mode
425 mode = os.stat(fname).st_mode
415 os.unlink(fname)
426 os.unlink(fname)
416 if mode & 0o777 != ~umask & 0o666:
427 if mode & 0o777 != ~umask & 0o666:
417 return False
428 return False
418 return True
429 return True
419 finally:
430 finally:
420 os.rmdir(d)
431 os.rmdir(d)
421
432
422 @check("unix-socket", "AF_UNIX socket family")
433 @check("unix-socket", "AF_UNIX socket family")
423 def has_unix_socket():
434 def has_unix_socket():
424 return getattr(socket, 'AF_UNIX', None) is not None
435 return getattr(socket, 'AF_UNIX', None) is not None
425
436
426 @check("root", "root permissions")
437 @check("root", "root permissions")
427 def has_root():
438 def has_root():
428 return getattr(os, 'geteuid', None) and os.geteuid() == 0
439 return getattr(os, 'geteuid', None) and os.geteuid() == 0
429
440
430 @check("pyflakes", "Pyflakes python linter")
441 @check("pyflakes", "Pyflakes python linter")
431 def has_pyflakes():
442 def has_pyflakes():
432 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
443 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
433 br"<stdin>:1: 're' imported but unused",
444 br"<stdin>:1: 're' imported but unused",
434 True)
445 True)
435
446
436 @check("pylint", "Pylint python linter")
447 @check("pylint", "Pylint python linter")
437 def has_pylint():
448 def has_pylint():
438 return matchoutput("pylint --help",
449 return matchoutput("pylint --help",
439 br"Usage: pylint",
450 br"Usage: pylint",
440 True)
451 True)
441
452
442 @check("clang-format", "clang-format C code formatter")
453 @check("clang-format", "clang-format C code formatter")
443 def has_clang_format():
454 def has_clang_format():
444 return matchoutput("clang-format --help",
455 return matchoutput("clang-format --help",
445 br"^OVERVIEW: A tool to format C/C\+\+[^ ]+ code.")
456 br"^OVERVIEW: A tool to format C/C\+\+[^ ]+ code.")
446
457
447 @check("jshint", "JSHint static code analysis tool")
458 @check("jshint", "JSHint static code analysis tool")
448 def has_jshint():
459 def has_jshint():
449 return matchoutput("jshint --version 2>&1", br"jshint v")
460 return matchoutput("jshint --version 2>&1", br"jshint v")
450
461
451 @check("pygments", "Pygments source highlighting library")
462 @check("pygments", "Pygments source highlighting library")
452 def has_pygments():
463 def has_pygments():
453 try:
464 try:
454 import pygments
465 import pygments
455 pygments.highlight # silence unused import warning
466 pygments.highlight # silence unused import warning
456 return True
467 return True
457 except ImportError:
468 except ImportError:
458 return False
469 return False
459
470
460 @check("outer-repo", "outer repo")
471 @check("outer-repo", "outer repo")
461 def has_outer_repo():
472 def has_outer_repo():
462 # failing for other reasons than 'no repo' imply that there is a repo
473 # failing for other reasons than 'no repo' imply that there is a repo
463 return not matchoutput('hg root 2>&1',
474 return not matchoutput('hg root 2>&1',
464 br'abort: no repository found', True)
475 br'abort: no repository found', True)
465
476
466 @check("ssl", "ssl module available")
477 @check("ssl", "ssl module available")
467 def has_ssl():
478 def has_ssl():
468 try:
479 try:
469 import ssl
480 import ssl
470 ssl.CERT_NONE
481 ssl.CERT_NONE
471 return True
482 return True
472 except ImportError:
483 except ImportError:
473 return False
484 return False
474
485
475 @check("sslcontext", "python >= 2.7.9 ssl")
486 @check("sslcontext", "python >= 2.7.9 ssl")
476 def has_sslcontext():
487 def has_sslcontext():
477 try:
488 try:
478 import ssl
489 import ssl
479 ssl.SSLContext
490 ssl.SSLContext
480 return True
491 return True
481 except (ImportError, AttributeError):
492 except (ImportError, AttributeError):
482 return False
493 return False
483
494
484 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
495 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
485 def has_defaultcacerts():
496 def has_defaultcacerts():
486 from mercurial import sslutil, ui as uimod
497 from mercurial import sslutil, ui as uimod
487 ui = uimod.ui.load()
498 ui = uimod.ui.load()
488 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
499 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts
489
500
490 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
501 @check("defaultcacertsloaded", "detected presence of loaded system CA certs")
491 def has_defaultcacertsloaded():
502 def has_defaultcacertsloaded():
492 import ssl
503 import ssl
493 from mercurial import sslutil, ui as uimod
504 from mercurial import sslutil, ui as uimod
494
505
495 if not has_defaultcacerts():
506 if not has_defaultcacerts():
496 return False
507 return False
497 if not has_sslcontext():
508 if not has_sslcontext():
498 return False
509 return False
499
510
500 ui = uimod.ui.load()
511 ui = uimod.ui.load()
501 cafile = sslutil._defaultcacerts(ui)
512 cafile = sslutil._defaultcacerts(ui)
502 ctx = ssl.create_default_context()
513 ctx = ssl.create_default_context()
503 if cafile:
514 if cafile:
504 ctx.load_verify_locations(cafile=cafile)
515 ctx.load_verify_locations(cafile=cafile)
505 else:
516 else:
506 ctx.load_default_certs()
517 ctx.load_default_certs()
507
518
508 return len(ctx.get_ca_certs()) > 0
519 return len(ctx.get_ca_certs()) > 0
509
520
510 @check("tls1.2", "TLS 1.2 protocol support")
521 @check("tls1.2", "TLS 1.2 protocol support")
511 def has_tls1_2():
522 def has_tls1_2():
512 from mercurial import sslutil
523 from mercurial import sslutil
513 return 'tls1.2' in sslutil.supportedprotocols
524 return 'tls1.2' in sslutil.supportedprotocols
514
525
515 @check("windows", "Windows")
526 @check("windows", "Windows")
516 def has_windows():
527 def has_windows():
517 return os.name == 'nt'
528 return os.name == 'nt'
518
529
519 @check("system-sh", "system() uses sh")
530 @check("system-sh", "system() uses sh")
520 def has_system_sh():
531 def has_system_sh():
521 return os.name != 'nt'
532 return os.name != 'nt'
522
533
523 @check("serve", "platform and python can manage 'hg serve -d'")
534 @check("serve", "platform and python can manage 'hg serve -d'")
524 def has_serve():
535 def has_serve():
525 return True
536 return True
526
537
527 @check("test-repo", "running tests from repository")
538 @check("test-repo", "running tests from repository")
528 def has_test_repo():
539 def has_test_repo():
529 t = os.environ["TESTDIR"]
540 t = os.environ["TESTDIR"]
530 return os.path.isdir(os.path.join(t, "..", ".hg"))
541 return os.path.isdir(os.path.join(t, "..", ".hg"))
531
542
532 @check("tic", "terminfo compiler and curses module")
543 @check("tic", "terminfo compiler and curses module")
533 def has_tic():
544 def has_tic():
534 try:
545 try:
535 import curses
546 import curses
536 curses.COLOR_BLUE
547 curses.COLOR_BLUE
537 return matchoutput('test -x "`which tic`"', br'')
548 return matchoutput('test -x "`which tic`"', br'')
538 except ImportError:
549 except ImportError:
539 return False
550 return False
540
551
541 @check("msys", "Windows with MSYS")
552 @check("msys", "Windows with MSYS")
542 def has_msys():
553 def has_msys():
543 return os.getenv('MSYSTEM')
554 return os.getenv('MSYSTEM')
544
555
545 @check("aix", "AIX")
556 @check("aix", "AIX")
546 def has_aix():
557 def has_aix():
547 return sys.platform.startswith("aix")
558 return sys.platform.startswith("aix")
548
559
549 @check("osx", "OS X")
560 @check("osx", "OS X")
550 def has_osx():
561 def has_osx():
551 return sys.platform == 'darwin'
562 return sys.platform == 'darwin'
552
563
553 @check("osxpackaging", "OS X packaging tools")
564 @check("osxpackaging", "OS X packaging tools")
554 def has_osxpackaging():
565 def has_osxpackaging():
555 try:
566 try:
556 return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
567 return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1)
557 and matchoutput(
568 and matchoutput(
558 'productbuild', br'Usage: productbuild ',
569 'productbuild', br'Usage: productbuild ',
559 ignorestatus=1)
570 ignorestatus=1)
560 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
571 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1)
561 and matchoutput(
572 and matchoutput(
562 'xar --help', br'Usage: xar', ignorestatus=1))
573 'xar --help', br'Usage: xar', ignorestatus=1))
563 except ImportError:
574 except ImportError:
564 return False
575 return False
565
576
566 @check('linuxormacos', 'Linux or MacOS')
577 @check('linuxormacos', 'Linux or MacOS')
567 def has_linuxormacos():
578 def has_linuxormacos():
568 # This isn't a perfect test for MacOS. But it is sufficient for our needs.
579 # This isn't a perfect test for MacOS. But it is sufficient for our needs.
569 return sys.platform.startswith(('linux', 'darwin'))
580 return sys.platform.startswith(('linux', 'darwin'))
570
581
571 @check("docker", "docker support")
582 @check("docker", "docker support")
572 def has_docker():
583 def has_docker():
573 pat = br'A self-sufficient runtime for'
584 pat = br'A self-sufficient runtime for'
574 if matchoutput('docker --help', pat):
585 if matchoutput('docker --help', pat):
575 if 'linux' not in sys.platform:
586 if 'linux' not in sys.platform:
576 # TODO: in theory we should be able to test docker-based
587 # TODO: in theory we should be able to test docker-based
577 # package creation on non-linux using boot2docker, but in
588 # package creation on non-linux using boot2docker, but in
578 # practice that requires extra coordination to make sure
589 # practice that requires extra coordination to make sure
579 # $TESTTEMP is going to be visible at the same path to the
590 # $TESTTEMP is going to be visible at the same path to the
580 # boot2docker VM. If we figure out how to verify that, we
591 # boot2docker VM. If we figure out how to verify that, we
581 # can use the following instead of just saying False:
592 # can use the following instead of just saying False:
582 # return 'DOCKER_HOST' in os.environ
593 # return 'DOCKER_HOST' in os.environ
583 return False
594 return False
584
595
585 return True
596 return True
586 return False
597 return False
587
598
588 @check("debhelper", "debian packaging tools")
599 @check("debhelper", "debian packaging tools")
589 def has_debhelper():
600 def has_debhelper():
590 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first
601 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first
591 # quote), so just accept anything in that spot.
602 # quote), so just accept anything in that spot.
592 dpkg = matchoutput('dpkg --version',
603 dpkg = matchoutput('dpkg --version',
593 br"Debian .dpkg' package management program")
604 br"Debian .dpkg' package management program")
594 dh = matchoutput('dh --help',
605 dh = matchoutput('dh --help',
595 br'dh is a part of debhelper.', ignorestatus=True)
606 br'dh is a part of debhelper.', ignorestatus=True)
596 dh_py2 = matchoutput('dh_python2 --help',
607 dh_py2 = matchoutput('dh_python2 --help',
597 br'other supported Python versions')
608 br'other supported Python versions')
598 # debuild comes from the 'devscripts' package, though you might want
609 # debuild comes from the 'devscripts' package, though you might want
599 # the 'build-debs' package instead, which has a dependency on devscripts.
610 # the 'build-debs' package instead, which has a dependency on devscripts.
600 debuild = matchoutput('debuild --help',
611 debuild = matchoutput('debuild --help',
601 br'to run debian/rules with given parameter')
612 br'to run debian/rules with given parameter')
602 return dpkg and dh and dh_py2 and debuild
613 return dpkg and dh and dh_py2 and debuild
603
614
604 @check("debdeps",
615 @check("debdeps",
605 "debian build dependencies (run dpkg-checkbuilddeps in contrib/)")
616 "debian build dependencies (run dpkg-checkbuilddeps in contrib/)")
606 def has_debdeps():
617 def has_debdeps():
607 # just check exit status (ignoring output)
618 # just check exit status (ignoring output)
608 path = '%s/../contrib/debian/control' % os.environ['TESTDIR']
619 path = '%s/../contrib/debian/control' % os.environ['TESTDIR']
609 return matchoutput('dpkg-checkbuilddeps %s' % path, br'')
620 return matchoutput('dpkg-checkbuilddeps %s' % path, br'')
610
621
611 @check("demandimport", "demandimport enabled")
622 @check("demandimport", "demandimport enabled")
612 def has_demandimport():
623 def has_demandimport():
613 # chg disables demandimport intentionally for performance wins.
624 # chg disables demandimport intentionally for performance wins.
614 return ((not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable')
625 return ((not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable')
615
626
616 @check("py3k", "running with Python 3.x")
627 @check("py3k", "running with Python 3.x")
617 def has_py3k():
628 def has_py3k():
618 return 3 == sys.version_info[0]
629 return 3 == sys.version_info[0]
619
630
620 @check("py3exe", "a Python 3.x interpreter is available")
631 @check("py3exe", "a Python 3.x interpreter is available")
621 def has_python3exe():
632 def has_python3exe():
622 return 'PYTHON3' in os.environ
633 return 'PYTHON3' in os.environ
623
634
624 @check("py3pygments", "Pygments available on Python 3.x")
635 @check("py3pygments", "Pygments available on Python 3.x")
625 def has_py3pygments():
636 def has_py3pygments():
626 if has_py3k():
637 if has_py3k():
627 return has_pygments()
638 return has_pygments()
628 elif has_python3exe():
639 elif has_python3exe():
629 # just check exit status (ignoring output)
640 # just check exit status (ignoring output)
630 py3 = os.environ['PYTHON3']
641 py3 = os.environ['PYTHON3']
631 return matchoutput('%s -c "import pygments"' % py3, br'')
642 return matchoutput('%s -c "import pygments"' % py3, br'')
632 return False
643 return False
633
644
634 @check("pure", "running with pure Python code")
645 @check("pure", "running with pure Python code")
635 def has_pure():
646 def has_pure():
636 return any([
647 return any([
637 os.environ.get("HGMODULEPOLICY") == "py",
648 os.environ.get("HGMODULEPOLICY") == "py",
638 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
649 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure",
639 ])
650 ])
640
651
641 @check("slow", "allow slow tests (use --allow-slow-tests)")
652 @check("slow", "allow slow tests (use --allow-slow-tests)")
642 def has_slow():
653 def has_slow():
643 return os.environ.get('HGTEST_SLOW') == 'slow'
654 return os.environ.get('HGTEST_SLOW') == 'slow'
644
655
645 @check("hypothesis", "Hypothesis automated test generation")
656 @check("hypothesis", "Hypothesis automated test generation")
646 def has_hypothesis():
657 def has_hypothesis():
647 try:
658 try:
648 import hypothesis
659 import hypothesis
649 hypothesis.given
660 hypothesis.given
650 return True
661 return True
651 except ImportError:
662 except ImportError:
652 return False
663 return False
653
664
654 @check("unziplinks", "unzip(1) understands and extracts symlinks")
665 @check("unziplinks", "unzip(1) understands and extracts symlinks")
655 def unzip_understands_symlinks():
666 def unzip_understands_symlinks():
656 return matchoutput('unzip --help', br'Info-ZIP')
667 return matchoutput('unzip --help', br'Info-ZIP')
657
668
658 @check("zstd", "zstd Python module available")
669 @check("zstd", "zstd Python module available")
659 def has_zstd():
670 def has_zstd():
660 try:
671 try:
661 import mercurial.zstd
672 import mercurial.zstd
662 mercurial.zstd.__version__
673 mercurial.zstd.__version__
663 return True
674 return True
664 except ImportError:
675 except ImportError:
665 return False
676 return False
666
677
667 @check("devfull", "/dev/full special file")
678 @check("devfull", "/dev/full special file")
668 def has_dev_full():
679 def has_dev_full():
669 return os.path.exists('/dev/full')
680 return os.path.exists('/dev/full')
670
681
671 @check("virtualenv", "Python virtualenv support")
682 @check("virtualenv", "Python virtualenv support")
672 def has_virtualenv():
683 def has_virtualenv():
673 try:
684 try:
674 import virtualenv
685 import virtualenv
675 virtualenv.ACTIVATE_SH
686 virtualenv.ACTIVATE_SH
676 return True
687 return True
677 except ImportError:
688 except ImportError:
678 return False
689 return False
679
690
680 @check("fsmonitor", "running tests with fsmonitor")
691 @check("fsmonitor", "running tests with fsmonitor")
681 def has_fsmonitor():
692 def has_fsmonitor():
682 return 'HGFSMONITOR_TESTS' in os.environ
693 return 'HGFSMONITOR_TESTS' in os.environ
683
694
684 @check("fuzzywuzzy", "Fuzzy string matching library")
695 @check("fuzzywuzzy", "Fuzzy string matching library")
685 def has_fuzzywuzzy():
696 def has_fuzzywuzzy():
686 try:
697 try:
687 import fuzzywuzzy
698 import fuzzywuzzy
688 fuzzywuzzy.__version__
699 fuzzywuzzy.__version__
689 return True
700 return True
690 except ImportError:
701 except ImportError:
691 return False
702 return False
@@ -1,108 +1,106
1 Require lfs-test-server (https://github.com/git-lfs/lfs-test-server)
1 #require lfs-test-server
2
3 $ hash lfs-test-server || { echo 'skipped: missing lfs-test-server'; exit 80; }
4
2
5 $ LFS_LISTEN="tcp://:$HGPORT"
3 $ LFS_LISTEN="tcp://:$HGPORT"
6 $ LFS_HOST="localhost:$HGPORT"
4 $ LFS_HOST="localhost:$HGPORT"
7 $ LFS_PUBLIC=1
5 $ LFS_PUBLIC=1
8 $ export LFS_LISTEN LFS_HOST LFS_PUBLIC
6 $ export LFS_LISTEN LFS_HOST LFS_PUBLIC
9 $ lfs-test-server &> lfs-server.log &
7 $ lfs-test-server &> lfs-server.log &
10 $ echo $! >> $DAEMON_PIDS
8 $ echo $! >> $DAEMON_PIDS
11
9
12 $ cat >> $HGRCPATH <<EOF
10 $ cat >> $HGRCPATH <<EOF
13 > [extensions]
11 > [extensions]
14 > lfs=
12 > lfs=
15 > [lfs]
13 > [lfs]
16 > url=http://foo:bar@$LFS_HOST/
14 > url=http://foo:bar@$LFS_HOST/
17 > threshold=1
15 > threshold=1
18 > EOF
16 > EOF
19
17
20 $ hg init repo1
18 $ hg init repo1
21 $ cd repo1
19 $ cd repo1
22 $ echo THIS-IS-LFS > a
20 $ echo THIS-IS-LFS > a
23 $ hg commit -m a -A a
21 $ hg commit -m a -A a
24
22
25 $ hg init ../repo2
23 $ hg init ../repo2
26 $ hg push ../repo2 -v
24 $ hg push ../repo2 -v
27 pushing to ../repo2
25 pushing to ../repo2
28 searching for changes
26 searching for changes
29 lfs: uploading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
27 lfs: uploading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
30 1 changesets found
28 1 changesets found
31 uncompressed size of bundle content:
29 uncompressed size of bundle content:
32 * (changelog) (glob)
30 * (changelog) (glob)
33 * (manifests) (glob)
31 * (manifests) (glob)
34 * a (glob)
32 * a (glob)
35 adding changesets
33 adding changesets
36 adding manifests
34 adding manifests
37 adding file changes
35 adding file changes
38 added 1 changesets with 1 changes to 1 files
36 added 1 changesets with 1 changes to 1 files
39
37
40 $ cd ../repo2
38 $ cd ../repo2
41 $ hg update tip -v
39 $ hg update tip -v
42 resolving manifests
40 resolving manifests
43 getting a
41 getting a
44 lfs: downloading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
42 lfs: downloading 31cf46fbc4ecd458a0943c5b4881f1f5a6dd36c53d6167d5b69ac45149b38e5b (12 bytes)
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46
44
47 When the server has some blobs already
45 When the server has some blobs already
48
46
49 $ hg mv a b
47 $ hg mv a b
50 $ echo ANOTHER-LARGE-FILE > c
48 $ echo ANOTHER-LARGE-FILE > c
51 $ echo ANOTHER-LARGE-FILE2 > d
49 $ echo ANOTHER-LARGE-FILE2 > d
52 $ hg commit -m b-and-c -A b c d
50 $ hg commit -m b-and-c -A b c d
53 $ hg push ../repo1 -v | grep -v '^ '
51 $ hg push ../repo1 -v | grep -v '^ '
54 pushing to ../repo1
52 pushing to ../repo1
55 searching for changes
53 searching for changes
56 lfs: need to transfer 2 objects (39 bytes)
54 lfs: need to transfer 2 objects (39 bytes)
57 lfs: uploading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
55 lfs: uploading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
58 lfs: uploading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
56 lfs: uploading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
59 1 changesets found
57 1 changesets found
60 uncompressed size of bundle content:
58 uncompressed size of bundle content:
61 adding changesets
59 adding changesets
62 adding manifests
60 adding manifests
63 adding file changes
61 adding file changes
64 added 1 changesets with 3 changes to 3 files
62 added 1 changesets with 3 changes to 3 files
65
63
66 $ hg --repo ../repo1 update tip -v
64 $ hg --repo ../repo1 update tip -v
67 resolving manifests
65 resolving manifests
68 getting b
66 getting b
69 getting c
67 getting c
70 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
68 lfs: downloading d11e1a642b60813aee592094109b406089b8dff4cb157157f753418ec7857998 (19 bytes)
71 getting d
69 getting d
72 lfs: downloading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
70 lfs: downloading 37a65ab78d5ecda767e8622c248b5dbff1e68b1678ab0e730d5eb8601ec8ad19 (20 bytes)
73 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
74
72
75 Check error message when the remote missed a blob:
73 Check error message when the remote missed a blob:
76
74
77 $ echo FFFFF > b
75 $ echo FFFFF > b
78 $ hg commit -m b -A b
76 $ hg commit -m b -A b
79 $ echo FFFFF >> b
77 $ echo FFFFF >> b
80 $ hg commit -m b b
78 $ hg commit -m b b
81 $ rm -rf .hg/store/lfs
79 $ rm -rf .hg/store/lfs
82 $ hg update -C '.^'
80 $ hg update -C '.^'
83 abort: LFS server claims required objects do not exist:
81 abort: LFS server claims required objects do not exist:
84 8e6ea5f6c066b44a0efa43bcce86aea73f17e6e23f0663df0251e7524e140a13!
82 8e6ea5f6c066b44a0efa43bcce86aea73f17e6e23f0663df0251e7524e140a13!
85 [255]
83 [255]
86
84
87 Check error message when object does not exist:
85 Check error message when object does not exist:
88
86
89 $ hg init test && cd test
87 $ hg init test && cd test
90 $ echo "[extensions]" >> .hg/hgrc
88 $ echo "[extensions]" >> .hg/hgrc
91 $ echo "lfs=" >> .hg/hgrc
89 $ echo "lfs=" >> .hg/hgrc
92 $ echo "[lfs]" >> .hg/hgrc
90 $ echo "[lfs]" >> .hg/hgrc
93 $ echo "threshold=1" >> .hg/hgrc
91 $ echo "threshold=1" >> .hg/hgrc
94 $ echo a > a
92 $ echo a > a
95 $ hg add a
93 $ hg add a
96 $ hg commit -m 'test'
94 $ hg commit -m 'test'
97 $ echo aaaaa > a
95 $ echo aaaaa > a
98 $ hg commit -m 'largefile'
96 $ hg commit -m 'largefile'
99 $ hg debugdata .hg/store/data/a.i 1 # verify this is no the file content but includes "oid", the LFS "pointer".
97 $ hg debugdata .hg/store/data/a.i 1 # verify this is no the file content but includes "oid", the LFS "pointer".
100 version https://git-lfs.github.com/spec/v1
98 version https://git-lfs.github.com/spec/v1
101 oid sha256:bdc26931acfb734b142a8d675f205becf27560dc461f501822de13274fe6fc8a
99 oid sha256:bdc26931acfb734b142a8d675f205becf27560dc461f501822de13274fe6fc8a
102 size 6
100 size 6
103 x-is-binary 0
101 x-is-binary 0
104 $ cd ..
102 $ cd ..
105 $ hg --config 'lfs.url=https://dewey-lfs.vip.facebook.com/lfs' clone test test2
103 $ hg --config 'lfs.url=https://dewey-lfs.vip.facebook.com/lfs' clone test test2
106 updating to branch default
104 updating to branch default
107 abort: LFS server error. Remote object for file data/a.i not found:(.*)! (re)
105 abort: LFS server error. Remote object for file data/a.i not found:(.*)! (re)
108 [255]
106 [255]
General Comments 0
You need to be logged in to leave comments. Login now