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.
12 from build_paths
import SDK_SRC_DIR
, SCRIPT_DIR
, OUT_DIR
14 # Add SDK make tools scripts to the python path.
15 sys
.path
.append(os
.path
.join(SDK_SRC_DIR
, 'tools'))
19 VALID_PLATFORMS
= ['linux', 'mac', 'win']
20 PLATFORM_PREFIX_RE
= re
.compile(r
'^\[([^\]]*)\](.*)$')
22 class ParseException(Exception):
23 def __init__(self
, filename
, line
, message
):
24 Exception.__init
__(self
)
25 self
.filename
= filename
27 self
.message
= message
30 return '%s:%d: %s' % (self
.filename
, self
.line
, self
.message
)
33 def SplitPattern(pattern
):
34 match
= PLATFORM_PREFIX_RE
.match(pattern
)
38 # platform-specific line
39 platforms
= match
.group(1).split(',')
41 # If this platform is included, strip the [...] part.
42 pattern
= match
.group(2)
43 return pattern
, platforms
46 class VerifyException(Exception):
50 def __init__(self
, filename
, platform
=None, contents
=None):
51 self
.glob_prefixes
= []
52 self
.exact_filenames
= set()
53 self
.filename
= filename
54 self
.platform
= platform
or getos
.GetPlatform()
55 self
.exe_ext
= '.exe' if self
.platform
== 'win' else ''
57 if self
.platform
not in VALID_PLATFORMS
:
58 raise ParseException(self
.filename
, 1,
59 'Unknown platform %s' % self
.platform
)
62 with
open(filename
) as f
:
65 for line_no
, rule
in enumerate(contents
.split('\n')):
68 self
.ParsePattern(line_no
+ 1, rule
)
70 def ParsePattern(self
, line_no
, pattern
):
71 pattern
, platforms
= SplitPattern(pattern
)
73 unknown_platforms
= set(platforms
) - set(VALID_PLATFORMS
)
75 msg
= 'Unknown platform(s) %s.' % (
76 ', '.join('"%s"' % platform
for platform
in unknown_platforms
))
77 raise ParseException(self
.filename
, line_no
, msg
)
78 if self
.platform
not in platforms
:
81 pattern
= pattern
.replace('${PLATFORM}', self
.platform
)
82 pattern
= pattern
.replace('${EXE_EXT}', self
.exe_ext
)
86 # We only support * at the end.
87 if pattern
.find('*') != len(pattern
) - 1:
88 msg
= '* is only allowed at the end of the line.'
89 raise ParseException(self
.filename
, line_no
, msg
)
92 pattern
= pattern
[:-1]
93 self
.glob_prefixes
.append(pattern
)
94 # Sort by longest prefix first; otherwise the rules:
99 # Won't work properly. A file "foo/bar/baz" will match the first rule,
101 self
.glob_prefixes
.sort(cmp=lambda x
, y
: cmp(len(y
), len(x
)))
103 self
.exact_filenames
.add(pattern
)
105 def VerifyDirectoryList(self
, directory_list
):
106 exact_filenames_used
= set()
107 glob_prefixes_used
= set()
108 expected_globs
= set()
109 expected_filenames
= set()
110 unexpected_filenames
= set()
112 for filename
in directory_list
:
113 if os
.path
.sep
!= '/':
114 filename
= filename
.replace(os
.path
.sep
, '/')
115 if filename
in self
.exact_filenames
:
116 exact_filenames_used
.add(filename
)
121 for prefix
in self
.glob_prefixes
:
122 if filename
.startswith(prefix
):
123 glob_prefixes_used
.add(prefix
)
128 unexpected_filenames
.add(filename
)
130 if len(exact_filenames_used
) != len(self
.exact_filenames
):
131 # We looped through the directory list, so if the lengths are unequal, it
132 # must be that we expected something that isn't there.
133 expected_filenames
= self
.exact_filenames
- exact_filenames_used
135 if len(glob_prefixes_used
) != self
.glob_prefixes
:
136 expected_globs
= set(self
.glob_prefixes
) - glob_prefixes_used
138 if expected_filenames
or unexpected_filenames
or expected_globs
:
140 if unexpected_filenames
:
141 msg
+= '>>> Unexpected filenames: <<<\n%s\n' % (
142 '\n'.join(sorted(unexpected_filenames
)))
143 if expected_filenames
:
144 msg
+= '>>> Expected filenames: <<<\n%s\n' % (
145 '\n'.join(sorted(expected_filenames
)))
147 msg
+= '>>> Expected 1+ files in these directories: <<< \n%s\n' % (
148 '\n'.join(sorted(expected_globs
)))
149 raise VerifyException(msg
)
152 def GetDirectoryList(directory_path
):
154 for root
, _
, files
in os
.walk(directory_path
):
155 rel_root
= os
.path
.relpath(root
, directory_path
)
158 for base_name
in files
:
159 result
.append(os
.path
.join(rel_root
, base_name
))
163 def Verify(rule_path
, directory_path
, platform
=None):
164 rules
= Rules(rule_path
, platform
=platform
)
165 directory_list
= GetDirectoryList(directory_path
)
166 rules
.VerifyDirectoryList(directory_list
)
169 def SortFile(rule_path
):
170 with
open(rule_path
) as infile
:
171 lines
= infile
.readlines()
173 def compare(line1
, line2
):
174 line1
= SplitPattern(line1
)[0].lower()
175 line2
= SplitPattern(line2
)[0].lower()
176 return cmp(line1
, line2
)
179 with
open(rule_path
, 'w') as output
:
185 parser
= optparse
.OptionParser(usage
='%prog <rule file> <directory>')
186 parser
.add_option('-p', '--platform',
187 help='Test with this platform, instead of the system\'s platform')
188 parser
.add_option('-s', '--sort', action
='store_true',
189 help='Sort the file list in place, rather than verifying the contents.')
190 options
, args
= parser
.parse_args(args
)
193 args
= [os
.path
.join(SCRIPT_DIR
, 'sdk_files.list')]
197 parser
.error('Expected rule file.')
202 version
= build_version
.ChromeMajorVersion()
203 args
.append(os
.path
.join(OUT_DIR
, 'pepper_%s' % version
))
205 rule_path
, directory_path
= args
207 if options
.platform
not in VALID_PLATFORMS
:
208 parser
.error('Unknown platform: %s' % options
.platform
)
209 platform
= options
.platform
211 platform
= getos
.GetPlatform()
214 return Verify(rule_path
, directory_path
, platform
)
215 except ParseException
, e
:
216 print >> sys
.stderr
, 'Error parsing rules:\n', e
218 except VerifyException
, e
:
219 print >> sys
.stderr
, 'Error verifying file list:\n', e
224 if __name__
== '__main__':
225 sys
.exit(main(sys
.argv
[1:]))