#!/usr/bin/python3
import os
import subprocess
import logging
import re
import sys
import time
import tempfile
import shutil
import string
from apt.cache import Cache
from math import ceil

log_file="/var/log/astra-update-service/update.log"
upgradable_stamp="/var/cache/astra-update-service/upgradable"
snapshot_stamp="/var/cache/astra-update-service/snapshot"
success_stamp="/var/cache/astra-update-service/successful"
failure_stamp="/var/cache/astra-update-service/unsuccessful"
success_dir="/var/cache/astra-update-service"
scripts_dir="/usr/share/astra-update-service/scripts"
sorted_scripts_dir="/var/cache/astra-update-service/scripts"

sys_upd_link="/system-update"
plymouth_running = False;
conf_file = "/etc/astra-update-service/temp.ini"
boot_snap_path = "/var/tmp/boot_snap.tar.bz2";
xfs_snapshot_path = "/var/tmp/xfssnap.bin"

def set_logger():
    global logger
    logger = logging.getLogger("astra-update-service")
    logger.setLevel(logging.INFO)
            
    # create the logging file handler
    fh = logging.FileHandler(log_file)
        
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter)
           
    # add handler to logger object
    logger.addHandler(fh)
    #DEBUG, INFO, WARNING, ERROR и CRITICAL.

def usage():
    # Help screen
    print("Please, don't operate this service manually.")
#    print('\t' + os.path.basename(__file__) + ' [command]')
#    print('Available commands:')
#    print('\t update \t Check updates')
#    print('\t download \t Download packages')
#    print('\t upgrade \t Upgrade packages')
#    print('\t clean \t\t Clean package archive')
#    print('\t check \t\t Check broken packages')
#    print('\t ping HOSTADDR\t Wait for the host HOSTADDR to be pinged')
    return -1

def plymouth_check():
    global plymouth_running
    plymouth_run = subprocess.run(['plymouth', '--ping'])
    if plymouth_run.returncode == 0:
        plymouth_running = True;
    else:
        plymouth_running = False;
                              
def display_message(text):
    if plymouth_running:
        #Print message on console or Plymouth
        subprocess.run(["plymouth", "message", "--text", text])

        #if plymouth_running:
        #    subprocess.run(["plymouth", "display-message", "--text", text])
    else:
        print(text)

def plymouth_update_mode ():
    #print("Setting system-upgrade mode")
    subprocess.run(["plymouth", "change-mode", "--updates"])

def plymouth_update_status(status):
    #print(percent)
    subprocess.run(["plymouth", "update", "--status", status])

def plymouth_boot_mode ():
    #print("Setting boot-up mode")
    subprocess.run(["plymouth", "change-mode", "--boot-up"])

def check_dirs ():
    # Check log dir, if dir not found, create it
    logdir = "/var/log/astra-update-service"
    if os.path.exists(logdir) == False:
        os.mkdir(logdir)
    logdir = "/var/cache/astra-update-service"
    if os.path.exists(logdir) == False:
        os.mkdir(logdir)
    if os.path.exists(log_file) == False:
        open(log_file, 'a')

def clean_cache():
    logger.info("Clean apt caches")
    cleanproc = subprocess.run(['apt-get', 'clean'])
    if cleanproc.returncode != 0:
        return 1
    cleanproc = subprocess.run(['apt-get', '-qq', '-y', 'autoclean'])
    if cleanproc.returncode != 0:
        return 2
    return 0

def wait_online(ping_address):
    #wait for internet connection
#    logger.info("Waiting for internet connection: " + ping_address)
    not_connected = True
    while not_connected:
        pingproc = subprocess.run(["ping", "-c1", "-W1", ping_address])
        if pingproc.returncode == 0:
            not_connected = False 
#            logger.info("Succesfully pinged") 
            return 0
        if pingproc.returncode == 2: #code 2 - other errors - exit immediately
            logger.error("Trying to ping \"" + ping_address + "\" raised an error")
            return 1
        time.sleep(1)
    return 0

def check_battery_charge():
    # Check battery charge. If charge < 50% - disable update.
    if os.path.exists("/sys/class/power_supply/BAT0"):
        with open("/sys/class/power_supply/BAT0/capacity") as f:
            if int(f.read()) > 50:
                logger.info("power supply: battery capacity more than 50 percents")
                return 0
            else:
                logger.error("Battery charge less then 50%")
                return 1
    else:
        logger.warning("no information about battery")
        return 0

def check_power_supply() :
    if os.path.exists("/sys/class/power_supply/AC"):
        with open("/sys/class/power_supply/AC/online") as f:
            if int(f.read(1)) == 1:
                logger.info("power supply: AC")
                return 0
            else:
                return check_battery_charge()
    else:
        logger.warning("no information about ac")
        return 0


def update_symlink(create):
    # create or remove /system-update symlink
    if create == True:
        if not os.path.exists(sys_upd_link):
            os.symlink("/var/cache/apt/archives", sys_upd_link)
        else:
            logger.warning("the symlink already exists and will be not created again")
                
    else:
        if os.path.exists(sys_upd_link):
            os.remove(sys_upd_link)
        else:
            logger.warning("the symlink not exists and will be not removed therefore")

def fix_dpkg():
    #fixing broken packages
    logger.info("Try to fix broken packages...")
    with tempfile.TemporaryFile(mode='w+') as temp_file:
        fixproc = subprocess.run(["dpkg", "--configure", "-a"], capture_output=True, text=True)
        res = fixproc.returncode
        if res != 0:
            logger.error("Can't fix broken packages")
            temp_file.seek(0)
            logger.error(temp_file.read())
            return 1
        else:
            logger.info("Broken packages fixed")
            return 0

def check_pkgmngr():
    # check packet manager on errors
    if os.path.islink(sys_upd_link):
        with tempfile.TemporaryFile(mode='w+') as temp_file:
            res = 0
            checkproc = subprocess.run(["dpkg", "--audit"], capture_output=True, text=True)
            res += checkproc.returncode
            temp_file.write(str(checkproc.stdout))
            checkproc = subprocess.run(["apt-get", "check"], capture_output=True, text=True)
            res += checkproc.returncode
            temp_file.write(str(checkproc.stdout))       
            checkproc = subprocess.run(["apt-get", "update"], capture_output=True, text=True)
            temp_file.write(str(checkproc.stdout))      
            if res != 0:
                logger.warning("Packet management system has problems")
                temp_file.seek(0)
                logger.warning(temp_file.read())                
                return fix_dpkg()
            logger.info("Package management is OK")
            return 0
    else:
        logger.warning(sys_upd_link + " checking failed")
    return 2


def checks_before_update():
    # check if the system is ready for update
    logger.info("Checking if the system is ready for update")
    if os.path.isfile(upgradable_stamp):
        if (check_power_supply() or check_pkgmngr()):
            update_symlink(False)
            logger.error("Errors detected during the system check, disabling update")
            return 1
        else:
            return 0
    else:
        logger.info("Upgradable stamp is missing or corrupted, an update will be cancelled")
        update_symlink(False)
        return 2


def get_update_packages_list():
    # update packages list
    clearlist = []
    subprocess.run(["apt-get", "update"])
    aptproc = subprocess.run(["apt", "list", "--upgradable"], capture_output=True, text=True)
    if aptproc.returncode == 0:
        list = aptproc.stdout.split("\n")
        for package in list[1:]:
            if (not package.isspace()) and (len(package) != 0) & (package.find("/") > 0): #TODO test &
                clearlist.append(package[0:package.find('/')])
    return clearlist

def check_updates():
    subprocess.run(["apt-get", "update"])
    aptproc = subprocess.run(["apt", "list", "--upgradable"], capture_output=True, text=True)
    if aptproc.returncode == 0:
        list = aptproc.stdout.split("\n")
        for package in list[1:]:
            if (not package.isspace()) and (len(package) != 0) & (package.find("/") > 0):
                return 1
    return 0
    
def get_new_astra_version():
    aptproc = subprocess.run(["apt-cache", "policy", "astra-version"], capture_output=True, text=True)
    if aptproc.returncode == 0:
        list = aptproc.stdout.split("\n")
        if len(list) < 3:
            return 1
        versions = []
        for package in list[1:3]:
            if (not package.isspace()) and (len(package) != 0) :
                split = package.split(":")
                if len(split) >= 2:
                    version = split[1].strip()
                    match = re.search('\+v', version)
                    if match:
                        versions.append(version[match.end():])
        if len(versions) == 2:
            if (versions[0] == versions[1]):
                return 2
            else:
                pos = versions[1].rfind('.')
                versions[1] = versions[1].replace('.', '')
                return int(versions[1][:pos-2])
    return 3

def download_packages():
    # download  packages
    packages_list = get_update_packages_list()
    if len(packages_list) == 0:
        logger.info("No packages to upgrade")
        file = open(conf_file, "w")
        file.write("2");
        file.close();
        return 2
    else:        
        logger.info("Start downloading updates")
        aptproc = subprocess.Popen(["apt-get", "--download-only", "-y", "dist-upgrade"], stdout=subprocess.PIPE, text=True)
        while True:
            output = aptproc.stdout.readline()
            if output == '' and aptproc.poll() is not None:
                break
            if output:
                match = re.search(r'\w\w\w:[0-9]', output)
                if match:
                    split = output.split(' ') 
                    if len(split) >= 7:
                        logger.info(str("Get: " + split[4] + "_" + split[6]))
                    else:
                        logger.warning("Strange info, full print:")
                        logger.warning(output)
        if aptproc.returncode == 0:
            logger.info("Downloading complete")
            file = open(conf_file, "w")
            file.write("0");
            file.close();
            return 0

        else:
            logger.error("Error while downloading packages:")
            for err_pack in packages_list:
                logger.error(err_pack)
            file = open(conf_file, "w")
            file.write("1");
            file.close();
            return 1
    
def get_download_result():
    with open(conf_file, "r") as f:
        for line in f:
            res = int(line)
    return res

def show_error_message(msg):
    plymouth_update_status(msg)
    for i in range(5):
        msg = str("Перезагрузка через " + str(5 - i))
        if (i == 0 ):
            msg += " секунд"
        else:
            if (i == 4):
                msg += " секунду"
            else:
                msg += " секунды"
        plymouth_update_status(msg)
        time.sleep(1)

def get_fs_type():
    global fs_type
    fs_type = -1
    global free_space
    free_space = -1
#    global mount_point
    global disk_name
    global disk_ok
    disk_ok = False

    dfproc = subprocess.run(["df", "-T", "-h"], capture_output=True, text=True)
    if dfproc.returncode == 0:
        list = dfproc.stdout.split("\n")
        for device in list[1:]:
            if (not device.isspace()) and (len(device) != 0):
                if re.match(".*\s\/$", device):
                    split = device.split()
                    if len(split) == 7:
                        disk_ok = True
                    else:
                        disk_ok = False
                        return
                    disk_name = split[0]
                    free_space = split[4]
#                    mount_point = split[6]
                    if split[1] == 'xfs':
                        logger.info("File system type: XFS")
                        fs_type = 0
                    elif '/dev/mapper/' in split[0]:
                        logger.info("File system type: LMV")
                        fs_type = 1
                    else:
                        fs_type = 2
    else:
        disk_ok = False

def create_snapshot():
    get_fs_type()
    if (fs_type == 0):
        create_xfs_snapshot()
    elif (fs_type == 1):
        create_lvm_snapshot()
    else:
        plymouth_update_status("Снимки поддерживаются только для LVM и XFS систем")
        logger.info("Snapshots are not supported for this system type")

def create_xfs_snapshot():
    plymouth_update_status("Создание снимка системы")
    logger.info("XFS snapshot creating")
    snap_proc = subprocess.Popen(["xfsdump",  "-l", "0", "-L", "session_astra", "-M",
                                    "tape_astra", "-f", xfs_snapshot_path, "/"],
                                    stdout=subprocess.PIPE, text=True)
#    subprocess.run(["xfsdump",  "-l", "0", "-L", "session_astra", "-M", "tape_astra", "-f", xfs_snapshot_path, "/"],
#                   stdout=subprocess.PIPE, text=True)
    #TODO add stdout processing
    while True:
        if snap_proc.poll() is None:
            plymouth_update_status("Идёт создание снимка, ожидайте")
            logger.info("XFS snapshot creating is in progress")
            time.sleep(5)
        else:
            logger.info("XFS snapshot created: returncode = " + str(snap_proc.poll()))
            break

def get_diskname_for_lvm():
    m_disk_name = disk_name.replace("--", "|")
    m_disk_name = m_disk_name.replace("-", "/")
    m_disk_name = m_disk_name.replace("|", "-")
    m_disk_name = m_disk_name.replace("mapper/", "")
    return m_disk_name

def get_vg_section():
    match = re.search("^\/dev\/(?P<vg>.*)\/.+$", get_diskname_for_lvm())
    if match:
        m_vg = match.group('vg')
    else:
        m_vg = ""
    return m_vg

def create_lvm_snapshot():
    plymouth_update_status("Создание снимка системы")
    logger.info("LVM snapshot creating")
    tarproc = subprocess.run(["tar", "--xattrs", "--acls", "-czpf", boot_snap_path, "--exclude=/boot/lost+found", "/boot"])

    if (tarproc.returncode != 0):
        logger.warning("An archive already exists, aborting")
        print("already exists")
        return
    else:
        lvmproc = subprocess.run(["lvcreate", "-L", "6GB", "-s", "-n", "lvsnap", "-p", "r", get_diskname_for_lvm()])

def restore_snapshot():
    exec_current_stage_scripts(3, 1)
    get_fs_type()
    if (fs_type == 0):
        restore_xfs_snapshot()
    elif (fs_type == 1):
        restore_lvm_snapshot()
    else:
        plymouth_update_status("Снимки поддерживаются только для LVM и XFS систем")
        logger.info("Snapshots are not supported for this system type")
    exec_current_stage_scripts(3, 0)

def restore_xfs_snapshot():
    plymouth_update_status("Восстановление снимка системы")
    logger.info("XFS snapshot restoring: " + xfs_snapshot_path)
    subprocess.run(["xfsrestore", "-f", xfs_snapshot_path, "/"])

def restore_lvm_snapshot():
    plymouth_update_status("Восстановление снимка системы")
    logger.info("LVM snapshot restoring")
    lvm_snapshot_path = "/dev/" + get_vg_section() + "/lvsnap"
    lvmproc = subprocess.run(["lvconvert", "--merge", lvm_snapshot_path])
    if lvmproc.returncode != 0:
        return
    else:
        shutil.rmtree("/boot") #TODO check me
        if (os.path.exists(boot_snap_path)):
            tarproc = subprocess.run(["tar", "--xattrs", "--xattrs-include=security.{PDPL,AUDIT,DEF_AUDIT}", "--acls", "-xzf", boot_snap_path, "-C", "/"])
            os.remove(boot_snap_path)

def remove_snapshot():
    get_fs_type()
    if (fs_type == 0):
        remove_xfs_snapshot()
    elif (fs_type == 1):
        remove_lvm_snapshot()
    else:
        plymouth_update_status("Снимки поддерживаются только для LVM и XFS систем")
        logger.info("Snapshots are not supported for this system type")

def remove_xfs_snapshot():
    plymouth_update_status("Удаление снимка системы")
    logger.info("XFS snapshot deleting: " + xfs_snapshot_path)
    if (os.path.exists(xfs_snapshot_path)):
        os.remove(xfs_snapshot_path)
        logger.info("Snapshot has been deleted")
    else:
        logger.warning("Snapshot file hadn't been found")

def remove_lvm_snapshot():
    plymouth_update_status("Удаление снимка системы")
    logger.info("LVM snapshot deleting")
    umountproc = subprocess.run(["umount", "/var/lib/os-prober/mount"])
    lvm_snapshot_path = "/dev/" + get_vg_section() + "/lvsnap"
    lvmproc = subprocess.run(["lvremove", "-f",  lvm_snapshot_path])
    if os.path.exists(boot_snap_path):
        os.remove(boot_snap_path)
    else:
        logger.warning(boot_snap_path + " hadn't been found")

def upgrade():
    plymouth_check()
    exec_current_stage_scripts(2, 1)
    if ( checks_before_update() != 0):
        errmsg = "Ошибка при проверке к обновлению"
        show_error_message(errmsg)
        if os.path.exists(success_dir) == False:
            os.mkdir(success_dir)
        new_stamp = open(failure_stamp, 'w')
        new_stamp.write("0");
        new_stamp.close()
        logger.warning("Rebooting system due errors before update")
        subprocess.run(["systemctl", "reboot"])
        return
    plymouth_update_mode()
    plymouth_update_status("Идет обновление системы. Не выключайте компьютер!")
    if os.path.exists(snapshot_stamp):
        create_snapshot()
    start_msg = ("Идёт обновление. Не выключайте компьютер: ")
    logger.info("Symlink removing...")
    update_symlink(False)
    logger.info("Start system update")
    aptget_proc = subprocess.Popen(["astra-update", "-A", "-T", "-r", "-o", "APT::Status-Fd=2"], stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True)
#    aptget_proc = subprocess.Popen(["apt-get", "-f", "-y", "-o", "Apt::Status-fd=2", "-o",
#                                    "Dpkg::Options::=--force-confdef", "-o", "Dpkg::Options::=--force-confold",
#                                    "dist-upgrade"], stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True)
    while True:
        errdata = aptget_proc.stderr.readline()
        if errdata == '' and aptget_proc.poll() is not None:
            break
        if errdata:
            split = errdata.split(':')
            if len(split) >= 4:
                logger.info(str(split[2] + "% " + split[3]))
                int_percent = split[2].split('.')
                try:
                    percent = float(split[2])
                except ValueError:
                    percent = 0
                plymouth_update_status(start_msg + str(round(percent, 2)) + "%" + "|" + int_percent[0])
            else:
                logger.warning("Strange info, full print:")
                logger.warning(errdata)
    if aptget_proc.returncode!=0:
        errmsg = "Ошибка во время обновления. Обратитесь к системному администратору"
        show_error_message(errmsg)
        if os.path.exists(success_dir) == False:
            os.mkdir(success_dir)
        new_stamp = open(failure_stamp, 'w')
        new_stamp.write("1");
        new_stamp.close()
        logger.error("Error during upgrade. Contact your system administrator")
        logger.error(str(aptget_proc.stderr))
        logger.warning("Rebooting system due errors")
        plymouth_boot_mode()
        subprocess.run(["systemctl", "reboot"])
    else:
        logger.info("Autoremove unused packages")
        plymouth_update_status("Очистка кеша")
        os.remove(upgradable_stamp)
        clean_cache()
        if os.path.exists(success_dir) == False:
            os.mkdir(success_dir)
        new_stamp = open(success_stamp, 'w')
        new_stamp.close()
        exec_current_stage_scripts(2, 0)
        logger.info("Rebooting system")
        plymouth_boot_mode()
        subprocess.run(["systemctl", "reboot"])

def calc_installed_size(packlist: list):
    cache = Cache()
    size = 0
    for pack in packlist:
        size += cache[pack].candidate.installed_size / 1024
    return ceil(size / 1024)

def get_required_space_in_stdout():
    packages_list = get_update_packages_list()
    size_to_install_Mb = 0
    if len(packages_list) != 0:
        size_to_install_Mb = calc_installed_size(packages_list)
        print(size_to_install_Mb) #DO NOT REMOVE it
        return 0
    else:
        return 1

def check_arg():
    if len(sys.argv) - 1 == 0:
        return usage()
    else:
        if sys.argv[1] == "download":
            return download_packages()
        if sys.argv[1] == "upgrade":
            return upgrade()
        if sys.argv[1] == "clean":
            return clean_cache() #not sure            
        if sys.argv[1] == "ping":
            if len(sys.argv) < 3:
                return usage()
            else:
                wait_online(sys.argv[2])
            return
        if sys.argv[1] == "check":
            return checks_before_update()
        if sys.argv[1] == "update":
            return check_updates()
        if sys.argv[1] == "downresult":
            return get_download_result()
        if sys.argv[1] == "rm_snapshot":
            return remove_snapshot()
        if sys.argv[1] == "rollback":
            return restore_snapshot()
        if sys.argv[1] == "get_version":
            return get_new_astra_version()
        if sys.argv[1] == "get_required_space":
            return get_required_space_in_stdout()
        if sys.argv[1] == "exec_scripts":
            if len(sys.argv) < 4:
                return usage()
            else:
                try:
                    prev_stage = ""
                    stage = int(sys.argv[2])
                    pre_stage = int(sys.argv[3])
                    if (stage >= 0 and stage < 4) and (pre_stage == 0 or pre_stage == 1):
                        if (len(sys.argv) == 5):
                            prev_stage = int(sys.argv[4])
                            return(exec_current_stage_scripts(stage, pre_stage, prev_stage))
                        else:
                            return(exec_current_stage_scripts(stage, pre_stage))
                    else:
                        return usage()
                except ValueError:
                    return usage()
        return usage()

def create_script_dirs(): #do we need to clean existing folders?
    if os.path.exists(sorted_scripts_dir) == False:
        os.mkdir(sorted_scripts_dir)
    dirname = sorted_scripts_dir + "/pre_ready"
    if os.path.exists(dirname) == False:
        os.mkdir(dirname)
    dirname = sorted_scripts_dir + "/post_ready"
    if os.path.exists(dirname) == False:
        os.mkdir(dirname)
    dirname = sorted_scripts_dir + "/pre_activated"
    if os.path.exists(dirname) == False:
        os.mkdir(dirname)
    dirname = sorted_scripts_dir + "/post_activated"
    if os.path.exists(dirname) == False:
        os.mkdir(dirname)
    dirname = sorted_scripts_dir + "/pre_upgrade"
    if os.path.exists(dirname) == False:
        os.mkdir(dirname)
    dirname = sorted_scripts_dir + "/post_upgrade"
    if os.path.exists(dirname) == False:
        os.mkdir(dirname)
    dirname = sorted_scripts_dir + "/pre_rollback"
    if os.path.exists(dirname) == False:
        os.mkdir(dirname)
    dirname = sorted_scripts_dir + "/post_rollback"
    if os.path.exists(dirname) == False:
        os.mkdir(dirname)

def get_script_info(script_path):
    checkproc = subprocess.run([script_path, "config"], capture_output=True, text=True)
    pre_state = -1
    cout_list = checkproc.stdout.split("\n")
    for str in cout_list:
        if pre_state < 0:
            if str.find("substage: pre") == 0:
                pre_state = 1
            elif str.find("substage: post") == 0:
                pre_state = 0
    for str in cout_list:
        if str.find("stage") == 0:
            if str.find("ready") > 0:
                copy_script_to_folder(script_path, 0, pre_state)
            if str.find("activated") > 0:
                copy_script_to_folder(script_path, 1, pre_state)
            if str.find("upgrade") > 0:
                copy_script_to_folder(script_path, 2, pre_state)
            if str.find("rollback") > 0:
                copy_script_to_folder(script_path, 3, pre_state)

def generate_folder_by_stage(stage, pre_state):
    folder_name = ""
    if stage == 0:
        folder_name = "ready"
    elif stage == 1:
        folder_name = "activated"
    elif stage == 2:
        folder_name = "upgrade"
    elif stage == 3:
        folder_name = "rollback"
    if pre_state == 0:
        folder_name = "/post_" + folder_name
    else:
        folder_name = "/pre_" + folder_name
    return sorted_scripts_dir + folder_name

def copy_script_to_folder(script_name, stage, pre_state):
    abs_folder_name = generate_folder_by_stage(stage, pre_state)
    shutil.copy(script_name, abs_folder_name)

def load_scripts():
    for root, dirs, files in os.walk(scripts_dir):
        if len(files) > 0:
            create_script_dirs()
        for script in files:
            get_script_info(os.path.join(root, script))

def exec_current_stage_scripts(stage, pre_state, prev_stage = None):
    use_prev_name = False
    if (prev_stage is not None):
        use_prev_name = True

    stage_name = ""
    if stage == 0:
        stage_name = "ready"
    elif stage == 1:
        stage_name = "activated"
    elif stage == 2:
        stage_name = "upgrade"
    elif stage == 3:
        stage_name = "rollback"

    if pre_state == 0:
        substage_name = "post"
    else:
        substage_name = "pre"

    prev_stage_name = ""
    if prev_stage == 0:
        prev_stage_name = "ready"
    elif prev_stage == 1:
        prev_stage_name = "activated"
    elif prev_stage == 2:
        prev_stage_name = "upgrade"
    elif prev_stage == 3:
        prev_stage_name = "rollback"

    logger_text = "Scripts execution: stage = " + stage_name + " sub_stage = " + substage_name
    if use_prev_name:
        logger_text += " prev_stage = " + prev_stage_name
    logger.info(logger_text)
    current_folder = generate_folder_by_stage(stage, pre_state)
    summ_errors = 0
    for root, dirs, files in os.walk(current_folder):
        if len(files) == 0:
            logger.warning("No scripts were found")
            return
        for script in files:
            curr_error = 0
            logger.info("Current script: " + script)
            script_path = current_folder + "/" + script
            if use_prev_name:
                scriptproc = subprocess.run([script_path, "prev", prev_stage_name], capture_output=True, text=True)
            else:
                scriptproc = subprocess.run([script_path], capture_output=True, text=True)
            cout_list = scriptproc.stdout.split("\n")
            for out_str in cout_list:
                if out_str.find("message:") >= 0:
                    logger.info(out_str)
                if out_str.find("warning:") >= 0:
                    logger.warning(out_str)
                if out_str.find("error:") >= 0:
                    logger.error(out_str)
                    curr_error = 1
            if scriptproc.returncode == 0:
                logger.info("Script return code = 0")
            else:
                curr_error = 1
                logger.info("Script return code = " + str(scriptproc.returncode))
            if curr_error == 1:
                summ_errors = summ_errors + 1
    return summ_errors

check_dirs()
set_logger()
load_scripts()
exit(check_arg())
