#!/usr/bin/python2.7
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import os
import re
import sys
import glob
import shutil
import errno


def copy_dir_contents(src, dest):
    for f in glob.glob("%s/*" % src):
        try:
            destname = "%s/%s" % (dest, os.path.basename(f))
            if os.path.isdir(f):
                shutil.copytree(f, destname)
            else:
                shutil.copy2(f, destname)
        except OSError as e:
            if e.errno == errno.ENOTDIR:
                shutil.copy2(f, destname)
            elif e.errno == errno.EEXIST:
                if os.path.isdir(f):
                    copy_dir_contents(f, destname)
                else:
                    os.remove(destname)
                    shutil.copy2(f, destname)
            else:
                raise Exception('Directory not copied. Error: %s' % e)

def write_cmake(module_path):
  names = map(lambda f: '  ' + os.path.basename(f),
              glob.glob("%s/*.cpp" % module_path))
  with open(os.path.join(module_path, 'CMakeLists.txt'), 'wb') as f:
    f.write("""set(LLVM_LINK_COMPONENTS support)

add_definitions( -DCLANG_TIDY )
add_definitions( -DHAVE_NEW_ASTMATCHER_NAMES )

add_clang_library(clangTidyMozillaModule
%(names)s

  LINK_LIBS
  clangAST
  clangASTMatchers
  clangBasic
  clangLex
  clangTidy
  clangTidyReadabilityModule
  clangTidyUtils
  )""" % {'names': "\n".join(names)})

def add_item_to_cmake_section(cmake_path, section, library):
  with open(cmake_path, 'r') as f:
    lines = f.readlines()
  f.close()

  libs = []
  seen_target_libs = False
  for line in lines:
    if line.find(section) > -1:
      seen_target_libs = True
    elif seen_target_libs:
      if line.find(')') > -1:
        break
      else:
        libs.append(line.strip())
  libs.append(library)
  libs = sorted(libs, key = lambda s: s.lower())

  with open(cmake_path, 'wb') as f:
    seen_target_libs = False
    for line in lines:
      if line.find(section) > -1:
        seen_target_libs = True
        f.write(line)
        f.writelines(map(lambda p: '  ' + p + '\n', libs))
        continue
      elif seen_target_libs:
        if line.find(')') > -1:
          seen_target_libs = False
        else:
          continue
      f.write(line)

  f.close()


def do_import(mozilla_path, clang_tidy_path):
  module = 'mozilla'
  module_path = os.path.join(clang_tidy_path, module)
  if not os.path.isdir(module_path):
      os.mkdir(module_path)

  copy_dir_contents(mozilla_path, module_path)
  write_cmake(module_path)
  add_item_to_cmake_section(os.path.join(module_path, '..', 'plugin',
                                         'CMakeLists.txt'),
                            'LINK_LIBS', 'clangTidyMozillaModule')
  add_item_to_cmake_section(os.path.join(module_path, '..', 'tool',
                                         'CMakeLists.txt'),
                            'target_link_libraries', 'clangTidyMozillaModule')
  with open(os.path.join(module_path, '..', 'CMakeLists.txt'), 'a') as f:
    f.write('add_subdirectory(%s)\n' % module)
  with open(os.path.join(module_path, '..', 'tool', 'ClangTidyMain.cpp'), 'a') as f:
    f.write('''
// This anchor is used to force the linker to link the MozillaModule.
extern volatile int MozillaModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED MozillaModuleAnchorDestination =
          MozillaModuleAnchorSource;
''')

def main():
  if len(sys.argv) != 3:
    print """\
Usage: import_mozilla_checks.py <mozilla-clang-plugin-path> <clang-tidy-path>
Imports the Mozilla static analysis checks into a clang-tidy source tree.
"""

    return

  mozilla_path = sys.argv[1]
  if not os.path.isdir(mozilla_path):
      print "Invalid path to mozilla clang plugin"

  clang_tidy_path = sys.argv[2]
  if not os.path.isdir(mozilla_path):
      print "Invalid path to clang-tidy source directory"

  do_import(mozilla_path, clang_tidy_path)


if __name__ == '__main__':
  main()
