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