diff --git a/lib/commands/install.dart b/lib/commands/install.dart index 67fc6623..aebccaed 100644 --- a/lib/commands/install.dart +++ b/lib/commands/install.dart @@ -3,7 +3,7 @@ import 'package:fvm/exceptions.dart'; import 'package:fvm/utils/guards.dart'; import 'package:fvm/utils/helpers.dart'; import 'package:fvm/utils/project_config.dart'; -import 'package:fvm/utils/version_installer.dart'; +import 'package:fvm/utils/release_installer.dart'; /// Installs Flutter SDK class InstallCommand extends Command { @@ -46,7 +46,7 @@ class InstallCommand extends Command { final flutterVersion = await inferFlutterVersion(version); - await installFlutterVersion(flutterVersion, skipSetup: skipSetup); + await installFlutterRelease(flutterVersion, skipSetup: skipSetup); if (hasConfig) { setAsProjectVersion(version); } diff --git a/lib/commands/use.dart b/lib/commands/use.dart index b3e05433..d5cd123b 100644 --- a/lib/commands/use.dart +++ b/lib/commands/use.dart @@ -4,6 +4,7 @@ import 'package:fvm/utils/flutter_tools.dart'; import 'package:fvm/utils/guards.dart'; import 'package:fvm/utils/helpers.dart'; import 'package:fvm/utils/project_config.dart'; +import 'package:fvm/utils/pubdev.dart'; /// Use an installed SDK version class UseCommand extends Command { @@ -55,5 +56,7 @@ class UseCommand extends Command { // Updates the project config with version setAsProjectVersion(flutterVersion); } + + await checkIfLatestVersion(); } } diff --git a/lib/utils/helpers.dart b/lib/utils/helpers.dart index 7ec111c2..d31e8a86 100644 --- a/lib/utils/helpers.dart +++ b/lib/utils/helpers.dart @@ -8,7 +8,7 @@ import 'package:fvm/utils/confirm.dart'; import 'package:fvm/utils/print.dart'; import 'package:fvm/utils/project_config.dart'; import 'package:fvm/utils/releases_helper.dart'; -import 'package:fvm/utils/version_installer.dart'; +import 'package:fvm/utils/release_installer.dart'; import 'package:path/path.dart' as path; import 'package:fvm/utils/flutter_tools.dart'; @@ -51,7 +51,7 @@ Future checkAndInstallVersion(String version) async { // Install if input is confirmed if (await confirm('Would you like to install it?')) { - await installFlutterVersion(version); + await installFlutterRelease(version); } else { // If do not install exist exit(0); diff --git a/lib/utils/pubdev.dart b/lib/utils/pubdev.dart new file mode 100644 index 00000000..3cb5164b --- /dev/null +++ b/lib/utils/pubdev.dart @@ -0,0 +1,75 @@ +import 'dart:convert'; +import 'package:fvm/src/version.dart'; +import 'package:http/http.dart' as http; +import 'package:io/ansi.dart'; +import 'package:version/version.dart'; + +PubPackage pubPackageFromMap(String str) => + PubPackage.fromMap(json.decode(str) as Map); + +String pubPackageToMap(PubPackage data) => json.encode(data.toMap()); + +/// Pub.dev FVM info +const kPubDevUrl = 'https://pub.dev/packages/fvm.json'; + +class PubPackage { + PubPackage({ + this.name, + this.uploaders, + this.versions, + }); + + final String name; + final List uploaders; + final List versions; + + factory PubPackage.fromMap(Map json) { + // final uploaders = json['uploaders'] as List; + return PubPackage( + name: json['name'] as String, + uploaders: List.from(json['uploaders'] as List), + versions: List.from(json['versions'] as List), + ); + } + + Map toMap() => { + 'name': name, + 'uploaders': List.from(uploaders.map((x) => x)), + 'versions': List.from(versions.map((x) => x)), + }; +} + +Future _fetchPubPackageInfo() async { + final response = await http.get(kPubDevUrl); + return pubPackageFromMap(response.body); +} + +Future checkIfLatestVersion({String currentVersion}) async { + try { + // option to pass currentVersion for testing + currentVersion ??= packageVersion; + final pubPackage = await _fetchPubPackageInfo(); + + final latestVersion = pubPackage.versions.last; + + if (Version.parse(currentVersion) < Version.parse(latestVersion)) { + final updateCmd = cyan.wrap('(flutter) pub global activate fvm'); + + print(divider); + print( + 'FVM Update Available $packageVersion → ${green.wrap(latestVersion)} '); + print('Run $updateCmd to update'); + print(divider); + return false; + } + return true; + } on Exception { + // Don't do anything fail silently + return true; + } +} + +String get divider { + return yellow + .wrap('\n___________________________________________________\n\n'); +} diff --git a/lib/utils/version_installer.dart b/lib/utils/release_installer.dart similarity index 94% rename from lib/utils/version_installer.dart rename to lib/utils/release_installer.dart index b6a0bcbe..b300e3cf 100644 --- a/lib/utils/version_installer.dart +++ b/lib/utils/release_installer.dart @@ -3,7 +3,7 @@ import 'package:fvm/utils/flutter_tools.dart'; import 'package:fvm/utils/helpers.dart'; import 'package:fvm/utils/print.dart'; -Future installFlutterVersion(String version, +Future installFlutterRelease(String version, {bool skipSetup = false}) async { if (version == null) { throw ExceptionMissingChannelVersion(); diff --git a/lib/utils/releases_helper.dart b/lib/utils/releases_helper.dart index 087ce4de..7c3df878 100644 --- a/lib/utils/releases_helper.dart +++ b/lib/utils/releases_helper.dart @@ -26,7 +26,7 @@ Future getReleases() async { } // Returns Version based on semver -Future getVersion(String version) async { +Future getVersion(String version) async { final releases = await getReleases(); return releases.getVersion(version); } @@ -59,21 +59,21 @@ class Releases { final String baseUrl; final Channels channels; - final List versions; + final List versions; factory Releases.fromMap(Map json) { final currentRelease = parseCurrentReleases(json); return Releases( baseUrl: json['base_url'] as String, channels: Channels.fromMap(currentRelease), - versions: List.from(json['releases'] - .map((x) => Version.fromMap(x as Map)) + versions: List.from(json['releases'] + .map((x) => Release.fromMap(x as Map)) as Iterable), ); } /// Retrieves version information - Version getVersion(String version) { + Release getVersion(String version) { return versions.firstWhere((v) => v.version == version); } @@ -101,17 +101,17 @@ class Channels { this.stable, }); - final Version beta; - final Version dev; - final Version stable; + final Release beta; + final Release dev; + final Release stable; factory Channels.fromMap(Map json) => Channels( - beta: Version.fromMap(json['beta'] as Map), - dev: Version.fromMap(json['dev'] as Map), - stable: Version.fromMap(json['stable'] as Map), + beta: Release.fromMap(json['beta'] as Map), + dev: Release.fromMap(json['dev'] as Map), + stable: Release.fromMap(json['stable'] as Map), ); - Version operator [](String key) { + Release operator [](String key) { if (key == 'beta') return beta; if (key == 'dev') return dev; if (key == 'stable') return stable; @@ -131,8 +131,8 @@ class Channels { }; } -class Version { - Version({ +class Release { + Release({ this.hash, this.channel, this.version, @@ -148,7 +148,7 @@ class Version { final String archive; final String sha256; - factory Version.fromMap(Map json) => Version( + factory Release.fromMap(Map json) => Release( hash: json['hash'] as String, channel: channelValues.map[json['channel']], version: json['version'] as String, diff --git a/pubspec.yaml b/pubspec.yaml index ed78f7b4..c8b7207f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: fvm description: A simple cli to manage Flutter SDK versions per project. Support channels, releases, and local cache for fast switching between versions. -version: 1.1.0 +version: 1.1.1 homepage: https://github.com/leoafarias/fvm environment: @@ -18,6 +18,7 @@ dependencies: process_run: ^0.10.10+1 http: ^0.12.1 date_format: ^1.0.8 + version: ^1.2.0 dev_dependencies: pedantic: ^1.8.0 diff --git a/test/utils/helpers_test.dart b/test/utils/helpers_test.dart index 85342a0a..1375956e 100644 --- a/test/utils/helpers_test.dart +++ b/test/utils/helpers_test.dart @@ -1,3 +1,4 @@ +import 'package:fvm/utils/pubdev.dart'; import 'package:test/test.dart'; import 'package:fvm/utils/helpers.dart'; @@ -22,4 +23,12 @@ void main() { expect(inferFlutterVersion('1.8.0.2'), throwsA(anything)); expect(inferFlutterVersion('v1.17.0-dev.3.1'), throwsA(anything)); }); + + test('Check if FVM latest version', () async { + var isLatest = await checkIfLatestVersion(currentVersion: '1.0.0'); + expect(isLatest, false); + + isLatest = await checkIfLatestVersion(currentVersion: '5.0.0'); + expect(isLatest, true); + }); }