-
-
Notifications
You must be signed in to change notification settings - Fork 665
/
create_monorepo.py
137 lines (106 loc) · 3.68 KB
/
create_monorepo.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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python3
import glob
import os
import subprocess
TREZOR_REPO = "https://github.com/trezor"
NAME="monorepo"
MAIN_REPO = "trezor-core"
SUBREPOS = {
"trezor-common": "common",
"trezor-crypto": "crypto",
"trezor-mcu": "legacy",
"trezor-storage": "storage",
"python-trezor": "python",
}
PUBLISHED_SUBREPOS = ["trezor-common", "trezor-crypto"]
KEEP_TAGS = ["trezor-core", "trezor-mcu", "python-trezor"]
GITSUBREPO_TEMPLATE = """\
; DO NOT EDIT (unless you know what you are doing)
;
; This subdirectory is a git "subrepo", and this file is maintained by the
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
;
[subrepo]
remote = git+ssh://[email protected]/trezor/{remote}
branch = main
commit = {remote_head}
parent = {current_head}
method = rebase
cmdver = 0.4.0
"""
def lines(s):
yield from s.strip().split("\n")
def git(args):
print("+ git:", args)
return subprocess.check_output("git " + args, universal_newlines=True, shell=True)
def move_to_subtree(remote, dst):
os.makedirs(dst, exist_ok=True)
for fn in lines(git(f"ls-tree --name-only remotes/{remote}/main")):
if fn == ".gitmodules":
continue
git(f"mv {fn} {dst}/{fn}")
def rewrite_gitmodules(remote, dst):
main_gitmodules = git("show main:.gitmodules")
try:
gitmodules = git(f"show {remote}/main:.gitmodules")
except:
# no gitmodules
return
gitmodules = gitmodules.replace('submodule "', f'submodule "{dst}/')
with open(".gitmodules", "w") as f:
f.write(main_gitmodules + gitmodules)
git("add .gitmodules")
def merge_remote(remote, dst):
git(f"remote add {remote} {TREZOR_REPO}/{remote}")
git(f"fetch {remote}")
try:
git(f"merge --no-commit --allow-unrelated-histories {remote}/main")
except:
# this might fail because of .gitmodules conflict
pass
rewrite_gitmodules(remote, dst)
move_to_subtree(remote, dst)
def retag_remote(remote, dst):
for tagline in lines(git(f"ls-remote -t {remote}")):
commit, tagpath = tagline.split()
tagname = os.path.basename(tagpath)
git(f"tag {dst}/{tagname} {commit}")
git(f"tag -d {tagname}")
def generate_subrepo_file(remote):
current_head = git("rev-parse main").strip()
remote_head = git(f"rev-parse {remote}/main").strip()
dst = SUBREPOS[remote]
with open(f"{dst}/.gitrepo", "w") as f:
f.write(GITSUBREPO_TEMPLATE.format(remote=remote, current_head=current_head, remote_head=remote_head))
git(f"add {dst}/.gitrepo")
def main():
git(f"clone {TREZOR_REPO}/{MAIN_REPO} {NAME}")
os.chdir(NAME)
move_to_subtree("origin", "core")
git(f"commit -m 'MONOREPO CREATE FROM {MAIN_REPO}'")
retag_remote("origin", "core")
for remote, dst in SUBREPOS.items():
merge_remote(remote, dst)
if remote in PUBLISHED_SUBREPOS:
with open(f"{dst}/.gitmodules", "w") as f:
f.write(git(f"show {remote}/main:.gitmodules"))
git(f"add {dst}/.gitmodules")
git(f"commit -m 'MONOREPO MERGE {remote}'")
try:
retag_remote(remote, dst)
except:
pass
for submodule in glob.glob("*/vendor/*"):
modname = os.path.basename(submodule)
if modname not in SUBREPOS:
continue
git(f"rm {submodule}")
symlink_target = f"../../{SUBREPOS[modname]}"
os.symlink(symlink_target, submodule)
git(f"add {submodule}")
git(f"commit -m 'MONOREPO RELINK SUBMODULES'")
for remote in PUBLISHED_SUBREPOS:
generate_subrepo_file(remote)
git(f"commit -m 'MONOREPO SUBREPO FILES'")
if __name__ == "__main__":
main()