Exemple #1
0
def __run_dependencies(config, should_run):
    store = config_to_dict(config)
    importlib.reload(config)
    importlib.reload(config.confply)
    confply.config.run = should_run
    depends_return = 0
    if len(store["confply"]["dependencies"]) > 0:
        for d in store["confply"]["dependencies"]:
            if d not in __configs_run:
                confply.config.log_topic = store["confply"]["log_topic"]
                log.normal("running dependency: " + str(d))
                confply.config.log_topic = "confply"
                log.linebreak()
                __configs_run.add(d)
                depends_return = run_commandline(["--in", d])
                if depends_return < 0:
                    confply.config.log_topic = store["confply"]["log_topic"]
                    confply.config.log_file = store["confply"]["log_file"]
                    log.error("failed to run: " + str(d))
                    if not input_prompt("continue execution?"):
                        log.normal("aborting final commands")
                        break
                    else:
                        log.normal("continuing execution.")
        pass
    # reset confply.config
    apply_to_config(store)
    # #todo: make this jump to the mail section
    return depends_return
Exemple #2
0
def __handle_new_tool_arg(in_args):
    if len(in_args) < 1:
        log.error("--new_tool requires a value.")
        log.normal("\t--new_tool [config_type]")
        return
    module_dir = os.path.relpath(__file__)
    module_dir = os.path.dirname(module_dir)
    config_type = in_args.pop(0)
    config_type_dir = os.path.join(module_dir, config_type)
    if not os.path.exists(config_type_dir):
        module_dir = os.path.join(module_dir, "new_tool")
        os.mkdir(config_type_dir)
        files = [
            "__init__.py", "help.md", "default.py", "config/__init__.py",
            "options/__init__.py", "options/tool.py"
        ]
        for file_name in files:
            with open(os.path.join(module_dir, file_name)) as in_file:
                file_str = in_file.read()
                file_str = file_str.format_map({"config_type": config_type})
                tool_file = os.path.join(config_type_dir, file_name)
                os.makedirs(os.path.dirname(tool_file), exist_ok=True)
                with open(tool_file, "w") as out_file:
                    out_file.write(file_str)
        log.success("created " + config_type + " config_type!")
        log.normal("generate a config file by calling: " +
                   "'./confply.py --new_config " + config_type +
                   " my_config.py'")
    else:
        log.error(config_type + " already exists. (--new_tool)")
        pass
Exemple #3
0
def __print_config(config_name, config):
    diff_config = __get_diff_config(config)
    config_type_path = config.__file__

    if (os.path.exists(config_type_path)):
        log.normal(config_name + " configuration:")
        log.normal("")

        def print_dict(d1, depth=0):
            for k, v in d1.items():
                if isinstance(v, list):
                    log.bold("\t" * depth + log.format.bold(str(k)) + ": ")
                    for i in v:
                        log.normal("\t" * (depth + 1) + str(i))
                elif isinstance(v, dict):
                    log.normal("\t" * depth + log.format.bold(k) + ":")
                    print_dict(v, depth=depth + 1)
                    pass
                elif inspect.isfunction(v):
                    log.normal("\t" * depth + log.format.bold(str(k)) + ": " +
                               v.__name__)
                else:
                    log.normal("\t" * depth + log.format.bold(str(k)) + ": " +
                               str(v))

        if "confply" in diff_config:
            del diff_config["confply"]
        print_dict(diff_config)
        log.normal("")
    else:
        log.error(confply.config_config_type +
                  " is not a valid confply_config_type" +
                  " and should not be set by users.")
        log.normal("\tuse: 'import confply.[config_type].config" +
                   " as confply' to import confply_config_type.")
Exemple #4
0
def __handle_in_arg(in_args):
    if len(in_args) < 1:
        log.error("--in requires a value.")
        log.normal("\t--in [config_path]")
        return
    in_path = in_args.pop(0)
    confply.config.config_path = in_path
Exemple #5
0
def __handle_listen_arg(in_args):
    if len(in_args) < 1:
        log.error("--listen requires a value.")
        log.normal("\t--listen [launcher_file]")
        return

    arguement = in_args.pop(0)
    launcher_path = os.path.abspath(os.path.curdir) + "/" + arguement
    if os.path.exists(launcher_path):
        with pushd(os.path.dirname(__file__)):
            confply.server.start_server(launcher=launcher_path)
    else:
        log.error(launcher_path + " not found!")
Exemple #6
0
 def validate_dict(d1, d2):
     valid = True
     for k, v in d1.items():
         if isinstance(v, dict) and isinstance(d2[k], dict):
             valid = valid and validate_dict(v, d2[k])
         elif not isinstance(v, type(d2[k])):
             # edge case, allow tuples as lists & vice versa
             if isinstance(v, (tuple, list)) and isinstance(
                     d2[k], (tuple, list)):
                 continue
             valid = False
             log.error(k + ": expected '" + type(d2[k]).__name__ +
                       "' got '" + type(v).__name__ + "'")
     return valid
Exemple #7
0
def __handle_help_config_arg(option, in_args):
    module_dir = os.path.relpath(__file__)
    module_dir = os.path.dirname(module_dir)
    help_path = option.split(".")[1]
    help_path = os.path.join(module_dir, help_path)
    if os.path.exists(help_path):
        help_path = os.path.join(help_path, "help.md")
        if os.path.exists(help_path):
            with open(help_path) as help_file:
                print("\n" + help_file.read())
        else:
            log.error(option + " does not have an associated help file")
    else:
        log.error(option + " is not a valid command type")
Exemple #8
0
def generate():
    def __parse_deps(deps_string):
        deps_json = json.loads(deps_string)
        if "Data" in deps_json:
            deps_json = deps_json["Data"]
            out_deps = deps_json["Includes"]
            out_deps.append(deps_json["Source"])
            return out_deps
        pass

    try:
        config.link_libraries.remove("stdc++")
        log.warning("removing stdc++ from link_libraries, it's not valid when using cl.exe")
    except:
        pass
    try:
        config.warnings.remove("pedantic")
        log.warning("removing pedantic from warnings, it's not valid when using cl.exe")
    except:
        pass
    try:
        config.warnings.remove("extra")
        log.warning("removing extra from warnings, it's not valid when using cl.exe")
    except:
        pass
        

    if config.confply.platform == "windows":
        cpp_compiler.tool = "cl"
        cpp_compiler.output_obj = "-Fo"
        cpp_compiler.output_exe = "-Fe"
        cpp_compiler.standard = "-std:"
        cpp_compiler.dependencies = ""
        cpp_compiler.link = ""
        cpp_compiler.library = "-LIBPATH:"
        cpp_compiler.dependencies_output = "-sourceDependencies"
        cpp_compiler.exception_handling = "-EHsc"
        cpp_compiler.pass_to_linker = "-link"
        cpp_compiler.object_ext = ".obj"
        cpp_compiler.parse_deps = __parse_deps
        cpp_compiler.debug = "-Zi"
        return cpp_compiler.generate()
    else:
        log.error("cl only supports windows platforms")
        return None
Exemple #9
0
def __tool_select(in_tools):
    def _print_tools():
        num = -1
        for k in in_tools.keys():
            num += 1
            if not in_tools[k].is_found():
                log.warning("\t" + str(num) + ") " + k + " (not found)")
            else:
                log.normal("\t" + str(num) + ") " + k)

    shown_options = False
    while True:
        if input_prompt("continue with a different tool?"):
            if not shown_options:
                log.normal("which tool? options:")
                _print_tools()
                log.normal("")
                shown_options = True
            log.normal("tool: ", end="", flush=True)
            in_tool = input("")
            if (in_tool.isdigit()):
                tool_num = int(in_tool)
                if tool_num < len(in_tools):
                    tool_keys = list(in_tools.keys())
                    confply.config.tool = tool_keys[tool_num]
                    return True
                else:
                    log.error("'" + in_tool + "' is out of range.")
                pass
            else:
                if in_tool in in_tools:
                    confply.config.tool = in_tool
                    return True
                else:
                    log.error("'" + in_tool + "' could not be found," +
                              " is it installed?")
        else:
            if not shown_options:
                log.normal("options:")
                _print_tools()
                log.normal("")
            return False
Exemple #10
0
def launcher(in_args, aliases):
    return_code = -999999

    def print_header():
        log.confply_header()
        log.linebreak()

    confply_dir = __get_confply_dir()
    if len(in_args) != 0:
        alias = in_args[0]
        args = " ".join(in_args[1:])

        if alias in aliases:
            system_code = 0
            cmd = ("python " + confply_dir + "/confply.py ")
            cmd += (aliases[alias] + " " + args)
            cmd = cmd.replace(" -- ", " " + args + " -- ")
            # windows doesn't support os.WEXITSTATUS
            if os.name == 'nt':
                system_code = os.system(cmd)
            else:
                system_code = os.WEXITSTATUS(os.system(cmd))

            if (system_code > return_code) and (system_code != 0):
                return_code = system_code
        else:
            print_header()
            log.error(alias + " is not in aliases.")
            return_code = -1
    else:
        print_header()
        log.error("no arguements supplied.")
        with open(os.path.join(confply_dir, "help.md")) as help_file:
            print("\n" + help_file.read())
        return_code = -1
    log.linebreak()

    if (return_code != -999999):
        exit(abs(return_code))
    else:
        exit(0)
Exemple #11
0
def __run_shell_cmd(shell_cmd, cmd_env, tool):
    if confply.config.log_file:
        sys.stdout.flush()
        # #todo: check if this can be ansi-coloured
        result = subprocess.run(shell_cmd,
                                stdout=sys.stdout,
                                stderr=subprocess.STDOUT,
                                text=True,
                                shell=True,
                                env=cmd_env)
    else:
        result = subprocess.run(shell_cmd, shell=True, env=cmd_env)

    if result.returncode == 0:
        log.linebreak()
        log.success(tool + " succeeded!")
        return 0
    else:
        log.linebreak()
        log.error(tool + " failed.")
        log.error(tool + " return code: " + str(result.returncode))
        return -2
Exemple #12
0
def send_report(report):
    html_file = os.path.dirname(__file__)
    html_file = os.path.join(html_file, "mail.html")
    message = mime_multipart.MIMEMultipart('html')
    message["Subject"] = (pathlib.Path(report["vcs_root"]).name + ": " +
                          report["config_path"])
    message["From"] = sender
    message["To"] = recipients

    with open(html_file) as mail_file:
        message_str = mail_file.read()

        for key, val in report.items():
            message_str = message_str.replace("{" + key + "}", str(val))

        message_mime = mime_text.MIMEText(message_str, 'html')
        message.attach(message_mime)
        for f in attachments:
            if f is None or (not os.path.exists(f)):
                log.error("failed to send attachment: " + str(f))
                continue
            with open(f, "rb") as fil:
                part = mime_application.MIMEApplication(
                    fil.read(), Name=os.path.basename(f))
            # After the file is closed
            part['Content-Disposition'] = ('attachment; filename="%s"' %
                                           os.path.basename(f))
            message.attach(part)

    if login:
        try:
            server = smtplib.SMTP_SSL(host)
            server.ehlo()
            server.login(*login)
            server.send_message(message)
            server.quit()
        except:
            log.error("failed to send mail")
Exemple #13
0
def __handle_launcher_arg(in_args):
    if len(in_args) < 1:
        log.error("--launcher requires a value.")
        log.normal("\t--launcher [new_launcher_file]")
        return
    confply_dir = __get_confply_dir()
    arguement = in_args.pop(0)
    launcher_path = os.path.abspath(os.path.curdir) + "/" + arguement
    if not os.path.exists(launcher_path):
        with open(launcher_path, "w") as launcher_file:
            launcher_str = __new_launcher_str.format_map({
                "confply_dir":
                confply_dir,
                "launcher":
                arguement,
                "comment":
                "{\n    # 'myconfig':'path/to/config.py'\n}"
            })
            launcher_file.write(launcher_str)
        st = os.stat(launcher_path)
        os.chmod(launcher_path, st.st_mode | stat.S_IEXEC)
        log.success("wrote: " + launcher_path)
    else:
        log.error(launcher_path + " already exists!")
Exemple #14
0
def _handle_config_dict_arg(in_args):
    if len(in_args) < 1:
        log.error("--config requires a value.")
        log.normal("\t--config \"{'confply':{'tool':'cl'}}\"")
        return
    overide_dict = None
    try:
        overide_dict = ast.literal_eval(in_args.pop(0))
        if not isinstance(overide_dict, dict):
            log.error("--config must be a dictionary.")
            log.normal("\t--config \"{'confply':{'tool':'cl'}}\"")
            return
        elif "confply" in overide_dict:
            if not isinstance(overide_dict["confply"], dict):
                log.error("--config.confply must be a dictionary.")
                log.normal("\t--config \"{'confply':{'tool':'cl'}}\"")
                return
        else:
            overide_dict["confply"] = {}
    except Exception:
        log.error("--config failed to parse argument as a dictionary")
        return

    confply.config.__override_dict.update(overide_dict)
Exemple #15
0
def __handle_new_config_arg(in_args):
    if len(in_args) < 2:
        log.error("--config requires two values:")
        log.normal("\t--new_config [config_type] [new_config_file]")
        log.normal("")
        log.normal("valid tool types:")
        module_dir = os.path.dirname(__file__)
        files = os.listdir(module_dir)
        for dir in files:
            if (os.path.isdir(os.path.join(module_dir, dir))
                    and not dir == "__pycache__" and not dir == "new_tool"):
                log.normal("\t" + dir)
        return

    confply_dir = __get_confply_dir()
    config_type_arg = in_args.pop(0)
    config_arg = in_args.pop(0)
    config_path = os.path.abspath(os.path.curdir) + "/" + config_arg
    config_type_dir = os.path.dirname(os.path.relpath(__file__))
    config_type_dir = os.path.join(config_type_dir, config_type_arg)

    if not os.path.exists(config_type_dir):
        log.error(config_type_arg + " is not a valid config_type, consider:")
        for dir_file in os.listdir(confply_dir + "/confply/"):
            if os.path.isdir(confply_dir + "/confply/" + dir_file):
                if not dir_file == "__pycache__":
                    log.normal("\t" + dir_file)
        return

    hash_file = os.path.join(config_type_dir, "config/__init__.py")
    config_hash = md5_file(hash_file)
    if not os.path.exists(config_path):
        with open(config_path, "w") as config_file:
            config_str = __new_config_str.format_map({
                "confply_dir": confply_dir,
                "config_type_arg": config_type_arg,
                "config_file": config_arg,
                "config_hash": config_hash
            })
            config_file.write(config_str)
        st = os.stat(config_path)
        os.chmod(config_path, st.st_mode | stat.S_IEXEC)
        log.success("wrote: " + config_path)
    else:
        log.error(config_path + " already exists!")
        log.normal("aborted --new_config.")
Exemple #16
0
def __validate_config(config):
    tools = {}
    tool_dir = os.path.dirname(config.__file__)
    tool_dir = os.path.join(tool_dir, "..")
    if os.path.exists(tool_dir):
        files = os.listdir(tool_dir)
    else:
        log.error(config.__package__ + " is not a valid confply_config_type" +
                  " and should not be set by users.")
        log.normal("\tuse: " +
                   "'import confply.[config_type].config as config'" +
                   " to import confply_config_type.")
        return None

    tools = {}
    module_path = config.__package__.rsplit(".", 1)[0]
    for py in files:
        if py.endswith(".py") and not py == "__init__.py":
            tool = py[0:-3]
            tools[tool] = \
                importlib.import_module(module_path+"."+tool)

    tool = confply.config.tool
    pass

    #######
    if tool in tools:
        if not tools[tool].is_found():
            log.error("'" + tool + "' could not be found, is it installed?")
            if __tool_select(tools):
                return tools
            else:
                return None
        else:
            return tools
    else:
        log.error("'" + str(tool) + "' is not a valid tool.")
        if __tool_select(tools):
            return tools
        else:
            return None

    return tools
Exemple #17
0
def run_dict(in_dict):
    """
    runs the confply dict for the supplied config_type

    usage: run_dict(in_dict)
    """
    log.linebreak()
    log.header("run config")
    log.linebreak()

    # setup config run
    should_run = confply.config.run
    if ("config_path" in in_dict["confply"]):
        path = in_dict["confply"]["config_path"]
    else:
        path = None
    __load_vcs_info(path)
    confply.config.config_path = path
    config_name = os.path.basename(path)
    confply.config.config_name = config_name
    confply.config.modified = os.path.getmtime(path).real
    config_locals = apply_to_config(in_dict)
    if not config_locals:
        log.error("failed to load:  json")
        return -1

    if ("config" not in config_locals):
        log.error("confply failed import")
        log.normal(
            "\tuse: '__package__': 'confply.[config_type].config' in json/ini")
        clean_modules()
        return -1

    if (not __validate_types(config_locals["config"])):
        log.error("failed to run config")
        return -1

    # ensure we don't run if should_run was EVER false
    if should_run is not True:
        confply.config.run = should_run
    return __run_config(config_locals)
Exemple #18
0
def __handle_config_arg(option, in_args):
    global logged_overrides
    if len(in_args) < 1:
        log.error("--config requires a value.")
        log.normal("\t--config.confply.tool \"cl\"")
        return

    path = option.split(".")[1:]
    if len(path) == 0:
        log.error("--config invalid path.")
        log.normal("\t--config.confply.tool \"cl\"")
        return

    if path[0] == "confply" and len(path) == 1:
        log.error("--config invalid path, cannot set confply")
        log.normal("\t--config.confply.tool \"cl\"")
        return
    # #todo: this is pretty shit, it doesn't solve the general case at all
    #  but I'm being lazy you should be able to set values in a deep dictionary
    #  but you can't.
    arg = in_args.pop(0)
    value = None
    try:
        value = ast.literal_eval(arg)
    except Exception:
        value = arg

    # #todo: this should be done prior to running the config. not now.
    # this logging section is lazy af.
    if not logged_overrides:
        logged_overrides = True
        log.normal("overrides:")

    if isinstance(value, str):
        log.normal("\t" + option[2:] + " = \"" + str(value) + "\" <" +
                   type(value).__name__ + ">")
    else:
        log.normal("\t" + option[2:] + " = " + str(value) + " <" +
                   type(value).__name__ + ">")
    confply.config.__override_list.append([option[2:], value])
Exemple #19
0
def load_config(path):
    global config_modules
    if os.name == "nt":
        confply.config.platform = "windows"
    elif os.name == "posix":
        confply.config.platform = "linux"

    __load_vcs_info(path)
    # find group config in parent directories
    directory_paths = __get_group_configs(path)
    directory_paths.append(path)
    config_locals = {}
    # load and execute the config files
    for dir_path in directory_paths:
        if dir_path is None:
            continue
        if os.path.exists(dir_path) and os.path.isfile(dir_path):
            config_name = os.path.basename(dir_path)
            confply.config.config_name = config_name
            confply.config.modified = os.path.getmtime(dir_path).real
            with open(dir_path) as config_file:
                with pushd(os.path.dirname(dir_path)):
                    try:
                        exec(config_file.read(), {}, config_locals)
                        # find imported confply configs for cleanup
                        for k, v in config_locals.items():
                            m_valid = isinstance(v, types.ModuleType)
                            if not m_valid:
                                continue

                            v_name = v.__name__
                            m_valid = m_valid and v not in config_modules
                            m_valid = m_valid and v_name.startswith("confply.")
                            m_valid = m_valid and v_name.endswith(".config")
                            if m_valid:
                                config_modules.add(v)

                        # validate there are less than 2 imported configs
                        if len(config_modules) > 1:
                            log.error("too many confply configs imported:")
                            for c in config_modules:
                                log.normal("\t " + c)
                            log.normal(
                                "confply only supports one config import.")
                            clean_modules()
                            return None, None

                        log.linebreak()
                        log.success("loaded: " + str(dir_path))
                    except Exception:
                        log.error("failed to exec: " + str(dir_path))
                        trace = traceback.format_exc().replace(
                            "<string>", str(dir_path))
                        log.normal("traceback:\n\n" + trace)
                        return None, None

        else:
            log.error("failed to find: " + str(dir_path))
            return None, None

    return config_locals
Exemple #20
0
    cmd = "vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath"
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, env=envs)
    installation_path = proc.stdout.read().decode("utf-8").rstrip()
    installation_path = installation_path.replace("/", "\\")
    if not installation_path == "":
        _vs_tools = (installation_path+"/Common7/Tools/").replace("/", "\\")
        version_path = "/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt"
        version_path = (installation_path+version_path).replace("/", "\\")
        if os.path.exists(version_path):
            with open(version_path, "r") as version_file:
                version = version_file.read().rstrip()
                _cl_path = installation_path+"/VC/Tools/MSVC/"+version+"/bin/HostX64/x64/cl.exe"
                _cl_path.replace("/", "\\")
                _cl_found = os.path.exists(_cl_path)
    else:
        log.error("VisualStudio.Component.VC.Tools.x86.x64 not installed")

def get_environ():
    global _vs_tools
    if _cl_found:
        cl_envs = os.environ.copy()
        cl_envs["PATH"] += ";"+_vs_tools
        # #fixme: I think this is a hack, I feel like it should be passed like -arch
        cl_envs["VSCMD_DEBUG"] = "3"
        # #todo: add a way to set the architecture from the configs
        vsdevcmd = 'cmd.exe /s /c "call vsdevcmd.bat -arch=x64 -host_arch=x64 && set"'
        proc = subprocess.Popen(
            vsdevcmd, stdout=subprocess.PIPE, shell=True, env=cl_envs)
        lines = proc.stdout.readlines()
        for line in lines:
            line = line.decode("utf-8").rstrip()
Exemple #21
0
import sys
import confply
import confply.log as log

if __name__ == "__main__":
    in_args = sys.argv[1:]
    version = sys.version_info
    version = (version.major, version.minor, version.micro)
    if "--no_header" not in in_args:
        log.confply_header()
        log.linebreak()
        log.normal("python" + str(version))
        log.normal("confply " + confply.get_version())
        log.normal("date: " + str(confply.datetime.now()))
    if (version[0] < 3 or (version[0] == 3 and version[1] < 8)):
        log.error("python version must be 3.8 or above")
        log.linebreak()
        exit(1)

    return_code = -999999
    if len(in_args) != 0:
        while len(in_args) > 0:
            cmd_return = confply.run_commandline(in_args)

            if (cmd_return > return_code and cmd_return != 0):
                return_code = cmd_return

            # fatal error.
            if return_code == -1:
                log.linebreak()
                # failed to run command
Exemple #22
0
def run_commandline(in_args):
    """
    runs the confply config, with supplied arguements.
    confply reservered options will be stripped. e.g. --help
    see help.md

    usage: run_commandline(["path_to_config", "optional", "arguements"])
    """
    log.normal("called with args: " + str(in_args))
    in_args = __strip_confply_args(in_args)
    confply.config.args = in_args
    if confply.config.config_path:
        config_path = confply.config.config_path
        if not os.path.exists(config_path):
            log.error("couldn't find: " + config_path)
            return -1
        if config_path.endswith(".py"):
            log.linebreak()
            log.header("run config")
            log.linebreak()
            # setup config run
            should_run = confply.config.run
            config_locals = load_config(config_path)
            if not config_locals:
                log.error("failed to load: " + config_path)
                return -1

            if ("config" not in config_locals):
                log.error("confply config incorrectly imported")
                log.normal(
                    "\tuse: 'import confply.[config_type].config as config'")
                clean_modules()
                return -1

            config = config_locals["config"]
            if (not __validate_types(config)):
                log.error("failed to run config")
                return -1
            # ensure we don't run if should_run was EVER false
            if should_run is not True:
                confply.config.run = should_run
            # config
            config_hash = md5_file(config.__file__)
            if ("config_hash" not in config_locals
                    or config_hash != config_locals["config_hash"]):
                log.warning("warning: config_hash doesn't match expected hash")
                log.normal("\tconfig file might not function correctly")
                log.normal("\texpected:")
                log.normal("\t\t" + "config_hash='" + config_hash + "'")
                log.normal("")
            return __run_config(config_locals)

        elif config_path.endswith(".json"):
            if os.path.exists(config_path):
                with open(config_path) as in_json:
                    in_dict = json.loads(in_json.read())
                    in_dict["confply"].update({"config_path": config_path})
                    return run_dict(in_dict)
        elif config_path.endswith(".ini"):
            if os.path.exists(config_path):
                import configparser

                def parse_lit(in_val):
                    try:
                        return ast.literal_eval(in_val)
                    except Exception:
                        return in_val

                conf = configparser.ConfigParser()
                conf.read(config_path)
                in_dict = {"confply": {"config_path": config_path}}
                for (key, val) in conf["config"].items():
                    in_dict[key] = parse_lit(val)
                for (key, val) in conf["confply"].items():
                    in_dict["confply"][key] = parse_lit(val)
                return run_dict(in_dict)
        else:
            log.error("unsupported config type: " + config_path)
            return -1
    else:
        return 0
    return 0
Exemple #23
0
def __run_config(config_locals):
    in_args = confply.config.args
    config = config_locals["config"]
    return_code = 0
    should_run = confply.config.run
    file_path = confply.config.config_path
    __apply_overrides(config)
    new_working_dir = os.path.dirname(file_path)
    old_stdout = sys.stdout
    # setting confply command configuration up
    with pushd(new_working_dir):
        if confply.config.log_file:
            log.normal("writing to: " + confply.config.log_file + "....")
            try:
                sys.stdout = open(confply.config.log_file, "w")
                version = sys.version_info
                version = (version.major, version.minor, version.micro)
                if "--no_header" not in in_args:
                    log.confply_header()
                    log.linebreak()
                    log.normal("python" + str(version))
                    log.normal("confply " + get_version())
                    log.normal("date: " + str(datetime.now()))
                    log.linebreak()
                log.normal("confply logging to " + confply.config.log_file)
            except Exception:
                log.error("couldn't open " + confply.config.log_file +
                          " for write.")
                return_code = -1
        try:
            if (confply.config.post_load
                    and inspect.isfunction(confply.config.post_load)):
                log.normal("running post load script: " +
                           confply.config.post_load.__name__)
                sys.stdout.flush()
                exec(confply.config.post_load.__code__, config_locals, {})
                log.linebreak()

        except Exception:
            log.error("failed to exec " + confply.config.post_load.__name__)
            trace = traceback.format_exc()
            log.normal("traceback:\n\n" + trace)
            pass

        diff_config = __get_diff_config(config)
        should_run = confply.config.run
        report = {
            "config_path": file_path,
            "config_json": json.dumps(diff_config, indent=4),
            "config_type": "unknown",
            "tool": "unknown",
            "status": "failure",
            "vcs_root": confply.config.vcs_root,
            "vcs_log": confply.config.vcs_log,
            "vcs": confply.config.vcs,
            "vcs_branch": confply.config.vcs_branch,
            "vcs_author": confply.config.vcs_author,
            "time_taken": "00:00:00"
        }
        if return_code >= 0:
            if confply.config.log_config is not False:
                __print_config(os.path.basename(file_path), config)
            try:
                time_start = timeit.default_timer()
                # #todo: tool selection phase should happen first.
                tools = __validate_config(config)
                config_type = config.__package__
                tool = confply.config.tool
                report["tool"] = tool
                report["config_type"] = config_type
                if tools:
                    shell_cmd = tools[tool]
                    shell_cmd.handle_args()
                    # #todo: rename generate to gen_config_type.
                    shell_cmd = shell_cmd.generate() if tools else None
                else:
                    shell_cmd = None

                __run_dependencies(config, should_run)

                if shell_cmd is not None:
                    cmd_env = tools[tool].get_environ()
                    if len(shell_cmd) > 0:
                        if isinstance(shell_cmd, list):
                            log.normal("final commands:\n")
                            for shell_str in shell_cmd:
                                cmd = confply.config.command_prepend + shell_str
                                cmd = cmd + confply.config.command_append
                                print(cmd)
                            print("")
                        else:
                            cmd = confply.config.command_prepend + shell_cmd
                            cmd = shell_cmd + confply.config.command_append
                            log.normal("final command:\n\n" + str(cmd) + "\n")
                        if should_run:
                            log.header("begin " + tool)
                    sys.stdout.flush()

                    if should_run and isinstance(shell_cmd, list):
                        for cmd in shell_cmd:
                            cmd_time_start = timeit.default_timer()
                            sys.stdout.flush()
                            log.linebreak()
                            cmd = confply.config.command_prepend + cmd
                            cmd = cmd + confply.config.command_append
                            log.normal(cmd)
                            log.normal("", flush=True)
                            return_code = __run_shell_cmd(cmd, cmd_env, tool)
                            cmd_time_end = timeit.default_timer()
                            # #todo: this can be tidied with format var capture
                            s = cmd_time_end - cmd_time_start
                            m = int(s / 60)
                            h = int(m / 60)
                            # time formating via format specifiers
                            # https://docs.python.org/3.8/library/string.html#formatspec
                            time = f"{h:0>2.0f}:{m:0>2.0f}:{s:0>5.2f}"
                            log.normal("time elapsed " + time)
                    elif should_run:
                        return_code = __run_shell_cmd(shell_cmd, cmd_env, tool)
                    else:
                        log.warning("no commands run")
                else:
                    log.error("failed to generate a valid command.")
                    return_code = -1

                time_end = timeit.default_timer()
                s = time_end - time_start
                m = int(s / 60)
                h = int(m / 60)
                # time formating via format specifiers
                # https://docs.python.org/3.8/library/string.html#formatspec
                time = f"{h:0>2.0f}:{m:0>2.0f}:{s:0>5.2f}"
                log.normal("total time elapsed " + time)
                report["time_taken"] = time
                report["status"] = "success" if return_code == 0 else "failure"

            except Exception:
                log.error("failed to run config: ")
                trace = traceback.format_exc()
                log.normal("traceback:\n\n" + trace)
                return_code = -1
            sys.stdout.flush()
            if (confply.config.post_run
                    and inspect.isfunction(confply.config.post_run)):
                try:
                    log.linebreak()
                    log.normal("running post run script: " +
                               confply.config.post_run.__name__)
                    sys.stdout.flush()
                    exec(confply.config.post_run.__code__, config_locals, {})
                    log.linebreak()
                except Exception:
                    log.error("failed to exec " +
                              confply.config.post_run.__name__)
                    trace = traceback.format_exc()
                    log.normal("traceback:\n\n" + trace)
            log.normal("date: " + str(datetime.now()))
            log.linebreak()
            sys.stdout.flush()

            if sys.stdout != old_stdout:
                sys.stdout.close()
                sys.stdout = old_stdout
                if confply.config.log_echo_file:
                    with open(confply.config.log_file) as out_log:
                        log_str = out_log.read()
                        log_str = log_str.split("confply logging to " +
                                                confply.config.log_file)[1]
                        log.normal("wrote:" + log_str)

            if (confply.config.mail_send == report["status"]
                    or confply.config.mail_send == "all"):
                mail.host = confply.config.__mail_host
                mail.sender = confply.config.mail_from
                mail.recipients = confply.config.mail_to
                mail.login = confply.config.__mail_login
                mail.attachments = confply.config.mail_attachments
                if (confply.config.log_file and report["status"] == "failure"):
                    mail.attachments.append(
                        os.path.abspath(confply.config.log_file))
                    pass
                if mail.login:
                    mail.send_report(report)

            if (confply.config.slack_send == report["status"]
                    or confply.config.slack_send == "all"):
                slack.bot_token = confply.config.__slack_bot_token
                slack.uploads = confply.config.slack_uploads
                if (confply.config.log_file and report["status"] == "failure"):
                    slack.uploads.append(
                        os.path.abspath(confply.config.log_file))
                if slack.bot_token:
                    slack.send_report(report)
    clean_modules()
    return return_code