2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
22 # 'KEY' : ( <TYPE>, [Accepted Values], <Required?>)
24 'DISABLE': (bool, [True, False], False),
25 'SEL_LDR': (bool, [True, False], False),
26 # Disable this project from being included in the NaCl packaged app.
27 'DISABLE_PACKAGE': (bool, [True, False], False),
28 # Don't generate the additional files to allow this project to run as a
29 # packaged app (i.e. manifest.json, background.js, etc.).
30 'NO_PACKAGE_FILES': (bool, [True, False], False),
31 'TOOLS' : (list, VALID_TOOLCHAINS
, True),
32 'CONFIGS' : (list, ['Debug', 'Release'], False),
33 'PREREQ' : (list, '', False),
35 'NAME': (str, '', True),
37 # lib = library target
38 # so = shared object target, automatically added to NMF
39 # so-standalone = shared object target, not put into NMF
40 'TYPE': (str, ['main', 'lib', 'static-lib', 'so', 'so-standalone'],
42 'SOURCES': (list, '', True),
43 'CFLAGS': (list, '', False),
44 'CFLAGS_GCC': (list, '', False),
45 'CXXFLAGS': (list, '', False),
46 'DEFINES': (list, '', False),
47 'LDFLAGS': (list, '', False),
48 'INCLUDES': (list, '', False),
49 'LIBS' : (dict, VALID_TOOLCHAINS
, False),
50 'DEPS' : (list, '', False)
53 'FILES': (list, '', True),
54 'DEST': (str, '', True),
56 'SEARCH': (list, '', False),
57 'POST': (str, '', False),
58 'PRE': (str, '', False),
59 'DEST': (str, ['getting_started', 'examples/api', 'examples/benchmarks',
60 'examples/demo', 'examples/tutorial',
61 'src', 'tests'], True),
62 'NAME': (str, '', False),
63 'DATA': (list, '', False),
64 'TITLE': (str, '', False),
65 'GROUP': (str, '', False),
66 'EXPERIMENTAL': (bool, [True, False], False),
67 'PERMISSIONS': (list, '', False),
68 'SOCKET_PERMISSIONS': (list, '', False),
69 'FILESYSTEM_PERMISSIONS': (list, '', False),
70 'MULTI_PLATFORM': (bool, [True, False], False),
71 'MIN_CHROME_VERSION': (str, '', False),
75 class ValidationError(Exception):
79 def ValidateFormat(src
, dsc_format
):
80 # Verify all required keys are there
81 for key
in dsc_format
:
82 exp_type
, exp_value
, required
= dsc_format
[key
]
83 if required
and key
not in src
:
84 raise ValidationError('Missing required key %s.' % key
)
86 # For each provided key, verify it's valid
88 # Verify the key is known
89 if key
not in dsc_format
:
90 raise ValidationError('Unexpected key %s.' % key
)
92 exp_type
, exp_value
, required
= dsc_format
[key
]
95 # Verify the value is non-empty if required
96 if required
and not value
:
97 raise ValidationError('Expected non-empty value for %s.' % key
)
99 # If the expected type is a dict, but the provided type is a list
100 # then the list applies to all keys of the dictionary, so we reset
101 # the expected type and value.
103 if type(value
) is list:
107 # Verify the key is of the expected type
108 if exp_type
!= type(value
):
109 raise ValidationError('Key %s expects %s not %s.' % (
110 key
, exp_type
.__name
__.upper(), type(value
).__name
__.upper()))
112 # If it's a bool, the expected values are always True or False.
116 # If it's a string and there are expected values, make sure it matches
118 if type(exp_value
) is list and exp_value
:
119 if value
not in exp_value
:
120 raise ValidationError("Value '%s' not expected for %s." %
124 # if it's a list, then we need to validate the values
126 # If we expect a dictionary, then call this recursively
127 if type(exp_value
) is dict:
129 ValidateFormat(val
, exp_value
)
131 # If we expect a list of strings
132 if type(exp_value
) is str:
134 if type(val
) is not str:
135 raise ValidationError('Value %s in %s is not a string.' %
138 # if we expect a particular string
139 if type(exp_value
) is list:
141 if val
not in exp_value
:
142 raise ValidationError('Value %s not expected in %s.' %
146 # if we are expecting a dict, verify the keys are allowed
148 print "Expecting dict\n"
150 if sub
not in exp_value
:
151 raise ValidationError('Sub key %s not expected in %s.' %
155 # If we got this far, it's an unexpected type
156 raise ValidationError('Unexpected type %s for key %s.' %
157 (str(type(src
[key
])), key
))
160 def LoadProject(filename
):
161 with
open(filename
, 'r') as descfile
:
163 desc
= eval(descfile
.read(), {}, {})
164 except Exception as e
:
165 raise ValidationError(e
)
166 if desc
.get('DISABLE', False):
168 ValidateFormat(desc
, DSC_FORMAT
)
169 desc
['FILEPATH'] = os
.path
.abspath(filename
)
173 def LoadProjectTreeUnfiltered(srcpath
):
175 out
= collections
.defaultdict(list)
176 for root
, _
, files
in os
.walk(srcpath
):
177 for filename
in files
:
178 if fnmatch
.fnmatch(filename
, '*.dsc'):
179 filepath
= os
.path
.join(root
, filename
)
181 desc
= LoadProject(filepath
)
182 except ValidationError
as e
:
183 raise ValidationError("Failed to validate: %s: %s" % (filepath
, e
))
186 out
[key
].append(desc
)
190 def LoadProjectTree(srcpath
, include
, exclude
=None):
191 out
= LoadProjectTreeUnfiltered(srcpath
)
192 return FilterTree(out
, MakeDefaultFilterFn(include
, exclude
))
195 def GenerateProjects(tree
):
197 for val
in tree
[key
]:
201 def FilterTree(tree
, filter_fn
):
202 out
= collections
.defaultdict(list)
203 for branch
, desc
in GenerateProjects(tree
):
205 out
[branch
].append(desc
)
209 def MakeDefaultFilterFn(include
, exclude
):
210 def DefaultFilterFn(desc
):
211 matches_include
= not include
or DescMatchesFilter(desc
, include
)
212 matches_exclude
= exclude
and DescMatchesFilter(desc
, exclude
)
214 # Exclude list overrides include list.
217 return matches_include
219 return DefaultFilterFn
222 def DescMatchesFilter(desc
, filters
):
223 for key
, expected
in filters
.iteritems():
224 # For any filtered key which is unspecified, assumed False
225 value
= desc
.get(key
, False)
227 # If we provide an expected list, match at least one
228 if type(expected
) != list:
229 expected
= set([expected
])
230 if type(value
) != list:
233 if not set(expected
) & set(value
):
236 # If we fall through, then we matched the filters
240 def PrintProjectTree(tree
):
243 for val
in tree
[key
]:
244 print '\t' + val
['NAME']
248 parser
= optparse
.OptionParser(usage
='%prog [options] <dir>')
249 parser
.add_option('-e', '--experimental',
250 help='build experimental examples and libraries', action
='store_true')
251 parser
.add_option('-t', '--toolchain',
252 help='Build using toolchain. Can be passed more than once.',
255 options
, args
= parser
.parse_args(argv
)
260 parser
.error('Expected 0 or 1 args, got %d.' % len(args
))
263 load_from_dir
= args
[0]
265 if options
.toolchain
:
266 filters
['TOOLS'] = options
.toolchain
268 if not options
.experimental
:
269 filters
['EXPERIMENTAL'] = False
272 tree
= LoadProjectTree(load_from_dir
, include
=filters
)
273 except ValidationError
as e
:
274 sys
.stderr
.write(str(e
) + '\n')
277 PrintProjectTree(tree
)
281 if __name__
== '__main__':
282 sys
.exit(main(sys
.argv
[1:]))