# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 """Methods of manipulating the templates repository.""" import logging import os import shutil REPOSITORY_TEMPLATES = "template-for-repository" PROOF_TEMPLATES = "template-for-proof" PROOF_DIR = "proofs" # There are some files that we should copy to the project repository rather than # symlinking. This is because users are expected to modify these files. If the # files were symlinks, then modifying them would dirty up this submodule, which # would prevent project owners from cleanly updating it. COPY_INSTEAD = [ "Makefile-project-defines", "Makefile-project-targets", "Makefile-project-testing", ".gitignore", "run-cbmc-proofs.py", ] ################################################################ def script_dir(): """Directory containing setup scripts.""" return os.path.dirname(os.path.abspath(__file__)) def templates_root(): """Directory containing the AWS-templates-for-CBMC repository.""" return os.path.dirname(script_dir()) ################################################################ # Read configuration information from the standard input def read_from_stdin(): return input().strip() def read_path_from_stdin(description): print("What is the path to {}? ".format(description), end="") return os.path.abspath(os.path.expanduser(read_from_stdin())) def read_source_root_path(): return read_path_from_stdin("the source root") def read_proof_root_path(): return read_path_from_stdin("the 'proofs' directory (usually '.')") def read_litani_path(): return read_path_from_stdin("the litani script") def read_source_path(): return read_path_from_stdin("the source file defining the function") def read_function_name(): print("What is the function name? ", end="") return read_from_stdin() def read_project_name(): print("What is the project name? ", end="") return read_from_stdin() ################################################################ def files_under_root(root): """The list of files in the filesystem under root.""" cwd = os.getcwd() try: os.chdir(root) return [os.path.join(path, name) for path, _, files in os.walk('.') for name in files] finally: os.chdir(cwd) def link_files(name, src, dst): """Link file dst/name to file src/name, return number skipped""" src_name = os.path.normpath(os.path.join(src, name)) dst_name = os.path.normpath(os.path.join(dst, name)) os.makedirs(os.path.dirname(dst_name), exist_ok=True) src_link = os.path.relpath(src_name, os.path.dirname(dst_name)) if os.path.basename(name) in COPY_INSTEAD: install_method = ("copy", shutil.copyfile) src_link = src_name else: install_method = ("symlink", os.symlink) if os.path.exists(dst_name): logging.warning("Skipping %s %s -> %s: file exists", install_method[0], name, src_link) return 1 logging.warning( "Creating %s %s -> %s", install_method[0], name, src_link) install_method[1](src_link, dst_name) return 0 def copy_directory_contents(src, dst): """Link the contents of one directory into another.""" src = os.path.normpath(src) dst = os.path.normpath(dst) assert os.path.isdir(src) assert os.path.isdir(dst) skipped = 0 for name in files_under_root(src): name = os.path.normpath(name) skipped += link_files(name, src, dst) if skipped: logging.warning("To overwrite a skipped file, " "delete the file and rerun the script.") def copy_repository_templates(cbmc_root): """Copy the files in the repository template into the CBMC root.""" copy_directory_contents(os.path.join(templates_root(), REPOSITORY_TEMPLATES), cbmc_root)