This repository has been archived by the owner on Sep 12, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
grabrepos.py
executable file
·232 lines (208 loc) · 9.08 KB
/
grabrepos.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This python script will clone all repos defined in "multiversion.yml".
# It checks out all version tags (starting with "v") and grab all files matching
# the given file pattern. The files are prefixed with the version and added
# to the docs directory.
#
# A version switcher html code is generated and prepended to all copied files.
#
# License: Public domain
# Author: David Graeff <[email protected]>
import yaml
import io
import os
import re
import fnmatch
import shutil
import difflib
from git import Repo,Git
def readyaml():
with open("multiversion.yml", 'r') as stream:
try:
content = yaml.load(stream)
return content
except yaml.YAMLError as exc:
print(exc)
exit(-1)
# Split a markdown content by its 2nd level headings and return the array
def split_by_headings(data):
sections = []
index = 0
while True:
index = data.find("\n## ", index)
if index == -1:
break
nextindex = data.find("\n## ", index+1)
if nextindex == -1:
sections.append(data[index:])
break
else:
sections.append(data[index:nextindex])
index = nextindex
return sections
# Filter the given array with markdown 2nd level headings.
# Keep everything that is mentioned in "keepsections".
def filter_by_headings(sections, keepsections):
newsections = []
if len(keepsections)==0: return newsections
for section in sections:
for keep in keepsections:
if section.startswith("\n## "+keep):
newsections.append(section.strip())
return newsections
def remaining_headings(sections, removesections):
newsections = []
if len(removesections)==0: return newsections
for section in sections:
found = False
for keep in removesections:
if section.startswith("\n## "+keep):
found = True
if not found:
newsections.append(section.strip())
return newsections
# Create a destination filename, given the repo name ("core","ota" etc),
# and the tag name ("master","v2.0").
def dest_filepath(reponame, refname):
reponame = reponame.replace(" ","-").lower()
return "spec-"+reponame+"-"+refname.replace(".","_")
# Copy files to "docs/". Filter sections of file first. Add generated header to file.
def write_file(reponame, targetdir, srcdir, keepsections, filename, data, tagname, date, absurl):
sections = split_by_headings(data)
sections = filter_by_headings(sections, keepsections)
if len(sections)<=0:
return
# Generate version select box html code
# Hide page in the left nav panel if not the latest
header = "---\n"
header += "path: "+absurl+"\n"
header += "source: "+filename+"\n"
header += "version: "+tagname+"\n"
header += "releasedate: "+date.strftime("%d. %B %Y")+"\n"
header += "convention: "+reponame+"\n"
header += "layout: specification\n"
header += "---\n"
# New file content and filename
filecontent = header + "\n".join(sections)
filepath = os.path.join(targetdir,dest_filepath(reponame, tagname)+".md")
with open(filepath, "w") as text_file:
text_file.write(filecontent)
print("Wrote file: "+filepath)
def write_preface(tagname,reponame,repourl,localpath,keepsections):
filepath = os.path.join(localpath,"convention.md")
with open(filepath, 'r') as myfile:
localdata = myfile.read() + "\n"
sections = split_by_headings(localdata)
sections = remaining_headings(sections, keepsections)
absurl = repourl.replace(".git","")+"/tree/" + tagname
header = "---\n"
header += "path: "+absurl+"\n"
header += "source: convention.md\n"
header += "convention: "+reponame+"\n"
header += "preface: true\n"
header += "---\n"
filecontent = header + "\n".join(sections)
filepath = os.path.join(targetdir,"preface",dest_filepath(reponame, tagname)+".md")
prefacedir = os.path.join(targetdir,"preface")
if not os.path.exists(prefacedir):
os.makedirs(prefacedir)
with open(filepath, "w") as text_file:
text_file.write(filecontent)
print("Wrote file: "+filepath)
def write_diff_file(targetdir,reponame,ref,nextref):
outputfilename = dest_filepath(reponame, nextref.name)+"-diff.html"
header = "---\n"
header += "convention: "+reponame+"\n"
header += "oldfile: "+dest_filepath(reponame, ref.name)+".md\n"
header += "newfile: "+dest_filepath(reponame, nextref.name)+".md\n"
header += "oldversion: "+ref.name+"\n"
header += "newversion: "+nextref.name+"\n"
header += "diff: true\n"
header += "type: page\n"
header += "layout: diff\n"
header += "---\n"
with open(os.path.join(targetdir,dest_filepath(reponame, ref.name)+".md"), 'r') as firstfile:
with open(os.path.join(targetdir,dest_filepath(reponame, nextref.name)+".md"), 'r') as secondfile:
diff = difflib.HtmlDiff().make_table(firstfile.read().split("\n"),secondfile.read().split("\n"),ref.name,nextref.name,True,0)
with open(os.path.join(targetdir,outputfilename), "w") as outputfile:
outputfile.write(header+diff.replace("nowrap=\"nowrap\"","").replace(" "," "))
print("Wrote file: "+os.path.join(targetdir,outputfilename))
# Clone a repository url (or update repo), checkout all tags.
# Call copy_files for each checked out working directory
def checkout_repo(targetdir, reponame, repourl, filepattern, checkoutdir, keepsections, update_repos):
localpath = os.path.join(checkoutdir,reponame)
if os.path.exists(localpath):
repo = Repo(localpath)
if update_repos:
print("Updating "+reponame)
repo.remotes.origin.fetch()
else:
print("Clone "+reponame+" to "+localpath)
repo = Repo.clone_from(repourl, localpath)
# Add "develop" and all tags
refs = []
refs.append(repo.heads.develop)
refs.extend(repo.tags)
# Get all preface sections from the latest develop version
repo.head.reference = repo.heads.develop
repo.head.reset(index=True, working_tree=True)
write_preface(repo.head.reference.name,reponame,repourl,localpath,keepsections)
g = Git(localpath)
# Combine all files of a repo and create one specificaton file out of it
for ref in refs:
repo.head.reference = ref
repo.head.reset(index=True, working_tree=True)
data = ""
mainfile = ""
for filename in fnmatch.filter(os.listdir(localpath), filepattern):
filepath = os.path.join(localpath,filename)
with open(filepath, 'r') as myfile:
localdata = myfile.read() + "\n"
# Check if the file has relevant sections
sections = split_by_headings(localdata)
sections = filter_by_headings(sections, keepsections)
if len(sections)<=0:
continue
data += localdata
mainfile = filename
tagname = ref.name
date = ref.commit.committed_datetime
absurl = repourl.replace(".git","")+"/tree/"+ref.name
write_file(reponame, targetdir, localpath, keepsections, mainfile, data, tagname, date, absurl)
refs = []
refs.extend(repo.tags)
refs.append(repo.heads.develop)
for ref, nextref in zip(refs[:-1], refs[1:]):
write_diff_file(targetdir,reponame,ref, nextref)
hexshas = g.log("--pretty=format:|%s|%ai|%h|", ref.name+".."+nextref.name).split('\n')
changefilename = dest_filepath(reponame, nextref.name)+"-changes.md"
with open(os.path.join(targetdir,changefilename), "w") as outputfile:
header = "---\n"
header += "convention: "+reponame+"\n"
header += "oldfile: "+dest_filepath(reponame, ref.name)+".md\n"
header += "newfile: "+dest_filepath(reponame, nextref.name)+".md\n"
header += "oldversion: "+ref.name+"\n"
header += "newversion: "+nextref.name+"\n"
header += "changes: true\n"
header += "---\n| Commit title | Date | Hash |\n|---|---|---|\n"
outputfile.write(header+"\n".join(hexshas))
print("Wrote file: "+os.path.join(targetdir,changefilename))
def recreate_dir(file_path, clean):
directory = os.path.abspath(file_path)
if clean and os.path.exists(directory):
shutil.rmtree(directory)
if not os.path.exists(directory):
os.makedirs(directory)
return directory
# Main program
controlfile = readyaml()
checkoutdir = recreate_dir("temp", "clean" in controlfile and controlfile["clean"])
targetdir = os.path.abspath("content/specification")
update_repos = "updaterepos" in controlfile and controlfile["updaterepos"]
if os.path.exists(targetdir):
shutil.rmtree(targetdir)
os.makedirs(targetdir)
for entry in controlfile['specifications']:
if not 'disabled' in entry or not entry['disabled']:
checkout_repo(targetdir, entry['name'], entry['repo'], entry['filepattern'],checkoutdir, entry['keepsections'], update_repos)