import yaml
import click
import importlib
import os
from collections import deque

from migrations import MIGRATION_BASE_DIR

def read_conf(path):
    with open(path) as f:
        try:
            d = yaml.safe_load(f)
        except Exception as e:
            click.echo("parse config file err, make sure your harbor config version is above 1.8.0", e)
            exit(-1)
    return d

def _to_module_path(ver):
    return "migrations.version_{}".format(ver.replace(".","_"))

def search(input_ver: str, target_ver: str) -> deque :
    """
    Search accept a input version and the target version.
    Returns the module of migrations in the upgrade path
    """
    upgrade_path, visited = deque(), set()
    while True:
        module_path = _to_module_path(target_ver)
        visited.add(target_ver)  # mark current version for loop finding
        if os.path.isdir(os.path.join(MIGRATION_BASE_DIR, 'version_{}'.format(target_ver.replace(".","_")))):
            module = importlib.import_module(module_path)
            if module.revision == input_ver:    # migration path found
                break
            elif module.down_revision is None:  # migration path not found
                raise Exception('no migration path found')
            else:
                upgrade_path.appendleft(module)
                target_ver = module.down_revision
                if target_ver in visited: # version visited before, loop found
                    raise Exception('find a loop caused by {} on migration path'.format(target_ver))
        else:
            raise Exception('{} not dir'.format(os.path.join(MIGRATION_BASE_DIR, 'versions', target_ver.replace(".","_"))))
    return upgrade_path

import yaml
import click
import importlib
import os
from collections import deque

from migrations import MIGRATION_BASE_DIR

def read_conf(path):
    with open(path) as f:
        try:
            d = yaml.safe_load(f)
        except Exception as e:
            click.echo("parse config file err, make sure your harbor config version is above 1.8.0", e)
            exit(-1)
    return d

def _to_module_path(ver):
    return "migrations.version_{}".format(ver.replace(".","_"))

def search(input_ver: str, target_ver: str) -> deque :
    """
    Search accept a input version and the target version.
    Returns the module of migrations in the upgrade path
    """
    upgrade_path, visited = deque(), set()
    while True:
        module_path = _to_module_path(target_ver)
        visited.add(target_ver)  # mark current version for loop finding
        if os.path.isdir(os.path.join(MIGRATION_BASE_DIR, 'version_{}'.format(target_ver.replace(".","_")))):
            module = importlib.import_module(module_path)
            if module.revision == input_ver:    # migration path found
                break
            elif module.down_revision is None:  # migration path not found
                raise Exception('no migration path found')
            else:
                upgrade_path.appendleft(module)
                target_ver = module.down_revision
                if target_ver in visited: # version visited before, loop found
                    raise Exception('find a loop caused by {} on migration path'.format(target_ver))
        else:
            raise Exception('{} not dir'.format(os.path.join(MIGRATION_BASE_DIR, 'versions', target_ver.replace(".","_"))))
    return upgrade_path

Search accept a input version and the target version.     Returns the module of migrations in the upgrade path # mark current version for loop finding # migration path found # migration path not found # version visited before, loop found