Alien-SVN
view release on metacpan or search on metacpan
src/subversion/build/generator/gen_base.py view on Meta::CPAN
"""Find files matching a space separated list of globs
pats (string) is the list of glob patterns
path (string), if specified, is a path that will be prepended to each
glob pattern before it is evaluated
If path is none the return value is a list of filenames, otherwise
the return value is a list of 2-tuples. The first element in each tuple
is a matching filename and the second element is the portion of the
glob pattern which matched the file before its last forward slash (/)
"""
result = [ ]
for base_pat in pats.split():
if path:
pattern = build_path_join(path, base_pat)
else:
pattern = base_pat
files = sorted(glob.glob(native_path(pattern))) or [pattern]
if path is None:
# just append the names to the result list
for file in files:
result.append(build_path(file))
else:
# if we have paths, then we need to record how each source is located
# relative to the specified path
reldir = build_path_dirname(base_pat)
for file in files:
result.append((build_path(file), reldir))
return result
_re_public_include = re.compile(r'^subversion/include/(\w+)\.h$')
def _is_public_include(fname):
return _re_public_include.match(build_path(fname))
def _swig_include_wrapper(fname):
return native_path(_re_public_include.sub(
r"subversion/bindings/swig/proxy/\1_h.swg", build_path(fname)))
def _path_endswith(path, subpath):
"""Check if SUBPATH is a true path suffix of PATH.
"""
path_len = len(path)
subpath_len = len(subpath)
return (subpath_len > 0 and path_len >= subpath_len
and path[-subpath_len:] == subpath
and (path_len == subpath_len
or (subpath[0] == os.sep and path[-subpath_len] == os.sep)
or path[-subpath_len - 1] == os.sep))
class IncludeDependencyInfo:
"""Finds all dependencies between a named set of headers, and computes
closure, so that individual C and SWIG source files can then be scanned, and
the stored dependency data used to return all directly and indirectly
referenced headers.
Note that where SWIG is concerned, there are two different kinds of include:
(1) those that include files in SWIG processing, and so matter to the
generation of .c files. (These are %include, %import).
(2) those that include references to C headers in the generated output,
and so are not required at .c generation, only at .o generation.
(These are %{ #include ... %}).
This class works exclusively in native-style paths."""
def __init__(self, filenames, fnames_nonexist):
"""Operation of an IncludeDependencyInfo instance is restricted to a
'domain' - a set of header files which are considered interesting when
following and reporting dependencies. This is done to avoid creating any
dependencies on system header files. The domain is defined by three
factors:
(1) FILENAMES is a list of headers which are in the domain, and should be
scanned to discover how they inter-relate.
(2) FNAMES_NONEXIST is a list of headers which are in the domain, but will
be created by the build process, and so are not available to be
scanned - they will be assumed not to depend on any other interesting
headers.
(3) Files in subversion/bindings/swig/proxy/, which are based
autogenerated based on files in subversion/include/, will be added to
the domain when a file in subversion/include/ is processed, and
dependencies will be deduced by special-case logic.
"""
# This defines the domain (i.e. set of files) in which dependencies are
# being located. Its structure is:
# { 'basename.h': [ 'path/to/something/named/basename.h',
# 'path/to/another/named/basename.h', ] }
self._domain = {}
for fname in filenames + fnames_nonexist:
bname = os.path.basename(fname)
self._domain.setdefault(bname, []).append(fname)
if _is_public_include(fname):
swig_fname = _swig_include_wrapper(fname)
swig_bname = os.path.basename(swig_fname)
self._domain.setdefault(swig_bname, []).append(swig_fname)
# This data structure is:
# { 'full/path/to/header.h': { 'full/path/to/dependency.h': TYPECODE, } }
# TYPECODE is '#', denoting a C include, or '%' denoting a SWIG include.
self._deps = {}
for fname in filenames:
self._deps[fname] = self._scan_for_includes(fname)
if _is_public_include(fname):
hdrs = { self._domain["proxy.swg"][0]: '%',
self._domain["apr.swg"][0]: '%',
fname: '%' }
for h in self._deps[fname].keys():
if (_is_public_include(h)
or h == os.path.join('subversion', 'include', 'private',
'svn_debug.h')):
hdrs[_swig_include_wrapper(h)] = '%'
else:
raise RuntimeError("Public include '%s' depends on '%s', " \
"which is not a public include! What's going on?" % (fname, h))
swig_fname = _swig_include_wrapper(fname)
swig_bname = os.path.basename(swig_fname)
self._deps[swig_fname] = hdrs
for fname in fnames_nonexist:
self._deps[fname] = {}
# Keep recomputing closures until we see no more changes
while True:
changes = 0
for fname in self._deps.keys():
changes = self._include_closure(self._deps[fname]) or changes
if not changes:
break
def query_swig(self, fname):
"""Scan the C or SWIG file FNAME, and return the full paths of each
include file that is a direct or indirect dependency, as a 2-tuple:
(C_INCLUDES, SWIG_INCLUDES)."""
if fname in self._deps:
hdrs = self._deps[fname]
else:
hdrs = self._scan_for_includes(fname)
self._include_closure(hdrs)
c_filenames = []
swig_filenames = []
for hdr, hdr_type in hdrs.items():
( run in 0.374 second using v1.01-cache-2.11-cpan-02777c243ea )