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