From 6e08ea0a2cc0985c7ebc0acae83f3e780dd67499 Mon Sep 17 00:00:00 2001 From: Anurag Roy <44899587+RoyARG02@users.noreply.github.com> Date: Mon, 10 May 2021 22:34:02 +0530 Subject: [PATCH] [flutter_tools] Show linux distribution and kernel release in `flutter doctor` (#81368) --- packages/flutter_tools/lib/src/base/os.dart | 79 +++++++++++ .../test/general.shard/base/os_test.dart | 128 ++++++++++++++++++ 2 files changed, 207 insertions(+) diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart index 87b1740b7bb..62f50607ef3 100644 --- a/packages/flutter_tools/lib/src/base/os.dart +++ b/packages/flutter_tools/lib/src/base/os.dart @@ -35,6 +35,13 @@ abstract class OperatingSystemUtils { platform: platform, processManager: processManager, ); + } else if (platform.isLinux) { + return _LinuxUtils( + fileSystem: fileSystem, + logger: logger, + platform: platform, + processManager: processManager, + ); } else { return _PosixUtils( fileSystem: fileSystem, @@ -283,6 +290,78 @@ class _PosixUtils extends OperatingSystemUtils { } } +class _LinuxUtils extends _PosixUtils { + _LinuxUtils({ + required FileSystem fileSystem, + required Logger logger, + required Platform platform, + required ProcessManager processManager, + }) : super( + fileSystem: fileSystem, + logger: logger, + platform: platform, + processManager: processManager, + ); + + String? _name; + + @override + String get name { + if (_name == null) { + const String prettyNameKey = 'PRETTY_NAME'; + // If "/etc/os-release" doesn't exist, fallback to "/usr/lib/os-release". + final String osReleasePath = _fileSystem.file('/etc/os-release').existsSync() + ? '/etc/os-release' + : '/usr/lib/os-release'; + String prettyName; + String kernelRelease; + try { + final String osRelease = _fileSystem.file(osReleasePath).readAsStringSync(); + prettyName = _getOsReleaseValueForKey(osRelease, prettyNameKey); + } on Exception catch (e) { + _logger.printTrace('Failed obtaining PRETTY_NAME for Linux: $e'); + prettyName = ''; + } + try { + // Split the operating system version which should be formatted as + // "Linux kernelRelease build", by spaces. + final List osVersionSplitted = _platform.operatingSystemVersion.split(' '); + if (osVersionSplitted.length < 3) { + // The operating system version didn't have the expected format. + // Initialize as an empty string. + kernelRelease = ''; + } else { + kernelRelease = ' ${osVersionSplitted[1]}'; + } + } on Exception catch (e) { + _logger.printTrace('Failed obtaining kernel release for Linux: $e'); + kernelRelease = ''; + } + _name = '${prettyName.isEmpty ? super.name : prettyName}$kernelRelease'; + } + return _name!; + } + + String _getOsReleaseValueForKey(String osRelease, String key) { + final List osReleaseSplitted = osRelease.split('\n'); + for (String entry in osReleaseSplitted) { + entry = entry.trim(); + final List entryKeyValuePair = entry.split('='); + if(entryKeyValuePair[0] == key) { + final String value = entryKeyValuePair[1]; + // Remove quotes from either end of the value if they exist + final String quote = value[0]; + if (quote == '\'' || quote == '"') { + return value.substring(0, value.length - 1).substring(1); + } else { + return value; + } + } + } + return ''; + } +} + class _MacOSUtils extends _PosixUtils { _MacOSUtils({ required FileSystem fileSystem, diff --git a/packages/flutter_tools/test/general.shard/base/os_test.dart b/packages/flutter_tools/test/general.shard/base/os_test.dart index 24bbbc0bc6d..7af5b9cb82b 100644 --- a/packages/flutter_tools/test/general.shard/base/os_test.dart +++ b/packages/flutter_tools/test/general.shard/base/os_test.dart @@ -380,6 +380,134 @@ void main() { createOSUtils(FakePlatform(operatingSystem: 'macos')); expect(utils.name, 'product version build darwin-x64'); }); + + testWithoutContext('Windows name', () async { + fakeProcessManager.addCommands([ + const FakeCommand( + command: [ + 'ver', + ], + stdout: 'version', + ), + ]); + + final OperatingSystemUtils utils = + createOSUtils(FakePlatform(operatingSystem: 'windows')); + expect(utils.name, 'version'); + }); + + testWithoutContext('Linux name', () async { + const String fakeOsRelease = ''' + NAME="Name" + ID=id + ID_LIKE=id_like + BUILD_ID=build_id + PRETTY_NAME="Pretty Name" + ANSI_COLOR="ansi color" + HOME_URL="https://home.url/" + DOCUMENTATION_URL="https://documentation.url/" + SUPPORT_URL="https://support.url/" + BUG_REPORT_URL="https://bug.report.url/" + LOGO=logo + '''; + final FileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.directory('/etc').createSync(); + fileSystem.file('/etc/os-release').writeAsStringSync(fakeOsRelease); + + final OperatingSystemUtils utils = OperatingSystemUtils( + fileSystem: fileSystem, + logger: BufferLogger.test(), + platform: FakePlatform( + operatingSystem: 'linux', + operatingSystemVersion: 'Linux 1.2.3-abcd #1 SMP PREEMPT Sat Jan 1 00:00:00 UTC 2000', + ), + processManager: fakeProcessManager, + ); + expect(utils.name, 'Pretty Name 1.2.3-abcd'); + }); + + testWithoutContext('Linux name reads from "/usr/lib/os-release" if "/etc/os-release" is missing', () async { + const String fakeOsRelease = ''' + NAME="Name" + ID=id + ID_LIKE=id_like + BUILD_ID=build_id + PRETTY_NAME="Pretty Name" + ANSI_COLOR="ansi color" + HOME_URL="https://home.url/" + DOCUMENTATION_URL="https://documentation.url/" + SUPPORT_URL="https://support.url/" + BUG_REPORT_URL="https://bug.report.url/" + LOGO=logo + '''; + final FileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.directory('/usr/lib').createSync(recursive: true); + fileSystem.file('/usr/lib/os-release').writeAsStringSync(fakeOsRelease); + + expect(fileSystem.file('/etc/os-release').existsSync(), false); + + final OperatingSystemUtils utils = OperatingSystemUtils( + fileSystem: fileSystem, + logger: BufferLogger.test(), + platform: FakePlatform( + operatingSystem: 'linux', + operatingSystemVersion: 'Linux 1.2.3-abcd #1 SMP PREEMPT Sat Jan 1 00:00:00 UTC 2000', + ), + processManager: fakeProcessManager, + ); + expect(utils.name, 'Pretty Name 1.2.3-abcd'); + }); + + testWithoutContext('Linux name when reading "/etc/os-release" fails', () async { + final FileExceptionHandler handler = FileExceptionHandler(); + final FileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle); + + fileSystem.directory('/etc').createSync(); + final File osRelease = fileSystem.file('/etc/os-release'); + + handler.addError(osRelease, FileSystemOp.read, const FileSystemException()); + + final OperatingSystemUtils utils = OperatingSystemUtils( + fileSystem: fileSystem, + logger: BufferLogger.test(), + platform: FakePlatform( + operatingSystem: 'linux', + operatingSystemVersion: 'Linux 1.2.3-abcd #1 SMP PREEMPT Sat Jan 1 00:00:00 UTC 2000', + ), + processManager: fakeProcessManager, + ); + expect(utils.name, 'Linux 1.2.3-abcd'); + }); + + testWithoutContext('Linux name omits kernel release if undefined', () async { + const String fakeOsRelease = ''' + NAME="Name" + ID=id + ID_LIKE=id_like + BUILD_ID=build_id + PRETTY_NAME="Pretty Name" + ANSI_COLOR="ansi color" + HOME_URL="https://home.url/" + DOCUMENTATION_URL="https://documentation.url/" + SUPPORT_URL="https://support.url/" + BUG_REPORT_URL="https://bug.report.url/" + LOGO=logo + '''; + final FileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.directory('/etc').createSync(); + fileSystem.file('/etc/os-release').writeAsStringSync(fakeOsRelease); + + final OperatingSystemUtils utils = OperatingSystemUtils( + fileSystem: fileSystem, + logger: BufferLogger.test(), + platform: FakePlatform( + operatingSystem: 'linux', + operatingSystemVersion: 'undefinedOperatingSystemVersion', + ), + processManager: fakeProcessManager, + ); + expect(utils.name, 'Pretty Name'); + }); }); testWithoutContext('If unzip fails, include stderr in exception text', () {