<NME> main.py
<BEF> #!/usr/bin/env python
# Copyright FuseSoC contributors
# Licensed under the 2-Clause BSD License, see LICENSE for details.
# SPDX-License-Identifier: BSD-2-Clause

import argparse
import os
import shutil
import signal
import subprocess
import sys
import warnings

from fusesoc import __version__

# Check if this is run from a local installation
fusesocdir = os.path.abspath(
    os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")
)
if os.path.exists(os.path.join(fusesocdir, "fusesoc")):
    sys.path[0:0] = [fusesocdir]

import logging

try:
    from edalize.edatool import get_edatool
except ImportError:
    from edalize import get_edatool

from fusesoc.config import Config
from fusesoc.coremanager import CoreManager, DependencyError
from fusesoc.edalizer import Edalizer
from fusesoc.librarymanager import Library
from fusesoc.utils import Launcher, setup_logging, yaml_fread
from fusesoc.vlnv import Vlnv

logger = logging.getLogger(__name__)


def _get_core(cm, name):
    except DependencyError as e:
        logger.error("'" + name + "' or any of its dependencies requires '" + e.value + "', but this core was not found")
        exit(1)
    if has_system and not core.backend:
        logger.error("Unable to find .system file for '{}'".format(name))
        exit(1)
    return core

            "this core was not found"
        )
        exit(1)
    return core


def abort_handler(signal, frame):
    print("")
    logger.info("****************************")
    logger.info("****   FuseSoC aborted  ****")
    logger.info("****************************")
    print("")
    sys.exit(0)

def build(args):
    core = _get_core(args.system, True)

    try:
        backend =_import('build', core.main.backend)(core, export=True)
    except ImportError:
        logger.error('Backend "{}" not found'.format(core.main.backend))
        exit(1)
    except RuntimeError as e:
        logger.error("Failed to build '{}': {}".format(args.system, e))
    core = _get_core(cm, args.core)

    try:
        core.setup()
    except RuntimeError as e:
        logger.error("Failed to fetch '{}': {}".format(core.name, str(e)))
        exit(1)


def init(cm, args):
    warnings.warn(
        "The 'init' subcommand to fetch the FuseSoC standard library has been "
        "removed. Use 'fusesoc library add fusesoc_cores "

def pgm(args):
    core = _get_core(args.system, True)

    try:
        backend =_import('build', core.main.backend)(core, export=True)
        backend.pgm(args.backendargs)
    except ImportError:
        logger.error('Backend "{}" not found'.format(core.main.backend))
        exit(1)
    except RuntimeError as e:
        logger.error("Failed to program the FPGA: " + str(e))
    elif vars(args).get("global", False):
        location = os.path.join(cm._lm.library_root, args.name)
    else:
        location = os.path.join("fusesoc_libraries", args.name)

    if "sync-type" in vars(args):
        sync_type = vars(args)["sync-type"]
    else:
        sync_type = None

    # Check if it's a dir. Otherwise fall back to git repo
    if not sync_type:
        if os.path.isdir(sync_uri):
            sync_type = "local"
        else:
            sync_type = "git"

    if sync_type == "local":
        logger.info(
            "Interpreting sync-uri '{}' as location for local provider.".format(
                sync_uri
            )
        )
        location = os.path.abspath(sync_uri)

    auto_sync = not args.no_auto_sync
    library = Library(args.name, location, sync_type, sync_uri, auto_sync)

    if args.config:
        config = Config(args.config)
    elif vars(args)["global"]:
        xdg_config_home = os.environ.get("XDG_CONFIG_HOME") or os.path.join(
            os.path.expanduser("~"), ".config"
        )
        config_file = os.path.join(xdg_config_home, "fusesoc", "fusesoc.conf")
        config = Config(config_file)
    else:
        config = Config("fusesoc.conf")

    try:
        config.add_library(library)
    except RuntimeError as e:
        logger.error("`add library` failed: " + str(e))
        exit(1)


def library_list(cm, args):
    lengths = [4, 8, 9, 8, 9]
    for lib in cm.get_libraries():
        lengths[0] = max(lengths[0], len(lib.name))
        lengths[1] = max(lengths[1], len(lib.location))
        lengths[2] = max(lengths[2], len(lib.sync_type))
        lengths[3] = max(lengths[3], len(lib.sync_uri or ""))
    print(
        "{} : {} : {} : {} : {}".format(
            "Name".ljust(lengths[0]),
            "Location".ljust(lengths[1]),
            "Sync type".ljust(lengths[2]),
            "Sync URI".ljust(lengths[3]),
            "Auto sync".ljust(lengths[4]),
        )
    )
    for lib in cm.get_libraries():
        print(
            "{} : {} : {} : {} : {}".format(
                lib.name.ljust(lengths[0]),
                lib.location.ljust(lengths[1]),
                lib.sync_type.ljust(lengths[2]),
                (lib.sync_uri or "N/A").ljust(lengths[3]),
                ("y" if lib.auto_sync else "n").ljust(lengths[4]),
            )
        )


def list_cores(cm, args):
    cores = cm.get_cores()
    print("\nAvailable cores:\n")
    if not cores:
        cores_root = cm.get_libraries()
        if cores_root:
            logger.error("No cores found in any library")
        else:
            logger.error("No libraries registered")
        exit(1)
    maxlen = max(map(len, cores.keys()))
    print("Core".ljust(maxlen) + "  Cache status  Description")

def list_systems(args):
    print("Available systems:")
    for system in CoreManager().get_systems():
        print(system)

def sim(args):
    core = _get_core(args.system)
        )


def list_tools(cm, args):
    from edalize.edatool import walk_tool_packages

    _tp = list(walk_tool_packages())
    maxlen = max(map(len, _tp))

    for tool_name in _tp:
        try:
            tool_class = get_edatool(tool_name)
            desc = tool_class.get_doc(0)["description"]
            print(f"{tool_name:{maxlen}} : {desc}")
        # Ignore any misbehaving backends
        except Exception:
            pass


def gen_list(cm, args):
    cores = cm.get_generators()
    if not cores:
        print("\nNo available generators\n")
    else:
        print("\nAvailable generators:\n")
        maxlen = max(map(len, cores.keys()))
        print("Core".ljust(maxlen) + "   Generator")
        print("=" * (maxlen + 12))
        for core in sorted(cores.keys()):
            for generator_name, generator_data in cores[core].items():
                print(
                    "{} : {} : {}".format(
                        core.ljust(maxlen),
                        generator_name,
                        generator_data.description or "<No description>",
                    )
                )


def gen_show(cm, args):
    cores = cm.get_generators()
    for core in sorted(cores.keys()):
        for generator_name, generator_data in cores[core].items():
            if generator_name == args.generator:
                print(
                    """
Core        : {}
Generator   : {}
Description : {}
Usage       :

{}""".format(
                        core,
                        generator_name,
                        generator_data.description or "<No description>",
                        generator_data.usage or "",
                    )
                )


def core_info(cm, args):
    core = _get_core(cm, args.core)
    print(core.info())


def run(cm, args):
    stages = (args.setup, args.build, args.run)

    # Always run setup if build is true
    args.setup |= args.build

    # Run all stages by default if no stage flags are set
    if stages == (False, False, False):
        do_configure = True
        do_build = True
        do_run = True
    elif stages == (True, False, True):
        logger.error("Configure and run without build is invalid")
        exit(1)
    else:
        do_configure = args.setup
        do_build = args.build
        do_run = args.run

    flags = {"target": args.target or "default"}
    if args.tool:
        flags["tool"] = args.tool
    for flag in args.flag:
        if flag[0] == "+":
            flags[flag[1:]] = True
        elif flag[0] == "-":
            flags[flag[1:]] = False
        else:
            flags[flag] = True

    run_backend(
        cm,
        not args.no_export,
        do_configure,
        do_build,
        do_run,
        flags,
        args.system_name,
        args.system,
        args.backendargs,
        args.build_root,
        args.verbose,
    )


# Clean out old work root
def prepare_work_root(work_root):
    if os.path.exists(work_root):
        for f in os.listdir(work_root):
            if os.path.isdir(os.path.join(work_root, f)):
                shutil.rmtree(os.path.join(work_root, f))
            else:
                os.remove(os.path.join(work_root, f))
    else:
        os.makedirs(work_root)


def run_backend(
    cm,
    export,
    do_configure,
    do_build,
    do_run,
    flags,
    system_name,
    system,
    backendargs,
    build_root_arg,
    verbose,
):
    tool_error = (
        "No tool was supplied on command line or found in '{}' core description"
    )
    core = _get_core(cm, system)

    target = flags["target"]
    try:
        flags = dict(core.get_flags(target), **flags)
    except SyntaxError as e:
        logger.error(str(e))
        exit(1)

    tool = flags.get("tool")

    if not tool:
        logger.error(tool_error.format(system))
        exit(1)
    build_root = build_root_arg or os.path.join(
        cm.config.build_root, core.name.sanitized_name
    )
    logger.debug(f"Setting build_root to {build_root}")
    if export:
        export_root = os.path.join(build_root, "src")
    else:
        export_root = None
    try:
        work_root = os.path.join(build_root, f"{target}-{tool}")
    except SyntaxError as e:
        logger.error(e.msg)
        exit(1)
    edam_file = os.path.join(work_root, core.name.sanitized_name + ".eda.yml")
    if not os.path.exists(edam_file):
        do_configure = True

    try:
        backend_class = get_edatool(tool)
    except ImportError:
        logger.error(f"Backend {tool!r} not found")
        exit(1)

    edalizer = Edalizer(
        toplevel=core.name,
        flags=flags,
        core_manager=cm,
        work_root=work_root,
        export_root=export_root,
        system_name=system_name,
    )

    if do_configure:
        try:
            prepare_work_root(work_root)
            edam = edalizer.run()
            parsed_args = edalizer.parse_args(backend_class, backendargs, edam)
            edalizer.add_parsed_args(backend_class, parsed_args)

        except SyntaxError as e:
            logger.error(e.msg)
            exit(1)
        except RuntimeError as e:
            logger.error("Setup failed : {}".format(str(e)))
            exit(1)
        edalizer.to_yaml(edam_file)
    else:
        edam = yaml_fread(edam_file)
        parsed_args = edalizer.parse_args(backend_class, backendargs, edam)

    # Frontend/backend separation

    try:
        backend = backend_class(edam=edam, work_root=work_root, verbose=verbose)

    except RuntimeError as e:
        logger.error(str(e))
        exit(1)
    except FileNotFoundError as e:
        logger.error(f'Could not find EDA API file "{e.filename}"')
        exit(1)

    if do_configure:
        try:
            backend.configure([])
            print("")
        except RuntimeError as e:
            logger.error("Failed to configure the system")
            logger.error(str(e))
            exit(1)

    if do_build:
        try:
            backend.build()
        except RuntimeError as e:
            logger.error("Failed to build {} : {}".format(str(core.name), str(e)))
            exit(1)

    if do_run:
        try:
            backend.run(parsed_args)
        except RuntimeError as e:
            logger.error("Failed to run {} : {}".format(str(core.name), str(e)))
            exit(1)


def update(cm, args):
    if "warn" in args:
        logger.warning(args.warn)

    cm._lm.update(args.libraries)


def init_logging(verbose, monochrome, log_file=None):
    level = logging.DEBUG if verbose else logging.INFO

    setup_logging(level, monochrome, log_file)

    if verbose:
        logger.debug("Verbose output")
    else:
        logger.debug("Concise output")

    if monochrome:
        logger.debug("Monochrome output")
    else:
        logger.debug("Colorful output")


def init_coremanager(config, args_cores_root):
    logger.debug("Initializing core manager")
    cm = CoreManager(config)

    args_libs = [Library(acr, acr) for acr in args_cores_root]
    # Add libraries from config file, env var and command-line
    for library in config.libraries + args_libs:
        try:
            cm.add_library(library, config.ignored_dirs)
        except (RuntimeError, OSError) as e:
            _s = "Failed to register library '{}'"
            logger.warning(_s.format(str(e)))

    return cm


def get_parser():
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers()

    # Global actions
    parser.add_argument(
        "--version",
        help="Display the FuseSoC version",
        action="version",
        version=__version__,
    )

    # Global options
    parser.add_argument(
        "--cores-root",
        help="Add additional directories containing cores",
        default=[],
        action="append",
    )
    parser.add_argument("--config", help="Specify the config file to use")
    parser.add_argument(
        "--monochrome",
        help="Don't use color for messages",
        action="store_true",
        default=not sys.stdout.isatty(),
    )
    parser.add_argument("--verbose", help="More info messages", action="store_true")
    parser.add_argument("--log-file", help="Write log messages to file")

    # init subparser
    parser_init = subparsers.add_parser(
        "init", help="Initialize the FuseSoC core libraries. DEPRECATED"
    )
    parser_init.add_argument(
        "-y", action="store_true", help="Skip user input and use default settings"
    )
    parser_init.set_defaults(func=init)

    # pgm subparser
    parser_pgm = subparsers.add_parser(
        "pgm",
        help="Program an FPGA with a system configuration. DEPRECATED, use 'run' instead.",
    )
    parser_pgm.add_argument("system")
    parser_pgm.add_argument("backendargs", nargs=argparse.REMAINDER)
    parser_pgm.set_defaults(func=pgm)

    # fetch subparser
    parser_fetch = subparsers.add_parser(
        "fetch", help="Fetch a remote core and its dependencies to local cache"
    )
    parser_fetch.add_argument("core")
    parser_fetch.set_defaults(func=fetch)

    # core subparser
    parser_core = subparsers.add_parser(
        "core", help="Subcommands for dealing with cores"
    )
    core_subparsers = parser_core.add_subparsers()
    parser_core.set_defaults(subparser=parser_core)

    # core list subparser
    parser_core_list = core_subparsers.add_parser("list", help="List available cores")
    parser_core_list.set_defaults(func=list_cores)

    # core show subparser
    parser_core_show = core_subparsers.add_parser(
        "show", help="Show information about a core"
    )
    parser_core_show.add_argument("core", help="Name of the core to show")
    parser_core_show.set_defaults(func=core_info)

    # tool subparser
    parser_tool = subparsers.add_parser(
        "tool", help="Subcommands for dealing with tools"
    )
    tool_subparsers = parser_tool.add_subparsers()
    parser_tool.set_defaults(subparser=parser_tool)

    # tool list subparser
    parser_tool_list = tool_subparsers.add_parser("list", help="List available tools")
    parser_tool_list.set_defaults(func=list_tools)

    # list-cores subparser
    parser_list_cores = subparsers.add_parser("list-cores", help="List available cores")
    parser_list_cores.set_defaults(func=list_cores)

    # core-info subparser
    parser_core_info = subparsers.add_parser(
        "core-info", help="Display details about a core"
    )
    parser_core_info.add_argument("core")
    parser_core_info.set_defaults(func=core_info)

    # gen subparser
    parser_gen = subparsers.add_parser(
        "gen", help="Run or show information about generators"
    )
    parser_gen.set_defaults(subparser=parser_gen)
    gen_subparsers = parser_gen.add_subparsers()

    # gen list subparser
    parser_gen_list = gen_subparsers.add_parser(
        "list", help="List available generators"
    )
    parser_gen_list.set_defaults(func=gen_list)

    # gen show subparser
    parser_gen_show = gen_subparsers.add_parser(
        "show", help="Show information about a generator"
    )
    parser_gen_show.add_argument("generator", help="Name of the generator to show")
    parser_gen_show.set_defaults(func=gen_show)

    # list-paths subparser
    parser_list_paths = subparsers.add_parser(
        "list-paths", help="Display the search order for core root paths"
    )
    parser_list_paths.set_defaults(func=list_paths)

    # library subparser
    parser_library = subparsers.add_parser(
        "library", help="Subcommands for dealing with library management"
    )
    library_subparsers = parser_library.add_subparsers()
    parser_library.set_defaults(subparser=parser_library)

    # library add subparser
    parser_library_add = library_subparsers.add_parser(
        "add", help="Add new library to fusesoc.conf"
    )
    parser_library_add.add_argument("name", help="A friendly name  for the library")
    parser_library_add.add_argument(
        "sync-uri", help="The URI source for the library (can be a file system path)"
    )
    parser_library_add.add_argument(
        "--location",
        help="The location to store the library into (defaults to $XDG_DATA_HOME/[name])",
    )
    parser_library_add.add_argument(
        "--sync-type",
        help="The provider type for the library. Defaults to 'git'.",
        choices=["git", "local"],
    )
    parser_library_add.add_argument(
        "--no-auto-sync",
        action="store_true",
        help="Disable automatic updates of the library",
    )
    parser_library_add.add_argument(
        "--global",
        action="store_true",
        help="Use the global FuseSoC config file in $XDG_CONFIG_HOME/fusesoc/fusesoc.conf",
    )
    parser_library_add.set_defaults(func=add_library)

    # library list subparser
    parser_library_list = library_subparsers.add_parser(
        "list", help="List core libraries"
    )
    parser_library_list.set_defaults(func=library_list)

    # library update subparser
    parser_library_update = library_subparsers.add_parser(
        "update", help="Update the FuseSoC core libraries"
    )
    parser_library_update.add_argument(
        "libraries", nargs="*", help="The libraries to update (defaults to all)"
    )
    parser_library_update.set_defaults(func=update)

    # run subparser
    parser_run = subparsers.add_parser("run", help="Start a tool flow")
    parser_run.add_argument(
        "--no-export",
        action="store_true",
        help="Reference source files from their current location instead of exporting to a build tree",
    )
    parser_run.add_argument(
        "--build-root", help="Output directory for build. Defaults to build/$VLNV"
    )
    parser_run.add_argument("--setup", action="store_true", help="Execute setup stage")
    parser_run.add_argument("--build", action="store_true", help="Execute build stage")
    parser_run.add_argument("--run", action="store_true", help="Execute run stage")
    parser_run.add_argument("--target", help="Override default target")
    parser_run.add_argument("--tool", help="Override default tool for target")
    parser_run.add_argument(
        "--flag",
        help="Set custom use flags. Can be specified multiple times",
        action="append",
        default=[],
    )
    parser_run.add_argument(
        "--system-name", help="Override default VLNV name for system"
    )
    parser_run.add_argument("system", help="Select a system to operate on")
    parser_run.add_argument(
        "backendargs", nargs=argparse.REMAINDER, help="arguments to be sent to backend"
    )
    parser_run.set_defaults(func=run)

    # update subparser
    parser_update = subparsers.add_parser(
        "update", help="Update the FuseSoC core libraries"
    )
    parser_update.add_argument(
        "libraries",
        nargs="*",
        help="The libraries (or core roots) to update (defaults to all)",
    )
    parser_update.set_defaults(func=update)
    parser_update.set_defaults(
        warn="'fusesoc update' is deprecated. Use 'fusesoc library update' instead"
    )

    return parser


def parse_args(argv):
    parser = get_parser()

    args = parser.parse_args(argv)

    if hasattr(args, "func"):
        return args
    if hasattr(args, "subparser"):
        args.subparser.print_help()
    else:
        parser.print_help()
        return None


def fusesoc(args):
    init_logging(args.verbose, args.monochrome, args.log_file)
    config = Config(args.config)

    cm = init_coremanager(config, args.cores_root)
    # Run the function
    args.func(cm, args)


def main():
    args = parse_args(sys.argv[1:])
    if not args:
        exit(0)

    logger.debug("Command line arguments: " + str(sys.argv))

    fusesoc(args)


if __name__ == "__main__":
    main()

<MSG> Use get_tool in build flow and list_systems

<DFF> @@ -41,8 +41,9 @@ def _get_core(name, has_system=False):
     except DependencyError as e:
         logger.error("'" + name + "' or any of its dependencies requires '" + e.value + "', but this core was not found")
         exit(1)
-    if has_system and not core.backend:
-        logger.error("Unable to find .system file for '{}'".format(name))
+    if has_system and not core.get_tool({'flow' : 'synth',
+                                         'tool' : None}):
+        logger.error("Unable to find synthesis info for '{}'".format(name))
         exit(1)
     return core
 
@@ -62,11 +63,13 @@ signal.signal(signal.SIGINT, abort_handler)
 
 def build(args):
     core = _get_core(args.system, True)
-
+    flags = {'flow' : 'synth',
+             'tool' : None}
+    tool = core.get_tool(flags)
     try:
-        backend =_import('build', core.main.backend)(core, export=True)
+        backend =_import('build', tool)(core, export=True)
     except ImportError:
-        logger.error('Backend "{}" not found'.format(core.main.backend))
+        logger.error('Backend "{}" not found'.format(tool))
         exit(1)
     except RuntimeError as e:
         logger.error("Failed to build '{}': {}".format(args.system, e))
@@ -86,12 +89,14 @@ def build(args):
 
 def pgm(args):
     core = _get_core(args.system, True)
-
+    flags = {'flow' : 'synth',
+             'tool' : None}
+    tool = core.get_tool(flags)
     try:
-        backend =_import('build', core.main.backend)(core, export=True)
+        backend =_import('build', tool)(core, export=True)
         backend.pgm(args.backendargs)
     except ImportError:
-        logger.error('Backend "{}" not found'.format(core.main.backend))
+        logger.error('Backend "{}" not found'.format(tool))
         exit(1)
     except RuntimeError as e:
         logger.error("Failed to program the FPGA: " + str(e))
@@ -184,8 +189,9 @@ def core_info(args):
 
 def list_systems(args):
     print("Available systems:")
-    for system in CoreManager().get_systems():
-        print(system)
+    for core in CoreManager().get_cores().values():
+        if core.get_tool({'flow' : 'synth', 'tool' : None}):
+            print(str(core.name))
 
 def sim(args):
     core = _get_core(args.system)

{'commit': 'diff --git a/fusesoc/coremanager.py b/fusesoc/coremanager.py\nindex 75250c2..93c2a59 100644\n--- a/fusesoc/coremanager.py\n+++ b/fusesoc/coremanager.py\n@@ -176,6 +176,3 @@ class CoreManager(object):\n         c = self.db.find(name)\n         c.name.relation = "=="\n         return c\n-\n-    def get_systems(self):\n-        return {str(x.name) : x for x in self.db.find() if x.backend}\ndiff --git a/fusesoc/main.py b/fusesoc/main.py\nindex 8d00563..a2cd2c2 100644\n--- a/fusesoc/main.py\n+++ b/fusesoc/main.py\n@@ -41,8 +41,9 @@ def _get_core(name, has_system=False):\n     except DependencyError as e:\n         logger.error("\'" + name + "\' or any of its dependencies requires \'" + e.value + "\', but this core was not found")\n         exit(1)\n-    if has_system and not core.backend:\n-        logger.error("Unable to find .system file for \'{}\'".format(name))\n+    if has_system and not core.get_tool({\'flow\' : \'synth\',\n+                                         \'tool\' : None}):\n+        logger.error("Unable to find synthesis info for \'{}\'".format(name))\n         exit(1)\n     return core\n \n@@ -62,11 +63,13 @@ signal.signal(signal.SIGINT, abort_handler)\n \n def build(args):\n     core = _get_core(args.system, True)\n-\n+    flags = {\'flow\' : \'synth\',\n+             \'tool\' : None}\n+    tool = core.get_tool(flags)\n     try:\n-        backend =_import(\'build\', core.main.backend)(core, export=True)\n+        backend =_import(\'build\', tool)(core, export=True)\n     except ImportError:\n-        logger.error(\'Backend "{}" not found\'.format(core.main.backend))\n+        logger.error(\'Backend "{}" not found\'.format(tool))\n         exit(1)\n     except RuntimeError as e:\n         logger.error("Failed to build \'{}\': {}".format(args.system, e))\n@@ -86,12 +89,14 @@ def build(args):\n \n def pgm(args):\n     core = _get_core(args.system, True)\n-\n+    flags = {\'flow\' : \'synth\',\n+             \'tool\' : None}\n+    tool = core.get_tool(flags)\n     try:\n-        backend =_import(\'build\', core.main.backend)(core, export=True)\n+        backend =_import(\'build\', tool)(core, export=True)\n         backend.pgm(args.backendargs)\n     except ImportError:\n-        logger.error(\'Backend "{}" not found\'.format(core.main.backend))\n+        logger.error(\'Backend "{}" not found\'.format(tool))\n         exit(1)\n     except RuntimeError as e:\n         logger.error("Failed to program the FPGA: " + str(e))\n@@ -184,8 +189,9 @@ def core_info(args):\n \n def list_systems(args):\n     print("Available systems:")\n-    for system in CoreManager().get_systems():\n-        print(system)\n+    for core in CoreManager().get_cores().values():\n+        if core.get_tool({\'flow\' : \'synth\', \'tool\' : None}):\n+            print(str(core.name))\n \n def sim(args):\n     core = _get_core(args.system)\n', 'commit_subject': 'Use get_tool in build flow and list_systems', 'repo_name': 'olofk/fusesoc', 'committer': {'name': 'Olof Kindgren', 'email': '31cf4bdc038d9a62332766b559358ec4a0e176e7@gmail.com', 'time_sec': '1493934365', 'tz_offset': '120', 'date': {'seconds': '1493934365'}}, 'commit_tree': '9465ea9ceb1cd6f7cba7ddef6409a627b7fcc0c0', 'commit_message': 'Use get_tool in build flow and list_systems\n', 'language_name': 'Shell', 'license': 'bsd-2-clause', 'hunks': '@@ -41,8 +41,9 @@ def _get_core(name, has_system=False):\n     except DependencyError as e:\n         logger.error("\'" + name + "\' or any of its dependencies requires \'" + e.value + "\', but this core was not found")\n         exit(1)\n-    if has_system and not core.backend:\n-        logger.error("Unable to find .system file for \'{}\'".format(name))\n+    if has_system and not core.get_tool({\'flow\' : \'synth\',\n+                                         \'tool\' : None}):\n+        logger.error("Unable to find synthesis info for \'{}\'".format(name))\n         exit(1)\n     return core\n \n@@ -62,11 +63,13 @@ signal.signal(signal.SIGINT, abort_handler)\n \n def build(args):\n     core = _get_core(args.system, True)\n-\n+    flags = {\'flow\' : \'synth\',\n+             \'tool\' : None}\n+    tool = core.get_tool(flags)\n     try:\n-        backend =_import(\'build\', core.main.backend)(core, export=True)\n+        backend =_import(\'build\', tool)(core, export=True)\n     except ImportError:\n-        logger.error(\'Backend "{}" not found\'.format(core.main.backend))\n+        logger.error(\'Backend "{}" not found\'.format(tool))\n         exit(1)\n     except RuntimeError as e:\n         logger.error("Failed to build \'{}\': {}".format(args.system, e))\n@@ -86,12 +89,14 @@ def build(args):\n \n def pgm(args):\n     core = _get_core(args.system, True)\n-\n+    flags = {\'flow\' : \'synth\',\n+             \'tool\' : None}\n+    tool = core.get_tool(flags)\n     try:\n-        backend =_import(\'build\', core.main.backend)(core, export=True)\n+        backend =_import(\'build\', tool)(core, export=True)\n         backend.pgm(args.backendargs)\n     except ImportError:\n-        logger.error(\'Backend "{}" not found\'.format(core.main.backend))\n+        logger.error(\'Backend "{}" not found\'.format(tool))\n         exit(1)\n     except RuntimeError as e:\n         logger.error("Failed to program the FPGA: " + str(e))\n@@ -184,8 +189,9 @@ def core_info(args):\n \n def list_systems(args):\n     print("Available systems:")\n-    for system in CoreManager().get_systems():\n-        print(system)\n+    for core in CoreManager().get_cores().values():\n+        if core.get_tool({\'flow\' : \'synth\', \'tool\' : None}):\n+            print(str(core.name))\n \n def sim(args):\n     core = _get_core(args.system)\n', 'addition_count': 16, 'deletion_count': 10, 'src_file': 'a/fusesoc/main.py', 'tgt_file': 'b/fusesoc/main.py', 'file_extension': '.py', 'before_file': '#!/usr/bin/env python\n# Copyright FuseSoC contributors\n# Licensed under the 2-Clause BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-2-Clause\n\nimport argparse\nimport os\nimport shutil\nimport signal\nimport subprocess\nimport sys\nimport warnings\n\nfrom fusesoc import __version__\n\n# Check if this is run from a local installation\nfusesocdir = os.path.abspath(\n    os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")\n)\nif os.path.exists(os.path.join(fusesocdir, "fusesoc")):\n    sys.path[0:0] = [fusesocdir]\n\nimport logging\n\ntry:\n    from edalize.edatool import get_edatool\nexcept ImportError:\n    from edalize import get_edatool\n\nfrom fusesoc.config import Config\nfrom fusesoc.coremanager import CoreManager, DependencyError\nfrom fusesoc.edalizer import Edalizer\nfrom fusesoc.librarymanager import Library\nfrom fusesoc.utils import Launcher, setup_logging, yaml_fread\nfrom fusesoc.vlnv import Vlnv\n\nlogger = logging.getLogger(__name__)\n\n\ndef _get_core(cm, name):\n    except DependencyError as e:\n        logger.error("\'" + name + "\' or any of its dependencies requires \'" + e.value + "\', but this core was not found")\n        exit(1)\n    if has_system and not core.backend:\n        logger.error("Unable to find .system file for \'{}\'".format(name))\n        exit(1)\n    return core\n\n            "this core was not found"\n        )\n        exit(1)\n    return core\n\n\ndef abort_handler(signal, frame):\n    print("")\n    logger.info("****************************")\n    logger.info("****   FuseSoC aborted  ****")\n    logger.info("****************************")\n    print("")\n    sys.exit(0)\n\ndef build(args):\n    core = _get_core(args.system, True)\n\n    try:\n        backend =_import(\'build\', core.main.backend)(core, export=True)\n    except ImportError:\n        logger.error(\'Backend "{}" not found\'.format(core.main.backend))\n        exit(1)\n    except RuntimeError as e:\n        logger.error("Failed to build \'{}\': {}".format(args.system, e))\n    core = _get_core(cm, args.core)\n\n    try:\n        core.setup()\n    except RuntimeError as e:\n        logger.error("Failed to fetch \'{}\': {}".format(core.name, str(e)))\n        exit(1)\n\n\ndef init(cm, args):\n    warnings.warn(\n        "The \'init\' subcommand to fetch the FuseSoC standard library has been "\n        "removed. Use \'fusesoc library add fusesoc_cores "\n\ndef pgm(args):\n    core = _get_core(args.system, True)\n\n    try:\n        backend =_import(\'build\', core.main.backend)(core, export=True)\n        backend.pgm(args.backendargs)\n    except ImportError:\n        logger.error(\'Backend "{}" not found\'.format(core.main.backend))\n        exit(1)\n    except RuntimeError as e:\n        logger.error("Failed to program the FPGA: " + str(e))\n    elif vars(args).get("global", False):\n        location = os.path.join(cm._lm.library_root, args.name)\n    else:\n        location = os.path.join("fusesoc_libraries", args.name)\n\n    if "sync-type" in vars(args):\n        sync_type = vars(args)["sync-type"]\n    else:\n        sync_type = None\n\n    # Check if it\'s a dir. Otherwise fall back to git repo\n    if not sync_type:\n        if os.path.isdir(sync_uri):\n            sync_type = "local"\n        else:\n            sync_type = "git"\n\n    if sync_type == "local":\n        logger.info(\n            "Interpreting sync-uri \'{}\' as location for local provider.".format(\n                sync_uri\n            )\n        )\n        location = os.path.abspath(sync_uri)\n\n    auto_sync = not args.no_auto_sync\n    library = Library(args.name, location, sync_type, sync_uri, auto_sync)\n\n    if args.config:\n        config = Config(args.config)\n    elif vars(args)["global"]:\n        xdg_config_home = os.environ.get("XDG_CONFIG_HOME") or os.path.join(\n            os.path.expanduser("~"), ".config"\n        )\n        config_file = os.path.join(xdg_config_home, "fusesoc", "fusesoc.conf")\n        config = Config(config_file)\n    else:\n        config = Config("fusesoc.conf")\n\n    try:\n        config.add_library(library)\n    except RuntimeError as e:\n        logger.error("`add library` failed: " + str(e))\n        exit(1)\n\n\ndef library_list(cm, args):\n    lengths = [4, 8, 9, 8, 9]\n    for lib in cm.get_libraries():\n        lengths[0] = max(lengths[0], len(lib.name))\n        lengths[1] = max(lengths[1], len(lib.location))\n        lengths[2] = max(lengths[2], len(lib.sync_type))\n        lengths[3] = max(lengths[3], len(lib.sync_uri or ""))\n    print(\n        "{} : {} : {} : {} : {}".format(\n            "Name".ljust(lengths[0]),\n            "Location".ljust(lengths[1]),\n            "Sync type".ljust(lengths[2]),\n            "Sync URI".ljust(lengths[3]),\n            "Auto sync".ljust(lengths[4]),\n        )\n    )\n    for lib in cm.get_libraries():\n        print(\n            "{} : {} : {} : {} : {}".format(\n                lib.name.ljust(lengths[0]),\n                lib.location.ljust(lengths[1]),\n                lib.sync_type.ljust(lengths[2]),\n                (lib.sync_uri or "N/A").ljust(lengths[3]),\n                ("y" if lib.auto_sync else "n").ljust(lengths[4]),\n            )\n        )\n\n\ndef list_cores(cm, args):\n    cores = cm.get_cores()\n    print("\\nAvailable cores:\\n")\n    if not cores:\n        cores_root = cm.get_libraries()\n        if cores_root:\n            logger.error("No cores found in any library")\n        else:\n            logger.error("No libraries registered")\n        exit(1)\n    maxlen = max(map(len, cores.keys()))\n    print("Core".ljust(maxlen) + "  Cache status  Description")\n\ndef list_systems(args):\n    print("Available systems:")\n    for system in CoreManager().get_systems():\n        print(system)\n\ndef sim(args):\n    core = _get_core(args.system)\n        )\n\n\ndef list_tools(cm, args):\n    from edalize.edatool import walk_tool_packages\n\n    _tp = list(walk_tool_packages())\n    maxlen = max(map(len, _tp))\n\n    for tool_name in _tp:\n        try:\n            tool_class = get_edatool(tool_name)\n            desc = tool_class.get_doc(0)["description"]\n            print(f"{tool_name:{maxlen}} : {desc}")\n        # Ignore any misbehaving backends\n        except Exception:\n            pass\n\n\ndef gen_list(cm, args):\n    cores = cm.get_generators()\n    if not cores:\n        print("\\nNo available generators\\n")\n    else:\n        print("\\nAvailable generators:\\n")\n        maxlen = max(map(len, cores.keys()))\n        print("Core".ljust(maxlen) + "   Generator")\n        print("=" * (maxlen + 12))\n        for core in sorted(cores.keys()):\n            for generator_name, generator_data in cores[core].items():\n                print(\n                    "{} : {} : {}".format(\n                        core.ljust(maxlen),\n                        generator_name,\n                        generator_data.description or "<No description>",\n                    )\n                )\n\n\ndef gen_show(cm, args):\n    cores = cm.get_generators()\n    for core in sorted(cores.keys()):\n        for generator_name, generator_data in cores[core].items():\n            if generator_name == args.generator:\n                print(\n                    """\nCore        : {}\nGenerator   : {}\nDescription : {}\nUsage       :\n\n{}""".format(\n                        core,\n                        generator_name,\n                        generator_data.description or "<No description>",\n                        generator_data.usage or "",\n                    )\n                )\n\n\ndef core_info(cm, args):\n    core = _get_core(cm, args.core)\n    print(core.info())\n\n\ndef run(cm, args):\n    stages = (args.setup, args.build, args.run)\n\n    # Always run setup if build is true\n    args.setup |= args.build\n\n    # Run all stages by default if no stage flags are set\n    if stages == (False, False, False):\n        do_configure = True\n        do_build = True\n        do_run = True\n    elif stages == (True, False, True):\n        logger.error("Configure and run without build is invalid")\n        exit(1)\n    else:\n        do_configure = args.setup\n        do_build = args.build\n        do_run = args.run\n\n    flags = {"target": args.target or "default"}\n    if args.tool:\n        flags["tool"] = args.tool\n    for flag in args.flag:\n        if flag[0] == "+":\n            flags[flag[1:]] = True\n        elif flag[0] == "-":\n            flags[flag[1:]] = False\n        else:\n            flags[flag] = True\n\n    run_backend(\n        cm,\n        not args.no_export,\n        do_configure,\n        do_build,\n        do_run,\n        flags,\n        args.system_name,\n        args.system,\n        args.backendargs,\n        args.build_root,\n        args.verbose,\n    )\n\n\n# Clean out old work root\ndef prepare_work_root(work_root):\n    if os.path.exists(work_root):\n        for f in os.listdir(work_root):\n            if os.path.isdir(os.path.join(work_root, f)):\n                shutil.rmtree(os.path.join(work_root, f))\n            else:\n                os.remove(os.path.join(work_root, f))\n    else:\n        os.makedirs(work_root)\n\n\ndef run_backend(\n    cm,\n    export,\n    do_configure,\n    do_build,\n    do_run,\n    flags,\n    system_name,\n    system,\n    backendargs,\n    build_root_arg,\n    verbose,\n):\n    tool_error = (\n        "No tool was supplied on command line or found in \'{}\' core description"\n    )\n    core = _get_core(cm, system)\n\n    target = flags["target"]\n    try:\n        flags = dict(core.get_flags(target), **flags)\n    except SyntaxError as e:\n        logger.error(str(e))\n        exit(1)\n\n    tool = flags.get("tool")\n\n    if not tool:\n        logger.error(tool_error.format(system))\n        exit(1)\n    build_root = build_root_arg or os.path.join(\n        cm.config.build_root, core.name.sanitized_name\n    )\n    logger.debug(f"Setting build_root to {build_root}")\n    if export:\n        export_root = os.path.join(build_root, "src")\n    else:\n        export_root = None\n    try:\n        work_root = os.path.join(build_root, f"{target}-{tool}")\n    except SyntaxError as e:\n        logger.error(e.msg)\n        exit(1)\n    edam_file = os.path.join(work_root, core.name.sanitized_name + ".eda.yml")\n    if not os.path.exists(edam_file):\n        do_configure = True\n\n    try:\n        backend_class = get_edatool(tool)\n    except ImportError:\n        logger.error(f"Backend {tool!r} not found")\n        exit(1)\n\n    edalizer = Edalizer(\n        toplevel=core.name,\n        flags=flags,\n        core_manager=cm,\n        work_root=work_root,\n        export_root=export_root,\n        system_name=system_name,\n    )\n\n    if do_configure:\n        try:\n            prepare_work_root(work_root)\n            edam = edalizer.run()\n            parsed_args = edalizer.parse_args(backend_class, backendargs, edam)\n            edalizer.add_parsed_args(backend_class, parsed_args)\n\n        except SyntaxError as e:\n            logger.error(e.msg)\n            exit(1)\n        except RuntimeError as e:\n            logger.error("Setup failed : {}".format(str(e)))\n            exit(1)\n        edalizer.to_yaml(edam_file)\n    else:\n        edam = yaml_fread(edam_file)\n        parsed_args = edalizer.parse_args(backend_class, backendargs, edam)\n\n    # Frontend/backend separation\n\n    try:\n        backend = backend_class(edam=edam, work_root=work_root, verbose=verbose)\n\n    except RuntimeError as e:\n        logger.error(str(e))\n        exit(1)\n    except FileNotFoundError as e:\n        logger.error(f\'Could not find EDA API file "{e.filename}"\')\n        exit(1)\n\n    if do_configure:\n        try:\n            backend.configure([])\n            print("")\n        except RuntimeError as e:\n            logger.error("Failed to configure the system")\n            logger.error(str(e))\n            exit(1)\n\n    if do_build:\n        try:\n            backend.build()\n        except RuntimeError as e:\n            logger.error("Failed to build {} : {}".format(str(core.name), str(e)))\n            exit(1)\n\n    if do_run:\n        try:\n            backend.run(parsed_args)\n        except RuntimeError as e:\n            logger.error("Failed to run {} : {}".format(str(core.name), str(e)))\n            exit(1)\n\n\ndef update(cm, args):\n    if "warn" in args:\n        logger.warning(args.warn)\n\n    cm._lm.update(args.libraries)\n\n\ndef init_logging(verbose, monochrome, log_file=None):\n    level = logging.DEBUG if verbose else logging.INFO\n\n    setup_logging(level, monochrome, log_file)\n\n    if verbose:\n        logger.debug("Verbose output")\n    else:\n        logger.debug("Concise output")\n\n    if monochrome:\n        logger.debug("Monochrome output")\n    else:\n        logger.debug("Colorful output")\n\n\ndef init_coremanager(config, args_cores_root):\n    logger.debug("Initializing core manager")\n    cm = CoreManager(config)\n\n    args_libs = [Library(acr, acr) for acr in args_cores_root]\n    # Add libraries from config file, env var and command-line\n    for library in config.libraries + args_libs:\n        try:\n            cm.add_library(library, config.ignored_dirs)\n        except (RuntimeError, OSError) as e:\n            _s = "Failed to register library \'{}\'"\n            logger.warning(_s.format(str(e)))\n\n    return cm\n\n\ndef get_parser():\n    parser = argparse.ArgumentParser()\n    subparsers = parser.add_subparsers()\n\n    # Global actions\n    parser.add_argument(\n        "--version",\n        help="Display the FuseSoC version",\n        action="version",\n        version=__version__,\n    )\n\n    # Global options\n    parser.add_argument(\n        "--cores-root",\n        help="Add additional directories containing cores",\n        default=[],\n        action="append",\n    )\n    parser.add_argument("--config", help="Specify the config file to use")\n    parser.add_argument(\n        "--monochrome",\n        help="Don\'t use color for messages",\n        action="store_true",\n        default=not sys.stdout.isatty(),\n    )\n    parser.add_argument("--verbose", help="More info messages", action="store_true")\n    parser.add_argument("--log-file", help="Write log messages to file")\n\n    # init subparser\n    parser_init = subparsers.add_parser(\n        "init", help="Initialize the FuseSoC core libraries. DEPRECATED"\n    )\n    parser_init.add_argument(\n        "-y", action="store_true", help="Skip user input and use default settings"\n    )\n    parser_init.set_defaults(func=init)\n\n    # pgm subparser\n    parser_pgm = subparsers.add_parser(\n        "pgm",\n        help="Program an FPGA with a system configuration. DEPRECATED, use \'run\' instead.",\n    )\n    parser_pgm.add_argument("system")\n    parser_pgm.add_argument("backendargs", nargs=argparse.REMAINDER)\n    parser_pgm.set_defaults(func=pgm)\n\n    # fetch subparser\n    parser_fetch = subparsers.add_parser(\n        "fetch", help="Fetch a remote core and its dependencies to local cache"\n    )\n    parser_fetch.add_argument("core")\n    parser_fetch.set_defaults(func=fetch)\n\n    # core subparser\n    parser_core = subparsers.add_parser(\n        "core", help="Subcommands for dealing with cores"\n    )\n    core_subparsers = parser_core.add_subparsers()\n    parser_core.set_defaults(subparser=parser_core)\n\n    # core list subparser\n    parser_core_list = core_subparsers.add_parser("list", help="List available cores")\n    parser_core_list.set_defaults(func=list_cores)\n\n    # core show subparser\n    parser_core_show = core_subparsers.add_parser(\n        "show", help="Show information about a core"\n    )\n    parser_core_show.add_argument("core", help="Name of the core to show")\n    parser_core_show.set_defaults(func=core_info)\n\n    # tool subparser\n    parser_tool = subparsers.add_parser(\n        "tool", help="Subcommands for dealing with tools"\n    )\n    tool_subparsers = parser_tool.add_subparsers()\n    parser_tool.set_defaults(subparser=parser_tool)\n\n    # tool list subparser\n    parser_tool_list = tool_subparsers.add_parser("list", help="List available tools")\n    parser_tool_list.set_defaults(func=list_tools)\n\n    # list-cores subparser\n    parser_list_cores = subparsers.add_parser("list-cores", help="List available cores")\n    parser_list_cores.set_defaults(func=list_cores)\n\n    # core-info subparser\n    parser_core_info = subparsers.add_parser(\n        "core-info", help="Display details about a core"\n    )\n    parser_core_info.add_argument("core")\n    parser_core_info.set_defaults(func=core_info)\n\n    # gen subparser\n    parser_gen = subparsers.add_parser(\n        "gen", help="Run or show information about generators"\n    )\n    parser_gen.set_defaults(subparser=parser_gen)\n    gen_subparsers = parser_gen.add_subparsers()\n\n    # gen list subparser\n    parser_gen_list = gen_subparsers.add_parser(\n        "list", help="List available generators"\n    )\n    parser_gen_list.set_defaults(func=gen_list)\n\n    # gen show subparser\n    parser_gen_show = gen_subparsers.add_parser(\n        "show", help="Show information about a generator"\n    )\n    parser_gen_show.add_argument("generator", help="Name of the generator to show")\n    parser_gen_show.set_defaults(func=gen_show)\n\n    # list-paths subparser\n    parser_list_paths = subparsers.add_parser(\n        "list-paths", help="Display the search order for core root paths"\n    )\n    parser_list_paths.set_defaults(func=list_paths)\n\n    # library subparser\n    parser_library = subparsers.add_parser(\n        "library", help="Subcommands for dealing with library management"\n    )\n    library_subparsers = parser_library.add_subparsers()\n    parser_library.set_defaults(subparser=parser_library)\n\n    # library add subparser\n    parser_library_add = library_subparsers.add_parser(\n        "add", help="Add new library to fusesoc.conf"\n    )\n    parser_library_add.add_argument("name", help="A friendly name  for the library")\n    parser_library_add.add_argument(\n        "sync-uri", help="The URI source for the library (can be a file system path)"\n    )\n    parser_library_add.add_argument(\n        "--location",\n        help="The location to store the library into (defaults to $XDG_DATA_HOME/[name])",\n    )\n    parser_library_add.add_argument(\n        "--sync-type",\n        help="The provider type for the library. Defaults to \'git\'.",\n        choices=["git", "local"],\n    )\n    parser_library_add.add_argument(\n        "--no-auto-sync",\n        action="store_true",\n        help="Disable automatic updates of the library",\n    )\n    parser_library_add.add_argument(\n        "--global",\n        action="store_true",\n        help="Use the global FuseSoC config file in $XDG_CONFIG_HOME/fusesoc/fusesoc.conf",\n    )\n    parser_library_add.set_defaults(func=add_library)\n\n    # library list subparser\n    parser_library_list = library_subparsers.add_parser(\n        "list", help="List core libraries"\n    )\n    parser_library_list.set_defaults(func=library_list)\n\n    # library update subparser\n    parser_library_update = library_subparsers.add_parser(\n        "update", help="Update the FuseSoC core libraries"\n    )\n    parser_library_update.add_argument(\n        "libraries", nargs="*", help="The libraries to update (defaults to all)"\n    )\n    parser_library_update.set_defaults(func=update)\n\n    # run subparser\n    parser_run = subparsers.add_parser("run", help="Start a tool flow")\n    parser_run.add_argument(\n        "--no-export",\n        action="store_true",\n        help="Reference source files from their current location instead of exporting to a build tree",\n    )\n    parser_run.add_argument(\n        "--build-root", help="Output directory for build. Defaults to build/$VLNV"\n    )\n    parser_run.add_argument("--setup", action="store_true", help="Execute setup stage")\n    parser_run.add_argument("--build", action="store_true", help="Execute build stage")\n    parser_run.add_argument("--run", action="store_true", help="Execute run stage")\n    parser_run.add_argument("--target", help="Override default target")\n    parser_run.add_argument("--tool", help="Override default tool for target")\n    parser_run.add_argument(\n        "--flag",\n        help="Set custom use flags. Can be specified multiple times",\n        action="append",\n        default=[],\n    )\n    parser_run.add_argument(\n        "--system-name", help="Override default VLNV name for system"\n    )\n    parser_run.add_argument("system", help="Select a system to operate on")\n    parser_run.add_argument(\n        "backendargs", nargs=argparse.REMAINDER, help="arguments to be sent to backend"\n    )\n    parser_run.set_defaults(func=run)\n\n    # update subparser\n    parser_update = subparsers.add_parser(\n        "update", help="Update the FuseSoC core libraries"\n    )\n    parser_update.add_argument(\n        "libraries",\n        nargs="*",\n        help="The libraries (or core roots) to update (defaults to all)",\n    )\n    parser_update.set_defaults(func=update)\n    parser_update.set_defaults(\n        warn="\'fusesoc update\' is deprecated. Use \'fusesoc library update\' instead"\n    )\n\n    return parser\n\n\ndef parse_args(argv):\n    parser = get_parser()\n\n    args = parser.parse_args(argv)\n\n    if hasattr(args, "func"):\n        return args\n    if hasattr(args, "subparser"):\n        args.subparser.print_help()\n    else:\n        parser.print_help()\n        return None\n\n\ndef fusesoc(args):\n    init_logging(args.verbose, args.monochrome, args.log_file)\n    config = Config(args.config)\n\n    cm = init_coremanager(config, args.cores_root)\n    # Run the function\n    args.func(cm, args)\n\n\ndef main():\n    args = parse_args(sys.argv[1:])\n    if not args:\n        exit(0)\n\n    logger.debug("Command line arguments: " + str(sys.argv))\n\n    fusesoc(args)\n\n\nif __name__ == "__main__":\n    main()\n', 'message': 'Use get_tool in build flow and list_systems\n', 'author_name': 'Olof Kindgren', 'lang': 'py'}