xref: /aosp_15_r20/tools/doc_generation/switcher4.py (revision d62711e4cc089316f3222ca133eddbbd1a97649b)
1# Copyright 2019 - The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15###############################################################################
16# This script adds a HTML snippet to the generated reference docs located at
17# developer.android.com/reference.  The snippet renders HTML that adds links to
18# toggle between the Java and Kotlin versions of the page.
19###############################################################################
20
21import getopt
22import os
23import sys
24
25
26# GLOBAL FLAGS
27
28global stubs
29global java_stubs, kotlin_stubs
30global work, verbose, show_solo, max_stubs
31global java_source_abs_path
32global kotlin_source_abs_path
33
34verbose = False  # set True to list all files as they are stubbed (--verbose)
35work = False  # set True to insert stubs, False to do a dry run for stats (--work)
36show_solo = False  # set True to list files that only appear in one language, rather than both (--solo)
37max_stubs = 0  # set positive to create a limited number of stubs (--max 12)
38
39
40# You must run the script from the refodcs reference/ root directory
41
42java_ref_root = os.getcwd()
43kotlin_ref_root = os.path.join(java_ref_root, "kotlin")
44root = os.path.split(java_ref_root)[1]
45if root != "reference":
46  print("You must cd to the refocs reference/ root directory")
47  sys.exit()
48
49
50# This method inserts the language switcher into the two top-level Android
51# Platform pages: packages.html and classes.html
52# For both Java and Kotlin
53def insert_platform_summaries():
54  global stubs
55  global java_stubs, kotlin_stubs
56  global verbose, work, show_solo
57  global java_source_abs_path
58  global kotlin_source_abs_path
59
60  stubs = 0
61  java_stubs = 0
62  kotlin_stubs = 0
63
64  java_source_abs_path = java_ref_root
65  kotlin_source_abs_path = kotlin_ref_root
66  insert_stub(os.path.join(java_ref_root, "packages.html"), True, True)
67  insert_stub(os.path.join(kotlin_ref_root, "packages.html"), False, True)
68
69  insert_stub(os.path.join(java_ref_root, "classes.html"), True, True)
70  insert_stub(os.path.join(kotlin_ref_root, "classes.html"), False, True)
71
72# This method uses switcher2, which assumes the refdocs stay in their current
73# assymetrical dirs (ref/android and ref/kotlin/android)
74# And just puts the switcher in the existing docs
75def insert_stub(doc, java, both):
76  global stubs
77  global java_stubs, kotlin_stubs
78  global verbose, work, show_solo
79  global java_source_abs_path
80  global kotlin_source_abs_path
81
82  stubs = stubs+1
83
84  if verbose:
85    print("File: ", stubs, doc)
86  else:
87    fn  = os.path.split(doc)
88    print("File: ", stubs, fn[1], end="\r")
89
90  if (java):
91    java_stubs = java_stubs + 1
92  else:
93    kotlin_stubs = kotlin_stubs + 1
94
95  if (work):
96    with open(doc, "r") as f:
97      file_content = f.read()
98
99    if (java):
100      file_path = doc[len(java_ref_root) + 1 :]
101      if (both):
102        file_content = file_content.replace(
103            "</h1>",
104            "</h1>\n{% setvar page_path %}_page_path_{% endsetvar %}\n{% setvar"
105            " can_switch %}1{% endsetvar %}\n{% include"
106            ' "reference/_java_switcher2.md" %}',
107        )
108        file_content = file_content.replace("_page_path_", file_path)
109      else:
110        file_content = file_content.replace(
111            "</h1>", '</h1>\n{% include "reference/_java_switcher2.md" %}'
112        )
113    else:
114      file_path = doc[len(kotlin_ref_root) + 1 :]
115      if (both):
116        file_content = file_content.replace(
117            "</h1>",
118            "</h1>\n{% setvar page_path %}_page_path_{% endsetvar %}\n{% setvar"
119            " can_switch %}1{% endsetvar %}\n{% include"
120            ' "reference/_kotlin_switcher2.md" %}',
121        )
122        file_content = file_content.replace("_page_path_", file_path)
123      else:
124        file_content = file_content.replace(
125            "</h1>", '</h1>\n{% include "reference/_kotlin_switcher2.md" %}'
126        )
127
128    with open(doc, "w") as f:
129      f.write(file_content)
130    os.chmod(doc, 0o644)
131
132
133def scan_files(stem):
134  global work, verbose, show_solo, max_stubs
135  global stubs
136  global java_stubs, kotlin_stubs
137  global java_source_abs_path
138  global kotlin_source_abs_path
139
140  java_source_abs_path = os.path.join(java_ref_root, stem)
141  kotlin_source_abs_path = os.path.join(kotlin_ref_root, stem)
142
143  # Pass 1
144  # Loop over java content, create stubs for java,
145  # and for corresponding Kotlin (when it exsits)
146
147  # solo is java-only classes
148  # both is java+kotlin
149  stubs = 0
150  java_stubs = 0
151  kotlin_stubs = 0
152  solo = 0
153  both = 0
154
155  print("*** PASS1 (Java) ***")
156  maxed_out = False
157  for root, dirs, files in os.walk(java_source_abs_path):
158      if maxed_out:
159        break;
160      for file_ in files:
161        ext = os.path.splitext(file_)
162        ext = ext[1]
163        if not ext:
164          # this catches package-lists with no extension
165          print("***", os.path.join(root, file_))
166        elif ext != ".html":
167          # filter out png, yaml, etc
168          continue
169        else:
170          # we have java content
171          doc = os.path.join(root, file_)
172
173
174
175          # look for matching kotlin file
176          kotlinsource = doc.replace(java_source_abs_path, kotlin_source_abs_path)
177          if os.path.isfile(kotlinsource):
178             # corresponding kotlin content exists
179             insert_stub(doc, True, True)
180             insert_stub(kotlinsource, False, True)
181             both = both+1
182          else:
183            # no kotlin content
184            if (show_solo):
185              print("solo: ", doc)
186            insert_stub(doc, True, False)
187            solo = solo+1
188
189          if max_stubs>0 and stubs>=max_stubs:
190            print()
191            print("max java stubs: ", max_stubs)
192            maxed_out = True;
193            break
194
195  print("Java+Kotlin:", both, "Only Java:", solo)
196  print()
197
198
199  # PASS 2
200  # Loop over kotlin content, create stubs for Kotlin-only APIs
201  print("*** PASS2 (Kotlin) ***")
202  solo = 0
203  both = 0
204  maxed_out = False
205  stubs = 0
206  for root, dirs, files in os.walk(kotlin_source_abs_path):
207      if maxed_out:
208        break;
209      for file_ in files:
210        ext = os.path.splitext (file_)
211        ext = ext[1]
212        if not ext:
213          # this catches package-lists with no extension
214          print("***", os.path.join(root, file_))
215        elif ext != ".html":
216          # filter out png, yaml, etc
217          continue
218        else:
219          # we have kotlin content
220          doc = os.path.join(root, file_)
221          javadoc = doc.replace(kotlin_source_abs_path, java_source_abs_path)
222          file_name = os.path.splitext(file_)[0]
223          file_path = doc[len(kotlin_source_abs_path)+1:]
224          include_path = os.path.join("/reference/_kotlin", file_path)
225
226          if os.path.isfile(javadoc):
227             # corresponding java content exists
228             # so we already created the kotlin stub file
229             # nothing to do
230             both = both+1
231          else:
232            # no java content
233            # create the kotlin stub file
234            if (show_solo):
235              print("solo: ", doc)
236            insert_stub(doc , False, False)
237            solo = solo+1
238
239          if (max_stubs>0 and stubs>=max_stubs):
240            print()
241            print("max koltin stubs: ", max_stubs)
242            maxed_out = True;
243            break
244
245
246  print("Java+Kotlin:", both, "Only Kotlin:", solo)
247  print()
248  print("Java: ", java_stubs, " Kotlin: ", kotlin_stubs, "Total: ", java_stubs + kotlin_stubs)
249
250
251def main(argv):
252
253  global work, verbose, show_solo, max_stubs
254  global java_source_abs_path
255  global kotlin_source_abs_path
256  stem = ""
257
258  try:
259    opts, args = getopt.getopt(argv,"",["work","verbose","solo","max="])
260  except getopt.GetoptError:
261    print('USAGE: switcher --work --verbose --solo --max=<max_stubs> platform|androidx|support|chrome')
262    sys.exit(2)
263
264  for opt, arg in opts:
265    if opt == '--work':
266       work = True
267    elif opt == "--verbose":
268       print("verbose")
269       verbose = True
270    elif opt == "--solo":
271       print("verbose")
272       show_solo = True
273    elif opt == "--max":
274       max_stubs = int(arg)
275       print("max ", max_stubs)
276
277  if len(args)>0:
278    source = args[0]
279    if source == "platform":
280      stem = "android"
281      print()
282      print("*** PLATFORM PAGES ***")
283      print("======================")
284
285      # Insert the switchers at the top level first
286      insert_platform_summaries()
287
288    elif source == "androidx":
289      stem = "androidx"
290      print()
291      print("*** ANDROIDX SUPPORT LIBRARY PAGES ***")
292      print("======================================")
293
294    elif source == "support":
295      stem = "android/support/v4/media"
296      print()
297      print("*** ANDROIDX SUPPORT LIBRARY PAGES ***")
298      print("======================================")
299
300    elif source == "chrome":
301      stem = "org/chromium/support_lib_boundary"
302      print()
303      print("*** ANDROIDX CHROMIUM PAGES ***")
304      print("===============================")
305
306  if (len(stem)>0):
307    scan_files(stem)
308    print(" *** DONE ***")
309  else:
310      print('You must specify one of: platform|androidx|support|chrome')
311
312
313
314if __name__ == "__main__":
315   main(sys.argv[1:])
316
317