OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # | |
3 # Copyright 2015 The Chromium Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | |
5 # found in the LICENSE file. | |
6 | |
7 """Utility for dart_pkg and dart_pkg_app rules""" | |
8 | |
9 import argparse | |
10 import errno | |
11 import json | |
12 import os | |
13 import shutil | |
14 import subprocess | |
15 import sys | |
16 | |
17 USE_LINKS = sys.platform != "win32" | |
18 | |
19 DART_ANALYZE = os.path.join(os.path.dirname(os.path.abspath(__file__)), | |
20 "dart_analyze.py") | |
21 | |
22 def dart_filter(path): | |
23 if os.path.isdir(path): | |
24 return True | |
25 _, ext = os.path.splitext(path) | |
26 # .dart includes '.mojom.dart' | |
27 return ext == '.dart' | |
28 | |
29 | |
30 def ensure_dir_exists(path): | |
31 abspath = os.path.abspath(path) | |
32 if not os.path.exists(abspath): | |
33 os.makedirs(abspath) | |
34 | |
35 | |
36 def has_pubspec_yaml(paths): | |
37 for path in paths: | |
38 _, filename = os.path.split(path) | |
39 if 'pubspec.yaml' == filename: | |
40 return True | |
41 return False | |
42 | |
43 | |
44 def link(from_root, to_root): | |
45 ensure_dir_exists(os.path.dirname(to_root)) | |
46 try: | |
47 os.unlink(to_root) | |
48 except OSError as e: | |
49 if e.errno == errno.ENOENT: | |
50 pass | |
51 | |
52 try: | |
53 os.symlink(from_root, to_root) | |
54 except OSError as e: | |
55 if e.errno == errno.EEXIST: | |
56 pass | |
57 | |
58 | |
59 def copy(from_root, to_root, filter_func=None): | |
60 if not os.path.exists(from_root): | |
61 return | |
62 if os.path.isfile(from_root): | |
63 ensure_dir_exists(os.path.dirname(to_root)) | |
64 shutil.copy(from_root, to_root) | |
65 return | |
66 | |
67 ensure_dir_exists(to_root) | |
68 | |
69 for root, dirs, files in os.walk(from_root): | |
70 # filter_func expects paths not names, so wrap it to make them absolute. | |
71 wrapped_filter = None | |
72 if filter_func: | |
73 wrapped_filter = lambda name: filter_func(os.path.join(root, name)) | |
74 | |
75 for name in filter(wrapped_filter, files): | |
76 from_path = os.path.join(root, name) | |
77 root_rel_path = os.path.relpath(from_path, from_root) | |
78 to_path = os.path.join(to_root, root_rel_path) | |
79 to_dir = os.path.dirname(to_path) | |
80 if not os.path.exists(to_dir): | |
81 os.makedirs(to_dir) | |
82 shutil.copy(from_path, to_path) | |
83 | |
84 dirs[:] = filter(wrapped_filter, dirs) | |
85 | |
86 | |
87 def copy_or_link(from_root, to_root, filter_func=None): | |
88 if USE_LINKS: | |
89 link(from_root, to_root) | |
90 else: | |
91 copy(from_root, to_root, filter_func) | |
92 | |
93 | |
94 def link_if_possible(from_root, to_root): | |
95 if USE_LINKS: | |
96 link(from_root, to_root) | |
97 | |
98 | |
99 def remove_if_exists(path): | |
100 try: | |
101 os.remove(path) | |
102 except OSError as e: | |
103 if e.errno != errno.ENOENT: | |
104 raise | |
105 | |
106 | |
107 def list_files(from_root, filter_func=None): | |
108 file_list = [] | |
109 for root, dirs, files in os.walk(from_root): | |
110 # filter_func expects paths not names, so wrap it to make them absolute. | |
111 wrapped_filter = None | |
112 if filter_func: | |
113 wrapped_filter = lambda name: filter_func(os.path.join(root, name)) | |
114 for name in filter(wrapped_filter, files): | |
115 path = os.path.join(root, name) | |
116 file_list.append(path) | |
117 dirs[:] = filter(wrapped_filter, dirs) | |
118 return file_list | |
119 | |
120 | |
121 def remove_broken_symlink(path): | |
122 try: | |
123 link_path = os.readlink(path) | |
124 except OSError as e: | |
125 # Path was not a symlink. | |
126 if e.errno == errno.EINVAL: | |
127 pass | |
128 else: | |
129 if not os.path.exists(link_path): | |
130 remove_if_exists(path) | |
131 | |
132 | |
133 def remove_broken_symlinks(root_dir): | |
134 for current_dir, _, child_files in os.walk(root_dir): | |
135 for filename in child_files: | |
136 path = os.path.join(current_dir, filename) | |
137 remove_broken_symlink(path) | |
138 | |
139 | |
140 def analyze_entrypoints(dart_sdk, package_root, entrypoints): | |
141 cmd = [ "python", DART_ANALYZE ] | |
142 cmd.append("--dart-sdk") | |
143 cmd.append(dart_sdk) | |
144 cmd.append("--entrypoints") | |
145 cmd.extend(entrypoints) | |
146 cmd.append("--package-root") | |
147 cmd.append(package_root) | |
148 cmd.append("--no-hints") | |
149 try: | |
150 subprocess.check_output(cmd, stderr=subprocess.STDOUT) | |
151 except subprocess.CalledProcessError as e: | |
152 print('Failed analyzing %s' % entrypoints) | |
153 print(e.output) | |
154 return e.returncode | |
155 return 0 | |
156 | |
157 | |
158 def main(): | |
159 parser = argparse.ArgumentParser(description='Generate a dart-pkg') | |
160 parser.add_argument('--dart-sdk', | |
161 action='store', | |
162 metavar='dart_sdk', | |
163 help='Path to the Dart SDK.') | |
164 parser.add_argument('--package-name', | |
165 action='store', | |
166 metavar='package_name', | |
167 help='Name of package', | |
168 required=True) | |
169 parser.add_argument('--pkg-directory', | |
170 metavar='pkg_directory', | |
171 help='Directory where dart_pkg should go', | |
172 required=True) | |
173 parser.add_argument('--package-root', | |
174 metavar='package_root', | |
175 help='packages/ directory', | |
176 required=True) | |
177 parser.add_argument('--stamp-file', | |
178 metavar='stamp_file', | |
179 help='timestamp file', | |
180 required=True) | |
181 parser.add_argument('--entries-file', | |
182 metavar='entries_file', | |
183 help='script entries file', | |
184 required=True) | |
185 parser.add_argument('--package-sources', | |
186 metavar='package_sources', | |
187 help='Package sources', | |
188 nargs='+') | |
189 parser.add_argument('--package-entrypoints', | |
190 metavar='package_entrypoints', | |
191 help='Package entry points for analyzer', | |
192 nargs='*', | |
193 default=[]) | |
194 parser.add_argument('--sdk-ext-directories', | |
195 metavar='sdk_ext_directories', | |
196 help='Directory containing .dart sources', | |
197 nargs='*', | |
198 default=[]) | |
199 parser.add_argument('--sdk-ext-files', | |
200 metavar='sdk_ext_files', | |
201 help='List of .dart files that are part of of sdk_ext.', | |
202 nargs='*', | |
203 default=[]) | |
204 parser.add_argument('--sdk-ext-mappings', | |
205 metavar='sdk_ext_mappings', | |
206 help='Mappings for SDK extension libraries.', | |
207 nargs='*', | |
208 default=[]) | |
209 parser.add_argument('--read_only', | |
210 action='store_true', | |
211 dest='read_only', | |
212 help='Package is a read only package.', | |
213 default=False) | |
214 args = parser.parse_args() | |
215 | |
216 # We must have a pubspec.yaml. | |
217 assert has_pubspec_yaml(args.package_sources) | |
218 | |
219 target_dir = os.path.join(args.pkg_directory, args.package_name) | |
220 target_packages_dir = os.path.join(target_dir, 'packages') | |
221 lib_path = os.path.join(target_dir, "lib") | |
222 ensure_dir_exists(lib_path) | |
223 | |
224 mappings = {} | |
225 for mapping in args.sdk_ext_mappings: | |
226 library, path = mapping.split(',', 1) | |
227 mappings[library] = '../sdk_ext/%s' % path | |
228 | |
229 sdkext_path = os.path.join(lib_path, '_sdkext') | |
230 if mappings: | |
231 with open(sdkext_path, 'w') as stream: | |
232 json.dump(mappings, stream, sort_keys=True, | |
233 indent=2, separators=(',', ': ')) | |
234 else: | |
235 remove_if_exists(sdkext_path) | |
236 | |
237 # Copy or symlink package sources into pkg directory. | |
238 common_source_prefix = os.path.dirname(os.path.commonprefix( | |
239 args.package_sources)) | |
240 for source in args.package_sources: | |
241 relative_source = os.path.relpath(source, common_source_prefix) | |
242 target = os.path.join(target_dir, relative_source) | |
243 copy_or_link(source, target) | |
244 | |
245 entrypoint_targets = [] | |
246 for source in args.package_entrypoints: | |
247 relative_source = os.path.relpath(source, common_source_prefix) | |
248 target = os.path.join(target_dir, relative_source) | |
249 copy_or_link(source, target) | |
250 entrypoint_targets.append(target) | |
251 | |
252 # Copy sdk-ext sources into pkg directory | |
253 sdk_ext_dir = os.path.join(target_dir, 'sdk_ext') | |
254 for directory in args.sdk_ext_directories: | |
255 sdk_ext_sources = list_files(directory, dart_filter) | |
256 common_prefix = os.path.commonprefix(sdk_ext_sources) | |
257 for source in sdk_ext_sources: | |
258 relative_source = os.path.relpath(source, common_prefix) | |
259 target = os.path.join(sdk_ext_dir, relative_source) | |
260 copy_or_link(source, target) | |
261 | |
262 common_source_prefix = os.path.dirname(os.path.commonprefix( | |
263 args.sdk_ext_files)) | |
264 for source in args.sdk_ext_files: | |
265 relative_source = os.path.relpath(source, common_source_prefix) | |
266 target = os.path.join(sdk_ext_dir, relative_source) | |
267 copy_or_link(source, target) | |
268 | |
269 # Symlink packages/ | |
270 package_path = os.path.join(args.package_root, args.package_name) | |
271 link(lib_path, package_path) | |
272 | |
273 # Link dart-pkg/$package/packages to dart-pkg/packages | |
274 link_if_possible(args.package_root, target_packages_dir) | |
275 | |
276 # Remove any broken symlinks in target_dir and package root. | |
277 remove_broken_symlinks(target_dir) | |
278 remove_broken_symlinks(args.package_root) | |
279 | |
280 # If any entrypoints are defined, write them to disk so that the analyzer | |
281 # test can find them. | |
282 with open(args.entries_file, 'w') as f: | |
283 for entrypoint in entrypoint_targets: | |
284 f.write(entrypoint + '\n') | |
285 | |
286 # Write stamp file. | |
287 with open(args.stamp_file, 'w'): | |
288 pass | |
289 | |
290 return 0 | |
291 | |
292 if __name__ == '__main__': | |
293 sys.exit(main()) | |
OLD | NEW |