[med-svn] [seqan2] 01/01: New upstream version 2.3.2+dfsg2
Michael Crusoe
misterc-guest at moszumanska.debian.org
Fri Oct 13 12:04:37 UTC 2017
This is an automated email from the git hooks/post-receive script.
misterc-guest pushed a commit to annotated tag upstream/2.3.2+dfsg2
in repository seqan2.
commit 5f349621ab5eb6643ed8a5f373b865daf0f65b6b
Author: Michael R. Crusoe <michael.crusoe at gmail.com>
Date: Fri Oct 13 04:38:14 2017 -0700
New upstream version 2.3.2+dfsg2
---
util/py_lib/CMakeLists.txt | 34 ++
util/py_lib/seqan/LICENSE | 26 ++
util/py_lib/seqan/__init__.py | 0
util/py_lib/seqan/app_tests.py | 458 ++++++++++++++++++++
util/py_lib/seqan/auto_build.py | 532 ++++++++++++++++++++++++
util/py_lib/seqan/fixgcov/README | 22 +
util/py_lib/seqan/fixgcov/__init__.py | 10 +
util/py_lib/seqan/fixgcov/app.py | 291 +++++++++++++
util/py_lib/seqan/paths.py | 65 +++
util/py_lib/seqan/pyclangcheck/__init__.py | 10 +
util/py_lib/seqan/pyclangcheck/app.py | 322 ++++++++++++++
util/py_lib/seqan/pyclangcheck/rules.py | 201 +++++++++
util/py_lib/seqan/pyclangcheck/simple_checks.py | 117 ++++++
util/py_lib/seqan/pyclangcheck/suppressions.py | 1 +
util/py_lib/seqan/pyclangcheck/violations.py | 91 ++++
util/py_lib/seqan/seqan.css | 7 +
util/py_lib/seqan/seqan.html | 148 +++++++
util/py_lib/seqan/skel.py | 467 +++++++++++++++++++++
18 files changed, 2802 insertions(+)
diff --git a/util/py_lib/CMakeLists.txt b/util/py_lib/CMakeLists.txt
new file mode 100644
index 0000000..ef4b578
--- /dev/null
+++ b/util/py_lib/CMakeLists.txt
@@ -0,0 +1,34 @@
+# ===========================================================================
+# SeqAn - The Library for Sequence Analysis
+# ===========================================================================
+# File: /util/py_lib/CMakeLists.txt
+#
+# CMakeLists.txt file for Python stuff.
+# ===========================================================================
+# Kicks off tests using Python nosetests.
+# ===========================================================================
+
+# Look for Python and stop if it could not be found.
+find_package (PythonInterp)
+
+if (NOT PYTHONINTERP_FOUND)
+ message (STATUS " Python not found, cannot test py_lib.")
+ return ()
+endif (NOT PYTHONINTERP_FOUND)
+
+# Look for nosetests and stop if it cannot be found
+execute_process(COMMAND ${PYTHON_EXECUTABLE} -m "nose"
+ RESULT_VARIABLE PYTHON_NOSETESTS_NOT_FOUND
+ OUTPUT_VARIABLE _IGNORED
+ ERROR_VARIABLE _IGNORED)
+
+if (PYTHON_NOSETESTS_NOT_FOUND)
+ message (STATUS " Python nosetests ('import nose' failed), cannot add tests for seqan.dox")
+ return ()
+endif (PYTHON_NOSETESTS_NOT_FOUND)
+
+# Adding test for dox.
+message (STATUS " adding nosetests for seqan.dox")
+add_test (NAME test_py_lib_dox
+ COMMAND nosetests
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/seqan/dox)
diff --git a/util/py_lib/seqan/LICENSE b/util/py_lib/seqan/LICENSE
new file mode 100644
index 0000000..61f9fdf
--- /dev/null
+++ b/util/py_lib/seqan/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2006-2016, Knut Reinert, FU Berlin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/util/py_lib/seqan/__init__.py b/util/py_lib/seqan/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/util/py_lib/seqan/app_tests.py b/util/py_lib/seqan/app_tests.py
new file mode 100644
index 0000000..2cc71bc
--- /dev/null
+++ b/util/py_lib/seqan/app_tests.py
@@ -0,0 +1,458 @@
+#!/usr/bin/env python2
+"""Helper code for app tests.
+
+This module contains helper functions and classes for making app tests easy.
+The advantage of using Python for this is easier portability instead of relying
+on Unix tools such as bash and diff which are harder to install on Windows than
+Python.
+
+App tests are performed by executing the programs on test data and comparing
+their output to previously generated "golden" output files.
+
+Classes/Functions:
+
+ class TestConf -- stores configuration of a test.
+ class TestPathHelper -- helps with constructing paths.
+ function runTest -- runs a test configured by a TestConf object.
+ function autolocateBinary -- locates a binary, possibly in an intermediary
+ directory.
+"""
+
+from __future__ import with_statement
+
+__author__ = 'Manuel Holtgrewe <manuel.holtgrewe at fu-berlin.de>'
+
+import difflib
+import hashlib
+import logging
+import optparse
+import os
+import os.path
+import re
+import subprocess
+import shutil
+import sys
+import tempfile
+import gzip
+
+def md5ForFile(f, block_size=2**20):
+ """Compute MD5 of a file.
+
+ Taken from http://stackoverflow.com/a/1131255/84349.
+ """
+ md5 = hashlib.md5()
+ while True:
+ data = f.read(block_size)
+ if not data:
+ break
+ md5.update(data)
+ return md5.hexdigest()
+
+
+# Valgrind flags, taken from CMake output, ideally given to test script by CMake?
+SUPPRESSIONS = '--suppressions=' + os.path.join(os.path.dirname(__file__), '..', '..', '..', 'misc', 'seqan.supp')
+VALGRIND_FLAGS = [SUPPRESSIONS] + '--error-exitcode=1 -q --tool=memcheck --leak-check=yes --show-reachable=yes --workaround-gcc296-bugs=yes --num-callers=50 --'.split()
+VALGRIND_PATH = '/usr/bin/valgrind'
+
+class BadResultException(Exception):
+ pass
+
+
+class TestConf(object):
+ """Configuration for one tests.
+
+ A test configuration consists of the parameters to give to the
+ program and the expected result.
+
+ Attrs:
+ program -- string, path to binary to execute.
+ args -- list of strings with arguments to the program.
+ to_diff -- optional list of pairs with (output-file, expected-file) paths
+ diff, the contents of output-file should be equal to the
+ contents of expected-file.
+ name -- optional string, name of the test.
+ redir_stdout -- optional string that gives the path to redirect stdout to
+ if the variable is not None.
+ redir_stderr -- optional string that gives the path to redirect stderr to
+ if the variable is not None.
+ check_callback -- callable throwing an exception on erorrs.
+ """
+
+ def __init__(self, program, args, to_diff=[], name=None,
+ redir_stdout=None, redir_stderr=None,
+ check_callback=None):
+ """Constructor, args correspond to attrs."""
+ self.program = program
+ self.args = args
+ self.to_diff = to_diff
+ self.name = name
+ self.redir_stdout = redir_stdout
+ self.redir_stderr = redir_stderr
+ if not hasattr(TestConf, 'valgrind'):
+ self.valgrind = False
+ else:
+ self.valgrind = TestConf.valgrind
+ self.check_callback = check_callback
+
+ def __str__(self):
+ fmt = 'TestConf(%s, %s, %s, %s, %s, %s)'
+ return fmt % (repr(self.program), self.args, self.to_diff, self.name,
+ self.redir_stdout, self.redir_stderr)
+
+ def commandLineArgs(self):
+ """Returns the command line."""
+ args = [x for x in self.args if x != '']
+ args = [self.program] + args
+ if self.valgrind:
+ args = [VALGRIND_PATH] + VALGRIND_FLAGS + args
+ return args
+
+
+class TestPathHelper(object):
+ """Helper class for paths.
+
+ TestPathHelper objects are configured with the appropriate paths. The
+ provide functions to construct when executing tests.
+ """
+
+ def __init__(self, source_base_path, binary_base_path,
+ tests_dir):
+ self.temp_dir = None
+ self.source_base_path = source_base_path
+ self.binary_base_path = binary_base_path
+ self.tests_dir = tests_dir
+ self.created_paths = []
+
+ def inFile(self, path):
+ """Convert the path of a test file.
+
+ The given path, relative to the test directory, will be transformed into an
+ absolute path to the file.
+
+ Args:
+ path -- relative path to a file in the test directory.
+
+ Returns:
+ Absolute to the file.
+ """
+ result = os.path.join(self.source_base_path, self.tests_dir, path)
+ logging.debug('inFile(%s) = %s', path, result)
+ return result
+
+ def outFile(self, path, subdir=None):
+ """Convert the path of an output file.
+
+ The given path will be converted to a path to a temporary file. The path
+ to this file will be created.
+
+ If subdir is set then a subdirectory with this name will be created and
+ the output will be relative to subdir.
+ """
+ if not self.temp_dir:
+ self.temp_dir = tempfile.mkdtemp()
+ if not os.path.isdir(self.temp_dir):
+ self.created_paths.append(self.temp_dir)
+ os.makedirs(self.temp_dir)
+ target_dir = self.temp_dir
+ if subdir:
+ target_dir = os.path.join(self.temp_dir, subdir)
+ if not os.path.isdir(target_dir):
+ self.created_paths.append(target_dir)
+ os.makedirs(target_dir)
+ logging.debug('outFile(%s, %s) = %s', path, subdir, self.temp_dir)
+ res = os.path.join(target_dir, path)
+ self.created_paths.append(res)
+ return res
+
+ def deleteTempDir(self):
+ """Remove the temporary directory created earlier and all files below."""
+ print >>sys.stderr, 'DELETING TEMP DIR', self.temp_dir
+ if self.temp_dir:
+ shutil.rmtree(self.temp_dir)
+
+
+def autolocateBinary(base_path, relative_path, binary_name):
+ """Autolocates a binary, possibly in an intermediary path.
+
+ When building applications with CMake, they do not always have the same
+ relative path from the binary build directory. For Unix Makefiles, the path
+ could be 'apps/tree_recon' whereas for Visual Studio, it could be
+ 'apps/Release/tree_recon'.
+
+ Also, it searches for the binary name in "${base_path}/bin".
+
+ This function tries to automatically guess the name of the file and return
+ the first one it finds.
+ """
+ # Names of intermediary directories and possible file extensions.
+ intermediary_dir_names = ['', 'Debug', 'Release']
+ extensions = ['', '.exe']
+ paths = [os.path.join(base_path, 'bin', binary_name),
+ os.path.join(base_path, 'bin', 'Debug', binary_name),
+ os.path.join(base_path, 'bin', 'Release', binary_name),
+ os.path.join(base_path, 'bin', binary_name + '.exe'),
+ os.path.join(base_path, 'bin', 'Debug', binary_name + '.exe'),
+ os.path.join(base_path, 'bin', 'Release', binary_name + '.exe')]
+ # Try all possible paths.
+ for dir_name in intermediary_dir_names:
+ for ext in extensions:
+ # With CMAKE_BINARY_DIR not set to "bin".
+ res_list = [base_path, relative_path, dir_name, binary_name + ext]
+ filtered_list = [x for x in res_list if x] # Filter out empty strings.
+ paths.append(os.path.join(*filtered_list))
+ if dir_name:
+ paths.append('/'.join([base_path] + relative_path.split('/')[:-1] +
+ [dir_name] + relative_path.split('/')[-1:] +
+ [binary_name]))
+ for path in paths:
+ logging.debug('Trying path %s', path)
+ if os.path.isfile(path):
+ logging.debug(' Found binary %s', path)
+ return path
+ # Fall back ot Unix default.
+ return os.path.join(base_path, relative_path, binary_name)
+
+
+def runTest(test_conf):
+ """Run the test configured in test_conf.
+
+ Args:
+ test_conf -- TestConf object to run test for.
+
+ Returns:
+ True on success, False on any errors.
+
+ Side Effects:
+ Errors are printed to stderr.
+ """
+ # Execute the program.
+ logging.debug('runTest(%s)', test_conf)
+ logging.debug('Executing "%s"', ' '.join(test_conf.commandLineArgs()))
+ stdout_file = subprocess.PIPE
+ if test_conf.redir_stdout:
+ logging.debug(' Redirecting stdout to "%s".' % test_conf.redir_stdout)
+ stdout_file = open(test_conf.redir_stdout, 'w+')
+ stderr_file = subprocess.PIPE
+ if test_conf.redir_stderr:
+ logging.debug(' Redirecting stderr to "%s".' % test_conf.redir_stderr)
+ stderr_file = open(test_conf.redir_stderr, 'w+')
+ try:
+ process = subprocess.Popen(test_conf.commandLineArgs(), stdout=stdout_file,
+ stderr=stderr_file)
+ retcode = process.wait()
+ logging.debug(' return code is %d', retcode)
+ if retcode != 0:
+ fmt = 'Return code of command "%s" was %d.'
+ print >>sys.stderr, '--- stdout begin --'
+ print >>sys.stderr, fmt % (' '.join(test_conf.commandLineArgs()), retcode)
+ print >>sys.stderr, stdout_file.read()
+ print >>sys.stderr, '--- stdout end --'
+ stdout_file.close()
+ if process.stderr:
+ stderr_contents = process.stderr.read()
+ else:
+ stderr_contents = ''
+ print >>sys.stderr, '-- stderr begin --'
+ print >>sys.stderr, stderr_contents
+ print >>sys.stderr, '-- stderr end --'
+ return False
+ except Exception, e:
+ # Print traceback.
+ import traceback
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ traceback.print_exception(exc_type, exc_value, exc_traceback)
+ fmt = 'ERROR (when executing "%s"): %s'
+ if stdout_file is not subprocess.PIPE:
+ stdout_file.close()
+ print >>sys.stderr, fmt % (' '.join(test_conf.commandLineArgs()), e)
+ return False
+ # Handle error of program, indicated by return code != 0.
+ if retcode != 0:
+ print >>sys.stderr, 'Error when executing "%s".' % ' '.join(test_conf.commandLineArgs())
+ print >>sys.stderr, 'Return code is %d' % retcode
+ if stdout_file is not subprocess.PIPE:
+ stdout_file.seek(0)
+ stdout_contents = process.stdout.read()
+ if stdout_contents:
+ print >>sys.stderr, '-- stdout begin --'
+ print >>sys.stderr, stdout_contents
+ print >>sys.stderr, '-- stdout end --'
+ else:
+ print >>sys.stderr, '-- stdout is empty --'
+ stderr_contents = process.stderr.read()
+ if stderr_contents:
+ print >>sys.stderr, '-- stderr begin --'
+ print >>sys.stderr, stderr_contents
+ print >>sys.stderr, '-- stderr end --'
+ else:
+ print >>sys.stderr, '-- stderr is empty --'
+ # Close standard out file if necessary.
+ if stdout_file is not subprocess.PIPE:
+ stdout_file.close()
+ # Compare results with expected results, if the expected and actual result
+ # are not equal then print diffs.
+ result = True
+ for tuple_ in test_conf.to_diff:
+ expected_path, result_path = tuple_[:2]
+ binary = False
+ gunzip = False
+ transforms = [NormalizeLineEndingsTransform()]
+ if len(tuple_) >= 3:
+ if tuple_[2] == 'md5':
+ binary = True
+ elif tuple_[2] == 'gunzip':
+ binary = True
+ gunzip = True
+ else:
+ transforms += tuple_[2]
+ try:
+ if gunzip:
+ f = gzip.open(expected_path, 'rb')
+ expected_md5 = md5ForFile(f)
+ f.close()
+ f = gzip.open(result_path, 'rb')
+ result_md5 = md5ForFile(f)
+ f.close()
+ if expected_md5 == result_md5:
+ continue
+ else:
+ tpl = (expected_path, expected_md5, result_md5, result_path)
+ print >>sys.stderr, 'md5(gunzip(%s)) == %s != %s == md5(gunzip(%s))' % tpl
+ result = False
+ if binary:
+ with open(expected_path, 'rb') as f:
+ expected_md5 = md5ForFile(f)
+ with open(result_path, 'rb') as f:
+ result_md5 = md5ForFile(f)
+ if expected_md5 == result_md5:
+ continue
+ else:
+ tpl = (expected_path, expected_md5, result_md5, result_path)
+ print >>sys.stderr, 'md5(%s) == %s != %s == md5(%s)' % tpl
+ result = False
+ else:
+ with open(expected_path, 'rb') as f:
+ expected_str = f.read()
+ for t in transforms:
+ expected_str = t.apply(expected_str, True)
+ with open(result_path, 'rb') as f:
+ result_str = f.read()
+ for t in transforms:
+ result_str = t.apply(result_str, False)
+ if expected_str == result_str:
+ continue
+ fmt = 'Comparing %s against %s'
+ print >>sys.stderr, fmt % (expected_path, result_path)
+ diff = difflib.unified_diff(expected_str.splitlines(),
+ result_str.splitlines())
+ for line in diff:
+ print >>sys.stderr, line
+ result = False
+ except Exception, e:
+ fmt = 'Error when trying to compare %s to %s: %s ' + str(type(e))
+ print >>sys.stderr, fmt % (expected_path, result_path, e)
+ result = False
+ # Call check callable.
+ if test_conf.check_callback:
+ try:
+ test_conf.check_callback()
+ except BadResultException, e:
+ print >>sys.stderr, 'Bad result: ' + str(e)
+ result = False
+ except Exception, e:
+ print >>sys.stderr, 'Error in checker: ' + str(type(e)) + ' ' + str(e)
+ result = False
+ return result
+
+
+class ReplaceTransform(object):
+ """Transformation on left and/or right files to diff."""
+
+ def __init__(self, needle, replacement, left=True, right=True):
+ self.needle = needle
+ self.replacement = replacement
+ self.left = left
+ self.right = right
+
+ def apply(self, text, is_left):
+ if (is_left and not self.left) or (not is_left and not self.right):
+ return text # Skip if no transform is to be applied.
+ return text.replace(self.needle, self.replacement)
+
+
+class NormalizeLineEndingsTransform(object):
+ """Normalizes line endings to '\n'."""
+
+ def __init__(self, left=True, right=True):
+ self.left = left
+ self.right = right
+
+ def apply(self, text, is_left):
+ if (is_left and not self.left) or (not is_left and not self.right):
+ return text # Skip if no transform is to be applied.
+ return text.replace('\r\n', '\n')
+
+
+class NormalizeScientificExponentsTransform(object):
+ """Transformation that normalized scientific notation exponents.
+
+ On Windows, scientific numbers are printed with an exponent padded to
+ a width of three with zeros, e.g. 1e003 instead of 1e03 as on Unix.
+
+ This transform normalizes to Unix or Windows.
+ """
+
+ def __init__(self, normalize_to_unix=True):
+ self.normalize_to_unix = normalize_to_unix
+
+ def apply(self, text, is_left):
+ """Apply the transform."""
+ if self.normalize_to_unix:
+ return re.sub(r'([-+]?(?:[0-9]*\.)?[0-9]+[eE][\-+]?)0([0-9]{2})', r'\1\2', text)
+ else:
+ return re.sub(r'([-+]?(?:[0-9]*\.)?[0-9]+[eE][\-+]?)([0-9]{2})', r'\10\2', text)
+
+
+class RegexpReplaceTransform(object):
+ """Transformation that applies regular expression replacement."""
+
+ def __init__(self, needle, replacement, left=True, right=True):
+ self.needle = needle
+ self.replacement = replacement
+ self.left = left
+ self.right = right
+
+ def apply(self, text, is_left):
+ """Apply the transform."""
+ if (is_left and not self.left) or (not is_left and not self.right):
+ return text # Skip if no transform is to be applied.
+ return re.sub(self.needle, self.replacement, text)
+
+
+class UniqueTransform(object):
+ """Unique sort transformation on left and/or right files to diff."""
+
+ def __init__(self, left=True, right=True):
+ self.left = left
+ self.right = right
+
+ def apply(self, text, is_left):
+ if (is_left and not self.left) or (not is_left and not self.right):
+ return text # Skip if no transform is to be applied.
+ return ''.join(sorted(set(text.splitlines(True))))
+
+
+def main(main_func, **kwargs):
+ """Run main_func with the first and second positional parameter."""
+ parser = optparse.OptionParser("usage: run_tests [options] SOURCE_ROOT_PATH BINARY_ROOT_PATH")
+ parser.add_option('-v', '--verbose', dest='verbose', action='store_true')
+ parser.add_option('--valgrind', dest='valgrind', action='store_true')
+ (options, args) = parser.parse_args()
+ if len(args) != 2:
+ parser.error('Incorrect number of arguments!')
+ return 2
+ if options.verbose:
+ logging.root.setLevel(logging.DEBUG)
+ if options.valgrind:
+ TestConf.valgrind = True
+ return main_func(args[0], args[1], **kwargs)
diff --git a/util/py_lib/seqan/auto_build.py b/util/py_lib/seqan/auto_build.py
new file mode 100755
index 0000000..9ae7e27
--- /dev/null
+++ b/util/py_lib/seqan/auto_build.py
@@ -0,0 +1,532 @@
+#!/usr/bin/env python2
+"""
+Automatic building of SeqAn apps and releases.
+"""
+
+from __future__ import print_function
+
+import subprocess
+import optparse
+import os.path
+import re
+import sys
+import shutil
+import tempfile
+
+# The git command to use.
+GIT_BINARY='git'
+# The CMake command to use.
+CMAKE_BINARY='cmake'
+
+# The default repository URL.
+REPOSITORY_URL='https://github.com/seqan/seqan.git'
+# The path to the package repository.
+DEFAULT_PACKAGE_DB='.'
+
+# Regular expression to use for tag names.
+TAG_RE=r'.*-v\d+\.\d+\.\d(-\w+)?'
+
+class MinisculeGitWrapper(object):
+ """Minimal git wrapper."""
+
+ def lsRemote(self, url):
+ """Execute 'git ls-remote ${url} --tags'."""
+ # Execute ls-remote command.
+ print('Executing "%s %s %s"' % (GIT_BINARY, 'ls-remote --tags', url), file=sys.stderr)
+ popen = subprocess.Popen([GIT_BINARY, 'ls-remote', '--tags', url],
+ stdout=subprocess.PIPE)
+ out_data, err_data = popen.communicate()
+ print(' => %d' % popen.returncode, file=sys.stderr)
+ if popen.returncode != 0:
+ print('ERROR during git call.', file=sys.stderr)
+ return 1
+ # Parse out revisions and tags names.
+ lines = out_data.splitlines()
+ revs_tags = [(line.split()[0], line.split()[-1]) for line in lines]
+ res = []
+ for rev, tag in revs_tags:
+ if '^{}' in tag:
+ continue # Skip with ^{} in tag name
+ tag2 = tag[10:]
+ res.append((rev, tag2))
+ return res
+
+ def checkout(self, path, treeish):
+ """Execute "git checkout" in the checkout at path."""
+ # Executing git checkout.
+ args = [GIT_BINARY, 'checkout', treeish]
+ print('Executing "%s" in "%s"' % (' '.join(args), path), file=sys.stderr)
+ popen = subprocess.Popen(args, cwd=path)
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during git call.', file=sys.stderr)
+ # Executing force resetting to current revision.
+ args = [GIT_BINARY, 'rm', '--cached', '.']
+ print('Executing "%s" in "%s"' % (' '.join(args), path), file=sys.stderr)
+ popen = subprocess.Popen(args, cwd=path)
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during git call.', file=sys.stderr)
+ args = [GIT_BINARY, 'reset', '--hard']
+ print('Executing "%s" in "%s"' % (' '.join(args), path), file=sys.stderr)
+ popen = subprocess.Popen(args, cwd=path)
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during git call.', file=sys.stderr)
+ return popen.returncode
+
+ def archive(self, path, treeish, output, prefix):
+ """Execute git archive."""
+ args = [GIT_BINARY, 'archive', '--prefix=%s/' % prefix, '--output=%s' % output, treeish]
+ print('Executing "%s" in "%s"' % (' '.join(args), path), file=sys.stderr)
+ popen = subprocess.Popen(args, cwd=path)
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during git call.', file=sys.stderr)
+ return popen.returncode
+
+ def clone(self, url, tag, dest_dir):
+ """Execute 'git clone ${url} ${dest_dir}' and then get specific tag."""
+ # Clone repository
+ args = [GIT_BINARY, 'clone', url, dest_dir]
+ print('Executing "%s"' % ' '.join(args), file=sys.stderr)
+ popen = subprocess.Popen(args)
+ popen.wait()
+ print(' => %d' % popen.returncode, file=sys.stderr)
+ if popen.returncode != 0:
+ return popen.returncode
+ return self.checkout(dest_dir, tag)
+
+
+class Package(object):
+ """Represent a package with a given name, version, OS and architeture."""
+
+ def __init__(self, name, version, os, word_size, pkg_format):
+ self.name = name
+ self.version = version
+ self.os = os
+ self.word_size = word_size
+ SYS_NAMES = {'Windows': {'32': 'win32-i686', '64': 'win64-x86_64'},
+ 'Linux': {'32': 'Linux-i686', '64': 'Linux-x86_64'},
+ 'Mac': {'32': 'Darwin-i686', '64': 'Darwin-x86_64'}}
+ self.system_name = SYS_NAMES[os][word_size]
+ self.pkg_format = pkg_format
+
+ def fileName(self):
+ if self.name == 'seqan-library':
+ return '%s-%s.%s' % (self.name, self.version, self.pkg_format)
+ else:
+ return '%s-%s-%s.%s' % (self.name, self.version, self.system_name,
+ self.pkg_format)
+
+
+class BuildStep(object):
+ """Management of one build step."""
+
+ def __init__(self, path, treeish, name, version, os, word_size, pkg_formats,
+ repository_url, make_args, options, tmp_dir=None):
+ self.base_path = path
+ self.treeish = treeish
+ self.name = name
+ self.version = version.split('-', 1)[0]
+ print ( 'Version: %s Self.Version: %s' % (version, self.version), file=sys.stdout)
+ self.major_version = int(self.version.split('.')[0])
+ print ( 'Major_Version: %s' % self.major_version, file=sys.stdout)
+ self.minor_version = int(self.version.split('.')[1])
+ print ( 'Minor_Version: %s' % self.minor_version, file=sys.stdout)
+ self.patch_version = 0
+ if len(self.version.split('.')) > 2:
+ self.patch_version = int(self.version.split('.')[2])
+ self.version = '%d.%d.%d' % (self.major_version, self.minor_version, self.patch_version)
+ print ( 'Self_Version: %s' % self.version, file=sys.stdout)
+ self.os = os
+ self.word_size = word_size
+ self.pkg_formats = pkg_formats
+ if name == 'seqan':
+ self.packages = [Package(name + suffix, self.version, os, word_size, f)
+ for f in pkg_formats for suffix in ['-apps', '-library']]
+ else:
+ self.packages = [Package(name, self.version, os, word_size, f)
+ for f in pkg_formats]
+ self.repository_url = repository_url
+ self.make_args = make_args
+ self.options = options
+ # If set then this is used instead of a random name in TMPDIR.
+ self.tmp_dir = tmp_dir
+
+ def buildNeeded(self):
+ """Returns whether one of the package files is missing."""
+ for p in self.packages:
+ package_path = os.path.join(self.base_path, p.name, p.fileName())
+ if 'x86' in package_path and 'x86_64' not in package_path: # fix processor name
+ package_path = package_path.replace('x86', 'x86_64')
+ if 'win32' in package_path or 'win64' in package_path: # fix OS name
+ package_path = package_path.replace('win32', 'Windows').replace('win64', 'Windows')
+ if 'Darwin' in package_path: # fix OS name
+ package_path = package_path.replace('Darwin', 'Mac')
+ if not os.path.exists(package_path):
+ if self.options.verbosity >= 1:
+ print('File %s does not exist yet.' % package_path, file=sys.stderr)
+ return True
+ elif self.options.verbosity >= 1:
+ print('File %s exists.' % package_path, file=sys.stderr)
+ return False
+
+ def copyArchives(self, build_dir):
+ """Copy built packages to base_path directory."""
+ for p in self.packages:
+ from_ = os.path.join(build_dir, p.fileName())
+ if os.path.exists(from_):
+ to = os.path.join(self.base_path, p.name, os.path.basename(from_))
+ if not os.path.exists(os.path.dirname(to)): # Create directory if necessary.
+ os.makedirs(os.path.dirname(to))
+ print("Copying %s => %s" % (from_, to), file=sys.stderr)
+ if 'x86' in to and 'x86_64' not in to: # fix processor name
+ to = to.replace('x86', 'x86_64')
+ if 'win32' in to or 'win64' in to: # fix OS name
+ to = to.replace('win32', 'Windows').replace('win64', 'Windows')
+ if 'Darwin' in to: # fix OS name
+ to = to.replace('Darwin', 'Mac')
+ shutil.copyfile(from_, to)
+ else:
+ print('%s does not exist (not fatal)' % from_, file=sys.stderr)
+
+ def buildSeqAnRelease(self, checkout_dir, build_dir):
+ """Build SeqAn release: Apps and library build."""
+ # Build seqan-apps.
+ #
+ # Create build directory.
+ if not os.path.exists(build_dir):
+ print('Creating build directory %s' % (build_dir,), file=sys.stderr)
+ os.mkdir(build_dir)
+ # Execute CMake.
+ cmake_args = [CMAKE_BINARY, checkout_dir,
+ '-DSEQAN_BUILD_SYSTEM=SEQAN_RELEASE_APPS']
+ # Use appropriate CMake flags for OS and processor.
+ # Use appropriate CMake flags for OS and processor.
+ if self.word_size == '32':
+ cmake_args.append('-DSEQAN_SYSTEM_PROCESSOR=i686')
+ if self.os != 'Windows':
+ cmake_args.append('-DCMAKE_CXX_FLAGS=-m32')
+ else:
+ cmake_args += ['-G', 'Visual Studio 10']
+ else: # self.word_size == '64'
+ cmake_args.append('-DSEQAN_SYSTEM_PROCESSOR=x86_64')
+ if self.os == 'Windows':
+ cmake_args += ['-G', 'Visual Studio 10 Win64']
+ print('Executing CMake: "%s"' % (' '.join(cmake_args),), file=sys.stderr)
+ popen = subprocess.Popen(cmake_args, cwd=build_dir, env=os.environ.copy())
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during make call.', file=sys.stderr)
+ print(out_data, file=sys.stderr)
+ print(err_data, file=sys.stderr)
+ return 1
+ # Execute Make.
+ cmake_args = [CMAKE_BINARY, '--build', build_dir, '--target', 'package', '--config', 'Release', '--'] + self.make_args
+ print('Building with CMake: "%s"' % (' '.join(cmake_args),), file=sys.stderr)
+ popen = subprocess.Popen(cmake_args, cwd=build_dir, env=os.environ.copy())
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during make call.', file=sys.stderr)
+ print(out_data, file=sys.stderr)
+ print(err_data, file=sys.stderr)
+ return 1
+ # Copy over the archives.
+ self.copyArchives(build_dir)
+ # Remove build directory.
+ if not self.options.keep_build_dir:
+ print('Removing build directory %s' % build_dir, file=sys.stderr)
+ shutil.rmtree(build_dir)
+ # Build seqan-library.
+ #
+ # Create build directory.
+ if not os.path.exists(build_dir):
+ print("Creating build directory %s" % (build_dir,), file=sys.stderr)
+ os.mkdir(build_dir)
+ # Execute CMake.
+ cmake_args = [CMAKE_BINARY, checkout_dir,
+ "-DSEQAN_BUILD_SYSTEM=SEQAN_RELEASE_LIBRARY"]
+ print('Executing CMake: "%s"' % (' '.join(cmake_args),), file=sys.stderr)
+ popen = subprocess.Popen(cmake_args, cwd=build_dir, env=os.environ.copy())
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during make call.', file=sys.stderr)
+ print(out_data, file=sys.stderr)
+ print(err_data, file=sys.stderr)
+ return 1
+ # Build Docs
+ cmake_args = [CMAKE_BINARY, '--build', build_dir, '--target', 'docs', '--'] + self.make_args
+ print('Building with CMake: "%s"' % (' '.join(cmake_args),), file=sys.stderr)
+ popen = subprocess.Popen(cmake_args, cwd=build_dir, env=os.environ.copy())
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during make dox call.', file=sys.stderr)
+ print(out_data, file=sys.stderr)
+ print(err_data, file=sys.stderr)
+ # Execute Make.
+ cmake_args = [CMAKE_BINARY, '--build', build_dir, '--target', 'package', '--'] + self.make_args
+ print('Building with CMake: "%s"' % (' '.join(cmake_args),), file=sys.stderr)
+ popen = subprocess.Popen(cmake_args, cwd=build_dir, env=os.environ.copy())
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during make call.', file=sys.stderr)
+ print(out_data, file=sys.stderr)
+ print(err_data, file=sys.stderr)
+ return 1
+ self.copyArchives(build_dir)
+ # Remove build directory.
+ if not self.options.keep_build_dir:
+ print('Removing build directory %s' % build_dir, file=sys.stderr)
+ shutil.rmtree(build_dir)
+
+ def buildApp(self, checkout_dir, build_dir):
+ """Build an application."""
+ # Create build directory.
+ print("Creating build directory %s" % (build_dir,), file=sys.stderr)
+ if not os.path.exists(build_dir):
+ os.mkdir(build_dir)
+ # Execute CMake.
+ cmake_args = [CMAKE_BINARY, checkout_dir,# '-G', 'Visual Studio 10',
+ "-DCMAKE_BUILD_TYPE=Release",
+ "-DSEQAN_BUILD_SYSTEM=APP:%s" % self.name,
+ "-DSEQAN_APP_VERSION=%d.%d.%d" %
+ (self.major_version, self.minor_version, self.patch_version)]
+ # Use appropriate CMake flags for OS and processor.
+ if self.word_size == '32':
+ cmake_args.append('-DSEQAN_SYSTEM_PROCESSOR=i686')
+ if self.os != 'Windows':
+ cmake_args.append('-DCMAKE_CXX_FLAGS=-m32')
+ else:
+ cmake_args += ['-G', 'Visual Studio 10']
+ else: # self.word_size == '64'
+ cmake_args.append('-DSEQAN_SYSTEM_PROCESSOR=x86_64')
+ if self.os == 'Windows':
+ cmake_args += ['-G', 'Visual Studio 10 Win64']
+ print('Executing CMake: "%s"' % (' '.join(cmake_args),), file=sys.stderr)
+ #for key in sorted(os.environ.keys()):
+ # print(key, ': ', os.environ[key], file=sys.stderr)
+ popen = subprocess.Popen(cmake_args, cwd=build_dir, env=os.environ.copy())
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during make call.', file=sys.stderr)
+ print(out_data, file=sys.stderr)
+ print(err_data, file=sys.stderr)
+ return 1
+ # Build and package project.
+ make_args = [CMAKE_BINARY, '--build', build_dir, '--target', 'package', '--config', 'Release']
+ if self.options.verbosity > 1:
+ make_args.insert(1, 'VERBOSE=1')
+ print('Building with CMake: "%s"' % (' '.join(make_args),), file=sys.stderr)
+ popen = subprocess.Popen(make_args, cwd=build_dir)
+ out_data, err_data = popen.communicate()
+ if popen.returncode != 0:
+ print('ERROR during make call.', file=sys.stderr)
+ print(out_data, file=sys.stderr)
+ print(err_data, file=sys.stderr)
+ return 1
+ # Copy out archives.
+ self.copyArchives(build_dir)
+ # Remove build directory.
+ if not self.options.keep_co_dir:
+ print('Removing build directory %s' % build_dir, file=sys.stderr)
+ shutil.rmtree(build_dir)
+
+ def tmpDir(self):
+ print('self.tmp_dir = %s' % self.tmp_dir, file=sys.stderr)
+ if self.tmp_dir:
+ if not os.path.exists(self.tmp_dir):
+ os.makedirs(self.tmp_dir)
+ return self.tmp_dir
+ else:
+ return tempfile.mkdtemp()
+
+ def execute(self):
+ """Execute build step."""
+ # Create temporary directory.
+ tmp_dir = self.tmpDir()
+ print('Temporary directory is %s' % (tmp_dir,), file=sys.stderr)
+ # Create Git checkout in temporary directory.
+ checkout_dir = os.path.join(tmp_dir, os.path.basename(self.repository_url))
+ print('Creating checkout in %s' % checkout_dir, file=sys.stderr)
+ git = MinisculeGitWrapper()
+ git.clone(self.repository_url, self.treeish, checkout_dir)
+ # Create build directory.
+ suffix = '-build-%s-%s' % (self.os, self.word_size)
+ build_dir = os.path.join(tmp_dir, os.path.basename(self.repository_url) + suffix)
+ if os.path.exists(build_dir) and not self.options.keep_build_dir:
+ print('Removing build directory %s' % (build_dir,), file=sys.stderr)
+ shutil.rmtree(build_dir)
+ # insert app tags
+ subprocess.call(['../tag-apps.sh', checkout_dir])
+ # Perform the build. We have to separate between app and whole SeqAn releases.
+ if self.name == 'seqan':
+ self.buildSeqAnRelease(checkout_dir, build_dir)
+ else:
+ self.buildApp(checkout_dir, build_dir)
+ if not self.options.keep_co_dir:
+ print('Removing checkout directory %s' % (checkout_dir,), file=sys.stderr)
+ shutil.rmtree(checkout_dir)
+ # Remove temporary directory again.
+ if self.tmp_dir and not self.options.keep_tmp_dir:
+ # Only remove if not explicitely given and not forced to keep.
+ print('Removing temporary directory %s' % (tmp_dir,), file=sys.stderr)
+ shutil.rmtree(tmp_dir)
+
+
+def workTags(options):
+ """Run the individual steps for tags."""
+ # Get the revisions and tag names.
+ git = MinisculeGitWrapper()
+ #revs_tags = [(rev, tag) for (rev, tag) in git.lsRemote(options.repository_url)
+ #if re.match(TAG_RE, tag)]
+ tags = [tag for (rev, tag) in git.lsRemote(options.repository_url)
+ if re.match(TAG_RE, tag)]
+ tags.extend(subprocess.check_output(['../tag-apps.sh', os.getcwd(), 'printonly']).split('\n'))
+ # Enumerate all package names that we could enumerate.
+ print('tags = %s' % tags, file=sys.stderr)
+ print('word_sizes = %s' % options.word_sizes, file=sys.stderr)
+ for tag in tags:
+ name, version = tag.rsplit('-v', 1)
+ #version = version[1:]
+ print ('Tag: %s Name: %s Version: %s' % (tag, name, version), file=sys.stdout)
+ for word_size in options.word_sizes.split(','):
+ # Create build step for this package name.
+ pkg_formats = options.package_formats.split(',')
+ build_step = BuildStep(options.package_db, tag, name, version, options.os,
+ word_size, pkg_formats, options.repository_url,
+ options.make_args.split(), options, options.tmp_dir)
+ # Check whether we need to build this.
+ if not build_step.buildNeeded():
+ continue # Skip
+ # Execute build step.
+ build_step.execute()
+ return 0
+
+
+def workTrunk(options):
+ """Run the individual steps for the trunk with fake tag name."""
+ # Get the revisions and tag names.
+ git = MinisculeGitWrapper()
+ # Enumerate all package names that we could enumerate.
+ print('fake tag = %s' % options.build_trunk_as, file=sys.stderr)
+ print('word_sizes = %s' % options.word_sizes, file=sys.stderr)
+ name, version = options.build_trunk_as.rsplit('-', 1)
+ version = version[1:]
+ for word_size in options.word_sizes.split(','):
+ # Create build step for this package name.
+ pkg_formats = options.package_formats.split(',')
+ build_step = BuildStep(options.package_db, 'master', name, version, options.os,
+ word_size, pkg_formats, options.repository_url,
+ options.make_args.split(), options, options.tmp_dir)
+ # Check whether we need to build this.
+ if not build_step.buildNeeded():
+ continue # Skip
+ # Execute build step.
+ build_step.execute()
+ return 0
+
+
+def workSrcTar(options):
+ """Build the source tarball."""
+ # Get the revisions and tag names.
+ git = MinisculeGitWrapper()
+ revs_tags = [(rev, tag) for (rev, tag) in git.lsRemote(options.repository_url)
+ if re.match(TAG_RE, tag)]
+ # Enumerate all package names that we could enumerate.
+ for rev, tag in revs_tags:
+ # Build URL.
+ name, version = tag.rsplit('-', 1)
+ version = version[1:] # remove prefix "v"
+ if name != 'seqan':
+ continue # only build source tarballs for seqan
+ # Create destination file name.
+ file_name = '%s-src-%s.tar.gz' % (name, version)
+ dest = os.path.join(options.package_db, '%s-src' % name, file_name)
+ # Check whether we need to rebuild.
+ if os.path.exists(dest):
+ print('Skipping %s; already exists.' % dest, file=sys.stderr)
+ continue
+ # Create temporary directory.
+ if options.tmp_dir:
+ if not os.path.exists(options.tmp_dir):
+ os.makedirs(options.tmp_dir)
+ tmp_dir = options.tmp_dir
+ else:
+ tmp_dir = tempfile.mkdtemp()
+ print('Temporary directory is %s' % tmp_dir, file=sys.stderr)
+ # Create git checkout in temporary directory.
+ checkout_dir = os.path.join(tmp_dir, tag)
+ print('Creating checkout in %s' % checkout_dir, file=sys.stderr)
+ from_ = os.path.join(tmp_dir, file_name)
+ git.clone(options.repository_url, tag, checkout_dir)
+ # Create target directory if it does not exist yet.
+ if not os.path.exists(os.path.dirname(dest)): # Create directory if necessary.
+ os.makedirs(os.path.dirname(dest))
+ # Create tarball.
+ git.archive(checkout_dir, tag, dest, prefix='%s-%s' % (name, version))
+ # Remove temporary directory again.
+ if tmp_dir and not options.keep_tmp_dir:
+ # Only remove if not explicitely given and not forced to keep.
+ print('Removing temporary directory %s' % (tmp_dir,), file=sys.stderr)
+ shutil.rmtree(tmp_dir)
+ return 0
+
+
+def work(options):
+ """Run the steps."""
+ if options.src_tar:
+ return workSrcTar(options)
+ elif not options.build_trunk_as:
+ return workTags(options)
+ else:
+ return workTrunk(options)
+
+
+def main():
+ """Program entry point."""
+ # Parse Arguments.
+ parser = optparse.OptionParser()
+
+ parser.add_option('-u', '--repository-url', default=REPOSITORY_URL,
+ help='The git repository URL.', metavar='URL')
+ parser.add_option('--package-db', dest='package_db', type='string',
+ default=DEFAULT_PACKAGE_DB,
+ help='Path the directory with the packages.')
+
+ parser.add_option('--src-tar', dest='src_tar', action='store_true',
+ help='If specified then only the src tarball will be created')
+ parser.add_option('-v', dest='verbosity', action='count', default=1,
+ help='Increase verbosity.')
+ parser.add_option('--package-formats', dest='package_formats',
+ default='tar.bz2,zip',
+ help='Expect the following packages to be created.')
+ parser.add_option('--os', dest='os', help='Expect the packages to be created for this OS.',
+ default='Linux')
+ parser.add_option('--word-sizes', dest='word_sizes', default='32,64',
+ help='Build binaries with the given word sizes')
+ parser.add_option('--make-args', dest='make_args', type="string", default='',
+ help='Arguments for make.')
+ parser.add_option('--tmp-dir', dest='tmp_dir', type='string', default=None,
+ help='Temporary directory to use. Use this to reuse the same checkout.')
+ parser.add_option('--build-trunk-as', dest='build_trunk_as', type='string', default=None,
+ help='Build current trunk with this string as a tag name.')
+ parser.add_option('--keep-build-dir', dest='keep_build_dir', default=False,
+ action='store_true', help='Keep build directory.')
+ parser.add_option('--keep-tmp-dir', dest='keep_tmp_dir', default=False,
+ action='store_true', help='Keep temporary directory.')
+ parser.add_option('--keep-co-dir', dest='keep_co_dir', default=False,
+ action='store_true', help='Keep checkout directory.')
+ parser.epilog = ('The program will use the environment variable TMPDIR as '
+ 'the directory for temporary files.')
+
+ options, args = parser.parse_args()
+ if args:
+ parser.error('No arguments expected!')
+ return 1
+
+ options.package_db = os.path.abspath(options.package_db)
+
+ # Fire up work.
+ print('Running SeqAn Auto Builder', file=sys.stderr)
+ return work(options)
diff --git a/util/py_lib/seqan/fixgcov/README b/util/py_lib/seqan/fixgcov/README
new file mode 100644
index 0000000..c3494f3
--- /dev/null
+++ b/util/py_lib/seqan/fixgcov/README
@@ -0,0 +1,22 @@
+gcov Output Fix Tool
+====================
+
+This tool can be used in nightly builds with CMake as follows.
+
+<code>
+export LD_LIBRARY_PATH=/group/ag_abi/software/x86_64/llvm-trunk/lib
+shift
+echo "pwd = `pwd`"
+echo /usr/bin/gcov $*
+/usr/bin/gcov $*
+ret=$?
+dir=$2
+echo find . -name '*.gcov' '>' /tmp/fixgcov.gcov.$$.txt
+find . -name '*.gcov' > /tmp/fixgcov.gcov.$$.txt
+echo grep '\.cpp' `dirname $3`/CXX.includecache
+src=$(grep '\.cpp' `dirname $3`/CXX.includecache)
+inc="-I $HOME/Nightly/`uname -m`/seqan-trunk/include -I $HOME/Nightly/`uname -m`/seqan-trunk/include"
+echo $HOME/Development/seqan-trunk/util/bin/fixgcov.py -s $src --gcov-files=/tmp/fixgcov.gcov.$$.txt -l /tmp/fixgcov.loc.$$.txt $inc
+$HOME/Development/seqan-trunk/util/bin/fixgcov.py -s $src --gcov-files /tmp/fixgcov.gcov.$$.txt -l /tmp/fixgcov.loc.$$.txt $inc
+exit $ret
+</code>
diff --git a/util/py_lib/seqan/fixgcov/__init__.py b/util/py_lib/seqan/fixgcov/__init__.py
new file mode 100755
index 0000000..c9f5931
--- /dev/null
+++ b/util/py_lib/seqan/fixgcov/__init__.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python2
+
+import sys
+
+import app
+
+main = app.main
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/util/py_lib/seqan/fixgcov/app.py b/util/py_lib/seqan/fixgcov/app.py
new file mode 100755
index 0000000..22a548c
--- /dev/null
+++ b/util/py_lib/seqan/fixgcov/app.py
@@ -0,0 +1,291 @@
+#!/usr/bin/env python2
+"""Small libclang based app to fix gcov output.
+
+Fix gcov output with templates. This is done by first parsing in the .cpp files
+(compilation units) with libclang. The AST is then parsed and all lines within
+composite statements ({ stmt; stmt; ... }) are memoized as 'interesting' lines.
+The resulting interesting lines are serialized to a location file with pickle.
+Finally, gcov output files are read and updated. If a line is interesting but
+not marked as covered or uncovered (marker '-'), it is marked as uncovered
+(marker '#####').
+
+USAGE: fixgcov.py -i $include_dir -g $gcov_file
+USAGE: fixgcov.py -i $include_dir -s $source_file
+
+Copyright: (c) 2010, Knut Reinert, FU Berlin
+License: 3-clause BSD (see LICENSE)
+"""
+
+from __future__ import with_statement
+
+__author__ = 'Manuel Holtgrewe <manuel.holtgrewe at fu-berlin.de>'
+
+import optparse
+import os
+import pickle
+import sys
+
+import clang.cindex as ci
+
+
+def _hasFileLocation(node):
+ """Return True if node has a file lcoation."""
+ if not hasattr(node, 'location'):
+ return False
+ if not hasattr(node.location, 'file'):
+ return False
+ if not node.location.file:
+ return False
+ if not hasattr(node.location.file, 'name'):
+ return False
+ if not node.location.file.name:
+ return False
+ return True
+
+
+class CollectCompoundStatementNodeVisitor(object):
+ """Visitor for AST nodes that collects compound statements."""
+
+ def __init__(self, options):
+ self.options = options
+ self.stack = []
+ self.ranges = []
+
+ def enterNode(self, node):
+ """Called when a node is entered ("pre-order" traversal)."""
+ self.stack.append(node)
+ ## print ' ' * len(self.stack), node.kind,
+ num_children = len([x for x in node.get_children()])
+ ## if _hasFileLocation(node):
+ ## print node.location.file.name, '%d-%d' % (node.extent.start.line, node.extent.end.line)
+ ## else:
+ ## print
+ # Only add range for statements that are no compound statements. Add
+ # for empty compounds.
+ if not node.kind.is_statement():
+ ## print 'skipping, no statement'
+ return
+ if node.kind == ci.CursorKind.COMPOUND_STMT and num_children > 0:
+ ## print 'skipping, non-empty compound statement', num_children
+ return
+ if node.kind == ci.CursorKind.DECL_STMT:
+ return # Skip declarations.
+ # Only add if has file location.
+ if _hasFileLocation(node):
+ self.ranges.append((node.location.file.name, node.extent.start.line, node.extent.end.line))
+
+ def exitNode(self, node):
+ """Called when a node is left ("post-order" traversa)."""
+ self.stack.pop()
+
+
+class VisitAllowedRule(object):
+ """Decides whether a AST node and its children is visited."""
+
+ def __init__(self, options):
+ self.options = options
+ self.include_dirs = [os.path.abspath(x) for x in options.include_dirs]
+ self.cache = {}
+
+ def visitAllowed(self, node):
+ """Return True if visiting is allowed."""
+ # TODO(holtgrew): For this application, stopping at compound statements
+ # would be enough. Visit if translation unit.
+ if node.kind == ci.CursorKind.TRANSLATION_UNIT:
+ return True
+ # Don't visit if it has no location (built-in).
+ if not _hasFileLocation(node):
+ return False
+ # Try to hit cache.
+ if self.cache.has_key(node.location.file.name):
+ return self.cache[node.location.file.name]
+ # Check whether node's location is below the include directories. It is
+ # only visited if this is the case.
+ filename = os.path.abspath(node.location.file.name)
+ result = False
+ for x in self.include_dirs:
+ if filename.startswith(x):
+ # print filename, x
+ result = True
+ break
+ self.cache[node.location.file.name] = result # Save in cache.
+ return result
+
+
+class AstTraverser(object):
+ """Traverses AST tree and applies given visitor object."""
+
+ def __init__(self, node_visitor, options):
+ self.node_visitor = node_visitor
+ self.options = options
+ self.visit_allowed_rule = VisitAllowedRule(options)
+
+ def _recurse(self, node):
+ """Recursion helper."""
+ if not self.visit_allowed_rule.visitAllowed(node):
+ return False # We did not visit this node.
+ self.node_visitor.enterNode(node)
+ for c in node.get_children():
+ self._recurse(c)
+ self.node_visitor.exitNode(node)
+ return True
+
+ def run(self, filename):
+ """Main entry point."""
+ index = ci.Index.create()
+ args = ['-I%s' % s for s in self.options.include_dirs]
+ # print args
+ tu = index.parse(filename, args=args)
+ if self.options.verbosity >= 1:
+ print 'Translation unit: %s.' % tu.spelling
+ return self._recurse(tu.cursor)
+
+ @classmethod
+ def visitFile(klass, filename, node_visitor, options):
+ """Don't instantiate AstTraverser yourself, use this function."""
+ traverser = AstTraverser(node_visitor, options)
+ res = traverser.run(filename)
+ return res == True
+
+
+def main():
+ """Main entry point."""
+ # ========================================================================
+ # Parse command line arguments.
+ # ========================================================================
+ parser = optparse.OptionParser("USAGE: %prog [options] -s file.cpp")
+ parser.add_option('-I', '--include-dir', dest='include_dirs', default=[],
+ type='string', help='Specify include directories',
+ action='append')
+ parser.add_option('-s', '--src-file', dest='source_files', default=[],
+ type='string', help='Specify compilation units.',
+ action='append')
+ parser.add_option('--src-file-files', dest='source_files_files', default=[],
+ type='string', help='Specify file with paths to compilation units.',
+ action='append')
+ parser.add_option('-l', '--location-file', dest='location_file',
+ default='locations.dat', type='string',
+ help='Path to file with compound statement locations.')
+ parser.add_option('-g', '--gcov-file', dest='gcov_files', default=[],
+ type='string', help='Specify gcov files to process.',
+ action='append')
+ parser.add_option('--gcov-files', dest='gcov_files_files', default=[],
+ type='string', help='Specify gcov files to process.',
+ action='append')
+ parser.add_option('-q', '--quiet', dest='verbosity', default=1,
+ action='store_const', const=0, help='Fewer message.')
+ parser.add_option('-v', '--verbose', dest='verbosity', default=1,
+ action='store_const', const=2, help='More messages.')
+ options, args = parser.parse_args()
+ if len(args) != 0:
+ parser.error('Incorrect number of arguments!')
+ return 1
+
+ options.include_dirs += [os.path.abspath(os.path.dirname(s)) for s in options.source_files]
+
+ # ========================================================================
+ # Read in files with paths from arguments.
+ # ========================================================================
+
+ for path in options.source_files_files:
+ with open(path, 'rb') as f:
+ options.source_files += [x.strip() for x in f.readlines()]
+ for path in options.gcov_files_files:
+ with open(path, 'rb') as f:
+ options.gcov_files += [x.strip() for x in f.readlines()]
+
+ if not options.source_files and not options.gcov_files:
+ parser.error('Neither source nor gcov file given!')
+ return 1
+
+ # ========================================================================
+ # Collect interesting lines if any source files given.
+ # ========================================================================
+
+ if options.source_files:
+ # If any source file is given, all given source files are parsed and all
+ # lines with compound statements in all included files are written to
+ # the location file.
+ if options.verbosity >= 1:
+ print >>sys.stderr, 'Building Locations'
+ if options.verbosity >= 2:
+ print >>sys.stderr, '=================='
+
+ # Fire off AST traversal.
+ if options.verbosity >= 1:
+ print >>sys.stderr, 'AST Traversal'
+ node_visitor = CollectCompoundStatementNodeVisitor(options)
+ for src in options.source_files:
+ if options.verbosity >= 2:
+ print >>sys.stderr, ' Compilation Unit', src
+ AstTraverser.visitFile(src, node_visitor, options)
+
+ # Convert locations into points.
+ locations = {}
+ for filename, start, stop in node_visitor.ranges:
+ filename = os.path.abspath(filename)
+ for i in range(start, stop + 1):
+ locations.setdefault(filename, set()).add(i)
+
+ # Write out the source locations.
+ if options.verbosity >= 1:
+ print >>sys.stderr, 'Writing out locations to', options.location_file
+ with open(options.location_file, 'wb') as f:
+ pickle.dump(locations, f)
+
+ # ========================================================================
+ # Process GCOV files if any are given.
+ # ========================================================================
+
+ if options.gcov_files:
+ # If no source files and gcov files are given then
+ if options.verbosity >= 1:
+ print >>sys.stderr, 'Updating gcov Results'
+ if options.verbosity >= 2:
+ print >>sys.stderr, '====================='
+
+ if not options.source_files:
+ if options.verbosity >= 1:
+ print >>sys.stderr, 'Loading locations from', options.location_file
+ with open(options.location_file, 'rb') as f:
+ locations = pickle.load(f)
+
+ for filename in options.gcov_files:
+ filename = os.path.abspath(filename)
+ if options.verbosity >= 2:
+ print >>sys.stderr, 'Processing', filename
+ with open(filename, 'rb') as f:
+ lines = f.readlines()
+ pos0 = lines[0].find(':')
+ pos1 = lines[0].find(':', pos0 + 1)
+ source = None
+ result = []
+ skip = False
+ for i, line in enumerate(lines):
+ coverage = line[:pos0]
+ lineno = int(line[pos0 + 1:pos1].strip())
+ slineno = line[pos0 + 1:pos1]
+ txt = line[pos1 + 1:]
+ if txt.startswith('Source:'):
+ source = os.path.abspath(txt[len('Source:'):].strip())
+ if not locations.has_key(source):
+ if options.verbosity >= 2:
+ print >>sys.stderr, ' Skipping.'
+ skip = True
+ break
+ if not source or lineno == 0:
+ result.append(line)
+ continue # Proceed only if in file.
+ if lineno in locations[source] and coverage.strip() == '-':
+ coverage = ('%%%ds' % pos0) % '#####'
+ result.append(':'.join([coverage, slineno, txt]))
+ # Write back file if not skipped.
+ if skip:
+ continue
+ with open (filename, 'wb') as f:
+ f.write(''.join(result))
+ #print ''.join(result)
+
+# Entry point if called as program.
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/util/py_lib/seqan/paths.py b/util/py_lib/seqan/paths.py
new file mode 100755
index 0000000..0bce2ef
--- /dev/null
+++ b/util/py_lib/seqan/paths.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python2
+"""SeqAn path utilities.
+
+Code to get paths within the SeqAn repository; Useful for setting defaults in
+options.
+
+When called as a program, the paths are printed.
+
+The main assumption is that this module lies in '/util/py_lib/seqan.'
+
+Copyright: (c) 2010, Knut Reinert, FU Berlin
+License: 3-clause BSD (see LICENSE)
+"""
+
+__author__ = 'Manuel Holtgrewe <manuel.holtgrewe at fu-berlin.de>'
+
+import os
+import os.path
+import sys
+
+def repositoryRoot():
+ """Return path to directory root."""
+ abs_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))
+ return os.path.relpath(abs_path, os.getcwd())
+
+def pathToSkeletons():
+ """Return path to '${REPOSITORY}/util/skel'."""
+ return os.path.join(repositoryRoot(), 'util/skel')
+
+def pathToTemplate(template, filename):
+ """Return path to file with given name in given template."""
+ return os.path.join(pathToSkeletons(), template, filename)
+
+def pathToApp(location, app):
+ """Return path to the app in the given location/repository."""
+ return os.path.join(repositoryRoot(), location, 'apps', app)
+
+def pathToInclude(location):
+ """Return path to the include dir in the given location/repository."""
+ return os.path.join(repositoryRoot(), location, 'include')
+
+def pathToDemo(location, demo):
+ """Return path to the demo file in the given location/repository."""
+ return os.path.join(repositoryRoot(), location, 'demos', '%s.cpp' % demo)
+
+def pathToTest(location, test):
+ """Return path to the test in the given location/repository."""
+ return os.path.join(repositoryRoot(), location, 'tests', test)
+
+def pathToRepository(location):
+ """Return path to the given location/repository."""
+ return os.path.join(repositoryRoot(), location)
+
+def pathToHeader(location, filename):
+ """Return path to the given header - just concatenate."""
+ return os.path.join(repositoryRoot(), location, filename)
+
+def main(args):
+ print 'SeqAn paths'
+ print
+ print 'repositoryRoot() ==', repositoryRoot()
+ print 'pathToSkeletons() ==', pathToSkeletons()
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/util/py_lib/seqan/pyclangcheck/__init__.py b/util/py_lib/seqan/pyclangcheck/__init__.py
new file mode 100755
index 0000000..c9f5931
--- /dev/null
+++ b/util/py_lib/seqan/pyclangcheck/__init__.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python2
+
+import sys
+
+import app
+
+main = app.main
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/util/py_lib/seqan/pyclangcheck/app.py b/util/py_lib/seqan/pyclangcheck/app.py
new file mode 100755
index 0000000..aa6d0cf
--- /dev/null
+++ b/util/py_lib/seqan/pyclangcheck/app.py
@@ -0,0 +1,322 @@
+#!/usr/bin/env python2
+"""pyclangcheck driver code
+
+This code is the driver code for the pyclangcheck tool.
+
+Copyright: (c) 2010, Knut Reinert, FU Berlin
+License: 3-clause BSD (see LICENSE)
+"""
+
+from __future__ import with_statement
+
+__author__ = 'Manuel Holtgrewe <manuel.holtgrewe at fu-berlin.de>'
+
+import datetime
+import optparse
+import os
+import os.path
+import sys
+
+import clang.cindex as ci
+
+import simple_checks
+import violations
+import rules
+
+def _hasFileLocation(node):
+ """Return True if node has a file lcoation."""
+ if hasattr(node, '_has_file_location'):
+ return node._has_file_location
+ if not hasattr(node, 'location'):
+ node._has_file_location = False
+ return False
+ if not hasattr(node.location, 'file'):
+ node._has_file_location = False
+ return False
+ if not node.location.file:
+ node._has_file_location = False
+ return False
+ if not hasattr(node.location.file, 'name'):
+ node._has_file_location = False
+ return False
+ if not node.location.file.name:
+ node._has_file_location = False
+ return False
+ node._has_file_location = True
+ return True
+
+
+class FileCache(object):
+ def __init__(self):
+ self.cache = {}
+
+ def get(self, path):
+ if self.cache.has_key(path):
+ return self.cache[path]
+ with open(path, 'rb') as f:
+ fcontents = f.readlines()
+ self.cache[path] = fcontents
+ return self.cache[path]
+
+
+class CollectViolationsVisitor(object):
+ """Visitor for AST nodes that collects rule violations."""
+
+ def __init__(self, options, rules):
+ self.options = options
+ self.rules = rules
+ for rule in self.rules:
+ rule.visitor = self
+ self.stack = []
+ self.violations = {}
+ self.file_cache = FileCache()
+ self.class_stack = []
+ self.seen_files = set()
+ self.blocked_files = set()
+
+ def seenToBlocked(self):
+ """Move seen files to blocked files."""
+ self.blocked_files |= self.seen_files
+
+ def enterNode(self, node):
+ """Called when a node is entered ("pre-order" traversal)."""
+ self.stack.append(node)
+ ck = ci.CursorKind
+ if node.kind in [ck.CLASS_TEMPLATE, ck.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, ck.CLASS_DECL]:
+ ## print 'PUSH CLASS', node.spelling
+ self.class_stack.append(node)
+
+ # Mark file as seen for nodes that are directly below the compilation unit.
+ if len(self.stack) <= 2 and _hasFileLocation(node):
+ self.seen_files.add(node.location.file.name)
+
+ if self.options.verbosity >= 2:
+ if node.extent.start.file:
+ filename = node.extent.start.file.name
+ lines = self.file_cache.get(filename)
+ start = "%s:%d:%d" % (os.path.basename(filename), node.extent.start.line-1, node.extent.start.column-1)
+ end = "%s:%d:%d" % ('#', node.extent.end.line-1, node.extent.end.column-1)
+ lines = [x for x in lines[node.extent.start.line-1:node.extent.end.line]]
+ if len(lines) == 1:
+ lines[0] = lines[0][node.extent.start.column - 1:node.extent.end.column-1]
+ else:
+ lines[0] = lines[0][node.extent.start.column - 1:]
+ lines[-1] = lines[-1][:node.extent.end.column-1]
+ if len(lines) > 1:
+ txt = '<multiline>'
+ else:
+ txt = ''.join(lines).replace('\n', '\\n')
+ print ' ' * len(self.stack), 'Entering', node.kind, node._kind_id, node.spelling, 'txt="%s"' % txt, "%s-%s" % (start, end)
+ violations = []
+ for rule in self.rules:
+ if rule.allowVisit(node):
+ #print ' ', ' ' * len(self.stack), 'Checking rule', rule.rule_id
+ vs = rule.check(node)
+ ## if self.options.verbosity >= 2:
+ ## for v in vs:
+ ## print 'VIOLATION', v
+ violations += vs
+ for v in violations:
+ ## if self.options.verbosity >= 2:
+ ## print v
+ self.violations[v.key()] = v
+
+ def exitNode(self, node):
+ """Called when a node is left ("post-order" traversa)."""
+ self.stack.pop()
+ if self.class_stack and self.class_stack[-1] is node:
+ ## print 'POP CLASS', node.spelling
+ self.class_stack.pop()
+
+ def getCurrentClassName(self):
+ """Returns name of current class."""
+ if not self.class_stack:
+ ## print 'CURRENT CLASS', None
+ return None
+ ## print 'CURRENT CLASS', self.class_stack[-1].spelling
+ return self.class_stack[-1].spelling
+
+
+class VisitAllowedRule(object):
+ """Decides whether a AST node and its children is visited."""
+
+ def __init__(self, options, blocked_files):
+ self.options = options
+ self.include_dirs = [os.path.abspath(x) for x in options.include_dirs]
+ self.cache = {}
+ self.blocked_files = blocked_files
+
+ def visitAllowed(self, node):
+ """Return True if visiting is allowed."""
+ # Visit if translation unit.
+ if node.kind == ci.CursorKind.TRANSLATION_UNIT:
+ return True
+ # Don't visit if it has no location (built-in).
+ if not _hasFileLocation(node):
+ return False
+ # Try to hit cache.
+ if self.cache.has_key(node.location.file.name):
+ return self.cache[node.location.file.name]
+ # Check whether the file is blocked.
+ if node.location.file.name in self.blocked_files:
+ # print 'Blocked', node.location.file.name
+ self.cache[node.location.file.name] = False
+ return False
+ # Check whether node's location is below the include directories. It is
+ # only visited if this is the case.
+ filename = os.path.abspath(node.location.file.name)
+ result = False
+ for x in self.include_dirs:
+ if filename.startswith(x):
+ # print filename, x
+ result = True
+ break
+ self.cache[node.location.file.name] = result # Save in cache.
+ return result
+
+
+class AstTraverser(object):
+ """Traverses AST tree and applies given visitor object."""
+
+ def __init__(self, node_visitor, options):
+ self.node_visitor = node_visitor
+ self.options = options
+ self.visit_allowed_rule = VisitAllowedRule(options, node_visitor.blocked_files)
+
+ def _recurse(self, node):
+ """Recursion helper."""
+ if not self.visit_allowed_rule.visitAllowed(node):
+ return False # We did not visit this node.
+ self.node_visitor.enterNode(node)
+ for c in node.get_children():
+ self._recurse(c)
+ self.node_visitor.exitNode(node)
+ return True
+
+ def run(self, filename):
+ """Main entry point."""
+ index = ci.Index.create()
+ args = ['-I%s' % s for s in self.options.include_dirs]
+ # print args
+ tu = index.parse(filename, args=args)
+ if self.options.verbosity >= 1:
+ print 'Translation unit: %s.' % tu.spelling
+ return self._recurse(tu.cursor)
+
+ @classmethod
+ def visitFile(klass, filename, node_visitor, options):
+ """Don't instantiate AstTraverser yourself, use this function."""
+ if options.verbosity >= 1:
+ print >>sys.stderr, 'Checking', filename
+ traverser = AstTraverser(node_visitor, options)
+ res = traverser.run(filename)
+ return res != True
+
+
+def main():
+ # ========================================================================
+ # Parse command line arguments.
+ # ========================================================================
+ parser = optparse.OptionParser("USAGE: %prog [options] file.cpp")
+ parser.add_option('-s', '--source-file', dest='source_files', default=[],
+ type='string', help='Specify source (.cpp) files.',
+ action='append')
+ parser.add_option('-S', '--source-file-file', dest='source_file_files', default=[],
+ type='string', help='File with path to source files.',
+ action='append')
+ parser.add_option('-i', '--include-dir', dest='include_dirs', default=[],
+ type='string', help='Specify include directories',
+ action='append')
+ parser.add_option('-e', '--exclude-dir', dest='exclude_dirs', default=[],
+ type='string', help='Violations in these directories are not shown.',
+ action='append')
+ parser.add_option('-q', '--quiet', dest='verbosity', default=1,
+ action='store_const', const=0, help='Fewer message.')
+ parser.add_option('-v', '--verbose', dest='verbosity', default=1,
+ action='store_const', const=2, help='More messages.')
+ parser.add_option('--ignore-nolint', dest='ignore_nolint', default=False,
+ action='store_const', const=True, help='Ignore // nolint statements.')
+ parser.add_option('--dont-show-source', dest='show_source', default=True,
+ action='store_const', const=False, help='Suppress source line display')
+ options, args = parser.parse_args()
+
+ if len(args) != 0:
+ parser.error('Incorrect number of arguments!')
+ return 1
+
+ # Load source files given in file of paths.
+ for filename in options.source_file_files:
+ with open(filename, 'rb') as f:
+ options.source_files += [x.strip() for x in f.readlines()]
+
+ # ========================================================================
+ # Setup traversal.
+ # ========================================================================
+
+ # Recursion Rule: Only check symbols within the include directories.
+ recurse_rules = []
+ recurse_rules.append(rules.InIncludeDirsRule(options.include_dirs, options.exclude_dirs, options.source_files))
+ # Define symbol naming rules.
+ R = rules.GenericSymbolNameRule
+ r = rules
+ ck = ci.CursorKind
+ check_rules = [
+ R(ck.STRUCT_DECL , r.RE_STRUCT , r.RULE_NAMING_STRUCT ),
+ R(ck.UNION_DECL , r.RE_TYPE , r.RULE_NAMING_UNION ),
+ R(ck.CLASS_DECL , r.RE_TYPE , r.RULE_NAMING_CLASS ),
+ R(ck.ENUM_DECL , r.RE_TYPE , r.RULE_NAMING_ENUM ),
+ R(ck.FIELD_DECL , r.RE_VARIABLE , r.RULE_NAMING_FIELD ),
+ R(ck.ENUM_CONSTANT_DECL , r.RE_CONSTANT , r.RULE_NAMING_ENUM_CONSTANT ),
+ R(ck.FUNCTION_DECL , r.RE_FUNCTION , r.RULE_NAMING_FUNCTION ),
+ R(ck.PARM_DECL , r.RE_VARIABLE , r.RULE_NAMING_PARAMETER ),
+ R(ck.TYPEDEF_DECL , r.RE_TYPE , r.RULE_NAMING_TYPEDEF ),
+ R(ck.CXX_METHOD , r.RE_FUNCTION , r.RULE_NAMING_CXX_METHOD ),
+ R(ck.TEMPLATE_TYPE_PARAMETER , r.RE_TYPE , r.RULE_NAMING_TPL_TYPE_PARAMETER ),
+ R(ck.TEMPLATE_NON_TYPE_PARAMETER , r.RE_CONSTANT , r.RULE_NAMING_TPL_NON_TYPE_PARAMETER),
+ R(ck.TEMPLATE_TEMPLATE_PARAMTER , r.RE_TYPE , r.RULE_NAMING_TPL_TPL_PARAMETER ),
+ #R(ck.FUNCTION_TEMPLATE , r.RE_FUNCTION , r.RULE_NAMING_FUNCTION_TPL ),
+ R(ck.CLASS_TEMPLATE , r.RE_TYPE_TEMPLATE, r.RULE_NAMING_CLASS_TPL ),
+ R(ck.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, r.RE_TYPE_TEMPLATE, r.RULE_NAMING_CLASS_TPL_SPEC ),
+ rules.FunctionTemplateRule(),
+ rules.VariableNameRule(),
+ ]
+
+ # ========================================================================
+ # Perform traversal.
+ # ========================================================================
+
+ node_visitor = CollectViolationsVisitor(options, check_rules)
+ for filename in options.source_files:
+ start = datetime.datetime.now()
+ res = AstTraverser.visitFile(filename, node_visitor, options)
+ node_visitor.seenToBlocked()
+ elapsed = datetime.datetime.now() - start
+ print >>sys.stderr, ' took', elapsed.seconds, 's'
+ if res:
+ break
+
+ # ========================================================================
+ # Dumber checks (e.g. whitespace at end of file).
+ # ========================================================================
+
+ checkers = [simple_checks.WhitespaceChecker(),
+ simple_checks.CommentChecker()]
+ vs = {}
+ for filename in node_visitor.seen_files:
+ for checker in checkers:
+ vs.update(checker.check(filename))
+
+ # ========================================================================
+ # Print violations.
+ # ========================================================================
+
+ print 'VIOLATIONS'
+ vs.update(node_visitor.violations)
+ printer = violations.ViolationPrinter(options.ignore_nolint,
+ options.show_source)
+ printer.show(vs)
+ return len(vs) > 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/util/py_lib/seqan/pyclangcheck/rules.py b/util/py_lib/seqan/pyclangcheck/rules.py
new file mode 100755
index 0000000..15c8d33
--- /dev/null
+++ b/util/py_lib/seqan/pyclangcheck/rules.py
@@ -0,0 +1,201 @@
+#!/usr/bin/env python2
+
+__author__ = 'Manuel Holtgrewe <manuel.holtgrewe at fu-berlin.de>'
+
+import os.path
+import re
+
+import clang.cindex as ci
+
+import app
+import violations
+
+RULE_NAMING_CONSTANT = 'naming.constant'
+RULE_NAMING_STRUCT = 'naming.struct'
+RULE_NAMING_UNION = 'naming.union'
+RULE_NAMING_CLASS = 'naming.class'
+RULE_NAMING_ENUM = 'naming.enum'
+RULE_NAMING_FIELD = 'naming.field'
+RULE_NAMING_ENUM_CONSTANT = 'naming.enum_constant'
+RULE_NAMING_VARIABLE = 'naming.variable'
+RULE_NAMING_FUNCTION = 'naming.function'
+RULE_NAMING_PARAMETER = 'naming.parameter'
+RULE_NAMING_VARIABLE = 'naming.variable'
+RULE_NAMING_CXX_METHOD = 'naming.method'
+RULE_NAMING_TYPEDEF = 'naming.typedef'
+RULE_NAMING_TPL_NON_TYPE_PARAMETER = 'naming.tpl_nontype_param'
+RULE_NAMING_TPL_TYPE_PARAMETER = 'naming.tpl_type_param'
+RULE_NAMING_TPL_TPL_PARAMETER = 'naming.tpl_tpl_param'
+RULE_NAMING_FUNCTION_TPL = 'naming.function_tpl'
+RULE_NAMING_CLASS_TPL = 'naming.class_tpl'
+RULE_NAMING_CLASS_TPL_SPEC = 'naming.class_tpl_spec'
+
+RE_CONSTANT = r'^[A-Z]([_A-Z0-9])*_*$'
+RE_VARIABLE = r'^_?[a-z]([_a-zA-Z0-9])*_*$'
+RE_FUNCTION = r'operator.*|^_?[a-z]([_a-zA-Z0-9])*\(.*\)_*$'
+RE_TYPE = r'^[A-Z]([a-zA-Z0-9])*_*$'
+RE_TYPE_TEMPLATE = r'^[A-Z]([a-zA-Z0-9])*_*<.*>$'
+RE_STRUCT = r'^[A-Z]([a-zA-Z0-9])*_*(<.*>)?$'
+
+RULE_TEXTS = {
+ RULE_NAMING_CONSTANT: 'Constant names must be all upper-case, separated by underscores.',
+ RULE_NAMING_STRUCT: 'Struct names must be all camel case, starting with upper case.',
+ RULE_NAMING_UNION: 'Union names must be all camel case, starting with upper case.',
+ RULE_NAMING_CLASS: 'Class names must be all camel case, starting with upper case.',
+ RULE_NAMING_ENUM: 'Enum names must be all camel case, starting with upper case.',
+ RULE_NAMING_FIELD: 'Field names must be camel case case, starting with lower case.',
+ RULE_NAMING_ENUM_CONSTANT: 'Enum constant names must be all upper-case, separated by underscores.',
+ RULE_NAMING_VARIABLE: 'Variable names must be camel case case, starting with lower case.',
+ RULE_NAMING_FUNCTION: 'Function names must be camel case case, starting with lower case.',
+ RULE_NAMING_PARAMETER: 'Parameter names must be camel case case, starting with lower case.',
+ RULE_NAMING_CXX_METHOD: 'Method names must be camel case case, starting with lower case.',
+ RULE_NAMING_TYPEDEF: 'Typedef names must be all camel case, starting with upper case.',
+ RULE_NAMING_TPL_NON_TYPE_PARAMETER: 'Template non-type parameters must be all upper-case, separated by underscores.',
+ RULE_NAMING_TPL_TYPE_PARAMETER: 'Template type parameter names must be all camel case, starting with upper case.',
+ RULE_NAMING_TPL_TPL_PARAMETER: 'Template template parameter names must be all camel case, starting with upper case.',
+ RULE_NAMING_FUNCTION_TPL: 'Function template names must be camel case case, starting with lower case.',
+ RULE_NAMING_CLASS_TPL: 'Class template names must be all camel case, starting with upper case.',
+ RULE_NAMING_CLASS_TPL_SPEC: 'Partial specialization names must be all camel case, starting with upper case.',
+}
+
+
+class GenericSymbolNameRule(object):
+ def __init__(self, kind, regular_ex, rule_name):
+ self.kind = kind
+ self.regular_ex = regular_ex
+ self.rule_name = rule_name
+ self.visitor = None
+
+ def allowVisit(self, node):
+ if not app._hasFileLocation(node):
+ #print 'no location'
+ return False
+ if not node.displayname:
+ #print 'no displayname'
+ return False # Ignore empty symbols.
+ # print 'allow visit template type?', displayname, node.kind
+ if node.kind == self.kind:
+ #print 'different kind'
+ return True
+ return False
+
+ def check(self, node):
+ displayname = node.displayname
+ #print 'checking', displayname
+ #import pdb; pdb.set_trace()
+ if not re.match(self.regular_ex, displayname):
+ v = violations.RuleViolation(
+ self.rule_name, displayname, node.location.file.name,
+ node.location.line, node.location.column)
+ return [v]
+ return []
+
+
+class VariableNameRule(object):
+ """Checks variable names (in variable declarations).
+
+ The name must either be camel case (starting with lower case character) or
+ all upper case.
+ """
+
+ def __init__(self):
+ self.visitor = None
+
+ def allowVisit(self, node):
+ if not app._hasFileLocation(node):
+ return False
+ displayname = node.displayname
+ if not displayname:
+ return False # Ignore empty symbols.
+ if node.kind == ci.CursorKind.VAR_DECL:
+ return True
+ return False
+
+ def check(self, node):
+ displayname = node.displayname
+ if not re.match(RE_VARIABLE, displayname) and not re.match(RE_CONSTANT, displayname):
+ # TODO(holtgrew): Only allow RE_CONSTANT if 'const' in declaration type.
+ v = violations.RuleViolation(
+ RULE_NAMING_VARIABLE, displayname, node.location.file.name,
+ node.location.line, node.location.column)
+ return [v]
+ return []
+
+
+class FunctionTemplateRule(object):
+ """Checks function templates.
+
+ Function template have to follow the function naming scheme. However,
+ libclang also exposes constructors with kind function template. The visitor
+ keeps a stack of current classes so we look whether the current class or
+ class template has the same name as the function template and allow this
+ besides the function naming scheme.
+ """
+
+ def __init__(self):
+ self.visitor = None
+
+ def allowVisit(self, node):
+ if not app._hasFileLocation(node):
+ return False
+ displayname = node.displayname
+ if not displayname:
+ return False # Ignore empty symbols.
+ if node.kind == ci.CursorKind.FUNCTION_TEMPLATE:
+ return True
+ return False
+
+ def check(self, node):
+ displayname = node.displayname
+ if not re.match(RE_FUNCTION, displayname):
+ up_to_bracket = displayname[:displayname.find('<')]
+ ## print 'CHECK', self.visitor.getCurrentClassName(), '!=?', up_to_bracket
+ if self.visitor.getCurrentClassName() != up_to_bracket:
+ v = violations.RuleViolation(
+ RULE_NAMING_FUNCTION_TPL, displayname, node.location.file.name,
+ node.location.line, node.location.column)
+ return [v]
+ return []
+
+
+class InIncludeDirsRule(object):
+ """Rule to block visiting and recursion outside include dirs."""
+
+ def __init__(self, include_dirs, exclude_dirs, source_files):
+ self.include_dirs = [os.path.abspath(x) for x in include_dirs]
+ self.source_files = [os.path.abspath(x) for x in source_files]
+ self.exclude_dirs = [os.path.abspath(x) for x in exclude_dirs]
+ self.cache = {}
+
+ def allowVisit(self, node):
+ """Return True if visiting is allowed."""
+ if node.kind == ci.CursorKind.TRANSLATION_UNIT:
+ return True
+ if not app._hasFileLocation(node):
+ return False
+ if self.cache.has_key(node.location.file.name):
+ return self.cache[node.location.file.name]
+ # Check whether node's location is below the include directories or one
+ # of the source files.
+ filename = os.path.abspath(node.location.file.name)
+ result = False
+ for x in self.include_dirs:
+ if filename.startswith(x):
+ result = True
+ break
+ if not result:
+ for x in self.source_files:
+ if filename == x:
+ result = True
+ break
+ if result:
+ for x in self.exclude_dirs:
+ if filename.startswith(x):
+ result = False
+ break
+ self.cache[node.location.file.name] = result
+ return result
+
+ def allowRecurse(self, node):
+ """Return True if we want to recurse below node."""
+ return self.allowVisit(node)
diff --git a/util/py_lib/seqan/pyclangcheck/simple_checks.py b/util/py_lib/seqan/pyclangcheck/simple_checks.py
new file mode 100755
index 0000000..b39a4aa
--- /dev/null
+++ b/util/py_lib/seqan/pyclangcheck/simple_checks.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python2
+"""Simple source code checks, e.g. trailing whitespace."""
+
+from __future__ import with_statement
+
+import bisect
+import re
+import sys
+
+import violations
+
+RULE_TRAILING_WHITESPACE = 'whitespace.trailing'
+RULE_TEXT_TRAILING_WHITESPACE = 'Trailing whitespace is not allowed.'
+
+RULE_TODO_ONE_SPACE = 'whitespace.todo'
+RULE_TEXT_TODO_ONE_SPACE= 'There should be exactly one space before TODO.'
+
+RULE_TODO_USERNAME = 'readability.todo'
+RULE_TEXT_TODO_USERNAME = 'TODO comments should look like this: "// TODO(username): Text".'
+
+RULE_TODO_SPACE_AFTER = 'whitespace.todo'
+RULE_TEXT_TODO_SPACE_AFTER = '"TODO (username):" should be followed by a space.'
+
+RE_TODO = r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?'
+
+class WhitespaceChecker(object):
+ """Performs simple white space checks."""
+
+ # TODO(holtgrew): Do not allow tabs.
+
+ def check(self, filename):
+ vs = []
+ with open(filename, 'rb') as f:
+ line_no = 0
+ for line in f:
+ line_no += 1
+ if line.rstrip() == line.rstrip('\r\n'):
+ continue
+ v = violations.SimpleRuleViolation(
+ RULE_TRAILING_WHITESPACE, filename, line_no,
+ len(line.rstrip()) + 1, RULE_TEXT_TRAILING_WHITESPACE)
+ vs.append(v)
+ return dict([(v.key(), v) for v in vs])
+
+
+class SourceFile(object):
+ def __init__(self, name):
+ self.name = name
+
+
+class SourceLocation(object):
+ def __init__(self, filename, line, column, offset):
+ self.file = SourceFile(filename)
+ self.line = line
+ self.column = column
+ self.offset = offset
+
+ def __str__(self):
+ return '%s:%d/%d (@%d)' % (self.file.name, self.line, self.column,
+ self.offset)
+
+ def __repr__(self):
+ return str(self)
+
+
+def enumerateComments(filename):
+ # Read file.
+ with open (filename, 'rb') as f:
+ lines = f.readlines()
+ fcontents = ''.join(lines)
+ # Build line break index.
+ line_starts = [0]
+ for line in lines:
+ line_starts.append(line_starts[-1] + len(line))
+ #print line_starts
+ # Search for all comments.
+ pattern = re.compile(
+ r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+ re.DOTALL | re.MULTILINE)
+ for match in re.finditer(pattern, fcontents):
+ line_start = bisect.bisect(line_starts, match.start(0))
+ line_end = bisect.bisect(line_starts, match.end(0) - 1)
+ column_start = match.start(0) - line_starts[line_start - 1]
+ column_end = match.end(0) - line_starts[line_end - 1]
+ yield (SourceLocation(filename, line_start, column_start + 1, match.start(0)),
+ SourceLocation(filename, line_end, column_end + 1, match.end(0)),
+ match.group(0))
+
+
+class CommentChecker(object):
+ """Performs the checks on comments."""
+
+ def check(self, filename):
+ vs = []
+ for cstart, cend, comment in enumerateComments(filename):
+ if comment.startswith('//'):
+ # Check TODO comments.
+ match = re.match(RE_TODO, comment)
+ if match:
+ if len(match.group(1)) > 1:
+ print comment
+ v = violations.SimpleRuleViolation(
+ RULE_TODO_ONE_SPACE, filename, cstart.line,
+ cstart.column, RULE_TEXT_TODO_ONE_SPACE)
+ vs.append(v)
+ if not match.group(2):
+ v = violations.SimpleRuleViolation(
+ RULE_TODO_USERNAME, filename, cstart.line,
+ cstart.column, RULE_TEXT_TODO_USERNAME)
+ vs.append(v)
+ if match.group(3) != ' ' and match.group(3) != '':
+ v = violations.SimpleRuleViolation(
+ RULE_TODO_SPACE_AFTER, filename, cstart.line,
+ cstart.column, RULE_TEXT_TODO_SPACE_AFTER)
+ vs.append(v)
+ return dict([(v.key(), v) for v in vs])
+
diff --git a/util/py_lib/seqan/pyclangcheck/suppressions.py b/util/py_lib/seqan/pyclangcheck/suppressions.py
new file mode 100755
index 0000000..18ff536
--- /dev/null
+++ b/util/py_lib/seqan/pyclangcheck/suppressions.py
@@ -0,0 +1 @@
+#!/usr/bin/env python2
diff --git a/util/py_lib/seqan/pyclangcheck/violations.py b/util/py_lib/seqan/pyclangcheck/violations.py
new file mode 100755
index 0000000..f91b8fb
--- /dev/null
+++ b/util/py_lib/seqan/pyclangcheck/violations.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python2
+"""Code related to violations and suppressions."""
+
+from __future__ import with_statement
+
+import os
+import os.path
+import sys
+
+import app
+import rules
+
+
+class RuleViolation(object):
+ def __init__(self, rule_id, violator, file, line, column):
+ self.rule_id = rule_id
+ self.violator = violator
+ self.file = file
+ self.line = line
+ self.column = column
+
+ def key(self):
+ return (self.file, self.line, self.column, self.rule_id, self.violator)
+
+ def __str__(self):
+ msg = '[%s:%d/%d] %s "%s": %s'
+ return msg % ('/'.join(self.file.split('/')[-2:]), self.line, self.column,
+ self.rule_id, self.violator, rules.RULE_TEXTS[self.rule_id])
+
+
+class SimpleRuleViolation(object):
+ def __init__(self, rule_id, file, line, column, msg):
+ self.rule_id = rule_id
+ self.file = file
+ self.line = line
+ self.column = column
+ self.msg = msg
+
+ def key(self):
+ return (self.file, self.line, self.column, self.rule_id)
+
+ def __str__(self):
+ msg = '[%s:%d/%d] %s : %s'
+ return msg % ('/'.join(self.file.split('/')[-2:]), self.line, self.column,
+ self.rule_id, self.msg)
+
+
+class NolintManager(object):
+ """Manage the lines ending in '//nolint'."""
+
+ def __init__(self):
+ self.locations = {}
+
+ def hasNolint(self, filename, lineno):
+ filename = os.path.abspath(filename)
+ # Ensure that the nolint lines are registered in self.locations[filename].
+ if not self.locations.has_key(filename):
+ line_set = set()
+ with open(filename, 'rb') as f:
+ line_no = 0
+ for line in f:
+ line_no += 1
+ if line.strip().endswith('// nolint'):
+ ## print 'nolint', filename, line_no
+ line_set.add(line_no)
+ self.locations[filename] = line_set
+ # Query self.locations[filename].
+ return lineno in self.locations[filename]
+
+
+class ViolationPrinter(object):
+ def __init__(self, ignore_nolint, show_source):
+ self.nolints = NolintManager()
+ self.file_cache = app.FileCache()
+ self.ignore_nolint = ignore_nolint
+ self.show_source = show_source
+
+ def show(self, vs):
+ previous = None
+ for k in sorted(vs.keys()):
+ violation = vs[k]
+ if self.ignore_nolint or not self.nolints.hasNolint(violation.file, violation.line):
+ print violation
+ line = self.file_cache.get(violation.file)[violation.line - 1]
+ if self.show_source:
+ print line.rstrip()
+ print '%s^' % (' ' * (violation.column - 1))
+ print
+ previous = violation
+ print 'Total: %d violations' % len(vs)
+
diff --git a/util/py_lib/seqan/seqan.css b/util/py_lib/seqan/seqan.css
new file mode 100644
index 0000000..ac38d89
--- /dev/null
+++ b/util/py_lib/seqan/seqan.css
@@ -0,0 +1,7 @@
+html .vlist {
+ border: none;
+ }
+
+table {
+ width: 100%;
+ }
\ No newline at end of file
diff --git a/util/py_lib/seqan/seqan.html b/util/py_lib/seqan/seqan.html
new file mode 100644
index 0000000..07015b4
--- /dev/null
+++ b/util/py_lib/seqan/seqan.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en-EN">
+ <head>
+ <title>Sub Page | SeqAn</title>
+ <!-- Meta Tags -->
+ <meta http-equiv="X-UA-Compatible" content="IE=9">
+ <!-- Enable IE9 Standards mode --> <!-- WordPress -->
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta http-equiv="content-script-type" content="text/javascript">
+ <meta name="keywords" content="">
+ <meta name="language" content="en">
+ <meta name="content-language" content="en">
+ <meta name="publisher" content="SeqAn">
+ <meta name="revisit-after" content="1 days">
+ <meta name="author" content="FU Berlin - http://www.fu-berlin.de">
+ <meta name="description" content=" - The C++ template library for sequence analysis.">
+ <!-- FU Berlin Layout -->
+ <meta http-equiv="cache-control" content="no-cache">
+ <meta http-equiv="pragma" content="no-cache">
+ <meta name="robots" content="index, follow">
+ <meta name="geo.region" content="DE-BE">
+ <meta name="geo.placename" content="Berlin">
+ <!-- CSS -->
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/style.css" media="" rel="stylesheet" type="text/css">
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/yaml_base.css" media="" rel="stylesheet" type="text/css">
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/nav_hlist.css" media="" rel="stylesheet" type="text/css">
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/nav_vlist.css" media="" rel="stylesheet" type="text/css">
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/basemod_fu_berlin.css" media="" rel="stylesheet" type="text/css">
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/content_fu.css" media="" rel="stylesheet" type="text/css">
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/yaml_print_base.css" media="" rel="stylesheet" type="text/css">
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/print.css" media="" rel="stylesheet" type="text/css">
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/yaml_forms.css" media="" rel="stylesheet" type="text/css">
+ <!--[if lte IE 7]>
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/yaml_iehacks.css" media="" rel="stylesheet" type="text/css" />
+ <link href="http://www.seqan.de/wp-content/themes/fub-theme/styles/patch.css" media="" rel="stylesheet" type="text/css" />
+ <![endif]--> <!-- Favicon, RSS Links -->
+ <link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="http://www.seqan.de/feed/">
+ <link rel="Shortcut Icon" type="image/x-icon" href="http://www.seqan.de/wp-content/uploads/2012/01/favicon.png">
+ <link rel="pingback" href="http://www.seqan.de/xmlrpc.php">
+ <link rel="stylesheet" id="wp_dlmp_styles-css" href="http://www.seqan.de/wp-content/plugins/download-monitor/page-addon/styles.css?ver=3.5.1" type="text/css" media="all">
+ <link rel="stylesheet" id="page-list-style-css" href="http://www.seqan.de/wp-content/plugins/page-list/css/page-list.css?ver=4.2" type="text/css" media="all">
+ <link rel="stylesheet" id="counterize_stylesheet-css" href="http://www.seqan.de/wp-content/plugins/counterize/counterize.css.php?ver=3.5.1" type="text/css" media="all">
+ <script type="text/javascript" src="http://www.seqan.de/wp-content/plugins/counterize/counterize.js.php?ver=3.5.1"></script>
+ <link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://www.seqan.de/xmlrpc.php?rsd">
+ <link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://www.seqan.de/wp-includes/wlwmanifest.xml">
+ <link rel="next" title="News" href="http://www.seqan.de/news/">
+ <meta name="generator" content="WordPress 3.5.1">
+ <link rel="canonical" href="http://www.seqan.de/">
+ <style type="text/css"> .download-info .download-button { background-image: url(http://www.seqan.de/wp-content/plugins/download-monitor/page-addon/downloadbutton.gif); } .download-info .more-button { background-image: url(http://www.seqan.de/wp-content/plugins/download-monitor/page-addon/morebutton.gif); } </style>
+ <link href="seqan.css" media="" rel="stylesheet" type="text/css">
+ </head>
+ <body>
+ <div class="page_margins gradient">
+ <div class="page">
+ <!-- Header -->
+ <div id="header">
+ <a accesskey="O" name="seitenanfang" id="seitenanfang"></a> <a href="http://www.seqan.de" accesskey="H"><img id="fu_logo" title="To the Homepage of SeqAn" src="http://www.seqan.de/wp-content/uploads/2012/02/seqan_logo_167x110.png" height="110"></a>
+ <h1 class="hideme">SeqAn</h1>
+ <hr class="hideme">
+ <div id="topnav">
+ <a class="skip" title="skip link" href="#content">Go To Contents</a><span class="hideme">.</span>
+ <h2 class="hideme">Service-Navigation</h2>
+ <ul>
+ <li><a href="http://www.seqan.de" title="Homepage">Homepage</a></li>
+ <li><a href="http://www.seqan.de/contact-us/" title="Contact">Contact</a></li>
+ <li><a href="http://www.seqan.de/legal-notice/" title="Legal notice according to § 5 TMG">Legal Notice</a></li>
+ <li><a href="http://www.seqan.de/sitemap/" title="Sitemap">Sitemap</a></li>
+ </ul>
+ </div>
+ <!-- #topnav -->
+ <div id="services">
+ <div id="search" class="search">
+ <div id="search_inner">
+ <form action="http://www.seqan.de" id="search_form" method="get"> <input class="search_input" id="search_input" locale="de" name="s" title="Enter Search Term" type="text" value=""> <input alt="Start Search" class="search_button" id="search_button" src="http://www.seqan.de/wp-content/themes/fub-theme/images/search_button.gif" title="Start Search" type="image"> </form>
+ </div>
+ </div>
+ <!-- #search -->
+ <div id="icons"> <a href="#print" onclick="javascript:self.print();return false;" title="Diese Seite drucken"><img alt="Print (Icon)" id="icon_print" src="http://www.seqan.de/wp-content/themes/fub-theme/images/icon_print.gif" title="print"></a> <a href="http://www.seqan.de/feed/" target="_blank" title="Subscribe to RSS2 Feed"><img alt="RSS (Icon)" id="icon_rss" src="http://www.seqan.de/wp-content/themes/fub-theme/images/icon_rss.gif" title=""></a> </div>
+ <!-- #icons -->
+ </div>
+ <!-- #services -->
+ </div>
+ <!-- #header --> <!-- Wrappers for Main Content Row -->
+ <div id="main" class="page_raster_10_off">
+ <div class="subcolumns margin_bottom">
+ <!-- Left Bar -->
+ <div class="c20l">
+ <!-- Navigational Menu Left -->
+ <div class="vlist"> </div>
+ <!-- Left Sidebar -->
+ </div>
+ <!-- Main Content -->
+ <div class="c60l" id="main_content">
+ <div class="post subc subc_default_padding" id="post-2">
+ <div class="breadcrumbs">
+ <p class="hideme">Breadcrumbs</p>
+ <ul>
+ <li class="first"><a href="http://www.seqan.de">SeqAn</a></li>
+ <li class="active">Sub Page</li>
+ </ul>
+ </div>
+ <h1 class="main_headline" style="margin-top:0;">Sub Page</h1>
+ <h2>What is SeqAn?</h2>
+ <p>SeqAn is an open source C++ library of efficient algorithms and data structures for the analysis of sequences with the focus on biological data. Our library applies a unique generic design that guarantees high performance, generality, extensibility, and integration with other libraries. SeqAn is easy to use and simplifies the development of new software tools with a minimal loss of performance.</p>
+ <h2>Quick Facts</h2>
+ <ul>
+ <li>Programming Language: C++98</li>
+ <li>License: BSD/3-clause</li>
+ <li>
+ Supported Platforms:
+ <ul>
+ <li>Windows: Visual C++ 8, 9, 10 and MinGW</li>
+ <li>Linux: GNU/g++, LLVM/Clang (3.0+)</li>
+ <li>Mac OS X: GNU/g++, LLVM/Clang (3.0+)</li>
+ </ul>
+ </li>
+ </ul>
+ <div class="last_updated"><small class="dimmed"> Last Update 12. September 2012 </small></div>
+ </div>
+ </div>
+ </div>
+ <!-- #main_content --> <!-- Banner Row -->
+ <div id="banner" class="subc box_border_top padding_top padding_left padding_bottom">
+ <div class="css_classhorizontal_banner">
+ <div class="textwidget"><a href="http://www.fu-berlin.de"><img src="http://www.seqan.de/wp-content/uploads/2012/02/fu_logo.gif" http:="" www.seqan.de=""></a> </div>
+ </div>
+ </div>
+ </div>
+ <!-- id="main" --> <!-- Page Footer -->
+ <div id="footer">
+ <div class="subcolumns" id="bottomnav">
+ <div class="subc padding_left padding_right">
+ <a href="http://www.seqan.de" title="Home">SeqAn</a>
+ <ul>
+ <li><a href="http://www.seqan.de" title="Homepage">Homepage</a></li>
+ <li><a href="http://www.seqan.de/contact-us/" title="Contact">Contact</a></li>
+ <li><a href="http://www.seqan.de/legal-notice/" title="Legal notice according to § 5 TMG">Legal Notice</a></li>
+ <li><a href="http://www.seqan.de/sitemap/" title="Sitemap">Sitemap</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <!-- class="page" -->
+ </div>
+ <!-- class="page_margins" -->
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/util/py_lib/seqan/skel.py b/util/py_lib/seqan/skel.py
new file mode 100755
index 0000000..d5a2197
--- /dev/null
+++ b/util/py_lib/seqan/skel.py
@@ -0,0 +1,467 @@
+#!/usr/bin/env python2
+"""SeqAn code generation from templates / skeletons.
+
+This module contains code to help the creation of modules, tests, apps etc.
+It can be called directly or imported and the main() function can be called.
+
+It will perform the following replacements:
+
+ %(AUTHOR)s will be replaced by the author's name, either given on command
+ line or taken from environment variable SEQAN_AUTHOR.
+
+ %(NAME)s will be replaced by the name of the generated code.
+ %(TITLE)s will be replaced by the name of the generated, but centered in
+ 74 characters, to be used in the file header comment.
+
+ %(YEAR)d will be replaced by the current year.
+ %(DATE)s will be replaced by the current date.
+ %(TIME)s will be replaced by the current time.
+
+ %(HEADER_GUARD)s will be replaced by the UPPER_CASE_PATH_H_ to the file.
+
+ %(CMAKE_PROJECT_NAME)s will be replaced by lower_case_path to the target
+ directory.
+
+ %(CMAKE_PROJECT_PATH)s will be replaced by the path to the target directory.
+
+Copyright: (c) 2010, Knut Reinert, FU Berlin
+License: 3-clause BSD (see LICENSE)
+"""
+
+from __future__ import with_statement
+
+__author__ = 'Manuel Holtgrewe <manuel.holtgrewe at fu-berlin.de>'
+
+import datetime
+import optparse
+import os
+import os.path
+import sys
+import string
+
+import paths
+
+# Add os.path.relpath if it is not already there, so we can use Python 2.5, too.
+# TODO(holtgrew): This could go into a "compatibility" module.
+if not 'relpath' in dir(os.path):
+ import posixpath
+ from posixpath import curdir, sep, pardir, join
+
+ def relpath(path, start=curdir):
+ """Return a relative version of a path"""
+ if not path:
+ raise ValueError("no path specified")
+ start_list = posixpath.abspath(start).split(sep)
+ path_list = posixpath.abspath(path).split(sep)
+ # Work out how much of the filepath is shared by start and path.
+ i = len(posixpath.commonprefix([start_list, path_list]))
+ rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
+ if not rel_list:
+ return curdir
+ return join(*rel_list)
+ os.path.relpath = relpath
+
+# Length of the header comment.
+HEADER_CENTER_WIDTH = 74
+
+# Fallback for author string if neither given on command line or environment
+# Variable SEQAN_AUTHOR.
+DEFAULT_AUTHOR = 'Your Name <your.email at example.net>'
+
+# Program usage string for command line parser.
+USAGE = """
+Usage: %prog [options] repository NAME
+ %prog [options] [module|test|app|demo|header|lheader] NAME LOCATION
+ %prog [options] app_tests LOCATION
+""".strip()
+
+# Program description, used for command line parser. Will be wrapped by, though.
+DESCRIPTION = """
+The SeqAn code generator.
+
+The first version ("repository") is to be be called to create your new entries
+below the directory sandbox. The second version is to be called to create new
+library modules, tests, apps, app tests, and demos inside a sandbox.
+""".strip()
+#"""
+#Example:
+#
+# %prog repository sandbox/john_doe
+#
+#The second version is to be called to create new library modules, tests, apps,
+#and demos inside a sandbox. Example:
+#
+# %prog module my_module sandbox/john_doe
+#
+#This command creates a new library module in sandbox/john_doe/include/seqan.
+#It consists of the directory my_module, the files my_module.h and
+#my_module/my_module_base.h.
+#
+# %prog test my_module sandbox/john_doe
+#
+#This command creates the tests for module "my_module" in sandbox/john_doe.
+#
+# %prog app my_app sandbox/john_doe
+#
+#This command creates a new application named my_app in sandbox/john_doe/apps.
+#
+# %prog demo my_demo sandbox/john_doe
+#
+#This command creates a new demo in sandbox/john_doe/demos.
+#""".strip()
+
+def createDirectory(path, dry_run=False):
+ print 'mkdir(%s)' % path
+ print
+ if not dry_run:
+ if not os.path.exists(path):
+ os.mkdir(path)
+
+def configureFile(target_file, source_file, replacements, dry_run, options):
+ print 'Configuring file.'
+ print ' Source:', source_file
+ print ' Target:', target_file
+ print
+ if os.path.exists(target_file) and not options.force:
+ msg = 'Target file already exists. Move it away and call the script again.'
+ print >>sys.stderr, msg
+ return 1
+
+ with open(source_file, 'rb') as f:
+ contents = f.read()
+ target_contents = contents % replacements
+ if dry_run:
+ print 'The contents of the target file are:'
+ print '-' * 78
+ print target_contents
+ print '-' * 78
+ else:
+ with open(target_file, 'wb') as f:
+ f.write(target_contents)
+ return 0
+
+def _pathToIdentifier(relative_path):
+ result = relative_path.replace('/', '_')
+ result = result.replace('\\', '_')
+ result = result.replace('-', '_')
+ result = result.replace('.', '_')
+ result = result.replace(' ', '_')
+ return result
+
+def buildReplacements(type_, name, location, target_file, options):
+ result = {}
+ result['AUTHOR'] = options.author
+ result['YEAR'] = datetime.date.today().year
+ result['TIME'] = datetime.datetime.now().strftime('%H:%M')
+ result['DATE'] = datetime.date.today().strftime('%Y-%m-%d')
+ result['NAME'] = name
+ result['TITLE'] = name.center(HEADER_CENTER_WIDTH).rstrip()
+ path = os.path.relpath(target_file, paths.repositoryRoot())
+ guard = _pathToIdentifier(path).upper()
+ result['HEADER_GUARD'] = guard + '_'
+ path = os.path.relpath(os.path.dirname(target_file),
+ paths.repositoryRoot())
+ cmake_project_name = _pathToIdentifier(path)
+ result['CMAKE_PROJECT_NAME'] = cmake_project_name
+ result['CMAKE_PROJECT_PATH'] = path.replace('\\', '\\\\')
+ if type_ == 'repository':
+ result['REPOSITORY_PSEUDO_TARGET_NAME'] = name.replace('/', '_').replace('\\', '_').replace(' ', '_')
+ if type_ == 'app_tests':
+ result['APP_NAME'] = os.path.split(os.path.split(location)[0])[1]
+ result['APP_NAME_U'] = result['APP_NAME'].upper()
+ result['LOCATION'] = os.path.join(os.path.split(os.path.normpath(location))[0])
+ return result
+
+def _checkTargetPaths(target_path, options):
+ """Check that the path does not exist but its parent does."""
+ # Check that the given path does not exist yet.
+ if os.path.exists(target_path) and not options.force:
+ msg = 'The path %s already exists. Move it and call this script again.'
+ print >>sys.stderr, msg % target_path
+ return False
+ # Check that the parent path already exists.
+ if not os.path.exists(os.path.dirname(target_path)):
+ msg = 'The parent of the target path does not exist yet: %s'
+ print >>sys.stderr, msg % os.path.dirname(target_path)
+ print >>sys.stderr, 'Please create it and call this script again.'
+ return False
+ return True
+
+def createModule(name, location, options):
+ include_path = paths.pathToInclude(location)
+ seqan_path = os.path.join(include_path, 'seqan')
+ module_path = os.path.join(seqan_path, name)
+ header_path = os.path.join(seqan_path, '%s.h' % name)
+ print 'Creating module in %s' % module_path
+ if options.create_dirs and not _checkTargetPaths(module_path, options):
+ return 1
+ if options.create_dirs and not _checkTargetPaths(header_path, options):
+ return 1
+ print ' Module path is: %s' % module_path
+ print ' Module header path is: %s' % header_path
+ print ''
+ if options.create_dirs:
+ # Create directory.
+ createDirectory(module_path, options.dry_run)
+ if options.create_programs:
+ # Copy over module header.
+ source_file = paths.pathToTemplate('module_template', 'module.h')
+ target_file = header_path
+ replacements = buildReplacements('module', name, seqan_path, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ # Copy over header inside module.
+ source_file = paths.pathToTemplate('module_template', 'header.h')
+ target_file = os.path.join(module_path, '%s_base.h' % name)
+ replacements = buildReplacements('module', name, seqan_path, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ return 0
+
+def createTest(name, location, options):
+ target_path = paths.pathToTest(location, name)
+ print 'Creating test in %s' % target_path
+ if options.create_dirs and not _checkTargetPaths(target_path, options):
+ return 1
+ print ' Target path is: %s' % target_path
+ print ''
+ if options.create_dirs:
+ # Create directory.
+ createDirectory(target_path, options.dry_run)
+ if options.create_programs:
+ # Copy over .cpp file for test and perform replacements.
+ source_file = paths.pathToTemplate('test_template', 'test.cpp')
+ target_file = os.path.join(target_path, 'test_%s.cpp' % name)
+ replacements = buildReplacements('test', name, location, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ # Copy over .h file for test and perform replacements.
+ source_file = paths.pathToTemplate('test_template', 'test.h')
+ target_file = os.path.join(target_path, 'test_%s.h' % name)
+ replacements = buildReplacements('test', name, location, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ if options.create_cmakelists:
+ # Copy over CMakeLists.txt file for test and perform replacements.
+ source_file = paths.pathToTemplate('test_template', 'CMakeLists.txt')
+ target_file = os.path.join(target_path, 'CMakeLists.txt')
+ replacements = buildReplacements('test', name, location, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ return 0
+
+def createApp(name, location, options):
+ target_path = paths.pathToApp(location, name)
+ print 'Creating app in %s' % target_path
+ if options.create_dirs and not _checkTargetPaths(target_path, options):
+ return 1
+ print ' Target path is: %s' % target_path
+ print ''
+ if options.create_programs:
+ # Create directory.
+ createDirectory(target_path, options.dry_run)
+ # Copy over .cpp file for app and perform replacements.
+ source_file = paths.pathToTemplate('app_template', 'app.cpp')
+ target_file = os.path.join(target_path, '%s.cpp' % name)
+ replacements = buildReplacements('app', name, location, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ if options.create_cmakelists:
+ # Copy over CMakeLists.txt file for app and perform replacements.
+ source_file = paths.pathToTemplate('app_template', 'CMakeLists.txt')
+ target_file = os.path.join(target_path, 'CMakeLists.txt')
+ replacements = buildReplacements('app', name, location, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ return 0
+
+def createDemo(name, location, options):
+ target_path = paths.pathToDemo(location, name)
+ print 'Creating demo in %s' % target_path
+ if options.create_dirs and not _checkTargetPaths(target_path, options):
+ return 1
+ print ' Target path is: %s' % target_path
+ print ''
+ if options.create_programs:
+ # Copy over .cpp file for app and perform replacements.
+ source_file = paths.pathToTemplate('demo_template', 'demo.cpp')
+ target_file = os.path.join(target_path)
+ replacements = buildReplacements('demo', name, location, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ return 0
+
+def createHeader(name, location, options):
+ target_path = paths.pathToHeader(location, name)
+ print 'Creating (non-library) header in %s' % target_path
+ if not _checkTargetPaths(target_path, options):
+ return 1
+ print ' Target path is: %s' % target_path
+ print ''
+ # Copy over .h file for app and perform replacements.
+ source_file = paths.pathToTemplate('header_template', 'header.h')
+ target_file = os.path.join(target_path)
+ replacements = buildReplacements('header', name, location, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ print 'NOTE: Do not forget to add the header to the CMakeLists.txt file!'
+ return 0
+
+def createLibraryHeader(name, location, options):
+ target_path = paths.pathToHeader(location, name)
+ print 'Creating library header in %s' % target_path
+ if not _checkTargetPaths(target_path, options):
+ return 1
+ print ' Target path is: %s' % target_path
+ print ''
+ # Copy over .h file for app and perform replacements.
+ source_file = paths.pathToTemplate('header_template', 'library_header.h')
+ target_file = os.path.join(target_path)
+ replacements = buildReplacements('library_header', name, location, target_file, options)
+ res = configureFile(target_file, source_file, replacements, options.dry_run, options)
+ if res: return res
+ return 0
+
+def createRepository(location, options):
+ print 'Creating module %s' % location
+ target_path = paths.pathToRepository(location)
+ if options.create_dirs and not _checkTargetPaths(target_path, options):
+ return 1
+ print ' Target path is: %s' % target_path
+ print ''
+ if options.create_dirs:
+ # Create directories.
+ createDirectory(target_path, options.dry_run)
+ createDirectory(os.path.join(target_path, 'apps'), options.dry_run)
+ createDirectory(os.path.join(target_path, 'demos'), options.dry_run)
+ createDirectory(os.path.join(target_path, 'include'), options.dry_run)
+ createDirectory(os.path.join(target_path, 'include', 'seqan'), options.dry_run)
+ createDirectory(os.path.join(target_path, 'tests'), options.dry_run)
+ if options.create_cmakelists:
+ # Copy over file ${REPOSITORY}/CMakeLists.txt.
+ target_file = os.path.join(target_path, 'CMakeLists.txt')
+ source_file = paths.pathToTemplate('repository_template', 'CMakeLists.txt')
+ replacements = buildReplacements('repository', location, target_path, target_file, options)
+ configureFile(target_file, source_file, replacements, options.dry_run, options)
+ # Copy over file ${REPOSITORY}/apps/CMakeLists.txt.
+ target_file = os.path.join(target_path, 'apps', 'CMakeLists.txt')
+ source_file = paths.pathToTemplate('repository_template', 'apps_CMakeLists.txt')
+ replacements = buildReplacements('repository', location, target_path, target_file, options)
+ configureFile(target_file, source_file, replacements, options.dry_run, options)
+ # Copy over file ${REPOSITORY}/tests/CMakeLists.txt.
+ target_file = os.path.join(target_path, 'tests', 'CMakeLists.txt')
+ source_file = paths.pathToTemplate('repository_template', 'tests_CMakeLists.txt')
+ replacements = buildReplacements('repository', location, target_path, target_file, options)
+ configureFile(target_file, source_file, replacements, options.dry_run, options)
+ # Copy over file ${REPOSITORY}/demos/CMakeLists.txt.
+ target_file = os.path.join(target_path, 'demos', 'CMakeLists.txt')
+ source_file = paths.pathToTemplate('repository_template', 'demos_CMakeLists.txt')
+ replacements = buildReplacements('repository', location, target_path, target_file, options)
+ configureFile(target_file, source_file, replacements, options.dry_run, options)
+ return 0
+
+def createAppTests(location, options):
+ print 'Creating app tests at %s' % location
+ tests_location = os.path.join(location, 'tests')
+ target_path = paths.pathToRepository(tests_location)
+ if options.create_dirs and not _checkTargetPaths(target_path, options):
+ return 1
+ print ' Target path is: %s' % target_path
+ print ''
+
+ # Create directories.
+ if options.create_dirs:
+ createDirectory(target_path, options.dry_run)
+
+ # Copy over file ${APP}/tests/generate_outputs.sh
+ target_file = os.path.join(target_path, 'generate_outputs.sh')
+ source_file = paths.pathToTemplate('app_tests_template', 'generate_outputs.sh')
+ replacements = buildReplacements('app_tests', location, target_path, target_file, options)
+ configureFile(target_file, source_file, replacements, options.dry_run, options)
+ # Copy over file ${APP}/tests/run_tests.py
+ target_file = os.path.join(target_path, 'run_tests.py')
+ source_file = paths.pathToTemplate('app_tests_template', 'run_tests.py')
+ replacements = buildReplacements('app_tests', location, target_path, target_file, options)
+ configureFile(target_file, source_file, replacements, options.dry_run, options)
+
+ print '=' * 80
+ print 'Do not forget to add the tests in %s:' % os.path.join(location, 'CMakeLists.txt')
+ print ''
+ print '# Add app tests if Python interpreter could be found.'
+ print 'if(PYTHONINTERP_FOUND)'
+ print ' add_test(NAME app_test_%s COMMAND ${PYTHON_EXECUTABLE}' % os.path.split(location)[-1]
+ print ' ${CMAKE_CURRENT_SOURCE_DIR}/tests/run_tests.py ${CMAKE_SOURCE_DIR}'
+ print ' ${CMAKE_BINARY_DIR})'
+ print 'endif(PYTHONINTERP_FOUND)'
+ print '=' * 80
+
+ return 0
+
+def main():
+ # Parse arguments.
+ parser = optparse.OptionParser(usage=USAGE, description=DESCRIPTION)
+ parser.add_option('-s', '--skel-root', dest='skel_root',
+ help=('Set path to the directory where the skeletons '
+ 'live in. Taken from environment variable '
+ 'SEQAN_SKELS if available.'),
+ default=os.environ.get('SEQAN_SKELS',
+ paths.pathToSkeletons()))
+ parser.add_option('-a', '--author', dest='author',
+ help=('Set author to use. Should have the format USER '
+ '<EMAIL>. Taken from environment variable '
+ 'SEQAN_AUTHOR if it exists.'),
+ default=os.environ.get('SEQAN_AUTHOR', DEFAULT_AUTHOR))
+ parser.add_option('-d', '--dry-run', dest='dry_run', action='store_true',
+ help='Do not change anything, just simulate.',
+ default=False)
+ parser.add_option('-c', '--cmakelists-only', dest='cmakelists_only',
+ action='store_true',
+ help='Only create CMakeLists.txt files',
+ default=False)
+ parser.add_option('--force', dest='force', action='store_true',
+ help='Overwrite existing files and directories.',
+ default=False)
+ options, args = parser.parse_args()
+ options.create_cmakelists = True
+ options.create_infos = True
+ options.create_dirs = True
+ options.create_programs = True
+ if options.cmakelists_only:
+ options.create_dirs = False
+ options.create_programs = False
+
+ if not args:
+ parser.print_help(file=sys.stderr)
+ return 1
+ if len(args) < 2:
+ print >>sys.stderr, 'Invalid argument count!'
+ return 1
+ if args[0] not in ['module', 'test', 'app', 'demo', 'repository',
+ 'header', 'lheader', 'app_tests']:
+ print >>sys.stderr, 'Invalid template "%s".' % args[0]
+ return 1
+ if args[0] in['repository', 'app_tests']:
+ if len(args) != 2:
+ print >>sys.stderr, 'Invalid argument count!'
+ return 1
+
+ if args[0] == 'repository':
+ return createRepository(args[1], options)
+ elif args[0] == 'app_tests':
+ return createAppTests(args[1], options)
+ elif len(args) != 3:
+ print >>sys.stderr, 'Invalid argument count!'
+ return 1
+ create_methods = {
+ 'module' : createModule,
+ 'test': createTest,
+ 'app': createApp,
+ 'demo': createDemo,
+ 'header': createHeader,
+ 'lheader': createLibraryHeader,
+ }
+ return create_methods[args[0]](args[1], args[2], options)
+
+if __name__ == '__main__':
+ sys.exit(main())
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/seqan2.git
More information about the debian-med-commit
mailing list