Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env dart | 1 #!/usr/bin/env dart |
| 2 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 2 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 /// Command line tool to merge the SDK libraries and our patch files. | 6 /// Command line tool to merge the SDK libraries and our patch files. |
| 7 /// This is currently designed as an offline tool, but we could automate it. | 7 /// This is currently designed as an offline tool, but we could automate it. |
| 8 library dev_compiler.tool.patch_sdk; | 8 library dev_compiler.tool.patch_sdk; |
| 9 | 9 |
| 10 import 'dart:io'; | 10 import 'dart:io'; |
| 11 | 11 |
| 12 import 'package:analyzer/analyzer.dart'; | 12 import 'package:analyzer/analyzer.dart'; |
| 13 import 'package:analyzer/src/generated/sdk.dart'; | |
| 13 import 'package:path/path.dart' as path; | 14 import 'package:path/path.dart' as path; |
| 14 | 15 |
| 15 import 'input_sdk/lib/_internal/libraries.dart' as sdk; | 16 void main(List<String> argv) { |
|
Jennifer Messerly
2015/03/19 22:57:34
These changes aren't really needed, but they let p
| |
| 17 if (argv.length < 2) { | |
| 18 var self = path.relative(Platform.script.path); | |
| 19 var toolDir = path.relative(path.dirname(Platform.script.path)); | |
| 16 | 20 |
| 17 void main(List<String> argv) { | 21 var inputExample = path.join(toolDir, 'input_sdk'); |
| 18 var toolDir = path.relative(path.dirname(Platform.script.path)); | 22 var outExample = path.relative( |
| 19 var sdkLibIn = path.join(toolDir, 'input_sdk', 'lib'); | 23 path.normalize(path.join(toolDir, '..', 'test', 'generated_sdk'))); |
| 20 var patchIn = path.join(toolDir, 'input_sdk', 'patch'); | 24 |
| 21 var privateIn = path.join(toolDir, 'input_sdk', 'private'); | 25 print('Usage: $self INPUT_DIR OUTPUT_DIR'); |
| 22 var sdkOut = | 26 print('For example:'); |
| 23 path.normalize(path.join(toolDir, '..', 'test', 'generated_sdk', 'lib')); | 27 print('\$ $self $inputExample $outExample'); |
| 28 | |
| 29 inputExample = path.join(toolDir, 'min_sdk'); | |
| 30 outExample = path.join(toolDir, 'out', 'min_sdk'); | |
| 31 print('\$ $self $inputExample $outExample'); | |
| 32 exit(1); | |
| 33 } | |
| 34 | |
| 35 var input = argv[0]; | |
| 36 var sdkLibIn = path.join(input, 'lib'); | |
| 37 var patchIn = path.join(input, 'patch'); | |
| 38 var privateIn = path.join(input, 'private'); | |
| 39 var sdkOut = path.join(argv[1], 'lib'); | |
| 24 var privateLibOut = | 40 var privateLibOut = |
| 25 path.normalize(path.join(sdkOut, '_internal', 'compiler', 'js_lib')); | 41 path.normalize(path.join(sdkOut, '_internal', 'compiler', 'js_lib')); |
| 26 | 42 |
| 27 var INTERNAL_PATH = '_internal/compiler/js_lib/'; | 43 var INTERNAL_PATH = '_internal/compiler/js_lib/'; |
| 28 | 44 |
| 29 if (argv.isNotEmpty) { | |
| 30 print('Usage: ${path.relative(Platform.script.path)}\n'); | |
| 31 print('input SDK directory: $sdkLibIn'); | |
| 32 // We can freely make changes to these two. | |
| 33 print('input private libs directory: $privateIn'); | |
| 34 print('input patch directory: $patchIn'); | |
| 35 print('output SDK directory: $sdkOut'); | |
| 36 exit(1); | |
| 37 } | |
| 38 | |
| 39 // Copy libraries.dart and version | 45 // Copy libraries.dart and version |
| 40 _writeSync(path.join(sdkOut, '_internal', 'libraries.dart'), | 46 var libContents = new File(path.join(sdkLibIn, '_internal', 'libraries.dart')) |
| 41 new File(path.join(sdkLibIn, '_internal', 'libraries.dart')) | 47 .readAsStringSync(); |
| 42 .readAsStringSync()); | 48 _writeSync(path.join(sdkOut, '_internal', 'libraries.dart'), libContents); |
| 43 _writeSync(path.join(sdkOut, '..', 'version'), | 49 _writeSync(path.join(sdkOut, '..', 'version'), |
| 44 new File(path.join(sdkLibIn, '..', 'version')).readAsStringSync()); | 50 new File(path.join(sdkLibIn, '..', 'version')).readAsStringSync()); |
| 45 | 51 |
| 52 // Parse libraries.dart | |
| 53 var sdkLibraries = _getSdkLibraries(libContents); | |
| 54 | |
| 46 // Enumerate core libraries and apply patches | 55 // Enumerate core libraries and apply patches |
| 47 for (var library in sdk.LIBRARIES.values) { | 56 for (SdkLibrary library in sdkLibraries) { |
| 48 if (library.platforms & sdk.DART2JS_PLATFORM == 0) continue; | 57 // TODO(jmesserly): analyzer does not handle the default case of |
| 58 // "both platforms" correctly, and treats it as being supported on neither. | |
| 59 // So instead we skip explicitly marked as VM libs. | |
| 60 if (library.isVmLibrary) continue; | |
| 49 | 61 |
| 50 var libraryOut = path.join(sdkLibIn, library.path); | 62 var libraryOut = path.join(sdkLibIn, library.path); |
| 51 var libraryIn; | 63 var libraryIn; |
| 52 if (library.path.contains(INTERNAL_PATH)) { | 64 if (library.path.contains(INTERNAL_PATH)) { |
| 53 libraryIn = | 65 libraryIn = |
| 54 path.join(privateIn, library.path.replaceAll(INTERNAL_PATH, '')); | 66 path.join(privateIn, library.path.replaceAll(INTERNAL_PATH, '')); |
| 55 } else { | 67 } else { |
| 56 libraryIn = libraryOut; | 68 libraryIn = libraryOut; |
| 57 } | 69 } |
| 58 | 70 |
| 59 var libraryFile = new File(libraryIn); | 71 var libraryFile = new File(libraryIn); |
| 60 if (libraryFile.existsSync()) { | 72 if (libraryFile.existsSync()) { |
| 61 var contents = <String>[]; | 73 var contents = <String>[]; |
| 62 var paths = <String>[]; | 74 var paths = <String>[]; |
| 63 var libraryContents = libraryFile.readAsStringSync(); | 75 var libraryContents = libraryFile.readAsStringSync(); |
| 64 paths.add(libraryOut); | 76 paths.add(libraryOut); |
| 65 contents.add(libraryContents); | 77 contents.add(libraryContents); |
| 66 for (var part in parseDirectives(libraryContents).directives) { | 78 for (var part in parseDirectives(libraryContents).directives) { |
| 67 if (part is PartDirective) { | 79 if (part is PartDirective) { |
| 68 var partPath = part.uri.stringValue; | 80 var partPath = part.uri.stringValue; |
| 69 paths.add(path.join(path.dirname(libraryOut), partPath)); | 81 paths.add(path.join(path.dirname(libraryOut), partPath)); |
| 70 contents.add(new File(path.join(path.dirname(libraryIn), partPath)) | 82 contents.add(new File(path.join(path.dirname(libraryIn), partPath)) |
| 71 .readAsStringSync()); | 83 .readAsStringSync()); |
| 72 } | 84 } |
| 73 } | 85 } |
| 74 | 86 |
| 75 if (library.dart2jsPatchPath != null) { | 87 // See if we can find a patch file. |
| 76 var patchPath = path.join( | 88 var patchPath = path.join( |
| 77 patchIn, library.dart2jsPatchPath.replaceAll(INTERNAL_PATH, '')); | 89 patchIn, path.basenameWithoutExtension(libraryIn) + '_patch.dart'); |
| 90 | |
| 91 if (new File(patchPath).existsSync()) { | |
| 78 var patchContents = new File(patchPath).readAsStringSync(); | 92 var patchContents = new File(patchPath).readAsStringSync(); |
| 79 | |
| 80 contents = _patchLibrary(contents, patchContents); | 93 contents = _patchLibrary(contents, patchContents); |
| 81 } | 94 } |
| 82 for (var i = 0; i < paths.length; i++) { | 95 for (var i = 0; i < paths.length; i++) { |
| 83 var outPath = | 96 var outPath = |
| 84 path.join(sdkOut, path.relative(paths[i], from: sdkLibIn)); | 97 path.join(sdkOut, path.relative(paths[i], from: sdkLibIn)); |
| 85 _writeSync(outPath, contents[i]); | 98 _writeSync(outPath, contents[i]); |
| 86 } | 99 } |
| 87 } | 100 } |
| 88 } | 101 } |
| 89 } | 102 } |
| 90 | 103 |
| 91 /// Writes a file, creating the directory if needed. | 104 /// Writes a file, creating the directory if needed. |
| 92 void _writeSync(String filePath, String contents) { | 105 void _writeSync(String filePath, String contents) { |
| 93 print('Writing $filePath'); | |
| 94 | |
| 95 var outDir = new Directory(path.dirname(filePath)); | 106 var outDir = new Directory(path.dirname(filePath)); |
| 96 if (!outDir.existsSync()) outDir.createSync(recursive: true); | 107 if (!outDir.existsSync()) outDir.createSync(recursive: true); |
| 97 | 108 |
| 98 new File(filePath).writeAsStringSync(contents); | 109 new File(filePath).writeAsStringSync(contents); |
| 99 } | 110 } |
| 100 | 111 |
| 101 /// Merges dart:* library code with code from *_patch.dart file. | 112 /// Merges dart:* library code with code from *_patch.dart file. |
| 102 /// | 113 /// |
| 103 /// Takes a list of the library's parts contents, with the main library contents | 114 /// Takes a list of the library's parts contents, with the main library contents |
| 104 /// first in the list, and the contents of the patch file. | 115 /// first in the list, and the contents of the patch file. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 190 } | 201 } |
| 191 | 202 |
| 192 void _maybePatch(AstNode node) { | 203 void _maybePatch(AstNode node) { |
| 193 if (node is FieldDeclaration) return; | 204 if (node is FieldDeclaration) return; |
| 194 | 205 |
| 195 var externalKeyword = (node as dynamic).externalKeyword; | 206 var externalKeyword = (node as dynamic).externalKeyword; |
| 196 if (externalKeyword == null) return; | 207 if (externalKeyword == null) return; |
| 197 | 208 |
| 198 var name = _qualifiedName(node); | 209 var name = _qualifiedName(node); |
| 199 var patchNode = patch.patches[name]; | 210 var patchNode = patch.patches[name]; |
| 200 if (patchNode == null) throw 'patch not found for $name: $node'; | 211 if (patchNode == null) { |
| 212 print('warning: patch not found for $name: $node'); | |
| 213 return; | |
| 214 } | |
| 201 | 215 |
| 202 Annotation patchMeta = patchNode.metadata.lastWhere(_isPatchAnnotation); | 216 Annotation patchMeta = patchNode.metadata.lastWhere(_isPatchAnnotation); |
| 203 int start = patchMeta.endToken.next.offset; | 217 int start = patchMeta.endToken.next.offset; |
| 204 var code = patch.contents.substring(start, patchNode.end); | 218 var code = patch.contents.substring(start, patchNode.end); |
| 205 | 219 |
| 206 // For some node like static fields, the node's offset doesn't include | 220 // For some node like static fields, the node's offset doesn't include |
| 207 // the external keyword. Also starting from the keyword lets us preserve | 221 // the external keyword. Also starting from the keyword lets us preserve |
| 208 // documentation comments. | 222 // documentation comments. |
| 209 edits.replace(externalKeyword.offset, node.end, code); | 223 edits.replace(externalKeyword.offset, node.end, code); |
| 210 } | 224 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 patches[_qualifiedName(node)] = node; | 265 patches[_qualifiedName(node)] = node; |
| 252 } else { | 266 } else { |
| 253 mergeDeclarations.add(node); | 267 mergeDeclarations.add(node); |
| 254 } | 268 } |
| 255 } | 269 } |
| 256 | 270 |
| 257 @override visitFunctionBody(node) {} // skip method bodies | 271 @override visitFunctionBody(node) {} // skip method bodies |
| 258 } | 272 } |
| 259 | 273 |
| 260 String _qualifiedName(Declaration node) { | 274 String _qualifiedName(Declaration node) { |
| 261 assert(node is MethodDeclaration || | |
| 262 node is FunctionDeclaration || | |
| 263 node is ConstructorDeclaration); | |
| 264 | |
| 265 var parent = node.parent; | 275 var parent = node.parent; |
| 266 var className = ''; | 276 var className = ''; |
| 267 if (parent is ClassDeclaration) { | 277 if (parent is ClassDeclaration) { |
| 268 className = parent.name.name + '.'; | 278 className = parent.name.name + '.'; |
| 269 } | 279 } |
| 270 var name = (node as dynamic).name; | 280 var name = (node as dynamic).name; |
| 271 return className + (name != null ? name.name : ''); | 281 return className + (name != null ? name.name : ''); |
| 272 } | 282 } |
| 273 | 283 |
| 274 bool _isPatch(AnnotatedNode node) => node.metadata.any(_isPatchAnnotation); | 284 bool _isPatch(AnnotatedNode node) => node.metadata.any(_isPatchAnnotation); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 361 int get length => end - begin; | 371 int get length => end - begin; |
| 362 | 372 |
| 363 String toString() => '(Edit @ $begin,$end: "$replace")'; | 373 String toString() => '(Edit @ $begin,$end: "$replace")'; |
| 364 | 374 |
| 365 int compareTo(_StringEdit other) { | 375 int compareTo(_StringEdit other) { |
| 366 int diff = begin - other.begin; | 376 int diff = begin - other.begin; |
| 367 if (diff != 0) return diff; | 377 if (diff != 0) return diff; |
| 368 return end - other.end; | 378 return end - other.end; |
| 369 } | 379 } |
| 370 } | 380 } |
| 381 | |
| 382 List<SdkLibrary> _getSdkLibraries(String contents) { | |
| 383 var libraryBuilder = new SdkLibrariesReader_LibraryBuilder(true); | |
| 384 parseCompilationUnit(contents).accept(libraryBuilder); | |
| 385 return libraryBuilder.librariesMap.sdkLibraries; | |
| 386 } | |
| OLD | NEW |