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