def process_folder(item, destination_path, filters, root):
    if not (item and destination_path and root):
        return None
    new_directory = os.path.join(destination_path, item.name)
    if not wanted_folder(filters=filters, folder_path=new_directory,
                         root=root):
        LOGGER.debug(f"Skipping the unwanted folder {new_directory} ...")
        return None
    os.makedirs(new_directory, exist_ok=True)
    return new_directory
def wanted_file(filters, file_path):
    if not file_path:
        return False
    if not filters or len(filters) == 0:
        return True
    for file_extension in filters:
        if re.search(f"{file_extension}$", file_path, re.IGNORECASE):
            return True
    LOGGER.debug(f"Skipping the unwanted file {file_path}")
    return False
    def _process_str(self, value: str, execute: bool = True) -> str:
        LOGGER.debug(f"Processando parse de string {value}...")

        if _ismultiplechoice(value):
            return self._process_multiple_choice(value)
        elif _ismethod(value):
            return self._process_method(value, execute)
        elif _isvariable(value):
            return self._process_variable(value)

        return value
def file_exists(item, local_file):
    if item and local_file and os.path.isfile(local_file):
        local_file_modified_time = int(os.path.getmtime(local_file))
        remote_file_modified_time = int(item.date_modified.timestamp())
        local_file_size = os.path.getsize(local_file)
        remote_file_size = item.size
        if (local_file_modified_time == remote_file_modified_time
                and local_file_size == remote_file_size):
            LOGGER.debug(
                f"No changes detected. Skipping the file {local_file} ...")
            return True
    return False
def prepare_root_destination(config):
    LOGGER.debug("Checking root destination ...")
    root_destination = DEFAULT_ROOT_DESTINATION
    config_path = ["app", "root"]
    if not traverse_config_path(config=config, config_path=config_path):
        LOGGER.warning(
            f"Warning: root destination is missing in {config_path_to_string(config_path)}."
            + f" Using default root destination: {root_destination}", )
    else:
        root_destination = get_config_value(config=config,
                                            config_path=config_path)
    root_destination_path = os.path.abspath(root_destination)
    os.makedirs(root_destination_path, exist_ok=True)
    return root_destination_path
def get_photos_remove_obsolete(config):
    photos_remove_obsolete = False
    config_path = ["photos", "remove_obsolete"]
    if not traverse_config_path(config=config, config_path=config_path):
        LOGGER.warning(
            f"Warning: remove_obsolete is not found in {config_path_to_string(config_path)}."
            + " Not removing the obsolete photos.")
    else:
        photos_remove_obsolete = get_config_value(config=config,
                                                  config_path=config_path)
        LOGGER.debug(
            f"{'R' if photos_remove_obsolete else 'Not R'}emoving obsolete photos ..."
        )
    return photos_remove_obsolete
def get_drive_remove_obsolete(config):
    drive_remove_obsolete = False
    config_path = ["drive", "remove_obsolete"]
    if not traverse_config_path(config=config, config_path=config_path):
        LOGGER.warning(
            f"Warning: remove_obsolete is not found in {config_path_to_string(config_path)}."
            + " Not removing the obsolete files and folders.")
    else:
        drive_remove_obsolete = get_config_value(config=config,
                                                 config_path=config_path)
        LOGGER.debug(
            f"{'R' if drive_remove_obsolete else 'Not R'}emoving obsolete files and folders ..."
        )
    return drive_remove_obsolete
def prepare_drive_destination(config):
    LOGGER.debug("Checking drive destination ...")
    config_path = ["drive", "destination"]
    drive_destination = DEFAULT_DRIVE_DESTINATION
    if not traverse_config_path(config=config, config_path=config_path):
        LOGGER.warning(
            f"Warning: destination is missing in {config_path_to_string(config_path)}."
            + f" Using default drive destination: {drive_destination}.")
    else:
        drive_destination = get_config_value(config=config,
                                             config_path=config_path)
    drive_destination_path = os.path.abspath(
        os.path.join(prepare_root_destination(config=config),
                     drive_destination))
    os.makedirs(drive_destination_path, exist_ok=True)
    return drive_destination_path
def prepare_photos_destination(config):
    LOGGER.debug("Checking photos destination ...")
    config_path = ["photos", "destination"]
    photos_destination = DEFAULT_PHOTOS_DESTINATION
    if not traverse_config_path(config=config, config_path=config_path):
        LOGGER.warning(
            f"Warning: destination is missing in {photos_destination}." +
            f" Using default photos destination: {config_path_to_string(config_path)}"
        )
    else:
        photos_destination = get_config_value(config=config,
                                              config_path=config_path)
    photos_destination_path = os.path.abspath(
        os.path.join(prepare_root_destination(config=config),
                     photos_destination))
    os.makedirs(photos_destination_path, exist_ok=True)
    return photos_destination_path
    def _process_variable(self, value: str) -> str:
        LOGGER.debug(f"Processando parse de variável {value}...")

        variables = value.split("$")[1:]

        if "self" == variables[0]:
            pass  # this method will be implemented on version 1.1.0
        elif "version" == variables[0]:
            pass  # this method will be implemented on version 1.1.0
        else:
            for variable in variables:
                var = variable.replace("/", "")
                v = self._change_value(self._search_variable(var))

                if _is_regex(v):
                    v = v.replace("^", "").replace("$", "")

                value = value.replace(f"${var}", v)

        return value
    def _process_method(self, value: str, execute: bool = True) -> str:
        LOGGER.debug(f"Processando parse método {value}...")

        method_definition = value.split("@")[1]
        method_name = method_definition[0:method_definition.find("(")]

        if method_name not in AVAILABLE_METHODS:
            raise MethodNotImplementedException()

        if "user_input" == method_name and self.action_execution.arguments:
            return self.action_execution.arguments[self.index_method_executed]

        original_arguments = method_definition[method_definition.find("(") +
                                               1:method_definition.find(")")]

        # refs.: https://stackoverflow.com/a/48838456/7973282
        parsed_arguments = eval("dict({})".format(original_arguments))

        parsed_arguments = {
            k: self._change_value(v)
            for k, v in parsed_arguments.items()
        }

        parsed_arguments["execute"] = execute

        parsed_arguments = ",".join([
            f"{k}='{v}'" if isinstance(v, str) else f"{k}={v}"
            for k, v in parsed_arguments.items()
        ])

        method_definition = f"{method_name}({parsed_arguments})"

        try:
            return eval(f"template_methods.{method_definition}")
        except TypeError as e:
            LOGGER.error(str(e))
            raise InvalidTemplateException()
    def _process_multiple_choice(self, value: str) -> str:
        LOGGER.debug(f"Processando parse de escolhas {value}...")

        begin = 0
        end = len(value)

        if value.startswith("("):
            begin = 1
        if value.endswith(")"):
            end = -1

        value = value[begin:end]

        if "user_input" in value and self.action_execution.arguments:
            index = self.index_method_executed
            self.index_method_executed += 1
            return self.action_execution.arguments[index]

        choices = {}
        choice_index = 1

        for choice in value.split(" or "):
            choices[str(choice_index)] = Choice(
                choice_index, choice, self._change_value(choice,
                                                         execute=False))

            choice_index += 1

        choice = select(
            "Escolha uma das opções abaixo:",
            choices=[f"{k}. {v.text}" for k, v in choices.items()],
        )

        user_choice = choices.get(
            choice.get("answer").split(".")[0]).choice_text

        return self._change_value(user_choice)
 def execute(self):
     LOGGER.debug("Not implemented yet!")
    def _process_dict(self, value: Dict, execute: bool = True) -> Dict:
        LOGGER.debug(f"Processando parse de dicionário {value}...")

        return {k: self._change_value(v, execute) for k, v in value.items()}
    def _process_list(self, value: List, execute: bool = True) -> List:
        LOGGER.debug(f"Processando parse de lista {value}...")

        return [self._change_value(item, execute) for item in value]