Initial commit
[yaffs-website] / node_modules / node-gyp / gyp / pylib / gyp / ninja_syntax.py
1 # This file comes from
2 #   https://github.com/martine/ninja/blob/master/misc/ninja_syntax.py
3 # Do not edit!  Edit the upstream one instead.
4
5 """Python module for generating .ninja files.
6
7 Note that this is emphatically not a required piece of Ninja; it's
8 just a helpful utility for build-file-generation systems that already
9 use Python.
10 """
11
12 import textwrap
13 import re
14
15 def escape_path(word):
16     return word.replace('$ ','$$ ').replace(' ','$ ').replace(':', '$:')
17
18 class Writer(object):
19     def __init__(self, output, width=78):
20         self.output = output
21         self.width = width
22
23     def newline(self):
24         self.output.write('\n')
25
26     def comment(self, text):
27         for line in textwrap.wrap(text, self.width - 2):
28             self.output.write('# ' + line + '\n')
29
30     def variable(self, key, value, indent=0):
31         if value is None:
32             return
33         if isinstance(value, list):
34             value = ' '.join(filter(None, value))  # Filter out empty strings.
35         self._line('%s = %s' % (key, value), indent)
36
37     def pool(self, name, depth):
38         self._line('pool %s' % name)
39         self.variable('depth', depth, indent=1)
40
41     def rule(self, name, command, description=None, depfile=None,
42              generator=False, pool=None, restat=False, rspfile=None,
43              rspfile_content=None, deps=None):
44         self._line('rule %s' % name)
45         self.variable('command', command, indent=1)
46         if description:
47             self.variable('description', description, indent=1)
48         if depfile:
49             self.variable('depfile', depfile, indent=1)
50         if generator:
51             self.variable('generator', '1', indent=1)
52         if pool:
53             self.variable('pool', pool, indent=1)
54         if restat:
55             self.variable('restat', '1', indent=1)
56         if rspfile:
57             self.variable('rspfile', rspfile, indent=1)
58         if rspfile_content:
59             self.variable('rspfile_content', rspfile_content, indent=1)
60         if deps:
61             self.variable('deps', deps, indent=1)
62
63     def build(self, outputs, rule, inputs=None, implicit=None, order_only=None,
64               variables=None):
65         outputs = self._as_list(outputs)
66         all_inputs = self._as_list(inputs)[:]
67         out_outputs = list(map(escape_path, outputs))
68         all_inputs = list(map(escape_path, all_inputs))
69
70         if implicit:
71             implicit = map(escape_path, self._as_list(implicit))
72             all_inputs.append('|')
73             all_inputs.extend(implicit)
74         if order_only:
75             order_only = map(escape_path, self._as_list(order_only))
76             all_inputs.append('||')
77             all_inputs.extend(order_only)
78
79         self._line('build %s: %s' % (' '.join(out_outputs),
80                                         ' '.join([rule] + all_inputs)))
81
82         if variables:
83             if isinstance(variables, dict):
84                 iterator = iter(variables.items())
85             else:
86                 iterator = iter(variables)
87
88             for key, val in iterator:
89                 self.variable(key, val, indent=1)
90
91         return outputs
92
93     def include(self, path):
94         self._line('include %s' % path)
95
96     def subninja(self, path):
97         self._line('subninja %s' % path)
98
99     def default(self, paths):
100         self._line('default %s' % ' '.join(self._as_list(paths)))
101
102     def _count_dollars_before_index(self, s, i):
103       """Returns the number of '$' characters right in front of s[i]."""
104       dollar_count = 0
105       dollar_index = i - 1
106       while dollar_index > 0 and s[dollar_index] == '$':
107         dollar_count += 1
108         dollar_index -= 1
109       return dollar_count
110
111     def _line(self, text, indent=0):
112         """Write 'text' word-wrapped at self.width characters."""
113         leading_space = '  ' * indent
114         while len(leading_space) + len(text) > self.width:
115             # The text is too wide; wrap if possible.
116
117             # Find the rightmost space that would obey our width constraint and
118             # that's not an escaped space.
119             available_space = self.width - len(leading_space) - len(' $')
120             space = available_space
121             while True:
122               space = text.rfind(' ', 0, space)
123               if space < 0 or \
124                  self._count_dollars_before_index(text, space) % 2 == 0:
125                 break
126
127             if space < 0:
128                 # No such space; just use the first unescaped space we can find.
129                 space = available_space - 1
130                 while True:
131                   space = text.find(' ', space + 1)
132                   if space < 0 or \
133                      self._count_dollars_before_index(text, space) % 2 == 0:
134                     break
135             if space < 0:
136                 # Give up on breaking.
137                 break
138
139             self.output.write(leading_space + text[0:space] + ' $\n')
140             text = text[space+1:]
141
142             # Subsequent lines are continuations, so indent them.
143             leading_space = '  ' * (indent+2)
144
145         self.output.write(leading_space + text + '\n')
146
147     def _as_list(self, input):
148         if input is None:
149             return []
150         if isinstance(input, list):
151             return input
152         return [input]
153
154
155 def escape(string):
156     """Escape a string such that it can be embedded into a Ninja file without
157     further interpretation."""
158     assert '\n' not in string, 'Ninja syntax does not allow newlines'
159     # We only have one special metacharacter: '$'.
160     return string.replace('$', '$$')