#
# Copyright (C) 2012-2020 Euclid Science Ground Segment
#
# This library is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3.0 of the License, or (at your option)
# any later version.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
""" This script creates a new Elements module
:file: ElementsKernel/AddModule.py
:author: Nicolas Morisset
:date: 01/07/15
"""
import argparse
import os
from ElementsKernel import Exit
from ElementsKernel import Auxiliary
from ElementsKernel import ProjectCommonRoutines
from ElementsKernel import ParseCmakeLists
from ElementsKernel import ParseCmakeListsMacros
from ElementsKernel import Logging
try:
from builtins import input
except ImportError:
from __builtin__ import input
logger = Logging.getLogger('AddElementsModule')
# Define constants
CMAKE_LISTS_FILE = 'CMakeLists.txt'
CMAKE_LISTS_FILE_IN = 'CMakeLists.txt.mod.in'
AUX_MOD_RST_IN = 'doc_module.rst.in'
target_locations = { CMAKE_LISTS_FILE_IN: "CMakeLists.txt",
AUX_MOD_RST_IN: "doc/doc_module.rst"
}
################################################################################
[docs]def checkCmakelistFileExist(project_directory):
"""
Checks if a <CMakeLists.txt> file exists and is really an Elements
cmake file
"""
cmake_file = os.path.join(project_directory, CMAKE_LISTS_FILE)
if not os.path.isfile(cmake_file):
raise Exception("<%s> cmake project file is missing! Are you inside "
"a project directory?" % cmake_file)
else:
# Check the make file is an Elements cmake file
# it should contain the string : "elements_project"
f = open(cmake_file)
data = f.read()
if not 'elements_project' in data:
f.close()
raise Exception("<%s> is not an Elements project cmake file!"
"Can not find the <elements_project> directive." % cmake_file)
f.close()
################################################################################
[docs]def createModuleDirectories(project_dir, module_name):
"""
Create the directory structure for the module
"""
# Create standalone directories
standalone_directories = [module_name, "doc", "conf", "tests/src"]
for d in standalone_directories:
target_dir = os.path.join(project_dir, module_name, d)
os.makedirs(target_dir)
ProjectCommonRoutines.addItemToCreationList(target_dir)
[docs]def createCmakeListFile(project_dir, module_name, module_dep_list, standalone=False):
"""
Create the <CMakeList.txt> file and add dependencies to it
"""
for src in target_locations:
file_name = os.path.join("ElementsKernel", "templates", src)
tgt = target_locations[src]
module_dir = os.path.join(project_dir, module_name)
Auxiliary.configure(file_name, module_dir, tgt,
configuration="",
create_missing_dir=True)
ProjectCommonRoutines.addItemToCreationList(os.path.join(module_dir, tgt))
# Read the template file
cmake_list_file = os.path.join(module_dir, CMAKE_LISTS_FILE)
fo = open(cmake_list_file)
template_data = fo.read()
fo.close()
cmake_object = ParseCmakeLists.CMakeLists(template_data)
# Add elements_subdir macro
subdir_obj = ParseCmakeListsMacros.ElementsSubdir(module_name)
cmake_object.elements_subdir_list.append(subdir_obj)
# Set <ElementsKernel> as a default
if not standalone:
default_dependency = 'ElementsKernel'
if module_dep_list:
if not default_dependency in module_dep_list:
module_dep_list.insert(0, default_dependency)
else:
module_dep_list = [default_dependency]
# Update ElementsDependsOnSubdirs macro
if module_dep_list:
for mod_dep in module_dep_list:
dep_object = ParseCmakeListsMacros.ElementsDependsOnSubdirs([mod_dep])
cmake_object.elements_depends_on_subdirs_list.append(dep_object)
# Write new data
f = open(cmake_list_file, 'w')
f.write(str(cmake_object))
f.close()
################################################################################
[docs]def createModule(project_dir, module_name, dependency_list, standalone=False, answer_yes=False):
"""
Create a module, copy auxiliary files and substitute variables in the
CMakefile.txt file
"""
# Create module directory
mod_path = os.path.join(project_dir, module_name)
logger.info('# Creating the module: <%s> ', mod_path)
if os.path.exists(mod_path):
# Ask user
logger.warning('<%s> module ALREADY exists on disk!!!', module_name)
if not answer_yes:
response_key = input(
'Do you want to replace the existing module (y/n), default: n)?')
if answer_yes or response_key.lower() == "y":
logger.info('# Replacing the existing module: <%s>', module_name)
ProjectCommonRoutines.eraseDirectory(mod_path)
else:
raise Exception()
createModuleDirectories(project_dir, module_name)
createCmakeListFile(project_dir, module_name, dependency_list, standalone)
################################################################################
[docs]def checkDependencyListValid(str_list):
"""
Check if the dependency name(s) is(are) valid
"""
if str_list:
for elt in str_list:
ProjectCommonRoutines.checkNameAndVersionValid(elt, '1.0')
################################################################################
[docs]def makeChecks(project_dir, module_name, dependency_list):
"""
Make some checks
"""
# We absolutely need an Elements cmake file
checkCmakelistFileExist(project_dir)
ProjectCommonRoutines.checkNameAndVersionValid(module_name, '1.0')
checkDependencyListValid(dependency_list)
################################################################################
[docs]def defineSpecificProgramOptions():
"""
Define program option(s)
"""
description = """
This script creates an <Elements> module at your current directory
(default) but it must be inside a project directory. All necessary structure
(directory structure, makefiles etc...) will be automatically created for you.
"""
from argparse import RawTextHelpFormatter
parser = argparse.ArgumentParser(description=description,
formatter_class=RawTextHelpFormatter)
parser.add_argument('module_name', metavar='module-name',
type=str,
help='Module name')
parser.add_argument('-md', '--module-dependency', metavar='module_name',
action='append', type=str,
help='Dependency module name e.g "-md ElementsKernel"')
parser.add_argument('-s', '--standalone', default=False, action="store_true",
help='Remove the implicit dependency onto the ElementsKernel module (expert only)')
parser.add_argument('-y', '--yes', default=False, action="store_true",
help='Answer <yes> by default to any question, useful when the script is called by another'\
'script')
return parser
################################################################################
[docs]def mainMethod(args):
"""
Main
"""
exit_code = Exit.Code["OK"]
logger.info('#')
logger.info('# Logging from the mainMethod() of the AddModule script ')
logger.info('#')
module_name = args.module_name
dependency_list = args.module_dependency
standalone = args.standalone
answer_yes = args.yes
# Default is the current directory
project_dir = os.getcwd()
logger.info('# Current directory : %s', project_dir)
try:
makeChecks(project_dir, module_name, dependency_list)
createModule(project_dir, module_name, dependency_list, standalone, answer_yes)
logger.info('# <%s> module successfully created in <%s>.', module_name, project_dir)
# Print all files created
ProjectCommonRoutines.printCreationList()
except Exception as msg:
if str(msg):
logger.error(msg)
logger.error('# Script aborted.')
exit_code = Exit.Code["NOT_OK"]
else:
logger.info('# Script over.')
return exit_code