index.py 8.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#!/usr/bin/python -u
#
# Indexes the examples and build an XML description
#
import string
import glob
import sys
try:
    import libxml2
except:
    sys.exit(1)
sys.path.insert(0, "..")
from apibuild import CParser, escape

examples = []
extras = ['examples.xsl', 'index.py']
tests = []
sections = {}
symbols = {}
api_dict = None
api_doc = None

def load_api():
    global api_dict
    global api_doc

    if api_dict != None:
        return
    api_dict = {}
    try:
31 32
        print "loading ../libvirt-api.xml"
        api_doc = libxml2.parseFile("../libvirt-api.xml")
33
    except:
34
        print "failed to parse ../libvirt-api.xml"
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	sys.exit(1)

def find_symbol(name):
    global api_dict
    global api_doc

    if api_doc == None:
        load_api()

    if name == None:
        return
    if api_dict.has_key(name):
        return api_dict[name]
    ctxt = api_doc.xpathNewContext()
    res = ctxt.xpathEval("/api/symbols/*[@name = '%s']" % (name))
    if type(res) == type([]) and len(res) >= 1:
        if len(res) > 1:
	    print "Found %d references to %s in the API" % (len(res), name)
	node = res[0]
	typ = node.name
	file = node.xpathEval("string(@file)")
	info = node.xpathEval("string(info)")
    else:
        print "Reference %s not found in the API" % (name)
	return None
    ret = (typ, file, info)
    api_dict[name] = ret
    return ret

def parse_top_comment(filename, comment):
    res = {}
    lines = string.split(comment, "\n")
    item = None
    for line in lines:
        while line != "" and (line[0] == ' ' or line[0] == '\t'):
	    line = line[1:]
        while line != "" and line[0] == '*':
	    line = line[1:]
        while line != "" and (line[0] == ' ' or line[0] == '\t'):
	    line = line[1:]
	try:
	    (it, line) = string.split(line, ":", 1)
	    item = it
	    while line != "" and (line[0] == ' ' or line[0] == '\t'):
		line = line[1:]
	    if res.has_key(item):
	        res[item] = res[item] + " " + line
	    else:
		res[item] = line
	except:
	    if item != None:
	        if res.has_key(item):
		    res[item] = res[item] + " " + line
		else:
		    res[item] = line
    return res

def parse(filename, output):
    global symbols
    global sections

    parser = CParser(filename)
    parser.collect_references()
    idx = parser.parse()
    info = parse_top_comment(filename, parser.top_comment)
    output.write("  <example filename='%s'>\n" % filename)
    try:
        synopsis = info['synopsis']
	output.write("    <synopsis>%s</synopsis>\n" % escape(synopsis));
    except:
        print "Example %s lacks a synopsis description" % (filename)
    try:
        purpose = info['purpose']
	output.write("    <purpose>%s</purpose>\n" % escape(purpose));
    except:
        print "Example %s lacks a purpose description" % (filename)
    try:
        usage = info['usage']
	output.write("    <usage>%s</usage>\n" % escape(usage));
    except:
        print "Example %s lacks an usage description" % (filename)
    try:
        test = info['test']
	output.write("    <test>%s</test>\n" % escape(test));
	progname=filename[0:-2]
	command=string.replace(test, progname, './' + progname, 1)
	tests.append(command)
    except:
        pass
    try:
        author = info['author']
	output.write("    <author>%s</author>\n" % escape(author));
    except:
        print "Example %s lacks an author description" % (filename)
    try:
        copy = info['copy']
	output.write("    <copy>%s</copy>\n" % escape(copy));
    except:
        print "Example %s lacks a copyright description" % (filename)
    try:
        section = info['section']
	output.write("    <section>%s</section>\n" % escape(section));
	if sections.has_key(section):
	    sections[section].append(filename)
	else:
	    sections[section] = [filename]
    except:
        print "Example %s lacks a section description" % (filename)
    for topic in info.keys():
        if topic != "purpose" and topic != "usage" and \
	   topic != "author" and topic != "copy" and \
	   topic != "section" and topic != "synopsis" and topic != "test":
	    str = info[topic]
	    output.write("    <extra topic='%s'>%s</extra>\n" % (
	                 escape(topic), escape(str)))
    output.write("    <includes>\n")
    for include in idx.includes.keys():
        if include.find("libxml") != -1:
	    output.write("      <include>%s</include>\n" % (escape(include)))
    output.write("    </includes>\n")
    output.write("    <uses>\n")
    for ref in idx.references.keys():
        id = idx.references[ref]
	name = id.get_name()
	line = id.get_lineno()
	if symbols.has_key(name):
	    sinfo = symbols[name]
	    refs = sinfo[0]
	    # gather at most 5 references per symbols
	    if refs > 5:
	        continue
	    sinfo.append(filename)
	    sinfo[0] = refs + 1
	else:
	    symbols[name] = [1, filename]
	info = find_symbol(name)
	if info != None:
	    type = info[0]
	    file = info[1]
	    output.write("      <%s line='%d' file='%s' name='%s'/>\n" % (type,
	                 line, file, name))
	else:
	    type = id.get_type()
	    output.write("      <%s line='%d' name='%s'/>\n" % (type,
	                 line, name))
J
Jim Meyering 已提交
180

181 182
    output.write("    </uses>\n")
    output.write("  </example>\n")
J
Jim Meyering 已提交
183

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    return idx

def dump_symbols(output):
    global symbols

    output.write("  <symbols>\n")
    keys = symbols.keys()
    keys.sort()
    for symbol in keys:
        output.write("    <symbol name='%s'>\n" % (symbol))
	info = symbols[symbol]
	i = 1
	while i < len(info):
	    output.write("      <ref filename='%s'/>\n" % (info[i]))
	    i = i + 1
        output.write("    </symbol>\n")
    output.write("  </symbols>\n")

def dump_sections(output):
    global sections

    output.write("  <sections>\n")
    keys = sections.keys()
    keys.sort()
    for section in keys:
        output.write("    <section name='%s'>\n" % (section))
	info = sections[section]
	i = 0
	while i < len(info):
	    output.write("      <example filename='%s'/>\n" % (info[i]))
	    i = i + 1
        output.write("    </section>\n")
    output.write("  </sections>\n")

def dump_Makefile():
    for file in glob.glob('*.xml'):
        extras.append(file)
J
Jim Meyering 已提交
221 222
    Makefile="""# -*- buffer-read-only: t -*- vi: set ro:
# Beware this is autogenerated by index.py
223
SUBDIRS=python
224
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I@srcdir@/include
225
DEPS = $(top_builddir)/src/libvirt.la
226 227
LDADDS = @STATIC_BINARIES@ $(WARN_CFLAGS) $(top_builddir)/src/libvirt.la \
	$(COVERAGE_LDFLAGS)
228 229 230

rebuild: examples.xml index.html

J
Jim Meyering 已提交
231
examples.xml: index.py __C_SOURCES__
232 233
	-@($(srcdir)/index.py)

234
index.html: examples.xml examples.xsl $(top_srcdir)/docs/site.xsl
J
Jim Meyering 已提交
235 236 237 238 239
	-@(if [ -x $(XSLTPROC) ] ; then			\\
	   $(XSLTPROC) examples.xsl examples.xml	\\
	     && echo "Rebuilt web page"			\\
	     && xmllint --valid --noout index.html;	\\
	   fi)
240

J
Jim Meyering 已提交
241
install-data-local:
242
	$(mkinstalldirs) $(DESTDIR)$(HTML_DIR)
J
Jim Meyering 已提交
243
	-@INSTALL@ -m 0644 $(srcdir)/*.html $(srcdir)/*.c $(srcdir)/*.xml \\
244
	  $(srcdir)/*.xsl $(DESTDIR)$(HTML_DIR)
245 246

"""
247
    EXTRA_DIST= string.join(extras, ' ')
248
    Makefile = Makefile + "EXTRA_DIST=%s\n\n" % (EXTRA_DIST)
249
    noinst_PROGRAMS= string.join(examples, ' ')
250 251 252 253
    Makefile = Makefile + "noinst_PROGRAMS=%s\n\n" % (noinst_PROGRAMS)
    for example in examples:
        Makefile = Makefile + "%s_SOURCES=%s.c\n%s_LDFLAGS=\n%s_DEPENDENCIES= $(DEPS)\n%s_LDADD= $(LDADDS)\n\n" % (example, example, example,
	       example, example)
254
    Makefile = Makefile + "valgrind:\n\t$(MAKE) CHECKER='valgrind' tests\n\n"
255 256 257 258 259 260
    Makefile = Makefile + "tests: $(noinst_PROGRAMS)\n"
    Makefile = Makefile + "\t@(echo '## examples regression tests')\n"
#    Makefile = Makefile + "\t@(echo > .memdump)\n"
    for test in tests:
        Makefile = Makefile + "\t@($(CHECKER) %s)\n" % (test)
#        Makefile = Makefile + '\t@(grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0" ; exit 0)\n'
J
Jim Meyering 已提交
261 262 263

    c_src = [("%s.c" % x) for x in examples]
    Makefile = Makefile.replace("__C_SOURCES__", string.join(c_src, ' '))
264 265 266 267 268 269 270 271 272 273 274 275 276
    try:
	old = open("Makefile.am", "r").read()
	if old != Makefile:
	    n = open("Makefile.am", "w").write(Makefile)
	    print "Updated Makefile.am"
    except:
        print "Failed to read or save Makefile.am"
    #
    # Autogenerate the .cvsignore too ...
    #
    ignore = """.memdump
Makefile.in
Makefile
277 278
.deps
.libs
279 280 281 282 283 284 285 286 287 288
"""
    for example in examples:
        ignore = ignore + "%s\n" % (example)
    try:
	old = open(".cvsignore", "r").read()
	if old != ignore:
	    n = open(".cvsignore", "w").write(ignore)
	    print "Updated .cvsignore"
    except:
        print "Failed to read or save .cvsignore"
J
Jim Meyering 已提交
289

290 291 292 293 294
if __name__ == "__main__":
    load_api()
    output = open("examples.xml", "w")
    output.write("<examples>\n")

J
Jim Meyering 已提交
295 296 297
    c_src = glob.glob('*.c')
    c_src.sort()
    for file in c_src:
298 299 300 301 302 303 304 305
	parse(file, output)
	examples.append(file[:-2])

    dump_symbols(output)
    dump_sections(output)
    output.write("</examples>\n")
    output.close()
    dump_Makefile()