Blame googletest/scripts/fuse_gtest_files.py

Packit bd1cd8
#!/usr/bin/env python
Packit bd1cd8
#
Packit bd1cd8
# Copyright 2009, Google Inc.
Packit bd1cd8
# All rights reserved.
Packit bd1cd8
#
Packit bd1cd8
# Redistribution and use in source and binary forms, with or without
Packit bd1cd8
# modification, are permitted provided that the following conditions are
Packit bd1cd8
# met:
Packit bd1cd8
#
Packit bd1cd8
#     * Redistributions of source code must retain the above copyright
Packit bd1cd8
# notice, this list of conditions and the following disclaimer.
Packit bd1cd8
#     * Redistributions in binary form must reproduce the above
Packit bd1cd8
# copyright notice, this list of conditions and the following disclaimer
Packit bd1cd8
# in the documentation and/or other materials provided with the
Packit bd1cd8
# distribution.
Packit bd1cd8
#     * Neither the name of Google Inc. nor the names of its
Packit bd1cd8
# contributors may be used to endorse or promote products derived from
Packit bd1cd8
# this software without specific prior written permission.
Packit bd1cd8
#
Packit bd1cd8
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit bd1cd8
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit bd1cd8
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit bd1cd8
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit bd1cd8
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit bd1cd8
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit bd1cd8
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit bd1cd8
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit bd1cd8
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit bd1cd8
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit bd1cd8
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit bd1cd8
Packit bd1cd8
"""fuse_gtest_files.py v0.2.0
Packit bd1cd8
Fuses Google Test source code into a .h file and a .cc file.
Packit bd1cd8
Packit bd1cd8
SYNOPSIS
Packit bd1cd8
       fuse_gtest_files.py [GTEST_ROOT_DIR] OUTPUT_DIR
Packit bd1cd8
Packit bd1cd8
       Scans GTEST_ROOT_DIR for Google Test source code, and generates
Packit bd1cd8
       two files: OUTPUT_DIR/gtest/gtest.h and OUTPUT_DIR/gtest/gtest-all.cc.
Packit bd1cd8
       Then you can build your tests by adding OUTPUT_DIR to the include
Packit bd1cd8
       search path and linking with OUTPUT_DIR/gtest/gtest-all.cc.  These
Packit bd1cd8
       two files contain everything you need to use Google Test.  Hence
Packit bd1cd8
       you can "install" Google Test by copying them to wherever you want.
Packit bd1cd8
Packit bd1cd8
       GTEST_ROOT_DIR can be omitted and defaults to the parent
Packit bd1cd8
       directory of the directory holding this script.
Packit bd1cd8
Packit bd1cd8
EXAMPLES
Packit bd1cd8
       ./fuse_gtest_files.py fused_gtest
Packit bd1cd8
       ./fuse_gtest_files.py path/to/unpacked/gtest fused_gtest
Packit bd1cd8
Packit bd1cd8
This tool is experimental.  In particular, it assumes that there is no
Packit bd1cd8
conditional inclusion of Google Test headers.  Please report any
Packit bd1cd8
problems to googletestframework@googlegroups.com.  You can read
Packit bd1cd8
http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide for
Packit bd1cd8
more information.
Packit bd1cd8
"""
Packit bd1cd8
Packit bd1cd8
__author__ = 'wan@google.com (Zhanyong Wan)'
Packit bd1cd8
Packit bd1cd8
import os
Packit bd1cd8
import re
Packit bd1cd8
try:
Packit bd1cd8
  from sets import Set as set  # For Python 2.3 compatibility
Packit bd1cd8
except ImportError:
Packit bd1cd8
  pass
Packit bd1cd8
import sys
Packit bd1cd8
Packit bd1cd8
# We assume that this file is in the scripts/ directory in the Google
Packit bd1cd8
# Test root directory.
Packit bd1cd8
DEFAULT_GTEST_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..')
Packit bd1cd8
Packit bd1cd8
# Regex for matching '#include "gtest/..."'.
Packit bd1cd8
INCLUDE_GTEST_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(gtest/.+)"')
Packit bd1cd8
Packit bd1cd8
# Regex for matching '#include "src/..."'.
Packit bd1cd8
INCLUDE_SRC_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(src/.+)"')
Packit bd1cd8
Packit bd1cd8
# Where to find the source seed files.
Packit bd1cd8
GTEST_H_SEED = 'include/gtest/gtest.h'
Packit bd1cd8
GTEST_SPI_H_SEED = 'include/gtest/gtest-spi.h'
Packit bd1cd8
GTEST_ALL_CC_SEED = 'src/gtest-all.cc'
Packit bd1cd8
Packit bd1cd8
# Where to put the generated files.
Packit bd1cd8
GTEST_H_OUTPUT = 'gtest/gtest.h'
Packit bd1cd8
GTEST_ALL_CC_OUTPUT = 'gtest/gtest-all.cc'
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def VerifyFileExists(directory, relative_path):
Packit bd1cd8
  """Verifies that the given file exists; aborts on failure.
Packit bd1cd8
Packit bd1cd8
  relative_path is the file path relative to the given directory.
Packit bd1cd8
  """
Packit bd1cd8
Packit bd1cd8
  if not os.path.isfile(os.path.join(directory, relative_path)):
Packit bd1cd8
    print('ERROR: Cannot find %s in directory %s.' % (relative_path,
Packit bd1cd8
                                                      directory))
Packit bd1cd8
    print('Please either specify a valid project root directory '
Packit bd1cd8
          'or omit it on the command line.')
Packit bd1cd8
    sys.exit(1)
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def ValidateGTestRootDir(gtest_root):
Packit bd1cd8
  """Makes sure gtest_root points to a valid gtest root directory.
Packit bd1cd8
Packit bd1cd8
  The function aborts the program on failure.
Packit bd1cd8
  """
Packit bd1cd8
Packit bd1cd8
  VerifyFileExists(gtest_root, GTEST_H_SEED)
Packit bd1cd8
  VerifyFileExists(gtest_root, GTEST_ALL_CC_SEED)
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def VerifyOutputFile(output_dir, relative_path):
Packit bd1cd8
  """Verifies that the given output file path is valid.
Packit bd1cd8
Packit bd1cd8
  relative_path is relative to the output_dir directory.
Packit bd1cd8
  """
Packit bd1cd8
Packit bd1cd8
  # Makes sure the output file either doesn't exist or can be overwritten.
Packit bd1cd8
  output_file = os.path.join(output_dir, relative_path)
Packit bd1cd8
  if os.path.exists(output_file):
Packit bd1cd8
    # TODO(wan@google.com): The following user-interaction doesn't
Packit bd1cd8
    # work with automated processes.  We should provide a way for the
Packit bd1cd8
    # Makefile to force overwriting the files.
Packit bd1cd8
    print('%s already exists in directory %s - overwrite it? (y/N) ' %
Packit bd1cd8
          (relative_path, output_dir))
Packit bd1cd8
    answer = sys.stdin.readline().strip()
Packit bd1cd8
    if answer not in ['y', 'Y']:
Packit bd1cd8
      print('ABORTED.')
Packit bd1cd8
      sys.exit(1)
Packit bd1cd8
Packit bd1cd8
  # Makes sure the directory holding the output file exists; creates
Packit bd1cd8
  # it and all its ancestors if necessary.
Packit bd1cd8
  parent_directory = os.path.dirname(output_file)
Packit bd1cd8
  if not os.path.isdir(parent_directory):
Packit bd1cd8
    os.makedirs(parent_directory)
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def ValidateOutputDir(output_dir):
Packit bd1cd8
  """Makes sure output_dir points to a valid output directory.
Packit bd1cd8
Packit bd1cd8
  The function aborts the program on failure.
Packit bd1cd8
  """
Packit bd1cd8
Packit bd1cd8
  VerifyOutputFile(output_dir, GTEST_H_OUTPUT)
Packit bd1cd8
  VerifyOutputFile(output_dir, GTEST_ALL_CC_OUTPUT)
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def FuseGTestH(gtest_root, output_dir):
Packit bd1cd8
  """Scans folder gtest_root to generate gtest/gtest.h in output_dir."""
Packit bd1cd8
Packit bd1cd8
  output_file = open(os.path.join(output_dir, GTEST_H_OUTPUT), 'w')
Packit bd1cd8
  processed_files = set()  # Holds all gtest headers we've processed.
Packit bd1cd8
Packit bd1cd8
  def ProcessFile(gtest_header_path):
Packit bd1cd8
    """Processes the given gtest header file."""
Packit bd1cd8
Packit bd1cd8
    # We don't process the same header twice.
Packit bd1cd8
    if gtest_header_path in processed_files:
Packit bd1cd8
      return
Packit bd1cd8
Packit bd1cd8
    processed_files.add(gtest_header_path)
Packit bd1cd8
Packit bd1cd8
    # Reads each line in the given gtest header.
Packit bd1cd8
    for line in open(os.path.join(gtest_root, gtest_header_path), 'r'):
Packit bd1cd8
      m = INCLUDE_GTEST_FILE_REGEX.match(line)
Packit bd1cd8
      if m:
Packit bd1cd8
        # It's '#include "gtest/..."' - let's process it recursively.
Packit bd1cd8
        ProcessFile('include/' + m.group(1))
Packit bd1cd8
      else:
Packit bd1cd8
        # Otherwise we copy the line unchanged to the output file.
Packit bd1cd8
        output_file.write(line)
Packit bd1cd8
Packit bd1cd8
  ProcessFile(GTEST_H_SEED)
Packit bd1cd8
  output_file.close()
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def FuseGTestAllCcToFile(gtest_root, output_file):
Packit bd1cd8
  """Scans folder gtest_root to generate gtest/gtest-all.cc in output_file."""
Packit bd1cd8
Packit bd1cd8
  processed_files = set()
Packit bd1cd8
Packit bd1cd8
  def ProcessFile(gtest_source_file):
Packit bd1cd8
    """Processes the given gtest source file."""
Packit bd1cd8
Packit bd1cd8
    # We don't process the same #included file twice.
Packit bd1cd8
    if gtest_source_file in processed_files:
Packit bd1cd8
      return
Packit bd1cd8
Packit bd1cd8
    processed_files.add(gtest_source_file)
Packit bd1cd8
Packit bd1cd8
    # Reads each line in the given gtest source file.
Packit bd1cd8
    for line in open(os.path.join(gtest_root, gtest_source_file), 'r'):
Packit bd1cd8
      m = INCLUDE_GTEST_FILE_REGEX.match(line)
Packit bd1cd8
      if m:
Packit bd1cd8
        if 'include/' + m.group(1) == GTEST_SPI_H_SEED:
Packit bd1cd8
          # It's '#include "gtest/gtest-spi.h"'.  This file is not
Packit bd1cd8
          # #included by "gtest/gtest.h", so we need to process it.
Packit bd1cd8
          ProcessFile(GTEST_SPI_H_SEED)
Packit bd1cd8
        else:
Packit bd1cd8
          # It's '#include "gtest/foo.h"' where foo is not gtest-spi.
Packit bd1cd8
          # We treat it as '#include "gtest/gtest.h"', as all other
Packit bd1cd8
          # gtest headers are being fused into gtest.h and cannot be
Packit bd1cd8
          # #included directly.
Packit bd1cd8
Packit bd1cd8
          # There is no need to #include "gtest/gtest.h" more than once.
Packit bd1cd8
          if not GTEST_H_SEED in processed_files:
Packit bd1cd8
            processed_files.add(GTEST_H_SEED)
Packit bd1cd8
            output_file.write('#include "%s"\n' % (GTEST_H_OUTPUT,))
Packit bd1cd8
      else:
Packit bd1cd8
        m = INCLUDE_SRC_FILE_REGEX.match(line)
Packit bd1cd8
        if m:
Packit bd1cd8
          # It's '#include "src/foo"' - let's process it recursively.
Packit bd1cd8
          ProcessFile(m.group(1))
Packit bd1cd8
        else:
Packit bd1cd8
          output_file.write(line)
Packit bd1cd8
Packit bd1cd8
  ProcessFile(GTEST_ALL_CC_SEED)
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def FuseGTestAllCc(gtest_root, output_dir):
Packit bd1cd8
  """Scans folder gtest_root to generate gtest/gtest-all.cc in output_dir."""
Packit bd1cd8
Packit bd1cd8
  output_file = open(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w')
Packit bd1cd8
  FuseGTestAllCcToFile(gtest_root, output_file)
Packit bd1cd8
  output_file.close()
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def FuseGTest(gtest_root, output_dir):
Packit bd1cd8
  """Fuses gtest.h and gtest-all.cc."""
Packit bd1cd8
Packit bd1cd8
  ValidateGTestRootDir(gtest_root)
Packit bd1cd8
  ValidateOutputDir(output_dir)
Packit bd1cd8
Packit bd1cd8
  FuseGTestH(gtest_root, output_dir)
Packit bd1cd8
  FuseGTestAllCc(gtest_root, output_dir)
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
def main():
Packit bd1cd8
  argc = len(sys.argv)
Packit bd1cd8
  if argc == 2:
Packit bd1cd8
    # fuse_gtest_files.py OUTPUT_DIR
Packit bd1cd8
    FuseGTest(DEFAULT_GTEST_ROOT_DIR, sys.argv[1])
Packit bd1cd8
  elif argc == 3:
Packit bd1cd8
    # fuse_gtest_files.py GTEST_ROOT_DIR OUTPUT_DIR
Packit bd1cd8
    FuseGTest(sys.argv[1], sys.argv[2])
Packit bd1cd8
  else:
Packit bd1cd8
    print(__doc__)
Packit bd1cd8
    sys.exit(1)
Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
if __name__ == '__main__':
Packit bd1cd8
  main()