1#!/usr/bin/python3 2# 3# Copyright 2016-2021 The Khronos Group Inc. 4# 5# SPDX-License-Identifier: Apache-2.0 6 7# Retroactively insert markup in show both 1.1 core features and KHR 8# extensions they were promoted from. 9 10# Usage: promote.py [-overwrite] [-out dir] [-suffix str] files 11# -overwrite updates in place (can be risky, make sure there are backups) 12# -out specifies directory to create output file in, default 'out' 13# -suffix specifies suffix to add to output files, default '' 14# files are asciidoc source files from the Vulkan spec to reflow. 15 16# For error and file-loading interfaces only 17import argparse, copy, os, pdb, re, string, sys 18from reflib import * 19from promoted import * 20 21global anchor 22anchor = 0 23 24def anchorname(anchor): 25 return 'promoted-' + str(anchor) 26 27def printanchor(fp): 28 # Anchor index for navigation 29 global anchor 30 31 print('[[' + anchorname(anchor) + ']]', file=fp) 32 print('This anchor:', anchorname(anchor), file=fp) 33 print('<<' + anchorname(anchor+1) + ', OINK>>', file=fp) 34 anchor = anchor + 1 35 36# promote a core interface and include the extension it was promoted from 37# line - matching line with 1.1 interface 38# type - 'protos', 'structs', 'flags', 'enums' 39# name - interface name 40# extension - name of extension interface was promoted from 41# fp - output filename 42def promote(line, type, name, extension, fp): 43 if type == 'protos': 44 # printanchor(fp) 45 print('ifdef::VK_VERSION_1_1[]', file=fp) 46 print(line, file=fp, end='') 47 print('endif::VK_VERSION_1_1[]', file=fp) 48 print('', file=fp) 49 print('ifdef::VK_VERSION_1_1+' + extension + 50 '[or the equivalent command]', file=fp) 51 print('', file=fp) 52 print('ifdef::' + extension + '[]', file=fp) 53 print('include::../api/' + type + '/' + name + 'KHR.txt[]', file=fp) 54 print('endif::' + extension + '[]', file=fp) 55 del promoted[name] 56 elif type == 'structs' or type == 'enums' or type == 'flags' or type == 'handles': 57 # printanchor(fp) 58 print(line, file=fp, end='') 59 print('', file=fp) 60 print('ifdef::' + extension + '[]', file=fp) 61 print('or the equivalent', file=fp) 62 print('', file=fp) 63 print('include::../api/' + type + '/' + name + 'KHR.txt[]', file=fp) 64 print('endif::' + extension + '[]', file=fp) 65 del promoted[name] 66 else: 67 logWarn('Unrecognized promoted type', type, 'for interface', name) 68 print(line, file=fp, end='') 69 70 71def promoteFile(filename, args): 72 logDiag('promote: filename', filename) 73 74 lines = loadFile(filename) 75 if (lines == None): 76 return 77 78 # Output file handle and promote object for this file. There are no race 79 # conditions on overwriting the input, but it is not recommended unless 80 # you have backing store such as git. 81 82 if args.overwrite: 83 outFilename = filename 84 else: 85 outFilename = args.outDir + '/' + os.path.basename(filename) + args.suffix 86 87 try: 88 fp = open(outFilename, 'w', encoding='utf8') 89 True 90 except: 91 logWarn('Cannot open output file', filename, ':', sys.exc_info()[0]) 92 return None 93 94 lineno = 0 95 for line in lines: 96 lineno = lineno + 1 97 98 matches = includePat.search(line) 99 if matches != None: 100 type = matches.group('type') 101 name = matches.group('name') 102 if name in promoted: 103 extension = promoted[name]['extension'] 104 if extension: 105 # Promote core interface 106 promote(line, type, name, promoted[name]['extension'], fp) 107 continue 108 # Fallthrough 109 print(line, file=fp, end='') 110 111 fp.close() 112 113def promoteAllAdocFiles(folder_to_promote, args): 114 for root, subdirs, files in os.walk(folder_to_promote): 115 for file in files: 116 if file.endswith(".txt"): 117 file_path = os.path.join(root, file) 118 promoteFile(file_path, args) 119 for subdir in subdirs: 120 sub_folder = os.path.join(root, subdir) 121 print('Sub-folder = %s' % sub_folder) 122 if not (subdir.lower() == "scripts") and not (subdir.lower() == "style"): 123 print(' Parsing = %s' % sub_folder) 124 promoteAllAdocFiles(sub_folder, args) 125 else: 126 print(' Skipping = %s' % sub_folder) 127 128# Patterns used to recognize interesting lines in an asciidoc source file. 129# These patterns are only compiled once. 130 131if __name__ == '__main__': 132 parser = argparse.ArgumentParser() 133 134 parser.add_argument('-diag', action='store', dest='diagFile', 135 help='Set the diagnostic file') 136 parser.add_argument('-warn', action='store', dest='warnFile', 137 help='Set the warning file') 138 parser.add_argument('-log', action='store', dest='logFile', 139 help='Set the log file for both diagnostics and warnings') 140 parser.add_argument('-overwrite', action='store_true', 141 help='Overwrite input filenames instead of writing different output filenames') 142 parser.add_argument('-out', action='store', dest='outDir', 143 default='out', 144 help='Set the output directory in which updated files are generated (default: out)') 145 parser.add_argument('-suffix', action='store', dest='suffix', 146 default='', 147 help='Set the suffix added to updated file names (default: none)') 148 parser.add_argument('files', metavar='filename', nargs='*', 149 help='a filename to promote text in') 150 parser.add_argument('--version', action='version', version='%(prog)s 1.0') 151 152 args = parser.parse_args() 153 154 setLogFile(True, True, args.logFile) 155 setLogFile(True, False, args.diagFile) 156 setLogFile(False, True, args.warnFile) 157 158 if args.overwrite: 159 logWarn('promote.py: will overwrite all input files') 160 161 # If no files are specified, promote the entire specification chapters folder 162 if len(args.files) == 0: 163 folder_to_promote = os.getcwd() 164 folder_to_promote += '/chapters' 165 promoteAllAdocFiles(folder_to_promote, args) 166 else: 167 for file in args.files: 168 promoteFile(file, args) 169 170 print('At end, promoted interfaces remaining:') 171 for key in promoted: 172 if promoted[key]['extension'] != None: 173 print('\t' + key) 174