| // Copyright 2014 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'dart:io' as io; | |
| import 'package:file/file.dart'; | |
| import 'package:file/local.dart'; | |
| import 'package:meta/meta.dart'; | |
| import 'package:process_runner/process_runner.dart'; | |
| /// Checks if the contents of [versionPath] are the same as the output of [scriptPath]. | |
| /// | |
| /// ```dart | |
| /// final bool success = await checkEngineVersion( | |
| /// versionPath: 'bin/internal/engine.version', | |
| /// scriptPath: 'bin/internal/last_engine_commit.sh', | |
| /// ); | |
| /// ``` | |
| /// | |
| /// If the file described at [versionPath] does not exist, this check returns `true`. | |
| /// | |
| /// If [onlyIfVersionChanged] is `true` (default), and the file described by [versionPath] | |
| /// has not changed at the current commit SHA compared to HEAD, `true` is immediately | |
| /// returned without any additional checks. | |
| @useResult | |
| Future<bool> checkEngineVersion({ | |
| required String versionPath, | |
| required String scriptPath, | |
| bool onlyIfVersionChanged = true, | |
| @visibleForTesting FileSystem? fileSystem, | |
| @visibleForTesting ProcessRunner? runner, | |
| @visibleForTesting StringSink? stderr, | |
| }) async { | |
| fileSystem ??= const LocalFileSystem(); | |
| runner ??= ProcessRunner(); | |
| stderr ??= io.stderr; | |
| // If the file does not exist, immediately return true. | |
| final File versionFile = fileSystem.file(versionPath); | |
| if (!versionFile.existsSync()) { | |
| stderr.writeln('$versionPath does not exist, skipping engine.version check'); | |
| return true; | |
| } | |
| // The file exists. Do we need to verify it was updated? | |
| if (onlyIfVersionChanged && !await _wasUpdated(versionPath, runner, stderr)) { | |
| stderr.writeln('$versionPath has not changed, skipping engine.version check'); | |
| return true; | |
| } | |
| // Get the expected value. | |
| final ProcessRunnerResult expectedShaResult = await runner.runProcess(<String>[ | |
| scriptPath, | |
| ], failOk: true); | |
| if (expectedShaResult.exitCode != 0) { | |
| stderr.writeln('$scriptPath failed: ${expectedShaResult.stdout}'); | |
| return false; | |
| } | |
| final String expectedSha = expectedShaResult.stdout.trim(); | |
| // Get the actual value. | |
| final String actualSha = versionFile.readAsStringSync().trim(); | |
| // Compare | |
| if (expectedSha != actualSha) { | |
| stderr.writeln('$scriptPath output $expectedSha, but $versionPath is $actualSha'); | |
| return false; | |
| } | |
| return true; | |
| } | |
| Future<bool> _wasUpdated(String path, ProcessRunner runner, StringSink stderr) async { | |
| final ProcessRunnerResult diffResult = await runner.runProcess(<String>[ | |
| 'git', | |
| 'diff', | |
| '--name-only', | |
| '--relative', | |
| 'master...HEAD', | |
| '--', | |
| path, | |
| ], failOk: true); | |
| if (diffResult.exitCode != 0) { | |
| stderr.writeln('git diff failed: ${diffResult.stdout}'); | |
| return false; | |
| } | |
| final String diffOutput = diffResult.stdout.trim(); | |
| return diffOutput.split('\n').contains(path); | |
| } |