1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
#!/usr/bin/env python
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Helper script for PPAPI's PRESUBMIT.py to detect if additions or removals of
PPAPI interfaces have been propagated to the Native Client libraries (.dsc
files).
For example, if a user adds "ppapi/c/foo.h", we check that the interface has
been added to "native_client_sdk/src/libraries/ppapi/library.dsc".
"""
import argparse
import os
import sys
from build_paths import PPAPI_DIR, SRC_DIR, SDK_LIBRARY_DIR
import parse_dsc
# Add a file to this list if it should not be added to a .dsc file; i.e. if it
# should not be included in the Native Client SDK. This will silence the
# presubmit warning.
#
# Some examples of files that should not be added to the SDK are: Dev and
# Private interfaces that are either not available to NaCl plugins or are only
# available to Flash or other privileged plugins.
IGNORED_FILES = set([
'ppb_font_dev.h',
'pp_video_dev.h',
])
class VerifyException(Exception):
def __init__(self, lib_path, expected, unexpected):
self.expected = expected
self.unexpected = unexpected
msg = 'In %s:\n' % lib_path
if expected:
msg += ' these files are missing and should be added:\n'
for filename in sorted(expected):
msg += ' %s\n' % filename
if unexpected:
msg += ' these files no longer exist and should be removed:\n'
for filename in sorted(unexpected):
msg += ' %s\n' % filename
Exception.__init__(self, msg)
def PartitionFiles(filenames):
c_filenames = set()
cpp_filenames = set()
private_filenames = set()
for filename in filenames:
if os.path.splitext(filename)[1] not in ('.cc', '.h'):
continue
parts = filename.split(os.sep)
basename = os.path.basename(filename)
if basename in IGNORED_FILES:
continue
if 'private' in filename:
if 'flash' in filename:
continue
private_filenames.add(filename)
elif parts[0:2] == ['ppapi', 'c']:
if len(parts) >= 2 and parts[2] in ('documentation', 'trusted'):
continue
c_filenames.add(filename)
elif (parts[0:2] == ['ppapi', 'cpp'] or
parts[0:2] == ['ppapi', 'utility']):
if len(parts) >= 2 and parts[2] in ('documentation', 'trusted'):
continue
cpp_filenames.add(filename)
else:
continue
return {
'ppapi': c_filenames,
'ppapi_cpp': cpp_filenames,
'ppapi_cpp_private': private_filenames
}
def GetDirectoryList(directory_path, relative_to):
result = []
for root, _, files in os.walk(directory_path):
rel_root = os.path.relpath(root, relative_to)
if rel_root == '.':
rel_root = ''
for base_name in files:
result.append(os.path.join(rel_root, base_name))
return result
def GetDscSourcesAndHeaders(dsc):
result = []
for headers_info in dsc.get('HEADERS', []):
result.extend(headers_info['FILES'])
for targets_info in dsc.get('TARGETS', []):
result.extend(targets_info['SOURCES'])
return result
def GetChangedAndRemovedFilenames(modified_filenames, directory_list):
changed = set()
removed = set()
directory_list_set = set(directory_list)
for filename in modified_filenames:
if filename in directory_list_set:
# We can't know if a file was added (that would require knowing the
# previous state of the working directory). Instead, we assume that a
# changed file may have been added, and check it accordingly.
changed.add(filename)
else:
removed.add(filename)
return changed, removed
def GetDscFilenameFromLibraryName(lib_name):
return os.path.join(SDK_LIBRARY_DIR, lib_name, 'library.dsc')
def Verify(dsc_filename, dsc_sources_and_headers, changed_filenames,
removed_filenames):
expected_filenames = set()
unexpected_filenames = set()
for filename in changed_filenames:
basename = os.path.basename(filename)
if basename not in dsc_sources_and_headers:
expected_filenames.add(filename)
for filename in removed_filenames:
basename = os.path.basename(filename)
if basename in dsc_sources_and_headers:
unexpected_filenames.add(filename)
if expected_filenames or unexpected_filenames:
raise VerifyException(dsc_filename, expected_filenames,
unexpected_filenames)
def VerifyOrPrintError(dsc_filename, dsc_sources_and_headers, changed_filenames,
removed_filenames, is_private=False):
try:
Verify(dsc_filename, dsc_sources_and_headers, changed_filenames,
removed_filenames)
except VerifyException as e:
should_fail = True
if is_private and e.expected:
# For ppapi_cpp_private, we don't fail if there are expected filenames...
# we may not want to include them. We still want to fail if there are
# unexpected filenames, though.
sys.stderr.write('>>> WARNING: private interface files changed. '
'Should they be added to the Native Client SDK? <<<\n')
if not e.unexpected:
should_fail = False
sys.stderr.write(str(e) + '\n')
if should_fail:
return False
return True
def main(args):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('sources', nargs='+')
options = parser.parse_args(args)
retval = 0
lib_files = PartitionFiles(options.sources)
directory_list = GetDirectoryList(PPAPI_DIR, relative_to=SRC_DIR)
for lib_name, filenames in lib_files.iteritems():
if not filenames:
continue
changed_filenames, removed_filenames = \
GetChangedAndRemovedFilenames(filenames, directory_list)
dsc_filename = GetDscFilenameFromLibraryName(lib_name)
dsc = parse_dsc.LoadProject(dsc_filename)
dsc_sources_and_headers = GetDscSourcesAndHeaders(dsc)
# Use the relative path to the .dsc to make the error messages shorter.
rel_dsc_filename = os.path.relpath(dsc_filename, SRC_DIR)
is_private = lib_name == 'ppapi_cpp_private'
if not VerifyOrPrintError(rel_dsc_filename, dsc_sources_and_headers,
changed_filenames, removed_filenames,
is_private=is_private):
retval = 1
return retval
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
|