1#!/usr/bin/env python 2# 3# SPDX-License-Identifier: GPL-2.0-only 4# 5# documentation.conf update script 6# 7# Author: Paul Eggleton <paul.eggleton@linux.intel.com> 8# 9# Copyright (C) 2015 Intel Corporation 10# 11 12 13import sys 14import os 15import argparse 16import re 17from lxml import etree 18import logging 19 20def logger_create(name): 21 logger = logging.getLogger(name) 22 loggerhandler = logging.StreamHandler() 23 loggerhandler.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) 24 logger.addHandler(loggerhandler) 25 logger.setLevel(logging.INFO) 26 return logger 27logger = logger_create('docconfupdater') 28 29def main(): 30 parser = argparse.ArgumentParser(description="documentation.conf updater") 31 parser.add_argument('basepath', help='Path to OE-Core base directory') 32 parser.add_argument('-q', '--quiet', help='Print only warnings/errors', action='store_true') 33 34 args = parser.parse_args() 35 36 if args.quiet: 37 logger.setLevel(logging.WARN) 38 39 if not os.path.isdir(args.basepath): 40 logger.error('Specified base path %s not found') 41 return 1 42 43 doc_conf = os.path.join(args.basepath, 'meta', 'conf', 'documentation.conf') 44 if not os.path.exists(doc_conf): 45 logger.error('Unable to find %s' % doc_conf) 46 return 1 47 48 allowed_flags = ['doc'] 49 flag_re = re.compile(r'\[(.+?)\]') 50 51 infos = {} 52 tree = etree.parse('ref-manual/ref-variables.xml') 53 root = tree.getroot() 54 for glossary in root.findall('glossary'): 55 for glossdiv in glossary.findall('glossdiv'): 56 for glossentry in glossdiv.findall('glossentry'): 57 info = glossentry.find('info') 58 if info is not None: 59 infoline = ' '.join(info.text.split()) 60 infolinesplit = infoline.split('=', 1) 61 if len(infoline) < 2: 62 logger.warn('Invalid info line (no = character), ignoring: %s' % infoline) 63 continue 64 flags = flag_re.findall(infolinesplit[0]) 65 if not flags: 66 logger.warn('Invalid info line (no varflag), ignoring: %s' % infoline) 67 continue 68 for flag in flags: 69 if flag not in allowed_flags: 70 logger.warn('Invalid info line (varflag %s not in allowed list), ignoring: %s' % (flag, infoline)) 71 continue 72 infos[infolinesplit[0].rstrip()] = infolinesplit[1].lstrip() 73 74 if not infos: 75 logger.error('ERROR: Unable to find any info tags in the glossary') 76 return 1 77 78 def sortkey(key): 79 # Underscores sort undesirably, so replace them 80 return key.split('[')[0].replace('_', '-') 81 82 changed = False 83 lines = [] 84 invars = False 85 lastletter = None 86 added = [] 87 with open(doc_conf, 'r') as dcf: 88 for line in dcf: 89 if not invars: 90 if line.startswith('#') and 'DESCRIPTIONS FOR VARIABLES' in line: 91 invars = True 92 elif not line.startswith('#'): 93 linesplit = line.split('=', 1) 94 if len(linesplit) > 1: 95 key = linesplit[0].rstrip() 96 lastletter = key[0] 97 # Find anything in the dict that should come before the current key 98 for dkey in sorted(infos.keys()): 99 if sortkey(dkey) < sortkey(key): 100 lines.append('%s = %s\n' % (dkey, infos[dkey])) 101 added.append(dkey) 102 del infos[dkey] 103 changed = True 104 newvalue = infos.get(key, None) 105 if newvalue: 106 del infos[key] 107 if newvalue != linesplit[1].strip(): 108 lines.append('%s = %s\n' % (key, newvalue)) 109 changed = True 110 continue 111 elif key in added: 112 # We already added a new value for this key, so skip it 113 continue 114 elif lastletter: 115 # Ensure we write out anything anything left over for this letter 116 for dkey in sorted(infos.keys()): 117 if dkey[0] == lastletter: 118 lines.append('%s = %s\n' % (dkey, infos[dkey])) 119 del infos[dkey] 120 changed = True 121 elif dkey[0] > lastletter: 122 # List is sorted, so we're done 123 break 124 lastletter = None 125 lines.append(line) 126 127 if not invars: 128 logger.error('ERROR: Unable to find variables section in documentation.conf') 129 return 1 130 131 if infos: 132 changed = True 133 # Write out anything left over 134 lines.append('\n\n') 135 for key in sorted(infos.keys()): 136 lines.append('%s = %s\n' % (key, infos[key])) 137 138 if changed: 139 logger.info('Updating %s' % doc_conf) 140 with open(doc_conf, 'w') as dcf: 141 for line in lines: 142 dcf.write(line) 143 else: 144 logger.info('No changes required') 145 146 return 0 147 148 149if __name__ == "__main__": 150 try: 151 ret = main() 152 except Exception: 153 ret = 1 154 import traceback 155 traceback.print_exc(5) 156 sys.exit(ret) 157 158 159