tests/hghave
changeset 1007 4fad25af75dd
child 1010 13862cca5537
equal deleted inserted replaced
1006:826681fc0976 1007:4fad25af75dd
       
     1 #!/usr/bin/env python
       
     2 """Test the running system for features availability. Exit with zero
       
     3 if all features are there, non-zero otherwise. If a feature name is
       
     4 prefixed with "no-", the absence of feature is tested.
       
     5 """
       
     6 import optparse
       
     7 import os
       
     8 import re
       
     9 import sys
       
    10 import tempfile
       
    11 
       
    12 tempprefix = 'hg-hghave-'
       
    13 
       
    14 def matchoutput(cmd, regexp, ignorestatus=False):
       
    15     """Return True if cmd executes successfully and its output
       
    16     is matched by the supplied regular expression.
       
    17     """
       
    18     r = re.compile(regexp)
       
    19     fh = os.popen(cmd)
       
    20     s = fh.read()
       
    21     try:
       
    22         ret = fh.close()
       
    23     except IOError:
       
    24         # Happen in Windows test environment
       
    25         ret = 1
       
    26     return (ignorestatus or ret is None) and r.search(s)
       
    27 
       
    28 def has_baz():
       
    29     return matchoutput('baz --version 2>&1', r'baz Bazaar version')
       
    30 
       
    31 def has_bzr():
       
    32     try:
       
    33         import bzrlib
       
    34         return bzrlib.__doc__ != None
       
    35     except ImportError:
       
    36         return False
       
    37 
       
    38 def has_bzr114():
       
    39     try:
       
    40         import bzrlib
       
    41         return (bzrlib.__doc__ != None
       
    42                 and bzrlib.version_info[:2] >= (1, 14))
       
    43     except ImportError:
       
    44         return False
       
    45 
       
    46 def has_cvs():
       
    47     re = r'Concurrent Versions System.*?server'
       
    48     return matchoutput('cvs --version 2>&1', re)
       
    49 
       
    50 def has_darcs():
       
    51     return matchoutput('darcs --version', r'2\.[2-9]', True)
       
    52 
       
    53 def has_mtn():
       
    54     return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
       
    55         'mtn --version', r'monotone 0\.', True)
       
    56 
       
    57 def has_eol_in_paths():
       
    58     try:
       
    59         fd, path = tempfile.mkstemp(prefix=tempprefix, suffix='\n\r')
       
    60         os.close(fd)
       
    61         os.remove(path)
       
    62         return True
       
    63     except:
       
    64         return False
       
    65 
       
    66 def has_executablebit():
       
    67     fd, path = tempfile.mkstemp(prefix=tempprefix)
       
    68     os.close(fd)
       
    69     try:
       
    70         s = os.lstat(path).st_mode
       
    71         os.chmod(path, s | 0100)
       
    72         return (os.lstat(path).st_mode & 0100 != 0)
       
    73     finally:
       
    74         os.remove(path)
       
    75 
       
    76 def has_icasefs():
       
    77     # Stolen from mercurial.util
       
    78     fd, path = tempfile.mkstemp(prefix=tempprefix, dir='.')
       
    79     os.close(fd)
       
    80     try:
       
    81         s1 = os.stat(path)
       
    82         d, b = os.path.split(path)
       
    83         p2 = os.path.join(d, b.upper())
       
    84         if path == p2:
       
    85             p2 = os.path.join(d, b.lower())
       
    86         try:
       
    87             s2 = os.stat(p2)
       
    88             return s2 == s1
       
    89         except:
       
    90             return False
       
    91     finally:
       
    92         os.remove(path)
       
    93 
       
    94 def has_inotify():
       
    95     try:
       
    96         import hgext.inotify.linux.watcher
       
    97         return True
       
    98     except ImportError:
       
    99         return False
       
   100 
       
   101 def has_fifo():
       
   102     return hasattr(os, "mkfifo")
       
   103 
       
   104 def has_cacheable_fs():
       
   105     from mercurial import util
       
   106 
       
   107     fd, path = tempfile.mkstemp(prefix=tempprefix)
       
   108     os.close(fd)
       
   109     try:
       
   110         return util.cachestat(path).cacheable()
       
   111     finally:
       
   112         os.remove(path)
       
   113 
       
   114 def has_lsprof():
       
   115     try:
       
   116         import _lsprof
       
   117         return True
       
   118     except ImportError:
       
   119         return False
       
   120 
       
   121 def has_gettext():
       
   122     return matchoutput('msgfmt --version', 'GNU gettext-tools')
       
   123 
       
   124 def has_git():
       
   125     return matchoutput('git --version 2>&1', r'^git version')
       
   126 
       
   127 def has_docutils():
       
   128     try:
       
   129         from docutils.core import publish_cmdline
       
   130         return True
       
   131     except ImportError:
       
   132         return False
       
   133 
       
   134 def getsvnversion():
       
   135     m = matchoutput('svn --version 2>&1', r'^svn,\s+version\s+(\d+)\.(\d+)')
       
   136     if not m:
       
   137         return (0, 0)
       
   138     return (int(m.group(1)), int(m.group(2)))
       
   139 
       
   140 def has_svn15():
       
   141     return getsvnversion() >= (1, 5)
       
   142 
       
   143 def has_svn13():
       
   144     return getsvnversion() >= (1, 3)
       
   145 
       
   146 def has_svn():
       
   147     return matchoutput('svn --version 2>&1', r'^svn, version') and \
       
   148         matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
       
   149 
       
   150 def has_svn_bindings():
       
   151     try:
       
   152         import svn.core
       
   153         version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
       
   154         if version < (1, 4):
       
   155             return False
       
   156         return True
       
   157     except ImportError:
       
   158         return False
       
   159 
       
   160 def has_p4():
       
   161     return matchoutput('p4 -V', r'Rev\. P4/') and matchoutput('p4d -V', r'Rev\. P4D/')
       
   162 
       
   163 def has_symlink():
       
   164     return hasattr(os, "symlink")
       
   165 
       
   166 def has_tla():
       
   167     return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
       
   168 
       
   169 def has_gpg():
       
   170     return matchoutput('gpg --version 2>&1', r'GnuPG')
       
   171 
       
   172 def has_unix_permissions():
       
   173     d = tempfile.mkdtemp(prefix=tempprefix, dir=".")
       
   174     try:
       
   175         fname = os.path.join(d, 'foo')
       
   176         for umask in (077, 007, 022):
       
   177             os.umask(umask)
       
   178             f = open(fname, 'w')
       
   179             f.close()
       
   180             mode = os.stat(fname).st_mode
       
   181             os.unlink(fname)
       
   182             if mode & 0777 != ~umask & 0666:
       
   183                 return False
       
   184         return True
       
   185     finally:
       
   186         os.rmdir(d)
       
   187 
       
   188 def has_pyflakes():
       
   189     return matchoutput('echo "import re" 2>&1 | pyflakes',
       
   190                        r"<stdin>:1: 're' imported but unused",
       
   191                        True)
       
   192 
       
   193 def has_pygments():
       
   194     try:
       
   195         import pygments
       
   196         return True
       
   197     except ImportError:
       
   198         return False
       
   199 
       
   200 def has_outer_repo():
       
   201     return matchoutput('hg root 2>&1', r'')
       
   202 
       
   203 def has_ssl():
       
   204     try:
       
   205         import ssl
       
   206         import OpenSSL
       
   207         OpenSSL.SSL.Context
       
   208         return True
       
   209     except ImportError:
       
   210         return False
       
   211 
       
   212 checks = {
       
   213     "baz": (has_baz, "GNU Arch baz client"),
       
   214     "bzr": (has_bzr, "Canonical's Bazaar client"),
       
   215     "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"),
       
   216     "cacheable": (has_cacheable_fs, "cacheable filesystem"),
       
   217     "cvs": (has_cvs, "cvs client/server"),
       
   218     "darcs": (has_darcs, "darcs client"),
       
   219     "docutils": (has_docutils, "Docutils text processing library"),
       
   220     "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
       
   221     "execbit": (has_executablebit, "executable bit"),
       
   222     "fifo": (has_fifo, "named pipes"),
       
   223     "gettext": (has_gettext, "GNU Gettext (msgfmt)"),
       
   224     "git": (has_git, "git command line client"),
       
   225     "gpg": (has_gpg, "gpg client"),
       
   226     "icasefs": (has_icasefs, "case insensitive file system"),
       
   227     "inotify": (has_inotify, "inotify extension support"),
       
   228     "lsprof": (has_lsprof, "python lsprof module"),
       
   229     "mtn": (has_mtn, "monotone client (>= 1.0)"),
       
   230     "outer-repo": (has_outer_repo, "outer repo"),
       
   231     "p4": (has_p4, "Perforce server and client"),
       
   232     "pyflakes": (has_pyflakes, "Pyflakes python linter"),
       
   233     "pygments": (has_pygments, "Pygments source highlighting library"),
       
   234     "ssl": (has_ssl, "python >= 2.6 ssl module and python OpenSSL"),
       
   235     "svn": (has_svn, "subversion client and admin tools"),
       
   236     "svn13": (has_svn13, "subversion client and admin tools >= 1.3"),
       
   237     "svn15": (has_svn15, "subversion client and admin tools >= 1.5"),
       
   238     "svn-bindings": (has_svn_bindings, "subversion python bindings"),
       
   239     "symlink": (has_symlink, "symbolic links"),
       
   240     "tla": (has_tla, "GNU Arch tla client"),
       
   241     "unix-permissions": (has_unix_permissions, "unix-style permissions"),
       
   242 }
       
   243 
       
   244 def list_features():
       
   245     for name, feature in checks.iteritems():
       
   246         desc = feature[1]
       
   247         print name + ':', desc
       
   248 
       
   249 def test_features():
       
   250     failed = 0
       
   251     for name, feature in checks.iteritems():
       
   252         check, _ = feature
       
   253         try:
       
   254             check()
       
   255         except Exception, e:
       
   256             print "feature %s failed:  %s" % (name, e)
       
   257             failed += 1
       
   258     return failed
       
   259 
       
   260 parser = optparse.OptionParser("%prog [options] [features]")
       
   261 parser.add_option("--test-features", action="store_true",
       
   262                   help="test available features")
       
   263 parser.add_option("--list-features", action="store_true",
       
   264                   help="list available features")
       
   265 parser.add_option("-q", "--quiet", action="store_true",
       
   266                   help="check features silently")
       
   267 
       
   268 if __name__ == '__main__':
       
   269     options, args = parser.parse_args()
       
   270     if options.list_features:
       
   271         list_features()
       
   272         sys.exit(0)
       
   273 
       
   274     if options.test_features:
       
   275         sys.exit(test_features())
       
   276 
       
   277     quiet = options.quiet
       
   278 
       
   279     failures = 0
       
   280 
       
   281     def error(msg):
       
   282         global failures
       
   283         if not quiet:
       
   284             sys.stderr.write(msg + '\n')
       
   285         failures += 1
       
   286 
       
   287     for feature in args:
       
   288         negate = feature.startswith('no-')
       
   289         if negate:
       
   290             feature = feature[3:]
       
   291 
       
   292         if feature not in checks:
       
   293             error('skipped: unknown feature: ' + feature)
       
   294             continue
       
   295 
       
   296         check, desc = checks[feature]
       
   297         try:
       
   298             available = check()
       
   299         except Exception, e:
       
   300             error('hghave check failed: ' + feature)
       
   301             continue
       
   302 
       
   303         if not negate and not available:
       
   304             error('skipped: missing feature: ' + desc)
       
   305         elif negate and available:
       
   306             error('skipped: system supports %s' % desc)
       
   307 
       
   308     if failures != 0:
       
   309         sys.exit(1)