-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmigratree.py
78 lines (60 loc) · 1.85 KB
/
migratree.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# -*- coding: utf-8 -*-
"""
Generate the dependency tree of the migrations for a given Django application
"""
import os
import itertools
import glob
from importlib import import_module
def import_dependencies(filepath):
module_name = os.path.splitext(filepath)[0].replace('/', '.')
module = import_module(module_name)
if hasattr(module, 'Migration') and hasattr(module.Migration, 'dependencies'):
dependencies = [x[1] for x in module.Migration.dependencies]
else:
dependencies = []
return dependencies
def node_name(filepath):
return os.path.splitext(os.path.basename(filepath))[0]
def product(f, deps):
# The root has no deps
if len(deps) == 0:
return [(f, 'None',)]
else:
return list(itertools.product([f], deps))
def make_graph(app):
"""
Read the depedencies and store them in a dictionary
"""
graph = {}
migration_files = sorted(glob.glob(os.path.join(app, 'migrations', '0*.py')))
for f in migration_files:
dependencies = import_dependencies(f)
graph[node_name(f)] = dependencies
return graph
def make_pairs(graph):
"""
{A: [B, C]} -> [(A, B), (A, C)]
"""
return [product(f, deps) for f, deps in graph.items()]
def make_dot(pairs):
data = '\n'.join("m{1} -> m{0}".format(e[0], e[1]) for e in itertools.chain(*pairs))
dot = 'digraph g {\n'
dot += data
dot += '\n}'
return dot
def save_dot_file(filename, dot):
with open(filename, 'w') as f:
f.write(dot)
print('Saved the file {}'.format(filename))
def generate_graph(app, filename=''):
"""
Save the dependency graph of the migrations for the specified app
in a dot file.
"""
graph = make_graph(app)
pairs = make_pairs(graph)
dot = make_dot(pairs)
if not filename:
filename = app + '.dot'
save_dot_file(filename, dot)