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 | 8 |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 import 'dart:isolate' show RawReceivePort; | |
| 10 import 'dart:async'; | 11 import 'dart:async'; |
| 11 import 'dart:math' as math; | 12 import 'dart:math' as math; |
| 12 | 13 |
| 13 import 'package:analyzer/analyzer.dart'; | 14 import 'package:analyzer/analyzer.dart'; |
| 14 import 'package:analyzer/src/generated/sdk.dart'; | 15 import 'package:analyzer/src/generated/sdk.dart'; |
| 15 import 'package:path/path.dart' as path; | 16 import 'package:path/path.dart' as path; |
| 16 import 'package:front_end/src/fasta/compile_platform.dart' as compile_platform; | |
| 17 | 17 |
| 18 import 'package:front_end/src/fasta/fasta.dart' show CompileTask; | 18 import 'package:front_end/src/fasta/fasta.dart' |
| 19 | 19 show compilePlatform, writeDepsFile; |
| 20 import 'package:front_end/src/fasta/compiler_command_line.dart' | |
| 21 show CompilerCommandLine; | |
| 22 | |
| 23 import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext; | |
| 24 | |
| 25 import 'package:front_end/src/fasta/ticker.dart' show Ticker; | |
| 26 | 20 |
| 27 /// Set of input files that were read by this script to generate patched SDK. | 21 /// Set of input files that were read by this script to generate patched SDK. |
| 28 /// We will dump it out into the depfile for ninja to use. | 22 /// We will dump it out into the depfile for ninja to use. |
| 29 /// | 23 /// |
| 30 /// For more information see GN and Ninja references: | 24 /// For more information see GN and Ninja references: |
| 31 /// https://chromium.googlesource.com/chromium/src/+/56807c6cb383140af0c03da8 f6731d77785d7160/tools/gn/docs/reference.md#depfile_string_File-name-for-input-d ependencies-for-actions | 25 /// https://chromium.googlesource.com/chromium/src/+/56807c6cb383140af0c03da8 f6731d77785d7160/tools/gn/docs/reference.md#depfile_string_File-name-for-input-d ependencies-for-actions |
| 32 /// https://ninja-build.org/manual.html#_depfile | 26 /// https://ninja-build.org/manual.html#_depfile |
| 33 /// | 27 /// |
| 34 final deps = new Set<String>(); | 28 final deps = new Set<Uri>(); |
| 35 | 29 |
| 36 /// Create [File] object from the given path and register it as a dependency. | 30 /// Create [File] object from the given path and register it as a dependency. |
| 37 File getInputFile(String path, {canBeMissing: false}) { | 31 File getInputFile(String path, {canBeMissing: false}) { |
| 38 final file = new File(path); | 32 final file = new File(path); |
| 39 if (!file.existsSync()) { | 33 if (!file.existsSync()) { |
| 40 if (!canBeMissing) throw "patch_sdk.dart expects all inputs to exist"; | 34 if (!canBeMissing) throw "patch_sdk.dart expects all inputs to exist"; |
| 41 return null; | 35 return null; |
| 42 } | 36 } |
| 43 deps.add(file.absolute.path); | 37 deps.add(Uri.base.resolveUri(file.uri)); |
| 44 return file; | 38 return file; |
| 45 } | 39 } |
| 46 | 40 |
| 47 /// Read the given file synchronously as a string and register this path as | 41 /// Read the given file synchronously as a string and register this path as |
| 48 /// a dependency. | 42 /// a dependency. |
| 49 String readInputFile(String path, {canBeMissing: false}) => | 43 String readInputFile(String path, {canBeMissing: false}) => |
| 50 getInputFile(path, canBeMissing: canBeMissing)?.readAsStringSync(); | 44 getInputFile(path, canBeMissing: canBeMissing)?.readAsStringSync(); |
| 51 | 45 |
| 52 Future main(List<String> argv) async { | 46 Future main(List<String> argv) async { |
| 53 var base = path.fromUri(Platform.script); | 47 var port = new RawReceivePort(); |
| 54 var dartDir = path.dirname(path.dirname(path.absolute(base))); | 48 try { |
|
Vyacheslav Egorov (Google)
2017/03/15 13:43:59
With such a gigantic try { } finally { } it might
ahe
2017/03/31 15:05:02
Done.
| |
| 49 var base = path.fromUri(Platform.script); | |
| 50 var dartDir = path.dirname(path.dirname(path.absolute(base))); | |
| 55 | 51 |
| 56 if (argv.length != 5 || argv.first != 'vm') { | 52 if (argv.length != 5 || argv.first != 'vm') { |
| 57 final self = path.relative(base); | 53 final self = path.relative(base); |
| 58 print('Usage: $self vm SDK_DIR PATCH_DIR OUTPUT_DIR PACKAGES'); | 54 print('Usage: $self vm SDK_DIR PATCH_DIR OUTPUT_DIR PACKAGES'); |
| 59 | 55 |
| 60 final repositoryDir = path.relative(path.dirname(path.dirname(base))); | 56 final repositoryDir = path.relative(path.dirname(path.dirname(base))); |
| 61 final sdkExample = path.relative(path.join(repositoryDir, 'sdk')); | 57 final sdkExample = path.relative(path.join(repositoryDir, 'sdk')); |
| 62 final patchExample = path.relative( | 58 final patchExample = path.relative( |
| 63 path.join(repositoryDir, 'out', 'DebugX64', 'obj', 'gen', 'patch')); | 59 path.join(repositoryDir, 'out', 'DebugX64', 'obj', 'gen', 'patch')); |
| 64 final outExample = path.relative(path.join( | 60 final outExample = path.relative(path.join( |
| 65 repositoryDir, 'out', 'DebugX64', 'obj', 'gen', 'patched_sdk')); | 61 repositoryDir, 'out', 'DebugX64', 'obj', 'gen', 'patched_sdk')); |
| 66 print('For example:'); | 62 print('For example:'); |
| 67 print('\$ $self vm $sdkExample $patchExample $outExample'); | 63 print('\$ $self vm $sdkExample $patchExample $outExample'); |
| 68 | 64 |
| 69 exit(1); | 65 exit(1); |
| 70 } | 66 } |
| 71 | 67 |
| 72 var mode = argv[0]; | 68 var mode = argv[0]; |
| 73 assert(mode == "vm"); | 69 assert(mode == "vm"); |
| 74 var input = argv[1]; | 70 var input = argv[1]; |
| 75 var sdkLibIn = path.join(input, 'lib'); | 71 var sdkLibIn = path.join(input, 'lib'); |
| 76 var patchIn = argv[2]; | 72 var patchIn = argv[2]; |
| 77 var outDir = argv[3]; | 73 var outDir = argv[3]; |
| 78 var sdkOut = path.join(outDir, 'lib'); | 74 var sdkOut = path.join(outDir, 'lib'); |
| 79 var packagesFile = argv[4]; | 75 var packagesFile = argv[4]; |
| 80 | 76 |
| 81 // Copy and patch libraries.dart and version | 77 // Copy and patch libraries.dart and version |
| 82 var libContents = readInputFile(path.join( | 78 var libContents = readInputFile(path.join(sdkLibIn, '_internal', |
| 83 sdkLibIn, '_internal', 'sdk_library_metadata', 'lib', 'libraries.dart')); | 79 'sdk_library_metadata', 'lib', 'libraries.dart')); |
| 84 libContents = libContents.replaceAll( | 80 libContents = libContents.replaceAll( |
| 85 ' libraries = const {', | 81 ' libraries = const {', |
| 86 ''' libraries = const { | 82 ''' libraries = const { |
| 87 | 83 |
| 88 "_builtin": const LibraryInfo( | 84 "_builtin": const LibraryInfo( |
| 89 "_builtin/_builtin.dart", | 85 "_builtin/_builtin.dart", |
| 90 categories: "Client,Server", | 86 categories: "Client,Server", |
| 91 implementation: true, | 87 implementation: true, |
| 92 documented: false, | 88 documented: false, |
| 93 platforms: VM_PLATFORM), | 89 platforms: VM_PLATFORM), |
| 94 | 90 |
| 95 "profiler": const LibraryInfo( | 91 "profiler": const LibraryInfo( |
| 96 "profiler/profiler.dart", | 92 "profiler/profiler.dart", |
| 97 maturity: Maturity.DEPRECATED, | 93 maturity: Maturity.DEPRECATED, |
| 98 documented: false), | 94 documented: false), |
| 99 | 95 |
| 100 "_vmservice": const LibraryInfo( | 96 "_vmservice": const LibraryInfo( |
| 101 "vmservice/vmservice.dart", | 97 "vmservice/vmservice.dart", |
| 102 implementation: true, | 98 implementation: true, |
| 103 documented: false, | 99 documented: false, |
| 104 platforms: VM_PLATFORM), | 100 platforms: VM_PLATFORM), |
| 105 | 101 |
| 106 "vmservice_io": const LibraryInfo( | 102 "vmservice_io": const LibraryInfo( |
| 107 "vmservice_io/vmservice_io.dart", | 103 "vmservice_io/vmservice_io.dart", |
| 108 implementation: true, | 104 implementation: true, |
| 109 documented: false, | 105 documented: false, |
| 110 platforms: VM_PLATFORM), | 106 platforms: VM_PLATFORM), |
| 111 | 107 |
| 112 '''); | 108 '''); |
| 113 _writeSync( | 109 _writeSync( |
| 114 path.join( | 110 path.join(sdkOut, '_internal', 'sdk_library_metadata', 'lib', |
| 115 sdkOut, '_internal', 'sdk_library_metadata', 'lib', 'libraries.dart'), | 111 'libraries.dart'), |
| 116 libContents); | 112 libContents); |
| 117 | 113 |
| 118 // Parse libraries.dart | 114 // Parse libraries.dart |
| 119 var sdkLibraries = _getSdkLibraries(libContents); | 115 var sdkLibraries = _getSdkLibraries(libContents); |
| 120 | 116 |
| 121 // Enumerate core libraries and apply patches | 117 // Enumerate core libraries and apply patches |
| 122 for (SdkLibrary library in sdkLibraries) { | 118 for (SdkLibrary library in sdkLibraries) { |
| 123 if (library.isDart2JsLibrary) { | 119 if (library.isDart2JsLibrary) { |
| 124 continue; | 120 continue; |
| 125 } | |
| 126 | |
| 127 var libraryOut = path.join(sdkLibIn, library.path); | |
| 128 var libraryIn = libraryOut; | |
| 129 | |
| 130 var libraryFile = getInputFile(libraryIn, canBeMissing: true); | |
| 131 if (libraryFile != null) { | |
| 132 var outPaths = <String>[libraryOut]; | |
| 133 var libraryContents = libraryFile.readAsStringSync(); | |
| 134 | |
| 135 int inputModifyTime = | |
| 136 libraryFile.lastModifiedSync().millisecondsSinceEpoch; | |
| 137 var partFiles = <File>[]; | |
| 138 for (var part in parseDirectives(libraryContents).directives) { | |
| 139 if (part is PartDirective) { | |
| 140 var partPath = part.uri.stringValue; | |
| 141 outPaths.add(path.join(path.dirname(libraryOut), partPath)); | |
| 142 | |
| 143 var partFile = | |
| 144 getInputFile(path.join(path.dirname(libraryIn), partPath)); | |
| 145 partFiles.add(partFile); | |
| 146 inputModifyTime = math.max(inputModifyTime, | |
| 147 partFile.lastModifiedSync().millisecondsSinceEpoch); | |
| 148 } | |
| 149 } | 121 } |
| 150 | 122 |
| 151 // See if we can find a patch file. | 123 var libraryOut = path.join(sdkLibIn, library.path); |
| 152 var patchPath = path.join( | 124 var libraryIn = libraryOut; |
| 153 patchIn, path.basenameWithoutExtension(libraryIn) + '_patch.dart'); | |
| 154 | 125 |
| 155 var patchFile = getInputFile(patchPath, canBeMissing: true); | 126 var libraryFile = getInputFile(libraryIn, canBeMissing: true); |
| 156 if (patchFile != null) { | 127 if (libraryFile != null) { |
| 157 inputModifyTime = math.max(inputModifyTime, | 128 var outPaths = <String>[libraryOut]; |
| 158 patchFile.lastModifiedSync().millisecondsSinceEpoch); | 129 var libraryContents = libraryFile.readAsStringSync(); |
| 159 } | |
| 160 | 130 |
| 161 // Compute output paths | 131 int inputModifyTime = |
| 162 outPaths = outPaths | 132 libraryFile.lastModifiedSync().millisecondsSinceEpoch; |
| 163 .map((p) => path.join(sdkOut, path.relative(p, from: sdkLibIn))) | 133 var partFiles = <File>[]; |
| 164 .toList(); | 134 for (var part in parseDirectives(libraryContents).directives) { |
| 135 if (part is PartDirective) { | |
| 136 var partPath = part.uri.stringValue; | |
| 137 outPaths.add(path.join(path.dirname(libraryOut), partPath)); | |
| 165 | 138 |
| 166 // Compare output modify time with input modify time. | 139 var partFile = |
| 167 bool needsUpdate = false; | 140 getInputFile(path.join(path.dirname(libraryIn), partPath)); |
| 168 for (var outPath in outPaths) { | 141 partFiles.add(partFile); |
| 169 var outFile = new File(outPath); | 142 inputModifyTime = math.max(inputModifyTime, |
| 170 if (!outFile.existsSync() || | 143 partFile.lastModifiedSync().millisecondsSinceEpoch); |
| 171 outFile.lastModifiedSync().millisecondsSinceEpoch < | 144 } |
| 172 inputModifyTime) { | |
| 173 needsUpdate = true; | |
| 174 break; | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 if (needsUpdate) { | |
| 179 var contents = <String>[libraryContents]; | |
| 180 contents.addAll(partFiles.map((f) => f.readAsStringSync())); | |
| 181 if (patchFile != null) { | |
| 182 var patchContents = patchFile.readAsStringSync(); | |
| 183 contents = _patchLibrary(patchFile.path, contents, patchContents); | |
| 184 } | 145 } |
| 185 | 146 |
| 186 for (var i = 0; i < outPaths.length; i++) { | 147 // See if we can find a patch file. |
| 187 _writeSync(outPaths[i], contents[i]); | 148 var patchPath = path.join( |
| 149 patchIn, path.basenameWithoutExtension(libraryIn) + '_patch.dart'); | |
| 150 | |
| 151 var patchFile = getInputFile(patchPath, canBeMissing: true); | |
| 152 if (patchFile != null) { | |
| 153 inputModifyTime = math.max(inputModifyTime, | |
| 154 patchFile.lastModifiedSync().millisecondsSinceEpoch); | |
| 155 } | |
| 156 | |
| 157 // Compute output paths | |
| 158 outPaths = outPaths | |
| 159 .map((p) => path.join(sdkOut, path.relative(p, from: sdkLibIn))) | |
| 160 .toList(); | |
| 161 | |
| 162 // Compare output modify time with input modify time. | |
| 163 bool needsUpdate = false; | |
| 164 for (var outPath in outPaths) { | |
| 165 var outFile = new File(outPath); | |
| 166 if (!outFile.existsSync() || | |
| 167 outFile.lastModifiedSync().millisecondsSinceEpoch < | |
| 168 inputModifyTime) { | |
| 169 needsUpdate = true; | |
| 170 break; | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 if (needsUpdate) { | |
| 175 var contents = <String>[libraryContents]; | |
| 176 contents.addAll(partFiles.map((f) => f.readAsStringSync())); | |
| 177 if (patchFile != null) { | |
| 178 var patchContents = patchFile.readAsStringSync(); | |
| 179 contents = _patchLibrary(patchFile.path, contents, patchContents); | |
| 180 } | |
| 181 | |
| 182 for (var i = 0; i < outPaths.length; i++) { | |
| 183 _writeSync(outPaths[i], contents[i]); | |
| 184 } | |
| 188 } | 185 } |
| 189 } | 186 } |
| 190 } | 187 } |
| 191 } | |
| 192 | 188 |
| 193 for (var tuple in [ | 189 for (var tuple in [ |
| 194 ['_builtin', 'builtin.dart'] | 190 ['_builtin', 'builtin.dart'] |
| 195 ]) { | 191 ]) { |
| 196 var vmLibrary = tuple[0]; | 192 var vmLibrary = tuple[0]; |
| 197 var dartFile = tuple[1]; | 193 var dartFile = tuple[1]; |
| 198 | 194 |
| 199 // The "dart:_builtin" library is only available for the DartVM. | 195 // The "dart:_builtin" library is only available for the DartVM. |
| 200 var builtinLibraryIn = path.join(dartDir, 'runtime', 'bin', dartFile); | 196 var builtinLibraryIn = path.join(dartDir, 'runtime', 'bin', dartFile); |
| 201 var builtinLibraryOut = path.join(sdkOut, vmLibrary, '${vmLibrary}.dart'); | 197 var builtinLibraryOut = path.join(sdkOut, vmLibrary, '${vmLibrary}.dart'); |
| 202 _writeSync(builtinLibraryOut, readInputFile(builtinLibraryIn)); | 198 _writeSync(builtinLibraryOut, readInputFile(builtinLibraryIn)); |
| 203 } | 199 } |
| 204 | 200 |
| 205 for (var file in ['loader.dart', 'server.dart', 'vmservice_io.dart']) { | 201 for (var file in ['loader.dart', 'server.dart', 'vmservice_io.dart']) { |
| 206 var libraryIn = path.join(dartDir, 'runtime', 'bin', 'vmservice', file); | 202 var libraryIn = path.join(dartDir, 'runtime', 'bin', 'vmservice', file); |
| 207 var libraryOut = path.join(sdkOut, 'vmservice_io', file); | 203 var libraryOut = path.join(sdkOut, 'vmservice_io', file); |
| 208 _writeSync(libraryOut, readInputFile(libraryIn)); | 204 _writeSync(libraryOut, readInputFile(libraryIn)); |
| 209 } | 205 } |
| 210 | 206 |
| 211 final platform = path.join(outDir, 'platform.dill'); | 207 Uri platform = Uri.base |
| 208 .resolveUri(new Uri.directory(outDir).resolve('platform.dill.tmp')); | |
| 209 Uri packages = Uri.base.resolveUri(new Uri.file(packagesFile)); | |
| 210 await compilePlatform( | |
| 211 Uri.base.resolveUri(new Uri.directory(outDir)), platform, | |
| 212 packages: packages, verbose: false); | |
| 212 | 213 |
| 213 await compile_platform.mainEntryPoint(<String>[ | 214 Uri platformFinalLocation = |
| 214 '--packages', | 215 Uri.base.resolveUri(new Uri.directory(outDir).resolve('platform.dill')); |
| 215 new Uri.file(packagesFile).toString(), | |
| 216 new Uri.directory(outDir).toString(), | |
| 217 platform, | |
| 218 ]); | |
| 219 | 216 |
| 220 // TODO(kustermann): We suppress compiler hints/warnings/errors temporarily | 217 await writeDepsFile(Platform.script, |
| 221 // because everyone building the `runtime` target will get these now. | 218 Uri.base.resolveUri(new Uri.file("$outDir.d")), platformFinalLocation, |
| 222 // We should remove the suppression again once the underlying issues have | 219 packages: packages, |
| 223 // been fixed (either in fasta or the dart files in the patched_sdk). | 220 platform: platform, |
| 224 final capturedLines = <String>[]; | 221 extraDependencies: deps, |
| 225 try { | 222 verbose: false); |
| 226 await runZoned(() async { | |
| 227 // platform.dill was generated, now generate platform.dill.d depfile | |
| 228 // that captures all dependencies that participated in the generation. | |
| 229 // There are two types of dependencies: | |
| 230 // (1) all Dart sources that constitute this tool itself | |
| 231 // (2) Dart SDK and patch sources. | |
| 232 // We already collected all inputs from the second category in the deps | |
| 233 // set. To collect inputs from the first category we actually use Fasta: | |
| 234 // we ask Fasta to outline patch_sdk.dart and generate a depfile which | |
| 235 // would list all the sources. | |
| 236 final depfile = "${outDir}.d"; | |
| 237 await CompilerCommandLine.withGlobalOptions("outline", [ | |
| 238 '--packages', | |
| 239 new Uri.file(packagesFile).toString(), | |
| 240 '--platform', | |
| 241 new Uri.file(platform).toString(), // platform.dill | |
| 242 Platform.script.toString() // patch_sdk.dart | |
| 243 ], (CompilerContext c) async { | |
| 244 CompileTask task = | |
| 245 new CompileTask(c, new Ticker(isVerbose: c.options.verbose)); | |
| 246 final kernelTarget = await task.buildOutline(null); | |
| 247 await kernelTarget.writeDepsFile( | |
| 248 new Uri.file(platform), new Uri.file(depfile)); | |
| 249 }); | |
| 250 | 223 |
| 251 // Read depfile generated by Fasta and append deps that we have collected | 224 await new File.fromUri(platform).rename(platformFinalLocation.toFilePath()); |
| 252 // during generation of patched_sdk to it. | 225 } finally { |
| 253 // Note: we are splitting by ': ' because Windows paths can start with | 226 port.close(); |
| 254 // drive letter followed by a colon. | |
| 255 final list = new File(depfile).readAsStringSync().split(': '); | |
| 256 assert(list.length == 2); | |
| 257 deps.addAll(list[1].split(' ').where((str) => str.isNotEmpty)); | |
| 258 assert(list[0] == path.join('patched_sdk', 'platform.dill')); | |
| 259 new File(depfile).writeAsStringSync("${list[0]}: ${deps.join(' ')}\n"); | |
| 260 }, zoneSpecification: new ZoneSpecification(print: (_, _2, _3, line) { | |
| 261 capturedLines.add(line); | |
| 262 })); | |
| 263 } catch (_) { | |
| 264 for (final line in capturedLines) { | |
| 265 print(line); | |
| 266 } | |
| 267 rethrow; | |
| 268 } | 227 } |
| 269 } | 228 } |
| 270 | 229 |
| 271 /// Writes a file, creating the directory if needed. | 230 /// Writes a file, creating the directory if needed. |
| 272 void _writeSync(String filePath, String contents) { | 231 void _writeSync(String filePath, String contents) { |
| 273 var outDir = new Directory(path.dirname(filePath)); | 232 var outDir = new Directory(path.dirname(filePath)); |
| 274 if (!outDir.existsSync()) outDir.createSync(recursive: true); | 233 if (!outDir.existsSync()) outDir.createSync(recursive: true); |
| 275 | 234 |
| 276 new File(filePath).writeAsStringSync(contents); | 235 new File(filePath).writeAsStringSync(contents); |
| 277 } | 236 } |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 606 if (diff != 0) return diff; | 565 if (diff != 0) return diff; |
| 607 return end - other.end; | 566 return end - other.end; |
| 608 } | 567 } |
| 609 } | 568 } |
| 610 | 569 |
| 611 List<SdkLibrary> _getSdkLibraries(String contents) { | 570 List<SdkLibrary> _getSdkLibraries(String contents) { |
| 612 var libraryBuilder = new SdkLibrariesReader_LibraryBuilder(true); | 571 var libraryBuilder = new SdkLibrariesReader_LibraryBuilder(true); |
| 613 parseCompilationUnit(contents).accept(libraryBuilder); | 572 parseCompilationUnit(contents).accept(libraryBuilder); |
| 614 return libraryBuilder.librariesMap.sdkLibraries; | 573 return libraryBuilder.librariesMap.sdkLibraries; |
| 615 } | 574 } |
| OLD | NEW |