source: topdoc/branches/xml_2014-03-31/src/topdoc/TopDoc.py @ 1534

Last change on this file since 1534 was 1534, checked in by jemian, 9 years ago

remove token analyses from XML

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Date Revision Author HeadURL Id
File size: 8.1 KB
Line 
1#!/usr/bin/env python
2
3'''autogenerate documentation of EPICS IOCs'''
4
5
6import CmdReader
7import CommandTable
8import datetime
9import os
10import pprint           #@UnusedImport
11import shutil
12import SymbolTable
13import sys
14import traceback        #@UnusedImport
15import Trove
16import xmlTools
17import utilities
18
19
20SVN_ID = "$Id: TopDoc.py 1534 2014-04-01 16:52:56Z jemian $"
21
22
23class TopDoc():
24    '''
25    TopDoc documents IOCs in an EPICS top-level directory
26    '''
27    config = None
28
29    def __init__(self, config, keepAnalyses = True):
30        '''
31        Constructor
32        '''
33        self.config = config
34        self.keepAnalyses = keepAnalyses
35        self.project = None
36        self.topContent = {}
37        self.trove = Trove.Trove()
38
39    def learn(self):
40        '''
41        Learn about this EPICS top-level directory.
42        Store the results in self.topContent
43        '''
44        if self.config is None or 'rootDir' not in self.config:
45            return None
46        original_wd = os.getcwd()
47        config_dict = {'config': self.config, 'iocBoot': {}}
48        root = self.config['rootDir']
49        for iocConfig in self.config['IOCs']:
50            key = os.path.join(iocConfig['iocDir'], iocConfig['cmdFile'])
51            bootDir = os.path.join(root, iocConfig['iocDir'])
52            if os.path.exists( bootDir ):
53                pwd = os.getcwd()
54                utilities.chdir( bootDir )
55                self.trove.addFile(iocConfig['cmdFile'], os.path.join(root, key))
56                config_dict['iocBoot'][key] = self.addIOC(iocConfig)
57                utilities.chdir( pwd )
58        self.topContent = config_dict
59        utilities.chdir( original_wd )
60
61    def addIOC(self, config_dict):
62        '''
63        learn about this IOC
64
65        :param config_dict: configuration of this IOC
66        :return: dictionary of analyses
67        '''
68        tables = {
69            'symbols' :         SymbolTable.Symbols(),
70            'env' :             SymbolTable.Symbols(),
71            'commands' :        CommandTable.Commands(),
72            'includeFiles' :    SymbolTable.Symbols(),
73            'databases' :       SymbolTable.Symbols(),
74            'mounts' :          SymbolTable.Symbols(),
75        }
76        keys = tables.keys()
77        tables['analyses'] = {}
78       
79        path = os.path.join(config_dict['iocDir'], config_dict['cmdFile'])
80        utilities.logMessage("processing IOC: %s" % path)
81        cr = CmdReader.CmdReader( config_dict['cmdFile'], tables )
82       
83        results = {}
84        # command files, list avoids redundancy
85        results['filenames'] = [(fname, v.absolute_filename) for fname, v in cr.cache_dbFile.items()]
86        # databases
87        #    this code does not capture ALL PV instances, motor for example
88        #    results are available elsewhere
89        #     pv_xref = {}
90        #     for db in tables['databases'].table.values():
91        #         for pv_name, pv_dict in db.items():
92        #             pv_rtyp = pv_dict['RTYP']
93        #             if pv_rtyp not in pv_xref:
94        #                 pv_xref[pv_rtyp] = []
95        #             pv_xref[pv_rtyp].append(pv_name)
96        #     results['pv_rtyp'] = pv_xref
97        # templates
98        for item in keys:
99            results[item] = tables[item].list
100        if self.keepAnalyses:
101            results['analyses'] = tables['analyses']
102        return results
103
104    def remember(self):
105        '''
106        try to get the full path to the various component files, amongst other things
107        '''
108        utilities.logMessage("remember")
109
110    def write(self, targetDirectory):
111        '''
112        write what was discovered to file
113
114        :param targetDirectory: directory in which to write the results
115        :return: (string) name of html file written
116        '''
117        # TODO: major refactoring wanted, use ReST instead of XML
118        # this implies using proper objects rather than dicts and lists
119        # Why?  too cumbersome to preserve the analyses and propagate them to documentation via XML
120        description = self.config['description']
121        utilities.logMessage("learned about " + description)
122        utilities.logMessage("writing results in: %s" % targetDirectory)
123        # TODO: do something with other content found in docsDir
124        # TODO: should write the analysis into docsDir
125        # TODO: make the list of PVs and fields easily identifiable for bean counting
126        if self.config['project'] is None:
127            return
128        xmlFile = os.path.join(targetDirectory, "%s.xml" % self.config['project'])
129        writer = xmlTools.XmlWriter("TopDoc")
130        writer.root.attrib['file_name'] = xmlFile
131        writer.root.attrib['file_time'] = str(datetime.datetime.now())
132        writer.root.attrib['creator'] = SVN_ID
133        writer.addStructuredNode(writer.root, "top", {'name': description}, self.topContent)
134        xsltFile = 'topdoc.xsl'
135        writer.writeFile(xmlFile, xsltFile)
136        utilities.logMessage("Wrote file: %s" % xmlFile)
137        htmlFile = os.path.splitext(xmlFile)[0] + '.html'
138        xmlTools.xsltproc(xmlFile, xsltFile, htmlFile)
139        utilities.logMessage("Wrote file: %s" % htmlFile)
140        shutil.copy(xsltFile, targetDirectory)
141        utilities.logMessage("Wrote file: %s" % os.path.join(targetDirectory, xsltFile))
142        return "%s.html" % self.config['project']
143
144    def strip_analyses_tokens(self):
145        '''remove the token analyses from the TopDoc object'''
146        # deeply buried content:
147        # self.topContent['iocBoot'][*]['analyses'][*][*]['tokens']
148        for st_cmd in self.topContent['iocBoot'].values():
149            for cmd_file in st_cmd['analyses'].values():
150                for analysis in cmd_file.values():
151                    del analysis['tokens']
152
153def processConfigXml(xmlFile):
154    '''
155    process the contents of a given config.xml file
156    '''
157    utilities.logMessage("processing configuration file: %s" % os.path.abspath( xmlFile ))
158    configuration = xmlTools.readConfigurationXML(xmlFile)
159    reportDirectory = configuration['reportDirectory']
160   
161    html = xmlTools.XmlWriter("html")
162    headNode = html.addStructuredNode(html.root, "head")
163    html.addStructuredNode(headNode, "title", obj="IOCs")
164    bodyNode = html.addStructuredNode(html.root, "body")
165    html.addStructuredNode(bodyNode, "h1", obj="Documentation of IOCs")
166    listNode = html.addStructuredNode(bodyNode, "ul")
167    htmlFile = os.path.join(reportDirectory, 'index.html')
168    if not os.path.exists(reportDirectory):
169        os.makedirs(reportDirectory)
170   
171    for config in configuration['list']:
172        topLevelDirExists = os.path.exists(config['rootDir'])
173        msg = "Looking for: %s (exists=%s)" %(config['rootDir'], str(topLevelDirExists))
174        utilities.logMessage(msg)
175        if topLevelDirExists:
176            pwd = os.getcwd()
177            try:
178                td = TopDoc(config, keepAnalyses=True)
179                td.learn()
180                #td.remember()
181                utilities.chdir( pwd )
182                td.strip_analyses_tokens()
183                tdFile = td.write(reportDirectory)
184                node = html.addStructuredNode(listNode, "li")
185                desc = td.config['description']
186                html.addStructuredNode(node, "a", {'href':tdFile}, obj=desc)
187                html.writeFile(htmlFile)
188                utilities.logMessage("Wrote file: %s" % htmlFile)
189            except Exception, exc:
190                msg = "problem while handling: %s" % config['rootDir']
191                utilities.detailedExceptionLog(msg)
192                traceback.print_exc()
193            utilities.chdir( pwd )
194
195
196def main():
197    import argparse
198    parser = argparse.ArgumentParser(prog='topdoc', 
199                                     description=__doc__.strip())
200    parser.add_argument('xmlFile', 
201                        action='store', 
202                        #nargs=1,
203                        help="XML configuration file")
204    cmd_args = parser.parse_args()
205
206    processConfigXml(cmd_args.xmlFile)
207
208
209if __name__ == '__main__':
210
211    # developer use
212    #sys.argv.append('-h')
213    sys.argv.append('config.xml')
214
215    main()
216
217
218########### SVN repository information ###################
219# $Date: 2014-04-01 16:52:56 +0000 (Tue, 01 Apr 2014) $
220# $Author: jemian $
221# $Revision: 1534 $
222# $URL: topdoc/branches/xml_2014-03-31/src/topdoc/TopDoc.py $
223# $Id: TopDoc.py 1534 2014-04-01 16:52:56Z jemian $
224########### SVN repository information ###################
Note: See TracBrowser for help on using the repository browser.