def chown_to_user(path):
    shutil.chown(path, get_user_uid(), get_user_gid()) class FatalError(Error):
    """Exception raised for fatal errors needing corrective actions from user.

    Attributes:
        message -- explanation of the error
    """

    def __init__(self, message):
        self.message = message def get_workdir():
    return os.getcwd() def get_artifact_dir():
    return os.path.join(get_workdir(), 'artifacts') def create_artifact_dir():
    directory = get_artifact_dir()
    if not os.path.isdir(directory):
        logging.info('''Creating artifact directory '{}'.'''.format(directory))
        os.mkdir(directory)
        chown_to_user(directory) def print_success(*args, **kwargs):
    print('\033[92m', end="")
    print('Success: ', end="")
    print(*args, end="", **kwargs)
    print('\033[0m') def run(popenargs, sudo=False, input=None, timeout=None, check=True, universal_newlines=True,
        stdout=_ADAPTIVE, log_threshold=logging.DEBUG,
        **kwargs):
    """
    Small wrapper around subprocess.run().
    """

    assert type(popenargs) is list

    subprocess_stdout = stdout

    if subprocess_stdout == _ADAPTIVE:
        if logging.getLogger().isEnabledFor(log_threshold):
            subprocess_stdout = None
        else:
            subprocess_stdout = subprocess.PIPE

    all_args = list()
    if not sudo and os.getuid() == 0:
        current_user = get_user()
        if current_user != 'root':
            # drop privileges
            all_args.extend(['sudo', '-u', current_user])
    elif sudo and os.getuid() != 0:
        all_args.append('sudo')

    all_args.extend(popenargs)

    logging.log(log_threshold, "Running command: {0}".format(all_args))

    result = mockablerun.run_mockable(all_args, input=input, timeout=timeout, check=check,
                                      universal_newlines=universal_newlines,
                                      stdout=subprocess_stdout, **kwargs)

    if (logging.getLogger().isEnabledFor(log_threshold) and
            subprocess_stdout is subprocess.PIPE):
        logging.log(log_threshold, result.stdout)

    return result def safely_remove_artifacts_folder(abs_folder_path, sudo=False):
    """
    Do some paranoid checking before removing a folder possibly using sudo.
    :param abs_folder_path: Absolute path to folder that should get deleted.
    :param sudo: If True, use sudo to delete folder.
    """
    artifacts_dir = get_artifact_dir()
    assert 'artifacts' in str(abs_folder_path)
    assert str(artifacts_dir) in str(abs_folder_path)
    assert os.path.isdir(abs_folder_path)
    assert os.path.isabs(abs_folder_path)
    mount_result = run(['mount'], stdout=subprocess.PIPE)
    if str(abs_folder_path) in mount_result.stdout:
        raise FatalError(('''Refusing to delete '{}' since it contains mounted elements.'''
                          ).format(abs_folder_path))
    run(['rm', '-rf', abs_folder_path], sudo=sudo) def remove_passwords(dictionary):
    obfuscated_dictionary = {}

    url_items = ["edi_host_http_proxy", "edi_host_https_proxy",
                 "edi_host_ftp_proxy", "edi_host_socks_proxy"]

    for key, value in dictionary.items():
        if key in url_items:
            obfuscated_dictionary[key] = obfuscate_url_password(value)
        else:
            obfuscated_dictionary[key] = value

    return obfuscated_dictionary class LiteralString(str):
    pass
import os
import logging
import tempfile
import yaml
import jinja2
import stat
from codecs import open
from edi.lib.helpers import (chown_to_user, FatalError, get_workdir, get_artifact_dir,
                             create_artifact_dir, print_success)
from edi.lib.shellhelpers import run, safely_remove_artifacts_folder
from edi.lib.configurationparser import remove_passwords
from edi.lib.yamlhelpers import LiteralString
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Matthias Luescher
#
# Authors:
#  Matthias Luescher
#
# This file is part of edi.
#
# edi is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# edi is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with edi.  If not, see <http://www.gnu.org/licenses/>.



class CommandRunner():

    def __init__(self, config, section, input_artifact):
        self.config = config
        self.config_section = section
        self.input_artifact = input_artifact

    def run(self):
        workdir = get_workdir()
        create_artifact_dir()

        commands = self._get_commands()

        for filename, content, name, path, dictionary, raw_node, artifacts in commands:
            if self._are_all_artifacts_available(artifacts):
                logging.info(('''Artifacts for command '{}' are already there. '''
                              '''Delete them to regenerate them.'''
                              ).format(name))
            else:
                with tempfile.TemporaryDirectory(dir=workdir) as tmpdir:
                    chown_to_user(tmpdir)
                    require_root = raw_node.get('require_root', False)

                    logging.info(("Running command {} located in "
                                  "{} with dictionary:\n{}"
                                  ).format(name, path,
                                           yaml.dump(remove_passwords(dictionary),
                                                     default_flow_style=False)))

                    command_file = self._flush_command_file(tmpdir, filename, content)
                    self._run_command(command_file, require_root)
                    self._post_process_artifacts(name, artifacts)

        return self._result(commands)

    def require_root(self):
        commands = self._get_commands()

        for _, _, _, _, _, raw_node, artifacts in commands:
            if not self._are_all_artifacts_available(artifacts) and raw_node.get('require_root', False):
                return True

        return False

    def require_root_for_clean(self):
        for _, _, _, _, _, raw_node, artifacts in self._get_commands():
            if raw_node.get('require_root', False) and self._is_an_artifact_a_directory(artifacts):
                return True

        return False

    def get_plugin_report(self):
        result = {}

        commands = self._get_commands()

        if commands:
            result[self.config_section] = []

        for _, content, name, path, dictionary, _, _ in commands:
            plugin_info = {name: {'path': path, 'dictionary': dictionary, 'result': LiteralString(content)}}

            result[self.config_section].append(plugin_info)

        return result

    def clean(self):
        commands = self._get_commands()
        for filename, content, name, path, dictionary, raw_node, artifacts in commands:
            for _, artifact in artifacts.items():

                if not str(get_workdir()) in str(artifact):