2020-03-19 20:04:10 +01:00
|
|
|
import yaml
|
|
|
|
import click
|
|
|
|
import importlib
|
2020-03-23 14:26:28 +01:00
|
|
|
import os
|
2020-03-23 08:32:15 +01:00
|
|
|
from collections import deque
|
|
|
|
|
2020-06-28 11:49:14 +02:00
|
|
|
class MigratioNotFound(Exception): ...
|
|
|
|
|
|
|
|
class MigrationVersion:
|
|
|
|
'''
|
|
|
|
The version used to migration
|
|
|
|
|
|
|
|
Arttribute:
|
|
|
|
name(str): version name like `1.0.0`
|
|
|
|
module: the python module object for a specific migration which contains migrate info, codes and templates
|
|
|
|
down_versions(list): previous versions that can migrated to this version
|
|
|
|
'''
|
|
|
|
def __init__(self, version: str):
|
|
|
|
self.name = version
|
|
|
|
self.module = importlib.import_module("migrations.version_{}".format(version.replace(".","_")))
|
|
|
|
|
|
|
|
@property
|
|
|
|
def down_versions(self):
|
|
|
|
return self.module.down_revisions
|
2020-03-19 20:04:10 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2020-06-28 11:49:14 +02:00
|
|
|
def search(input_version: str, target_version: str) -> list :
|
2020-03-20 08:20:32 +01:00
|
|
|
"""
|
2020-06-28 11:49:14 +02:00
|
|
|
Find the migration path by BFS
|
|
|
|
Args:
|
|
|
|
input_version(str): The version migration start from
|
|
|
|
target_version(str): The target version migrated to
|
|
|
|
Returns:
|
|
|
|
list: the module of migrations in the upgrade path
|
2020-03-20 08:20:32 +01:00
|
|
|
"""
|
2020-06-28 11:49:14 +02:00
|
|
|
upgrade_path = []
|
|
|
|
next_version, visited, q = {}, set(), deque()
|
|
|
|
q.append(target_version)
|
|
|
|
found = False
|
|
|
|
while q: # BFS to find a valid path
|
|
|
|
version = MigrationVersion(q.popleft())
|
|
|
|
visited.add(version.name)
|
|
|
|
if version.name == input_version:
|
|
|
|
found = True
|
|
|
|
break # break loop cause migration path found
|
|
|
|
for v in version.down_versions:
|
|
|
|
next_version[v] = version.name
|
|
|
|
if v not in (visited.union(q)):
|
|
|
|
q.append(v)
|
|
|
|
|
|
|
|
if not found:
|
|
|
|
raise MigratioNotFound('no migration path found to target version')
|
|
|
|
|
|
|
|
current_version = MigrationVersion(input_version)
|
|
|
|
while current_version.name != target_version:
|
|
|
|
current_version = MigrationVersion(next_version[current_version.name])
|
|
|
|
upgrade_path.append(current_version)
|
|
|
|
return list(map(lambda x: x.module, upgrade_path))
|