• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# Copyright (C) 2012 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17"""
18A set of helpers for rendering Mako templates with a Metadata model.
19"""
20
21import metadata_model
22from collections import OrderedDict
23
24_context_buf = None
25
26def _is_sec_or_ins(x):
27  return isinstance(x, metadata_model.Section) or    \
28         isinstance(x, metadata_model.InnerNamespace)
29
30##
31## Metadata Helpers
32##
33
34def find_all_sections(root):
35  """
36  Find all descendants that are Section or InnerNamespace instances.
37
38  Args:
39    root: a Metadata instance
40
41  Returns:
42    A list of Section/InnerNamespace instances
43
44  Remarks:
45    These are known as "sections" in the generated C code.
46  """
47  return root.find_all(_is_sec_or_ins)
48
49def find_parent_section(entry):
50  """
51  Find the closest ancestor that is either a Section or InnerNamespace.
52
53  Args:
54    entry: an Entry or Clone node
55
56  Returns:
57    An instance of Section or InnerNamespace
58  """
59  return entry.find_parent_first(_is_sec_or_ins)
60
61# find uniquely named entries (w/o recursing through inner namespaces)
62def find_unique_entries(node):
63  """
64  Find all uniquely named entries, without recursing through inner namespaces.
65
66  Args:
67    node: a Section or InnerNamespace instance
68
69  Yields:
70    A sequence of MergedEntry nodes representing an entry
71
72  Remarks:
73    This collapses multiple entries with the same fully qualified name into
74    one entry (e.g. if there are multiple entries in different kinds).
75  """
76  if not isinstance(node, metadata_model.Section) and    \
77     not isinstance(node, metadata_model.InnerNamespace):
78      raise TypeError("expected node to be a Section or InnerNamespace")
79
80  d = OrderedDict()
81  # remove the 'kinds' from the path between sec and the closest entries
82  # then search the immediate children of the search path
83  search_path = isinstance(node, metadata_model.Section) and node.kinds \
84                or [node]
85  for i in search_path:
86      for entry in i.entries:
87          d[entry.name] = entry
88
89  for k,v in d.iteritems():
90      yield v.merge()
91
92def path_name(node):
93  """
94  Calculate a period-separated string path from the root to this element,
95  by joining the names of each node and excluding the Metadata/Kind nodes
96  from the path.
97
98  Args:
99    node: a Node instance
100
101  Returns:
102    A string path
103  """
104
105  isa = lambda x,y: isinstance(x, y)
106  fltr = lambda x: not isa(x, metadata_model.Metadata) and \
107                   not isa(x, metadata_model.Kind)
108
109  path = node.find_parents(fltr)
110  path = list(path)
111  path.reverse()
112  path.append(node)
113
114  return ".".join((i.name for i in path))
115
116##
117## Filters
118##
119
120# abcDef.xyz -> ABC_DEF_XYZ
121def csym(name):
122  """
123  Convert an entry name string into an uppercase C symbol.
124
125  Returns:
126    A string
127
128  Example:
129    csym('abcDef.xyz') == 'ABC_DEF_XYZ'
130  """
131  newstr = name
132  newstr = "".join([i.isupper() and ("_" + i) or i for i in newstr]).upper()
133  newstr = newstr.replace(".", "_")
134  return newstr
135
136# abcDef.xyz -> abc_def_xyz
137def csyml(name):
138  """
139  Convert an entry name string into a lowercase C symbol.
140
141  Returns:
142    A string
143
144  Example:
145    csyml('abcDef.xyz') == 'abc_def_xyz'
146  """
147  return csym(name).lower()
148
149# pad with spaces to make string len == size. add new line if too big
150def ljust(size, indent=4):
151  """
152  Creates a function that given a string will pad it with spaces to make
153  the string length == size. Adds a new line if the string was too big.
154
155  Args:
156    size: an integer representing how much spacing should be added
157    indent: an integer representing the initial indendation level
158
159  Returns:
160    A function that takes a string and returns a string.
161
162  Example:
163    ljust(8)("hello") == 'hello   '
164
165  Remarks:
166    Deprecated. Use pad instead since it works for non-first items in a
167    Mako template.
168  """
169  def inner(what):
170    newstr = what.ljust(size)
171    if len(newstr) > size:
172      return what + "\n" + "".ljust(indent + size)
173    else:
174      return newstr
175  return inner
176
177def _find_new_line():
178
179  if _context_buf is None:
180    raise ValueError("Context buffer was not set")
181
182  buf = _context_buf
183  x = -1 # since the first read is always ''
184  cur_pos = buf.tell()
185  while buf.tell() > 0 and buf.read(1) != '\n':
186    buf.seek(cur_pos - x)
187    x = x + 1
188
189  buf.seek(cur_pos)
190
191  return int(x)
192
193# Pad the string until the buffer reaches the desired column.
194# If string is too long, insert a new line with 'col' spaces instead
195def pad(col):
196  """
197  Create a function that given a string will pad it to the specified column col.
198  If the string overflows the column, put the string on a new line and pad it.
199
200  Args:
201    col: an integer specifying the column number
202
203  Returns:
204    A function that given a string will produce a padded string.
205
206  Example:
207    pad(8)("hello") == 'hello   '
208
209  Remarks:
210    This keeps track of the line written by Mako so far, so it will always
211    align to the column number correctly.
212  """
213  def inner(what):
214    wut = int(col)
215    current_col = _find_new_line()
216
217    if len(what) > wut - current_col:
218      return what + "\n".ljust(col)
219    else:
220      return what.ljust(wut - current_col)
221  return inner
222
223# int32 -> TYPE_INT32, byte -> TYPE_BYTE, etc. note that enum -> TYPE_INT32
224def ctype_enum(what):
225  """
226  Generate a camera_metadata_type_t symbol from a type string.
227
228  Args:
229    what: a type string
230
231  Returns:
232    A string representing the camera_metadata_type_t
233
234  Example:
235    ctype_enum('int32') == 'TYPE_INT32'
236    ctype_enum('int64') == 'TYPE_INT64'
237    ctype_enum('float') == 'TYPE_FLOAT'
238
239  Remarks:
240    An enum is coerced to a byte since the rest of the camera_metadata
241    code doesn't support enums directly yet.
242  """
243  return 'TYPE_%s' %(what.upper())
244