File: archive.py

package info (click to toggle)
tinyos-tools 1.4.2-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 3,140 kB
  • ctags: 1,626
  • sloc: cpp: 10,398; sh: 1,229; python: 1,200; ansic: 562; makefile: 305; xml: 24
file content (298 lines) | stat: -rw-r--r-- 10,107 bytes parent folder | download | duplicates (2)
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
31
32
33
34
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
180
181
182
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# -*- python -*-
# Copyright (c) 2005 Intel Corporation
# All rights reserved.
#
# This file is distributed under the terms in the attached INTEL-LICENSE     
# file. If you do not find these files, copies can be found by writing to
# Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
# 94704.  Attention:  Intel License Inquiry.

# Archive nesdoc information from a given compilation in a nesdoc repository.
#
# A nesdoc repository is a directory containing separate XML files for each
# known interface and component (in the "interfaces" and "components"
# subdirectories respectively). These files have basically the same format
# as a single interfacedef and component element from the nesC XML dump
# format, with the following changes:
#  - all "interfacedef", "interfacedef-ref", "component" and "component-ref"
#    elements have an extra "nicename" attribute which stores the full
#    `package name' for the corresponding element (see below for details)
#  - components have two extra sub-elements:
#    o "specification": a list of the "interface" and "function"
#       elements that form the components specification
#    o "referenced": the "interface" and "function" elements referenced
#      from the wiring graph
#      the "component" elements referenced from these "interface" and
#      "function" elements
#      (but the "referenced" list excludes self-references, i.e., the
#      component itself and the "interface" and "function" elements
#      already found in "specification")

# A `package name' is a component or interface name prefixed with its path
# relative to a set of "top directories", and with path separators replaced
# by dots. The root of a TinyOS installation is usually the single top
# directory, but more can be specified with the -topdir option.


from xml.dom import *
from xml.dom.minidom import *
from sys import *
from getopt import getopt
from string import *
from nesdoc.utils import *
from nesdoc.graph import generate_graph
from nesdoc.html import *
import os

def check(x):
  if not x:
    print "%s is not a nesC documentation file" % argv[1]
    exit(2)
  return x

def get1(x, tag):
  return check(xml_tagfind(x, tag))

def usage():
  print "Usage: %s [-t dir] [--topdir dir] [--preserve] [--app] [--quiet] repository" % argv[0]
  print "  where -t/--topdir specify prefixes to remove from file names"
  print "  to create nice, package-like names for interface and components"
  print "  (based on their full filename)."
  print "  If --preserve is specified, existing XML files are preserved."
  print "  If --app is specified, a page for this application is created in the"
  print "  current directory."
  print "  If --quiet is specified, the program is less verbose."
  print "  The XML input is read from stdin."

# Return package name for elem, or None if no valid name is found
# (i.e., if the element's file name does not match any known topdir)
def packagename(elem):
  loc = elem.getAttribute("loc")
  colon = index(loc, ":")
  filename = canonicalise(loc[colon + 1:])
  for dir in topdir:
    dirlen = len(dir)
    if filename[0:dirlen] == dir:
      filename = filename[dirlen:]
      break
  if filename[0] == "/":
    return None
  else:
    return replace(replace(filename, ".nc", ""), "/", ".")

# simplify file names (for generating package names, so no need to
# preserve path validity):
#  empty strings become ./
#  windows paths are made unix-like:
#    c: becomes /c/
#    all \ become /
def canonicalise(name):
  if name == "":
    name = "."
  if (name[1:2] == ":"): # windows disk names
    name = "/%s/%s" %(name[0], name[2:])
  name = replace(name, "\\", "/")
  return name
  
# canonicalise a directory. like canonicalise, but ensures
# there is trailing /
def canonicalisedir(dirname):
  dirname = canonicalise(dirname)
  if dirname[-1] != "/":
    return dirname + "/"
  else:
    return dirname

# option processing. See usage string for details.
def process_opts(argv):
  options = {
    "topdir":	 (True,  lambda (x): topdir + [canonicalisedir(x)]),
    "preserve":	 (False, lambda x: True),
    "app":	 (False, lambda x: True),
    "quiet":	 (False, lambda x: True),
  }
  getopt_args = []
  for p in options:
    globals()[p] = False
    opt = p
    if options[p][0]:
      opt += "="
    getopt_args += [ opt ]
  (opts, args) = getopt(argv, "", getopt_args)
  topdir = []
  highlight = ""
  for o, a in opts:
    opt = o[2:]
    globals()[opt] = options[opt][1](a)
  return args

args = process_opts(argv[1:])
if len(args) != 1:
  usage()
  exit(2)

repository = args[0]
try:
  dom = parse(stdin)
except xml.parsers.expat.ExpatError:
  nfail("nesdoc failed: no valid input")
creator = xml.dom.minidom.getDOMImplementation()
check(dom.documentElement.tagName == "nesc")

interfacedefs = get1(dom, "interfacedefs")
components = get1(dom, "components")
interfaces = get1(dom, "interfaces")
functions = get1(dom, "functions")

# index everything
refidx = {}
qnameidx = {}
for x in interfaces.getElementsByTagName("interface"):
  refidx[x.getAttribute("ref")] = x
for x in functions.getElementsByTagName("function"):
  refidx[x.getAttribute("ref")] = x
for x in components.getElementsByTagName("component"):
  qnameidx[x.getAttribute("qname")] = x
for x in interfacedefs.getElementsByTagName("interfacedef"):
  qnameidx[x.getAttribute("qname")] = x

# collect specification elements by component
speclist = {}
# interfaces
for x in interfaces.getElementsByTagName("interface"):
  incomponent = get1(x, "component-ref").getAttribute("qname")
  if speclist.has_key(incomponent):
    speclist[incomponent].append(x)
  else:
    speclist[incomponent] = [x]
# and bare commands, events
for x in functions.getElementsByTagName("function"):
  # hack: tasks don't show up with a command/event attribute
  # don't include commands/events from interfaces
  if (x.hasAttribute("event") or x.hasAttribute("command")) and (not xml_tag(x, "interface-ref")):
    incomponent = get1(x, "component-ref").getAttribute("qname")
    if speclist.has_key(incomponent):
      speclist[incomponent].append(x)
    else:
      speclist[incomponent] = [x]

# add nicename (i.e., with package prefix) attributes to all interfacedef,
# interfacedef-ref, component and component-ref elements
nicenames = {}
def define_nicename(x):
  name = x.getAttribute("qname")
  nicename = packagename(x)
  if nicename == None:
    nicename = name
  nicenames[name] = nicename
def set_nicename(x):
  x.setAttribute("nicename", nicenames[x.getAttribute("qname")])
for x in interfacedefs.getElementsByTagName("interfacedef"):
  define_nicename(x)
  set_nicename(x)
for x in components.getElementsByTagName("component"):
  define_nicename(x)
  set_nicename(x)
for x in dom.getElementsByTagName("interfacedef-ref"):
  set_nicename(x)
for x in dom.getElementsByTagName("component-ref"):
  set_nicename(x)

# Do the app stuff if requested
if app:
  # The firt component is the main application component.
  toplevel = xml_idx(components, 0)
  name = toplevel.getAttribute("qname")
  nicename = toplevel.getAttribute("nicename")
  wiring = xml_tag(xml_tag(dom, "nesc"), "wiring")
  generate_graph(".", repository, dom, wiring, name, nicename)

  ht = Html("%s.html" % nicename)
  ht.title("Application: " + nicename)
  ht.body()
  ht.push("h2");
  ht.p("Application: " + nicename)
  ht.popln();
  ht.pushln("map", 'name="comp"')
  cmap = file("%s.cmap" % nicename)
  for line in cmap.readlines():
    ht.pln(line)
  cmap.close()
  ht.popln()
  ht.tag("img", 'src="%s.png"' % nicename, 'usemap="#comp"', 'id=imgwiring')
  ht.close()

# save xml information per-interface and per-component in the specified
# repository
nmkdir(repository)
chdir(repository)
nmkdir("interfaces")
nmkdir("components")

# save interface definitions
for x in interfacedefs.getElementsByTagName("interfacedef"):
  name = x.getAttribute("qname")
  nicename = x.getAttribute("nicename")
  filename = "interfaces/%s.xml" % nicename
  if preserve and os.path.exists(filename):
    continue
  if not quiet:
    print "interface %s (%s)" % (name, nicename)
  doc = creator.createDocument(None, None, None)
  copy = x.cloneNode(True)
  doc.appendChild(copy)
  ifile = file(filename, "w")
  doc.writexml(ifile)
  doc.unlink()
  ifile.close()

# save component definitions, excluding instantiations
for x in components.getElementsByTagName("component"):
  if len(x.getElementsByTagName("instance")) == 0:
    # not an instance
    name = x.getAttribute("qname")
    nicename = x.getAttribute("nicename")
    filename = "components/%s.xml" % nicename
    if preserve and os.path.exists(filename):
      continue
    if not quiet:
      print "component %s (%s)" % (name, nicename)
    doc = creator.createDocument(None, None, None)
    # copy component and create its specification
    copy = x.cloneNode(True)
    spec = dom.createElement("specification")
    copy.appendChild(spec)
    try:
      for intf in speclist[name]:
        spec.appendChild(intf.cloneNode(True))
    except KeyError:
      0

    # collect information used in wiring graph
    allelems = {}
    allcomps = {}
    def addelem(wireref):
      actualref = xml_tagset(wireref, ["interface-ref", "function-ref"])
      elemref = actualref.getAttribute("ref")
      elem = refidx[elemref]
      compname = xml_tag(elem, "component-ref").getAttribute("qname")
      # exclude self-references, those are in the specification already
      if compname != name:
        allelems[elemref] = True
        allcomps[compname] = True
    for wireref in x.getElementsByTagName("from"): addelem(wireref)
    for wireref in x.getElementsByTagName("to"): addelem(wireref)

    # create the referenced element which will store the wiring information
    refd = dom.createElement("referenced")
    copy.appendChild(refd)
    for ref in allelems.keys():
      refd.appendChild(refidx[ref].cloneNode(True))
    for qname in allcomps.keys():
      refd.appendChild(qnameidx[qname].cloneNode(True))
    
    doc.appendChild(copy)
    ifile = file(filename, "w")
    doc.writexml(ifile)
    doc.unlink()
    ifile.close()