OSDN Git Service

Camera: Fix up metadata generation, including HIDL gen
[android-x86/system-media.git] / camera / docs / metadata_model.py
1 #!/usr/bin/python
2
3 #
4 # Copyright (C) 2012 The Android Open Source Project
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 #      http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18
19 """
20 A set of classes (models) each closely representing an XML node in the
21 metadata_definitions.xml file.
22
23   Node: Base class for most nodes.
24   Entry: A node corresponding to <entry> elements.
25   Clone: A node corresponding to <clone> elements.
26   MergedEntry: A node corresponding to either <entry> or <clone> elements.
27   Kind: A node corresponding to <dynamic>, <static>, <controls> elements.
28   InnerNamespace: A node corresponding to a <namespace> nested under a <kind>.
29   OuterNamespace: A node corresponding to a <namespace> with <kind> children.
30   Section: A node corresponding to a <section> element.
31   Enum: A class corresponding an <enum> element within an <entry>
32   EnumValue: A class corresponding to a <value> element within an Enum
33   Metadata: Root node that also provides tree construction functionality.
34   Tag: A node corresponding to a top level <tag> element.
35   Typedef: A node corresponding to a <typedef> element under <types>.
36 """
37
38 import sys
39 import itertools
40 from collections import OrderedDict
41
42 class Node(object):
43   """
44   Base class for most nodes that are part of the Metadata graph.
45
46   Attributes (Read-Only):
47     parent: An edge to a parent Node.
48     name: A string describing the name, usually but not always the 'name'
49           attribute of the corresponding XML node.
50   """
51
52   def __init__(self):
53     self._parent = None
54     self._name = None
55
56   @property
57   def parent(self):
58     return self._parent
59
60   @property
61   def name(self):
62     return self._name
63
64   def find_all(self, pred):
65     """
66     Find all descendants that match the predicate.
67
68     Args:
69       pred: a predicate function that acts as a filter for a Node
70
71     Yields:
72       A sequence of all descendants for which pred(node) is true,
73       in a pre-order visit order.
74     """
75     if pred(self):
76       yield self
77
78     if self._get_children() is None:
79       return
80
81     for i in self._get_children():
82       for j in i.find_all(pred):
83         yield j
84
85   def find_first(self, pred):
86     """
87     Find the first descendant that matches the predicate.
88
89     Args:
90       pred: a predicate function that acts as a filter for a Node
91
92     Returns:
93       The first Node from find_all(pred), or None if there were no results.
94     """
95     for i in self.find_all(pred):
96       return i
97
98     return None
99
100   def find_parent_first(self, pred):
101     """
102     Find the first ancestor that matches the predicate.
103
104     Args:
105       pred: A predicate function that acts as a filter for a Node
106
107     Returns:
108       The first ancestor closest to the node for which pred(node) is true.
109     """
110     for i in self.find_parents(pred):
111       return i
112
113     return None
114
115   def find_parents(self, pred):
116     """
117     Find all ancestors that match the predicate.
118
119     Args:
120       pred: A predicate function that acts as a filter for a Node
121
122     Yields:
123       A sequence of all ancestors (closest to furthest) from the node,
124       where pred(node) is true.
125     """
126     parent = self.parent
127
128     while parent is not None:
129       if pred(parent):
130         yield parent
131       parent = parent.parent
132
133   def sort_children(self):
134     """
135     Sorts the immediate children in-place.
136     """
137     self._sort_by_name(self._children)
138
139   def _sort_by_name(self, what):
140     what.sort(key=lambda x: x.name)
141
142   def _get_name(self):
143     return lambda x: x.name
144
145   # Iterate over all children nodes. None when node doesn't support children.
146   def _get_children(self):
147     return (i for i in self._children)
148
149   def _children_name_map_matching(self, match=lambda x: True):
150     d = {}
151     for i in self._get_children():
152       if match(i):
153         d[i.name] = i
154     return d
155
156   @staticmethod
157   def _dictionary_by_name(values):
158     d = OrderedDict()
159     for i in values:
160       d[i.name] = i
161
162     return d
163
164   def validate_tree(self):
165     """
166     Sanity check the tree recursively, ensuring for a node n, all children's
167     parents are also n.
168
169     Returns:
170       True if validation succeeds, False otherwise.
171     """
172     succ = True
173     children = self._get_children()
174     if children is None:
175       return True
176
177     for child in self._get_children():
178       if child.parent != self:
179         print >> sys.stderr, ("ERROR: Node '%s' doesn't match the parent" +    \
180                              "(expected: %s, actual %s)")                      \
181                              %(child, self, child.parent)
182         succ = False
183
184       succ = child.validate_tree() and succ
185
186     return succ
187
188   def __str__(self):
189     return "<%s name='%s'>" %(self.__class__, self.name)
190
191 class Metadata(Node):
192   """
193   A node corresponding to a <metadata> entry.
194
195   Attributes (Read-Only):
196     parent: An edge to the parent Node. This is always None for Metadata.
197     outer_namespaces: A sequence of immediate OuterNamespace children.
198     tags: A sequence of all Tag instances available in the graph.
199     types: An iterable of all Typedef instances available in the graph.
200   """
201
202   def __init__(self):
203     """
204     Initialize with no children. Use insert_* functions and then
205     construct_graph() to build up the Metadata from some source.
206     """
207 # Private
208     self._entries = []
209     # kind => { name => entry }
210     self._entry_map = { 'static': {}, 'dynamic': {}, 'controls': {} }
211     self._entries_ordered = [] # list of ordered Entry/Clone instances
212     self._clones = []
213
214 # Public (Read Only)
215     self._name = None
216     self._parent = None
217     self._outer_namespaces = None
218     self._tags = []
219     self._types = []
220
221   @property
222   def outer_namespaces(self):
223     if self._outer_namespaces is None:
224       return None
225     else:
226       return (i for i in self._outer_namespaces)
227
228   @property
229   def tags(self):
230     return (i for i in self._tags)
231
232   @property
233   def types(self):
234     return (i for i in self._types)
235
236   def _get_properties(self):
237
238     for i in self._entries:
239       yield i
240
241     for i in self._clones:
242       yield i
243
244   def insert_tag(self, tag, description=""):
245     """
246     Insert a tag into the metadata.
247
248     Args:
249       tag: A string identifier for a tag.
250       description: A string description for a tag.
251
252     Example:
253       metadata.insert_tag("BC", "Backwards Compatibility for old API")
254
255     Remarks:
256       Subsequent calls to insert_tag with the same tag are safe (they will
257       be ignored).
258     """
259     tag_ids = [tg.name for tg in self.tags if tg.name == tag]
260     if not tag_ids:
261       self._tags.append(Tag(tag, self, description))
262
263   def insert_type(self, type_name, type_selector="typedef", **kwargs):
264     """
265     Insert a type into the metadata.
266
267     Args:
268       type_name: A type's name
269       type_selector: The selector for the type, e.g. 'typedef'
270
271     Args (if type_selector == 'typedef'):
272       languages: A map of 'language name' -> 'fully qualified class path'
273
274     Example:
275       metadata.insert_type('rectangle', 'typedef',
276                            { 'java': 'android.graphics.Rect' })
277
278     Remarks:
279       Subsequent calls to insert_type with the same type name are safe (they
280       will be ignored)
281     """
282
283     if type_selector != 'typedef':
284       raise ValueError("Unsupported type_selector given " + type_selector)
285
286     type_names = [tp.name for tp in self.types if tp.name == tp]
287     if not type_names:
288       self._types.append(Typedef(type_name, self, kwargs.get('languages')))
289
290   def insert_entry(self, entry):
291     """
292     Insert an entry into the metadata.
293
294     Args:
295       entry: A key-value dictionary describing an entry. Refer to
296              Entry#__init__ for the keys required/optional.
297
298     Remarks:
299       Subsequent calls to insert_entry with the same entry+kind name are safe
300       (they will be ignored).
301     """
302     e = Entry(**entry)
303     self._entries.append(e)
304     self._entry_map[e.kind][e.name] = e
305     self._entries_ordered.append(e)
306
307   def insert_clone(self, clone):
308     """
309     Insert a clone into the metadata.
310
311     Args:
312       clone: A key-value dictionary describing a clone. Refer to
313             Clone#__init__ for the keys required/optional.
314
315     Remarks:
316       Subsequent calls to insert_clone with the same clone+kind name are safe
317       (they will be ignored). Also the target entry need not be inserted
318       ahead of the clone entry.
319     """
320     # figure out corresponding entry later. allow clone insert, entry insert
321     entry = None
322     c = Clone(entry, **clone)
323     self._entry_map[c.kind][c.name] = c
324     self._clones.append(c)
325     self._entries_ordered.append(c)
326
327   def prune_clones(self):
328     """
329     Remove all clones that don't point to an existing entry.
330
331     Remarks:
332       This should be called after all insert_entry/insert_clone calls have
333       finished.
334     """
335     remove_list = []
336     for p in self._clones:
337       if p.entry is None:
338         remove_list.append(p)
339
340     for p in remove_list:
341
342       # remove from parent's entries list
343       if p.parent is not None:
344         p.parent._entries.remove(p)
345       # remove from parents' _leafs list
346       for ancestor in p.find_parents(lambda x: not isinstance(x, Metadata)):
347         ancestor._leafs.remove(p)
348
349       # remove from global list
350       self._clones.remove(p)
351       self._entry_map[p.kind].pop(p.name)
352       self._entries_ordered.remove(p)
353
354   def is_entry_this_kind(self, entry, kind):
355     """
356     Check if input entry if of input kind
357
358     Args:
359       entry: an Entry object
360       kind: a string. Possible values are "static", "dynamic", "controls"
361
362     Returns:
363       A boolean indicating whether input entry is of input kind.
364     """
365     if kind not in ("static", "dynamic", "controls"):
366       assert(False), "Unknown kind value " + kind
367
368     return entry.name in self._entry_map[kind]
369
370   # After all entries/clones are inserted,
371   # invoke this to generate the parent/child node graph all these objects
372   def construct_graph(self):
373     """
374     Generate the graph recursively, after which all Entry nodes will be
375     accessible recursively by crawling through the outer_namespaces sequence.
376
377     Remarks:
378       This is safe to be called multiple times at any time. It should be done at
379       least once or there will be no graph.
380     """
381     self.validate_tree()
382     self._construct_tags()
383     self.validate_tree()
384     self._construct_types()
385     self.validate_tree()
386     self._construct_clones()
387     self.validate_tree()
388     self._construct_outer_namespaces()
389     self.validate_tree()
390
391   def _construct_tags(self):
392     tag_dict = self._dictionary_by_name(self.tags)
393     for p in self._get_properties():
394       p._tags = []
395       for tag_id in p._tag_ids:
396         tag = tag_dict.get(tag_id)
397
398         if tag not in p._tags:
399           p._tags.append(tag)
400
401         if p not in tag.entries:
402           tag._entries.append(p)
403
404   def _construct_types(self):
405     type_dict = self._dictionary_by_name(self.types)
406     for p in self._get_properties():
407       if p._type_name:
408         type_node = type_dict.get(p._type_name)
409         p._typedef = type_node
410
411         if p not in type_node.entries:
412           type_node._entries.append(p)
413
414   def _construct_clones(self):
415     for p in self._clones:
416       target_kind = p.target_kind
417       target_entry = self._entry_map[target_kind].get(p.name)
418       p._entry = target_entry
419
420       # should not throw if we pass validation
421       # but can happen when importing obsolete CSV entries
422       if target_entry is None:
423         print >> sys.stderr, ("WARNING: Clone entry '%s' target kind '%s'" +   \
424                               " has no corresponding entry")                   \
425                              %(p.name, p.target_kind)
426
427   def _construct_outer_namespaces(self):
428
429     if self._outer_namespaces is None: #the first time this runs
430       self._outer_namespaces = []
431
432     root = self._dictionary_by_name(self._outer_namespaces)
433     for ons_name, ons in root.iteritems():
434       ons._leafs = []
435
436     for p in self._entries_ordered:
437       ons_name = p.get_outer_namespace()
438       ons = root.get(ons_name, OuterNamespace(ons_name, self))
439       root[ons_name] = ons
440
441       if p not in ons._leafs:
442         ons._leafs.append(p)
443
444     for ons_name, ons in root.iteritems():
445
446       ons.validate_tree()
447
448       self._construct_sections(ons)
449
450       if ons not in self._outer_namespaces:
451         self._outer_namespaces.append(ons)
452
453       ons.validate_tree()
454
455   def _construct_sections(self, outer_namespace):
456
457     sections_dict = self._dictionary_by_name(outer_namespace.sections)
458     for sec_name, sec in sections_dict.iteritems():
459       sec._leafs = []
460       sec.validate_tree()
461
462     for p in outer_namespace._leafs:
463       does_exist = sections_dict.get(p.get_section())
464
465       sec = sections_dict.get(p.get_section(), \
466           Section(p.get_section(), outer_namespace))
467       sections_dict[p.get_section()] = sec
468
469       sec.validate_tree()
470
471       if p not in sec._leafs:
472         sec._leafs.append(p)
473
474     for sec_name, sec in sections_dict.iteritems():
475
476       if not sec.validate_tree():
477         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
478                              "construct_sections (start), with section = '%s'")\
479                              %(sec)
480
481       self._construct_kinds(sec)
482
483       if sec not in outer_namespace.sections:
484         outer_namespace._sections.append(sec)
485
486       if not sec.validate_tree():
487         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
488                               "construct_sections (end), with section = '%s'") \
489                              %(sec)
490
491   # 'controls', 'static' 'dynamic'. etc
492   def _construct_kinds(self, section):
493     for kind in section.kinds:
494       kind._leafs = []
495       section.validate_tree()
496
497     group_entry_by_kind = itertools.groupby(section._leafs, lambda x: x.kind)
498     leaf_it = ((k, g) for k, g in group_entry_by_kind)
499
500     # allow multiple kinds with the same name. merge if adjacent
501     # e.g. dynamic,dynamic,static,static,dynamic -> dynamic,static,dynamic
502     # this helps maintain ABI compatibility when adding an entry in a new kind
503     for idx, (kind_name, entry_it) in enumerate(leaf_it):
504       if idx >= len(section._kinds):
505         kind = Kind(kind_name, section)
506         section._kinds.append(kind)
507         section.validate_tree()
508
509       kind = section._kinds[idx]
510
511       for p in entry_it:
512         if p not in kind._leafs:
513           kind._leafs.append(p)
514
515     for kind in section._kinds:
516       kind.validate_tree()
517       self._construct_inner_namespaces(kind)
518       kind.validate_tree()
519       self._construct_entries(kind)
520       kind.validate_tree()
521
522       if not section.validate_tree():
523         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
524                              "construct_kinds, with kind = '%s'") %(kind)
525
526       if not kind.validate_tree():
527         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
528                               "construct_kinds, with kind = '%s'") %(kind)
529
530   def _construct_inner_namespaces(self, parent, depth=0):
531     #parent is InnerNamespace or Kind
532     ins_dict = self._dictionary_by_name(parent.namespaces)
533     for name, ins in ins_dict.iteritems():
534       ins._leafs = []
535
536     for p in parent._leafs:
537       ins_list = p.get_inner_namespace_list()
538
539       if len(ins_list) > depth:
540         ins_str = ins_list[depth]
541         ins = ins_dict.get(ins_str, InnerNamespace(ins_str, parent))
542         ins_dict[ins_str] = ins
543
544         if p not in ins._leafs:
545           ins._leafs.append(p)
546
547     for name, ins in ins_dict.iteritems():
548       ins.validate_tree()
549       # construct children INS
550       self._construct_inner_namespaces(ins, depth + 1)
551       ins.validate_tree()
552       # construct children entries
553       self._construct_entries(ins, depth + 1)
554
555       if ins not in parent.namespaces:
556         parent._namespaces.append(ins)
557
558       if not ins.validate_tree():
559         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
560                               "construct_inner_namespaces, with ins = '%s'")   \
561                              %(ins)
562
563   # doesnt construct the entries, so much as links them
564   def _construct_entries(self, parent, depth=0):
565     #parent is InnerNamespace or Kind
566     entry_dict = self._dictionary_by_name(parent.entries)
567     for p in parent._leafs:
568       ins_list = p.get_inner_namespace_list()
569
570       if len(ins_list) == depth:
571         entry = entry_dict.get(p.name, p)
572         entry_dict[p.name] = entry
573
574     for name, entry in entry_dict.iteritems():
575
576       old_parent = entry.parent
577       entry._parent = parent
578
579       if entry not in parent.entries:
580         parent._entries.append(entry)
581
582       if old_parent is not None and old_parent != parent:
583         print >> sys.stderr, ("ERROR: Parent changed from '%s' to '%s' for " + \
584                               "entry '%s'")                                    \
585                              %(old_parent.name, parent.name, entry.name)
586
587   def _get_children(self):
588     if self.outer_namespaces is not None:
589       for i in self.outer_namespaces:
590         yield i
591
592     if self.tags is not None:
593       for i in self.tags:
594         yield i
595
596 class Tag(Node):
597   """
598   A tag Node corresponding to a top-level <tag> element.
599
600   Attributes (Read-Only):
601     name: alias for id
602     id: The name of the tag, e.g. for <tag id="BC"/> id = 'BC'
603     description: The description of the tag, the contents of the <tag> element.
604     parent: An edge to the parent, which is always the Metadata root node.
605     entries: A sequence of edges to entries/clones that are using this Tag.
606   """
607   def __init__(self, name, parent, description=""):
608     self._name        = name  # 'id' attribute in XML
609     self._id          = name
610     self._description = description
611     self._parent      = parent
612
613     # all entries that have this tag, including clones
614     self._entries     = []  # filled in by Metadata#construct_tags
615
616   @property
617   def id(self):
618     return self._id
619
620   @property
621   def description(self):
622     return self._description
623
624   @property
625   def entries(self):
626     return (i for i in self._entries)
627
628   def _get_children(self):
629     return None
630
631 class Typedef(Node):
632   """
633   A typedef Node corresponding to a <typedef> element under a top-level <types>.
634
635   Attributes (Read-Only):
636     name: The name of this typedef as a string.
637     languages: A dictionary of 'language name' -> 'fully qualified class'.
638     parent: An edge to the parent, which is always the Metadata root node.
639     entries: An iterable over all entries which reference this typedef.
640   """
641   def __init__(self, name, parent, languages=None):
642     self._name        = name
643     self._parent      = parent
644
645     # all entries that have this typedef
646     self._entries     = []  # filled in by Metadata#construct_types
647
648     self._languages   = languages or {}
649
650   @property
651   def languages(self):
652     return self._languages
653
654   @property
655   def entries(self):
656     return (i for i in self._entries)
657
658   def _get_children(self):
659     return None
660
661 class OuterNamespace(Node):
662   """
663   A node corresponding to a <namespace> element under <metadata>
664
665   Attributes (Read-Only):
666     name: The name attribute of the <namespace name="foo"> element.
667     parent: An edge to the parent, which is always the Metadata root node.
668     sections: A sequence of Section children.
669   """
670   def __init__(self, name, parent, sections=[]):
671     self._name = name
672     self._parent = parent # MetadataSet
673     self._sections = sections[:]
674     self._leafs = []
675
676     self._children = self._sections
677
678   @property
679   def sections(self):
680     return (i for i in self._sections)
681
682 class Section(Node):
683   """
684   A node corresponding to a <section> element under <namespace>
685
686   Attributes (Read-Only):
687     name: The name attribute of the <section name="foo"> element.
688     parent: An edge to the parent, which is always an OuterNamespace instance.
689     description: A string description of the section, or None.
690     kinds: A sequence of Kind children.
691     merged_kinds: A sequence of virtual Kind children,
692                   with each Kind's children merged by the kind.name
693   """
694   def __init__(self, name, parent, description=None, kinds=[]):
695     self._name = name
696     self._parent = parent
697     self._description = description
698     self._kinds = kinds[:]
699
700     self._leafs = []
701
702
703   @property
704   def description(self):
705     return self._description
706
707   @property
708   def kinds(self):
709     return (i for i in self._kinds)
710
711   def sort_children(self):
712     self.validate_tree()
713     # order is always controls,static,dynamic
714     find_child = lambda x: [i for i in self._get_children() if i.name == x]
715     new_lst = find_child('controls') \
716             + find_child('static')   \
717             + find_child('dynamic')
718     self._kinds = new_lst
719     self.validate_tree()
720
721   def _get_children(self):
722     return (i for i in self.kinds)
723
724   @property
725   def merged_kinds(self):
726
727     def aggregate_by_name(acc, el):
728       existing = [i for i in acc if i.name == el.name]
729       if existing:
730         k = existing[0]
731       else:
732         k = Kind(el.name, el.parent)
733         acc.append(k)
734
735       k._namespaces.extend(el._namespaces)
736       k._entries.extend(el._entries)
737
738       return acc
739
740     new_kinds_lst = reduce(aggregate_by_name, self.kinds, [])
741
742     for k in new_kinds_lst:
743       yield k
744
745   def combine_kinds_into_single_node(self):
746     r"""
747     Combines the section's Kinds into a single node.
748
749     Combines all the children (kinds) of this section into a single
750     virtual Kind node.
751
752     Returns:
753       A new Kind node that collapses all Kind siblings into one, combining
754       all their children together.
755
756       For example, given self.kinds == [ x, y ]
757
758         x  y               z
759       / |  | \    -->   / | | \
760       a b  c d          a b c d
761
762       a new instance z is returned in this example.
763
764     Remarks:
765       The children of the kinds are the same references as before, that is
766       their parents will point to the old parents and not to the new parent.
767     """
768     combined = Kind(name="combined", parent=self)
769
770     for k in self._get_children():
771       combined._namespaces.extend(k.namespaces)
772       combined._entries.extend(k.entries)
773
774     return combined
775
776 class Kind(Node):
777   """
778   A node corresponding to one of: <static>,<dynamic>,<controls> under a
779   <section> element.
780
781   Attributes (Read-Only):
782     name: A string which is one of 'static', 'dynamic, or 'controls'.
783     parent: An edge to the parent, which is always a Section  instance.
784     namespaces: A sequence of InnerNamespace children.
785     entries: A sequence of Entry/Clone children.
786     merged_entries: A sequence of MergedEntry virtual nodes from entries
787   """
788   def __init__(self, name, parent):
789     self._name = name
790     self._parent = parent
791     self._namespaces = []
792     self._entries = []
793
794     self._leafs = []
795
796   @property
797   def namespaces(self):
798     return self._namespaces
799
800   @property
801   def entries(self):
802     return self._entries
803
804   @property
805   def merged_entries(self):
806     for i in self.entries:
807       yield i.merge()
808
809   def sort_children(self):
810     self._namespaces.sort(key=self._get_name())
811     self._entries.sort(key=self._get_name())
812
813   def _get_children(self):
814     for i in self.namespaces:
815       yield i
816     for i in self.entries:
817       yield i
818
819   def combine_children_by_name(self):
820     r"""
821     Combine multiple children with the same name into a single node.
822
823     Returns:
824       A new Kind where all of the children with the same name were combined.
825
826       For example:
827
828       Given a Kind k:
829
830               k
831             / | \
832             a b c
833             | | |
834             d e f
835
836       a.name == "foo"
837       b.name == "foo"
838       c.name == "bar"
839
840       The returned Kind will look like this:
841
842              k'
843             /  \
844             a' c'
845           / |  |
846           d e  f
847
848     Remarks:
849       This operation is not recursive. To combine the grandchildren and other
850       ancestors, call this method on the ancestor nodes.
851     """
852     return Kind._combine_children_by_name(self, new_type=type(self))
853
854   # new_type is either Kind or InnerNamespace
855   @staticmethod
856   def _combine_children_by_name(self, new_type):
857     new_ins_dict = OrderedDict()
858     new_ent_dict = OrderedDict()
859
860     for ins in self.namespaces:
861       new_ins = new_ins_dict.setdefault(ins.name,
862                                         InnerNamespace(ins.name, parent=self))
863       new_ins._namespaces.extend(ins.namespaces)
864       new_ins._entries.extend(ins.entries)
865
866     for ent in self.entries:
867       new_ent = new_ent_dict.setdefault(ent.name,
868                                         ent.merge())
869
870     kind = new_type(self.name, self.parent)
871     kind._namespaces = new_ins_dict.values()
872     kind._entries = new_ent_dict.values()
873
874     return kind
875
876 class InnerNamespace(Node):
877   """
878   A node corresponding to a <namespace> which is an ancestor of a Kind.
879   These namespaces may have other namespaces recursively, or entries as leafs.
880
881   Attributes (Read-Only):
882     name: Name attribute from the element, e.g. <namespace name="foo"> -> 'foo'
883     parent: An edge to the parent, which is an InnerNamespace or a Kind.
884     namespaces: A sequence of InnerNamespace children.
885     entries: A sequence of Entry/Clone children.
886     merged_entries: A sequence of MergedEntry virtual nodes from entries
887   """
888   def __init__(self, name, parent):
889     self._name        = name
890     self._parent      = parent
891     self._namespaces  = []
892     self._entries     = []
893     self._leafs       = []
894
895   @property
896   def namespaces(self):
897     return self._namespaces
898
899   @property
900   def entries(self):
901     return self._entries
902
903   @property
904   def merged_entries(self):
905     for i in self.entries:
906       yield i.merge()
907
908   def sort_children(self):
909     self._namespaces.sort(key=self._get_name())
910     self._entries.sort(key=self._get_name())
911
912   def _get_children(self):
913     for i in self.namespaces:
914       yield i
915     for i in self.entries:
916       yield i
917
918   def combine_children_by_name(self):
919     r"""
920     Combine multiple children with the same name into a single node.
921
922     Returns:
923       A new InnerNamespace where all of the children with the same name were
924       combined.
925
926       For example:
927
928       Given an InnerNamespace i:
929
930               i
931             / | \
932             a b c
933             | | |
934             d e f
935
936       a.name == "foo"
937       b.name == "foo"
938       c.name == "bar"
939
940       The returned InnerNamespace will look like this:
941
942              i'
943             /  \
944             a' c'
945           / |  |
946           d e  f
947
948     Remarks:
949       This operation is not recursive. To combine the grandchildren and other
950       ancestors, call this method on the ancestor nodes.
951     """
952     return Kind._combine_children_by_name(self, new_type=type(self))
953
954 class EnumValue(Node):
955   """
956   A class corresponding to a <value> element within an <enum> within an <entry>.
957
958   Attributes (Read-Only):
959     name: A string,                 e.g. 'ON' or 'OFF'
960     id: An optional numeric string, e.g. '0' or '0xFF'
961     deprecated: A boolean, True if the enum should be deprecated.
962     optional: A boolean
963     hidden: A boolean, True if the enum should be hidden.
964     ndk_hidden: A boolean, True if the enum should be hidden in NDK
965     notes: A string describing the notes, or None.
966     sdk_notes: A string describing extra notes for public SDK only
967     ndk_notes: A string describing extra notes for public NDK only
968     parent: An edge to the parent, always an Enum instance.
969   """
970   def __init__(self, name, parent,
971       id=None, deprecated=False, optional=False, hidden=False, notes=None, sdk_notes=None, ndk_notes=None, ndk_hidden=False):
972     self._name = name                    # str, e.g. 'ON' or 'OFF'
973     self._id = id                        # int, e.g. '0'
974     self._deprecated = deprecated        # bool
975     self._optional = optional            # bool
976     self._hidden = hidden                # bool
977     self._ndk_hidden = ndk_hidden        # bool
978     self._notes = notes                  # None or str
979     self._sdk_notes = sdk_notes          # None or str
980     self._ndk_notes = ndk_notes          # None or str
981     self._parent = parent
982
983   @property
984   def id(self):
985     return self._id
986
987   @property
988   def deprecated(self):
989     return self._deprecated
990
991   @property
992   def optional(self):
993     return self._optional
994
995   @property
996   def hidden(self):
997     return self._hidden
998
999   @property
1000   def ndk_hidden(self):
1001     return self._ndk_hidden
1002
1003   @property
1004   def notes(self):
1005     return self._notes
1006
1007   @property
1008   def sdk_notes(self):
1009     return self._sdk_notes
1010
1011   @property
1012   def ndk_notes(self):
1013     return self._ndk_notes
1014
1015   def _get_children(self):
1016     return None
1017
1018 class Enum(Node):
1019   """
1020   A class corresponding to an <enum> element within an <entry>.
1021
1022   Attributes (Read-Only):
1023     parent: An edge to the parent, always an Entry instance.
1024     values: A sequence of EnumValue children.
1025     has_values_with_id: A boolean representing if any of the children have a
1026         non-empty id property.
1027   """
1028   def __init__(self, parent, values, ids={}, deprecateds=[],
1029       optionals=[], hiddens=[], notes={}, sdk_notes={}, ndk_notes={}, ndk_hiddens=[]):
1030     self._values =                                                             \
1031       [ EnumValue(val, self, ids.get(val), val in deprecateds, val in optionals, val in hiddens,  \
1032                   notes.get(val), sdk_notes.get(val), ndk_notes.get(val), val in ndk_hiddens)     \
1033         for val in values ]
1034
1035     self._parent = parent
1036     self._name = None
1037
1038   @property
1039   def values(self):
1040     return (i for i in self._values)
1041
1042   @property
1043   def has_values_with_id(self):
1044     return bool(any(i for i in self.values if i.id))
1045
1046   def _get_children(self):
1047     return (i for i in self._values)
1048
1049 class Entry(Node):
1050   """
1051   A node corresponding to an <entry> element.
1052
1053   Attributes (Read-Only):
1054     parent: An edge to the parent node, which is an InnerNamespace or Kind.
1055     name: The fully qualified name string, e.g. 'android.shading.mode'
1056     name_short: The name attribute from <entry name="mode">, e.g. mode
1057     type: The type attribute from <entry type="bar">
1058     kind: A string ('static', 'dynamic', 'controls') corresponding to the
1059           ancestor Kind#name
1060     container: The container attribute from <entry container="array">, or None.
1061     container_sizes: A sequence of size strings or None if container is None.
1062     enum: An Enum instance if the enum attribute is true, None otherwise.
1063     visibility: The visibility of this entry ('system', 'hidden', 'public')
1064                 across the system. System entries are only visible in native code
1065                 headers. Hidden entries are marked @hide in managed code, while
1066                 public entries are visible in the Android SDK.
1067     applied_visibility: As visibility, but always valid, defaulting to 'system'
1068                         if no visibility is given for an entry.
1069     applied_ndk_visible: Always valid. Default is 'false'.
1070                          Set to 'true' when the visibility implied entry is visible
1071                          in NDK.
1072     synthetic: The C-level visibility of this entry ('false', 'true').
1073                Synthetic entries will not be generated into the native metadata
1074                list of entries (in C code). In general a synthetic entry is
1075                glued together at the Java layer from multiple visibiltity=hidden
1076                entries.
1077     hwlevel: The lowest hardware level at which the entry is guaranteed
1078              to be supported by the camera device. All devices with higher
1079              hwlevels will also include this entry. None means that the
1080              entry is optional on any hardware level.
1081     deprecated: Marks an entry as @Deprecated in the Java layer; if within an
1082                unreleased version this needs to be removed altogether. If applied
1083                to an entry from an older release, then this means the entry
1084                should be ignored by newer code.
1085     optional: a bool representing the optional attribute, which denotes the entry
1086               is required for hardware level full devices, but optional for other
1087               hardware levels.  None if not present.
1088     applied_optional: As optional but always valid, defaulting to False if no
1089                       optional attribute is present.
1090     tuple_values: A sequence of strings describing the tuple values,
1091                   None if container is not 'tuple'.
1092     description: A string description, or None.
1093     range: A string range, or None.
1094     units: A string units, or None.
1095     tags: A sequence of Tag nodes associated with this Entry.
1096     type_notes: A string describing notes for the type, or None.
1097     typedef: A Typedef associated with this Entry, or None.
1098
1099   Remarks:
1100     Subclass Clone can be used interchangeable with an Entry,
1101     for when we don't care about the underlying type.
1102
1103     parent and tags edges are invalid until after Metadata#construct_graph
1104     has been invoked.
1105   """
1106   def __init__(self, **kwargs):
1107     """
1108     Instantiate a new Entry node.
1109
1110     Args:
1111       name: A string with the fully qualified name, e.g. 'android.shading.mode'
1112       type: A string describing the type, e.g. 'int32'
1113       kind: A string describing the kind, e.g. 'static'
1114       hal_version: A string for the initial HIDL HAL metadata version this entry
1115                    was added in
1116
1117     Args (if container):
1118       container: A string describing the container, e.g. 'array' or 'tuple'
1119       container_sizes: A list of string sizes if a container, or None otherwise
1120
1121     Args (if container is 'tuple'):
1122       tuple_values: A list of tuple values, e.g. ['width', 'height']
1123
1124     Args (if the 'enum' attribute is true):
1125       enum: A boolean, True if this is an enum, False otherwise
1126       enum_values: A list of value strings, e.g. ['ON', 'OFF']
1127       enum_optionals: A list of optional enum values, e.g. ['OFF']
1128       enum_notes: A dictionary of value->notes strings.
1129       enum_ids: A dictionary of value->id strings.
1130
1131     Args (optional):
1132       description: A string with a description of the entry.
1133       range: A string with the range of the values of the entry, e.g. '>= 0'
1134       units: A string with the units of the values, e.g. 'inches'
1135       details: A string with the detailed documentation for the entry
1136       hal_details: A string with the HAL implementation details for the entry
1137       ndk_details: A string with the extra NDK API documentation for the entry=
1138       tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1139       type_notes: A string with the notes for the type
1140       visibility: A string describing the visibility, eg 'system', 'hidden',
1141                   'public'
1142       synthetic: A bool to mark whether this entry is visible only at the Java
1143                  layer (True), or at both layers (False = default).
1144       hwlevel: A string of the HW level (one of 'legacy', 'limited', 'full')
1145       deprecated: A bool to mark whether this is @Deprecated at the Java layer
1146                  (default = False).
1147       optional: A bool to mark whether optional for non-full hardware devices
1148       typedef: A string corresponding to a typedef's name attribute.
1149     """
1150
1151     if kwargs.get('type') is None:
1152       print >> sys.stderr, "ERROR: Missing type for entry '%s' kind  '%s'"     \
1153       %(kwargs.get('name'), kwargs.get('kind'))
1154
1155     # Attributes are Read-Only, but edges may be mutated by
1156     # Metadata, particularly during construct_graph
1157
1158     self._name = kwargs['name']
1159     self._type = kwargs['type']
1160     self._kind = kwargs['kind'] # static, dynamic, or controls
1161
1162     self._init_common(**kwargs)
1163
1164   @property
1165   def type(self):
1166     return self._type
1167
1168   @property
1169   def kind(self):
1170     return self._kind
1171
1172   @property
1173   def hal_version(self):
1174     return self._hal_version
1175
1176   @property
1177   def visibility(self):
1178     return self._visibility
1179
1180   @property
1181   def applied_visibility(self):
1182     return self._visibility or 'system'
1183
1184   @property
1185   def applied_ndk_visible(self):
1186     if self._visibility in ("public", "ndk_public"):
1187       return "true"
1188     return "false"
1189
1190   @property
1191   def synthetic(self):
1192     return self._synthetic
1193
1194   @property
1195   def hwlevel(self):
1196     return self._hwlevel
1197
1198   @property
1199   def deprecated(self):
1200     return self._deprecated
1201
1202   # TODO: optional should just return hwlevel is None
1203   @property
1204   def optional(self):
1205     return self._optional
1206
1207   @property
1208   def applied_optional(self):
1209     return self._optional or False
1210
1211   @property
1212   def name_short(self):
1213     return self.get_name_minimal()
1214
1215   @property
1216   def container(self):
1217     return self._container
1218
1219   @property
1220   def container_sizes(self):
1221     if self._container_sizes is None:
1222       return None
1223     else:
1224       return (i for i in self._container_sizes)
1225
1226   @property
1227   def tuple_values(self):
1228     if self._tuple_values is None:
1229       return None
1230     else:
1231       return (i for i in self._tuple_values)
1232
1233   @property
1234   def description(self):
1235     return self._description
1236
1237   @property
1238   def range(self):
1239     return self._range
1240
1241   @property
1242   def units(self):
1243     return self._units
1244
1245   @property
1246   def details(self):
1247     return self._details
1248
1249   @property
1250   def hal_details(self):
1251     return self._hal_details
1252
1253   @property
1254   def ndk_details(self):
1255     return self._ndk_details
1256
1257   @property
1258   def applied_ndk_details(self):
1259     return (self._details or "") + (self._ndk_details or "")
1260
1261   @property
1262   def tags(self):
1263     if self._tags is None:
1264       return None
1265     else:
1266       return (i for i in self._tags)
1267
1268   @property
1269   def type_notes(self):
1270     return self._type_notes
1271
1272   @property
1273   def typedef(self):
1274     return self._typedef
1275
1276   @property
1277   def enum(self):
1278     return self._enum
1279
1280   def _get_children(self):
1281     if self.enum:
1282       yield self.enum
1283
1284   def sort_children(self):
1285     return None
1286
1287   def is_clone(self):
1288     """
1289     Whether or not this is a Clone instance.
1290
1291     Returns:
1292       False
1293     """
1294     return False
1295
1296   def _init_common(self, **kwargs):
1297
1298     self._parent = None # filled in by Metadata::_construct_entries
1299
1300     self._container = kwargs.get('container')
1301     self._container_sizes = kwargs.get('container_sizes')
1302
1303     self._hal_version = kwargs.get('hal_version')
1304     if self._hal_version is None:
1305       self._hal_version = '3.2'
1306
1307     # access these via the 'enum' prop
1308     enum_values = kwargs.get('enum_values')
1309     enum_deprecateds = kwargs.get('enum_deprecateds')
1310     enum_optionals = kwargs.get('enum_optionals')
1311     enum_hiddens = kwargs.get('enum_hiddens')
1312     enum_ndk_hiddens = kwargs.get('enum_ndk_hiddens')
1313     enum_notes = kwargs.get('enum_notes')  # { value => notes }
1314     enum_sdk_notes = kwargs.get('enum_sdk_notes')  # { value => sdk_notes }
1315     enum_ndk_notes = kwargs.get('enum_ndk_notes')  # { value => ndk_notes }
1316     enum_ids = kwargs.get('enum_ids')  # { value => notes }
1317     self._tuple_values = kwargs.get('tuple_values')
1318
1319     self._description = kwargs.get('description')
1320     self._range = kwargs.get('range')
1321     self._units = kwargs.get('units')
1322     self._details = kwargs.get('details')
1323     self._hal_details = kwargs.get('hal_details')
1324     self._ndk_details = kwargs.get('ndk_details')
1325
1326     self._tag_ids = kwargs.get('tag_ids', [])
1327     self._tags = None  # Filled in by Metadata::_construct_tags
1328
1329     self._type_notes = kwargs.get('type_notes')
1330     self._type_name = kwargs.get('type_name')
1331     self._typedef = None # Filled in by Metadata::_construct_types
1332
1333     if kwargs.get('enum', False):
1334       self._enum = Enum(self, enum_values, enum_ids, enum_deprecateds, enum_optionals,
1335                         enum_hiddens, enum_notes, enum_sdk_notes, enum_ndk_notes, enum_ndk_hiddens)
1336     else:
1337       self._enum = None
1338
1339     self._visibility = kwargs.get('visibility')
1340     self._synthetic = kwargs.get('synthetic', False)
1341     self._hwlevel = kwargs.get('hwlevel')
1342     self._deprecated = kwargs.get('deprecated', False)
1343     self._optional = kwargs.get('optional')
1344     self._ndk_visible = kwargs.get('ndk_visible')
1345
1346     self._property_keys = kwargs
1347
1348   def merge(self):
1349     """
1350     Copy the attributes into a new entry, merging it with the target entry
1351     if it's a clone.
1352     """
1353     return MergedEntry(self)
1354
1355   # Helpers for accessing less than the fully qualified name
1356
1357   def get_name_as_list(self):
1358     """
1359     Returns the name as a list split by a period.
1360
1361     For example:
1362       entry.name is 'android.lens.info.shading'
1363       entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
1364     """
1365     return self.name.split(".")
1366
1367   def get_inner_namespace_list(self):
1368     """
1369     Returns the inner namespace part of the name as a list
1370
1371     For example:
1372       entry.name is 'android.lens.info.shading'
1373       entry.get_inner_namespace_list() == ['info']
1374     """
1375     return self.get_name_as_list()[2:-1]
1376
1377   def get_outer_namespace(self):
1378     """
1379     Returns the outer namespace as a string.
1380
1381     For example:
1382       entry.name is 'android.lens.info.shading'
1383       entry.get_outer_namespace() == 'android'
1384
1385     Remarks:
1386       Since outer namespaces are non-recursive,
1387       and each entry has one, this does not need to be a list.
1388     """
1389     return self.get_name_as_list()[0]
1390
1391   def get_section(self):
1392     """
1393     Returns the section as a string.
1394
1395     For example:
1396       entry.name is 'android.lens.info.shading'
1397       entry.get_section() == ''
1398
1399     Remarks:
1400       Since outer namespaces are non-recursive,
1401       and each entry has one, this does not need to be a list.
1402     """
1403     return self.get_name_as_list()[1]
1404
1405   def get_name_minimal(self):
1406     """
1407     Returns only the last component of the fully qualified name as a string.
1408
1409     For example:
1410       entry.name is 'android.lens.info.shading'
1411       entry.get_name_minimal() == 'shading'
1412
1413     Remarks:
1414       entry.name_short it an alias for this
1415     """
1416     return self.get_name_as_list()[-1]
1417
1418   def get_path_without_name(self):
1419     """
1420     Returns a string path to the entry, with the name component excluded.
1421
1422     For example:
1423       entry.name is 'android.lens.info.shading'
1424       entry.get_path_without_name() == 'android.lens.info'
1425     """
1426     return ".".join(self.get_name_as_list()[0:-1])
1427
1428
1429 class Clone(Entry):
1430   """
1431   A Node corresponding to a <clone> element. It has all the attributes of an
1432   <entry> element (Entry) plus the additions specified below.
1433
1434   Attributes (Read-Only):
1435     entry: an edge to an Entry object that this targets
1436     target_kind: A string describing the kind of the target entry.
1437     name: a string of the name, same as entry.name
1438     kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
1439           for the <clone> element.
1440     type: always None, since a clone cannot override the type.
1441   """
1442   def __init__(self, entry=None, **kwargs):
1443     """
1444     Instantiate a new Clone node.
1445
1446     Args:
1447       name: A string with the fully qualified name, e.g. 'android.shading.mode'
1448       type: A string describing the type, e.g. 'int32'
1449       kind: A string describing the kind, e.g. 'static'
1450       target_kind: A string for the kind of the target entry, e.g. 'dynamic'
1451       hal_version: A string for the initial HIDL HAL metadata version this entry
1452                    was added in
1453
1454     Args (if container):
1455       container: A string describing the container, e.g. 'array' or 'tuple'
1456       container_sizes: A list of string sizes if a container, or None otherwise
1457
1458     Args (if container is 'tuple'):
1459       tuple_values: A list of tuple values, e.g. ['width', 'height']
1460
1461     Args (if the 'enum' attribute is true):
1462       enum: A boolean, True if this is an enum, False otherwise
1463       enum_values: A list of value strings, e.g. ['ON', 'OFF']
1464       enum_optionals: A list of optional enum values, e.g. ['OFF']
1465       enum_notes: A dictionary of value->notes strings.
1466       enum_ids: A dictionary of value->id strings.
1467
1468     Args (optional):
1469       entry: An edge to the corresponding target Entry.
1470       description: A string with a description of the entry.
1471       range: A string with the range of the values of the entry, e.g. '>= 0'
1472       units: A string with the units of the values, e.g. 'inches'
1473       details: A string with the detailed documentation for the entry
1474       hal_details: A string with the HAL implementation details for the entry
1475       ndk_details: A string with the extra NDK documentation for the entry
1476       tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1477       type_notes: A string with the notes for the type
1478
1479     Remarks:
1480       Note that type is not specified since it has to be the same as the
1481       entry.type.
1482     """
1483     self._entry = entry  # Entry object
1484     self._target_kind = kwargs['target_kind']
1485     self._name = kwargs['name']  # same as entry.name
1486     self._kind = kwargs['kind']
1487
1488     # illegal to override the type, it should be the same as the entry
1489     self._type = None
1490     # the rest of the kwargs are optional
1491     # can be used to override the regular entry data
1492     self._init_common(**kwargs)
1493
1494   @property
1495   def entry(self):
1496     return self._entry
1497
1498   @property
1499   def target_kind(self):
1500     return self._target_kind
1501
1502   def is_clone(self):
1503     """
1504     Whether or not this is a Clone instance.
1505
1506     Returns:
1507       True
1508     """
1509     return True
1510
1511 class MergedEntry(Entry):
1512   """
1513   A MergedEntry has all the attributes of a Clone and its target Entry merged
1514   together.
1515
1516   Remarks:
1517     Useful when we want to 'unfold' a clone into a real entry by copying out
1518     the target entry data. In this case we don't care about distinguishing
1519     a clone vs an entry.
1520   """
1521   def __init__(self, entry):
1522     """
1523     Create a new instance of MergedEntry.
1524
1525     Args:
1526       entry: An Entry or Clone instance
1527     """
1528     props_distinct = ['description', 'units', 'range', 'details',
1529                       'hal_details', 'ndk_details', 'tags', 'kind']
1530
1531     for p in props_distinct:
1532       p = '_' + p
1533       if entry.is_clone():
1534         setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
1535       else:
1536         setattr(self, p, getattr(entry, p))
1537
1538     props_common = ['parent', 'name', 'container',
1539                     'container_sizes', 'enum',
1540                     'tuple_values',
1541                     'type',
1542                     'type_notes',
1543                     'visibility',
1544                     'ndk_visible',
1545                     'synthetic',
1546                     'hwlevel',
1547                     'deprecated',
1548                     'optional',
1549                     'typedef',
1550                     'hal_version'
1551                    ]
1552
1553     for p in props_common:
1554       p = '_' + p
1555       if entry.is_clone():
1556         setattr(self, p, getattr(entry.entry, p))
1557       else:
1558         setattr(self, p, getattr(entry, p))