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