-
Notifications
You must be signed in to change notification settings - Fork 6.4k
/
auto_link_to_docs.py
executable file
·144 lines (110 loc) · 3.78 KB
/
auto_link_to_docs.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
#!/usr/bin/env python
# Copyright 2013 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Process docs-links.json and updates all READMEs and replaces
<!-- auto-doc-link --><!-- end-auto-doc-link -->
With a generated list of documentation backlinks.
"""
from collections import defaultdict
import json
import os
import re
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
DOC_SITE_ROOT = "https://cloud.google.com"
AUTO_DOC_LINK_EXP = re.compile(
r"<!-- auto-doc-link -->.*?<!-- end-auto-doc-link -->\n", re.DOTALL
)
def invert_docs_link_map(docs_links):
"""
The docs links map is in this format:
{
"doc_path": [
"file_path",
]
}
This transforms it to:
{
"file_path": [
"doc_path",
]
}
"""
files_to_docs = defaultdict(list)
for doc, files in docs_links.iteritems():
for file in files:
files_to_docs[file].append(doc)
files_to_docs[file] = list(set(files_to_docs[file]))
return files_to_docs
def collect_docs_for_readmes(files_to_docs):
"""
There's a one-to-many relationship between readmes and files. This method
finds the readme for each file and consolidates all docs references.
"""
readmes_to_docs = defaultdict(list)
for file, docs in files_to_docs.iteritems():
readme = get_readme_path(file)
readmes_to_docs[readme].extend(docs)
readmes_to_docs[readme] = list(set(readmes_to_docs[readme]))
return readmes_to_docs
def linkify(docs):
"""Adds the documentation site root to doc paths, creating a full URL."""
return [DOC_SITE_ROOT + x for x in docs]
def replace_contents(file_path, regex, new_content):
with open(file_path, "r+") as f:
content = f.read()
content = regex.sub(new_content, content)
f.seek(0)
f.write(content)
def get_readme_path(file_path):
"""Gets the readme for an associated sample file, basically just the
README.md in the same directory."""
dir = os.path.dirname(file_path)
readme = os.path.join(REPO_ROOT, dir, "README.md")
return readme
def generate_doc_link_statement(docs):
links = linkify(docs)
if len(links) == 1:
return """<!-- auto-doc-link -->
These samples are used on the following documentation page:
> {}
<!-- end-auto-doc-link -->
""".format(
links.pop()
)
else:
return """<!-- auto-doc-link -->
These samples are used on the following documentation pages:
>
{}
<!-- end-auto-doc-link -->
""".format(
"\n".join(["* {}".format(x) for x in links])
)
def update_readme(readme_path, docs):
if not os.path.exists(readme_path):
print("{} doesn't exist".format(readme_path))
return
replace_contents(readme_path, AUTO_DOC_LINK_EXP, generate_doc_link_statement(docs))
print("Updated {}".format(readme_path))
def main():
docs_links = json.load(
open(os.path.join(REPO_ROOT, "scripts", "resources", "docs-links.json"), "r")
)
files_to_docs = invert_docs_link_map(docs_links)
readmes_to_docs = collect_docs_for_readmes(files_to_docs)
for readme, docs in readmes_to_docs.iteritems():
update_readme(readme, docs)
if __name__ == "__main__":
main()