Skip to main content
Glama
script_template_processor.py6.01 kB
#!/usr/bin/env python3 # Copyright (c) Meta Platforms, Inc. and affiliates. # # This source code is licensed under both the MIT license found in the # LICENSE-MIT file in the root directory of this source tree and the Apache # License, Version 2.0 found in the LICENSE-APACHE file in the root directory # of this source tree. """ Helper script to generate scripts required by haskell tools from script template files. These script templates require GHC and/or toolchain values, e.g. GHC flags used, paths to cxx tools. The macros in the script should be in the format `<MACRO_NAME>`. For example, `echo <binutils_path>` is an expression that would be replaced. """ # pyre-unsafe import argparse import os import re import sys from typing import Dict, List, Optional # Paths in the toolchain that are passed relative to the project's cell and # need to be canonicalized before being replaced in the script. TOOLCHAIN_PATHS = [ "binutils_path", "ghci_lib_path", "cc_path", "cpp_path", "cxx_path", "ghci_iserv_path", "ghc_pkg_path", "ghc_path", ] def _replace_template_values( template_file, output_fpath: str, user_ghci_path: Optional[str], rel_toolchain_paths: Dict[str, str], exposed_packages: List[str], package_dbs: Optional[str], prebuilt_package_dbs: Optional[str], string_macros: Dict[str, Optional[str]], ): script_template = template_file.read() for macro_name, rel_path in rel_toolchain_paths.items(): # Skip macro if its path wasn't provided for a specific template if not rel_path: continue # Follow symlink to get canonical path canonical_path = os.path.realpath(rel_path) script_template = re.sub( pattern=f"<{macro_name}>", repl=canonical_path, string=script_template, ) if user_ghci_path is not None: # user_ghci_path has to be handled separately because it needs to be passed # with the ghci_lib_path as the `-B` argument. ghci_lib_path = rel_toolchain_paths["ghci_lib_path"] if ghci_lib_path: ghci_lib_canonical_path = os.path.realpath(ghci_lib_path) replacement = "${{DIR}}/{user_ghci_path} -B{ghci_lib_path}".format( user_ghci_path=user_ghci_path, ghci_lib_path=ghci_lib_canonical_path, ) else: replacement = "${{DIR}}/{user_ghci_path}".format( user_ghci_path=user_ghci_path, ) script_template = re.sub( pattern="<user_ghci_path>", repl=replacement, string=script_template, ) if len(exposed_packages) > 0: script_template = re.sub( pattern="<exposed_packages>", repl=" ".join(exposed_packages), string=script_template, ) prebuilt_package_dbs_args = None package_dbs_args = None if prebuilt_package_dbs is not None: prebuilt_pkgs_canonical_paths = [ os.path.realpath( rel_path, ) for rel_path in prebuilt_package_dbs.split(" ") ] prebuilt_package_dbs_args = " ".join( ["-package-db {}".format(pkg) for pkg in prebuilt_pkgs_canonical_paths] ) if package_dbs is not None: package_dbs_args = " ".join( ["-package-db ${{DIR}}/{}".format(pkg) for pkg in package_dbs.split(" ")] ) script_template = re.sub( pattern="<package_dbs>", repl=" ".join(filter(None, [prebuilt_package_dbs_args, package_dbs_args])), string=script_template, ) # Replace all other macros for macro_name, macro_value in string_macros.items(): if macro_value is not None: script_template = re.sub( pattern=f"<{macro_name}>", repl=macro_value, string=script_template, ) with open(output_fpath, "w") as output_file: output_file.write(script_template) os.chmod(output_fpath, 0o777) # Script should be executable def main() -> int: parser = argparse.ArgumentParser() parser.add_argument( "--script_template", type=argparse.FileType("r"), ) for tpath in TOOLCHAIN_PATHS: parser.add_argument( "--{}".format(tpath), ) parser.add_argument( "--user_ghci_path", ) parser.add_argument( "--exposed_packages", type=str, nargs="+", ) parser.add_argument( "--output", help="The final script with all macros replaced.", ) STRING_ARGS = [ "package_dbs", "prebuilt_package_dbs", # Name of the buck target being built, e.g. haxlsh "target_name", "start_ghci", # Path to the final iserv script. Used by the final ghci script. "iserv_path", "compiler_flags", "srcs", "preload_libs", "squashed_so", ] for str_arg in STRING_ARGS: parser.add_argument( "--{}".format(str_arg), type=str, ) args = parser.parse_args() rel_toolchain_paths = {} for tpath in TOOLCHAIN_PATHS: rel_toolchain_paths[tpath] = getattr(args, tpath) # Macros that don't require special handling and are not paths that need # to be canonicalized. string_macros = { "name": args.target_name, "start_ghci": args.start_ghci, "iserv_path": args.iserv_path, "compiler_flags": args.compiler_flags, "srcs": args.srcs, "squashed_so": args.squashed_so, "preload_libs": args.preload_libs, } _replace_template_values( args.script_template, args.output, args.user_ghci_path, rel_toolchain_paths, args.exposed_packages, args.package_dbs, args.prebuilt_package_dbs, string_macros, ) return 0 sys.exit(main())

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server