diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart index 0119b5fb4d..fd605d7879 100644 --- a/dev/tools/create_api_docs.dart +++ b/dev/tools/create_api_docs.dart @@ -77,7 +77,7 @@ Future main(List arguments) async { configurator.generateConfiguration(); final PlatformDocGenerator platformGenerator = PlatformDocGenerator(outputDir: publishRoot, filesystem: filesystem); - platformGenerator.generatePlatformDocs(); + await platformGenerator.generatePlatformDocs(); final DartdocGenerator dartdocGenerator = DartdocGenerator( publishRoot: publishRoot, @@ -465,7 +465,7 @@ class DartdocGenerator { // Verify which version of snippets and dartdoc we're using. final ProcessResult snippetsResult = Process.runSync( - FlutterInformation.instance.getDartBinaryPath().path, + FlutterInformation.instance.getFlutterBinaryPath().path, [ 'pub', 'global', @@ -779,16 +779,16 @@ class PlatformDocGenerator { /// This downloads an archive of platform docs for the engine from the artifact /// store and extracts them to the location used for Dartdoc. - void generatePlatformDocs() { + Future generatePlatformDocs() async { final String realm = engineRealm.isNotEmpty ? '$engineRealm/' : ''; final String javadocUrl = 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/android-javadoc.zip'; - _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); + await _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); final String objcdocUrl = 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/ios-objcdoc.zip'; - _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); + await _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); } /// Fetches the zip archive at the specified url. @@ -935,7 +935,7 @@ Future runPubProcess({ @visibleForTesting FileSystem filesystem = const LocalFileSystem(), }) { return processManager.start( - [FlutterInformation.instance.getDartBinaryPath().path, 'pub', ...arguments], + [FlutterInformation.instance.getFlutterBinaryPath().path, 'pub', ...arguments], workingDirectory: (workingDirectory ?? filesystem.currentDirectory).path, environment: environment, ); @@ -968,21 +968,13 @@ List findPackages(FileSystem filesystem) { } /// An exception class used to indicate problems when collecting information. -class DartdocException implements Exception { - DartdocException(this.message, {this.file, this.line}); +class FlutterInformationException implements Exception { + FlutterInformationException(this.message); final String message; - final String? file; - final int? line; @override String toString() { - if (file != null || line != null) { - final String fileStr = file == null ? '' : '$file:'; - final String lineStr = line == null ? '' : '$line:'; - return '$runtimeType: $fileStr$lineStr: $message'; - } else { - return '$runtimeType: $message'; - } + return '$runtimeType: $message'; } } @@ -1017,6 +1009,13 @@ class FlutterInformation { return getFlutterRoot().childDirectory('bin').childFile('dart'); } + /// The path to the Dart binary in the Flutter repo. + /// + /// This is probably a shell script. + File getFlutterBinaryPath() { + return getFlutterRoot().childDirectory('bin').childFile('flutter'); + } + /// The path to the Flutter repo root directory. /// /// If the environment variable `FLUTTER_ROOT` is set, will use that instead @@ -1074,11 +1073,12 @@ class FlutterInformation { try { result = processManager.runSync([flutterCommand, '--version', '--machine'], stdoutEncoding: utf8); } on ProcessException catch (e) { - throw DartdocException( + throw FlutterInformationException( 'Unable to determine Flutter information. Either set FLUTTER_ROOT, or place flutter command in your path.\n$e'); } if (result.exitCode != 0) { - throw DartdocException('Unable to determine Flutter information, because of abnormal exit to flutter command.'); + throw FlutterInformationException( + 'Unable to determine Flutter information, because of abnormal exit to flutter command.'); } flutterVersionJson = (result.stdout as String) .replaceAll('Waiting for another flutter command to release the startup lock...', ''); @@ -1088,7 +1088,7 @@ class FlutterInformation { if (flutterVersion['flutterRoot'] == null || flutterVersion['frameworkVersion'] == null || flutterVersion['dartSdkVersion'] == null) { - throw DartdocException( + throw FlutterInformationException( 'Flutter command output has unexpected format, unable to determine flutter root location.'); } @@ -1097,14 +1097,13 @@ class FlutterInformation { info['flutterRoot'] = flutterRoot; info['frameworkVersion'] = Version.parse(flutterVersion['frameworkVersion'] as String); info['engineRevision'] = flutterVersion['engineRevision'] as String; - info['engineRealm'] = filesystem.file( - path.join(flutterRoot.path, 'bin', 'internal', 'engine.realm', - )).readAsStringSync().trim(); + final File engineRealm = flutterRoot.childDirectory('bin').childDirectory('internal').childFile('engine.realm'); + info['engineRealm'] = engineRealm.existsSync() ? engineRealm.readAsStringSync().trim() : ''; final RegExpMatch? dartVersionRegex = RegExp(r'(?[\d.]+)(?:\s+\(build (?[-.\w]+)\))?') .firstMatch(flutterVersion['dartSdkVersion'] as String); if (dartVersionRegex == null) { - throw DartdocException( + throw FlutterInformationException( 'Flutter command output has unexpected format, unable to parse dart SDK version ${flutterVersion['dartSdkVersion']}.'); } info['dartSdkVersion'] = diff --git a/dev/tools/examples_smoke_test.dart b/dev/tools/examples_smoke_test.dart index f4877ff11a..84660fda38 100644 --- a/dev/tools/examples_smoke_test.dart +++ b/dev/tools/examples_smoke_test.dart @@ -17,21 +17,21 @@ import 'package:path/path.dart' as path; import 'package:platform/platform.dart'; import 'package:process/process.dart'; -FileSystem filesystem = const LocalFileSystem(); -ProcessManager processManager = const LocalProcessManager(); -Platform platform = const LocalPlatform(); +const FileSystem _kFilesystem = LocalFileSystem(); +const ProcessManager _kProcessManager = LocalProcessManager(); +const Platform _kPlatform = LocalPlatform(); FutureOr main() async { - if (!platform.isLinux && !platform.isWindows && !platform.isMacOS) { + if (!_kPlatform.isLinux && !_kPlatform.isWindows && !_kPlatform.isMacOS) { stderr.writeln('Example smoke tests are only designed to run on desktop platforms'); exitCode = 4; return; } - final Directory flutterDir = filesystem.directory( + final Directory flutterDir = _kFilesystem.directory( path.absolute( path.dirname( path.dirname( - path.dirname(platform.script.toFilePath()), + path.dirname(_kPlatform.script.toFilePath()), ), ), ), @@ -63,16 +63,16 @@ Future runSmokeTests({ required Directory apiDir, }) async { final File flutterExe = - flutterDir.childDirectory('bin').childFile(platform.isWindows ? 'flutter.bat' : 'flutter'); + flutterDir.childDirectory('bin').childFile(_kPlatform.isWindows ? 'flutter.bat' : 'flutter'); final List cmd = [ // If we're in a container with no X display, then use the virtual framebuffer. - if (platform.isLinux && - (platform.environment['DISPLAY'] == null || - platform.environment['DISPLAY']!.isEmpty)) '/usr/bin/xvfb-run', + if (_kPlatform.isLinux && + (_kPlatform.environment['DISPLAY'] == null || + _kPlatform.environment['DISPLAY']!.isEmpty)) '/usr/bin/xvfb-run', flutterExe.absolute.path, 'test', '--reporter=expanded', - '--device-id=${platform.operatingSystem}', + '--device-id=${_kPlatform.operatingSystem}', integrationTest.absolute.path, ]; await runCommand(cmd, workingDirectory: apiDir); @@ -112,7 +112,7 @@ Future generateTest(Directory apiDir) async { .trim() .split('\n'); final Iterable examples = gitFiles.map((String examplePath) { - return filesystem.file(path.join(examplesLibDir.absolute.path, examplePath)); + return _kFilesystem.file(path.join(examplesLibDir.absolute.path, examplePath)); }); // Collect the examples, and import them all as separate symbols. @@ -202,7 +202,7 @@ Future runCommand( } try { - process = await processManager.start( + process = await _kProcessManager.start( cmd, workingDirectory: workingDirectory.absolute.path, environment: environment, diff --git a/dev/tools/test/create_api_docs_test.dart b/dev/tools/test/create_api_docs_test.dart index edf4b63d2a..6f98d1fae7 100644 --- a/dev/tools/test/create_api_docs_test.dart +++ b/dev/tools/test/create_api_docs_test.dart @@ -4,116 +4,14 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; -import 'package:path/path.dart' as path; import 'package:platform/platform.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; import '../create_api_docs.dart' as apidocs; -import '../examples_smoke_test.dart'; void main() { - test('getBranchName does not call git if env LUCI_BRANCH provided', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': branchName, - }, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test('getBranchName calls git if env LUCI_BRANCH not provided', () { - final Platform platform = FakePlatform( - environment: {}, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test('getBranchName calls git if env LUCI_BRANCH is empty', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': '', - }, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test("runPubProcess doesn't use the pub binary", () { - final Platform platform = FakePlatform( - environment: { - 'FLUTTER_ROOT': '/flutter', - }, - ); - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['/flutter/bin/dart', 'pub', '--one', '--two'], - ), - ], - ); - apidocs.FlutterInformation.instance = - apidocs.FlutterInformation(platform: platform, processManager: processManager); - - apidocs.runPubProcess( - arguments: ['--one', '--two'], - processManager: processManager, - filesystem: filesystem, - ); - - expect(processManager, hasNoRemainingExpectations); - }); - group('FlutterInformation', () { late FakeProcessManager fakeProcessManager; late FakePlatform fakePlatform; @@ -136,11 +34,96 @@ void main() { setUpWithEnvironment({}); }); + test('getBranchName does not call git if env LUCI_BRANCH provided', () { + setUpWithEnvironment( + { + 'LUCI_BRANCH': branchName, + }, + ); + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + expect( + apidocs.FlutterInformation.instance.getBranchName(), + branchName, + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH not provided', () { + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); + + expect( + apidocs.FlutterInformation.instance.getBranchName(), + branchName, + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH is empty', () { + setUpWithEnvironment( + { + 'LUCI_BRANCH': '', + }, + ); + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); + + expect( + apidocs.FlutterInformation.instance.getBranchName(), + branchName, + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + test("runPubProcess doesn't use the pub binary", () { + final Platform platform = FakePlatform( + environment: { + 'FLUTTER_ROOT': '/flutter', + }, + ); + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['/flutter/bin/flutter', 'pub', '--one', '--two'], + ), + ], + ); + apidocs.FlutterInformation.instance = + apidocs.FlutterInformation(platform: platform, processManager: processManager, filesystem: memoryFileSystem); + + apidocs.runPubProcess( + arguments: ['--one', '--two'], + processManager: processManager, + filesystem: memoryFileSystem, + ); + + expect(processManager, hasNoRemainingExpectations); + }); + test('calls out to flutter if FLUTTER_VERSION is not set', () async { - fakeProcessManager.addCommand( - const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); final Map info = flutterInformation.getFlutterInformation(); expect(fakeProcessManager, hasNoRemainingExpectations); expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); @@ -149,17 +132,23 @@ void main() { setUpWithEnvironment({ 'FLUTTER_VERSION': testVersionInfo, }); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); final Map info = flutterInformation.getFlutterInformation(); expect(fakeProcessManager, hasNoRemainingExpectations); expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); }); test('getFlutterRoot calls out to flutter if FLUTTER_ROOT is not set', () async { - fakeProcessManager.addCommand( - const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); final Directory root = flutterInformation.getFlutterRoot(); expect(fakeProcessManager, hasNoRemainingExpectations); expect(root.path, equals('/home/user/flutter')); @@ -172,8 +161,10 @@ void main() { }); test('parses version properly', () async { fakePlatform.environment['FLUTTER_VERSION'] = testVersionInfo; - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); final Map info = flutterInformation.getFlutterInformation(); expect(info['frameworkVersion'], isNotNull); expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); @@ -181,14 +172,26 @@ void main() { expect(info['dartSdkVersion'], equals(Version.parse('2.14.0-360.0.dev'))); }); test('the engine realm is read from the engine.realm file', () async { - const String flutterRoot = '/home/user/flutter'; - final File realmFile = memoryFileSystem.file( - path.join(flutterRoot, 'bin', 'internal', 'engine.realm', + final Directory flutterHome = memoryFileSystem + .directory('/home') + .childDirectory('user') + .childDirectory('flutter') + .childDirectory('bin') + .childDirectory('internal'); + flutterHome.childFile('engine.realm') + ..createSync(recursive: true) + ..writeAsStringSync('realm'); + setUpWithEnvironment({'FLUTTER_ROOT': '/home/user/flutter'}); + fakeProcessManager.addCommand(const FakeCommand( + command: ['/home/user/flutter/bin/flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', )); - realmFile.writeAsStringSync('realm'); - setUpWithEnvironment({'FLUTTER_ROOT': flutterRoot}); - expect(fakeProcessManager, hasNoRemainingExpectations); final Map info = flutterInformation.getFlutterInformation(); + expect(fakeProcessManager, hasNoRemainingExpectations); expect(info['engineRealm'], equals('realm')); }); });