blob: 82433606fcc18be6a238597efdcb8f200f07fe66 [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. 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:convert';
import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:pub_semver/pub_semver.dart';
import '../io.dart';
import '../log.dart';
import '../sdk.dart';
class FlutterSdk extends Sdk {
FlutterSdk._();
static final FlutterSdk _instance = FlutterSdk._();
factory FlutterSdk() => _instance;
@override
String get name => 'Flutter';
// We only consider the Flutter SDK to present if we find a root directory
// and the root directory contains a valid 'version' file.
@override
late final bool isAvailable = rootDirectory != null && version != null;
late final String? rootDirectory = () {
// If FLUTTER_ROOT is specified, then this always points to the Flutter SDK
if (Platform.environment.containsKey('FLUTTER_ROOT')) {
return Platform.environment['FLUTTER_ROOT'];
}
// We can try to find the Flutter SDK relative to the Dart SDK.
// We know that the Dart SDK is always present, this is found relative to
// the `dart` executable, for details see: lib/src/sdk/dart.dart
//
// Once we have the location of the Dart SDK, we can look at its parent
// directories, if going 3 levels-up and down `bin/cache/dart-sdk/` is equal
// to the Dart SDK root, then it's probably because we are located inside
// the Flutter SDK, at: `$FLUTTER_ROOT/bin/cache/dart-sdk`
final parts = p.split(sdk.rootDirectory);
if (parts.length > 3) {
// Go 3-levels up from the Dart SDK root
final flutterSdk = p.joinAll(parts.take(parts.length - 3));
// If going down 'bin/cache/dart-sdk/' yields the same path as the Dart
// SDK has, then it's probably because the Dart SDK is located inside
// the Flutter SDK.
final dartRootFromFlutterSdk = p.join(
flutterSdk,
'bin',
'cache',
'dart-sdk',
);
if (p.equals(sdk.rootDirectory, dartRootFromFlutterSdk)) {
return flutterSdk;
}
}
return null;
}();
@override
late final Version? version = () {
final rootDirectory = this.rootDirectory;
if (rootDirectory == null) return null;
if (!dirExists(rootDirectory)) {
// $FLUTTER_ROOT has been set, but doesn't exist.
return null;
}
final flutterVersionPath =
p.join(rootDirectory, 'bin', 'cache', 'flutter.version.json');
try {
final versionJson = jsonDecode(
readTextFile(flutterVersionPath),
);
if (versionJson is! Map) {
return null;
}
final flutterVersion = versionJson['flutterVersion'];
if (flutterVersion is! String) {
throw FormatException('flutter-version is not a string');
}
return Version.parse(flutterVersion);
} on IOException catch (e) {
warning(
'Could not open flutter version file at `$flutterVersionPath`: $e\n',
);
return null;
} on FormatException catch (e) {
fine('Bad flutter version file at `$flutterVersionPath` $e');
return null; // I guess the file has the wrong format
}
}();
@override
String get installMessage =>
'Flutter users should use `flutter pub` instead of `dart pub`.';
@override
String? packagePath(String name) {
if (!isAvailable) return null;
// Flutter packages exist in both `$flutter/packages` and
// `$flutter/bin/cache/pkg`. This checks both locations in order. If [name]
// exists in neither place, it returns the `$flutter/packages` location
// which is more human-readable for error messages.
var packagePath = p.join(rootDirectory!, 'packages', name);
if (dirExists(packagePath)) return packagePath;
var cachePath = p.join(rootDirectory!, 'bin', 'cache', 'pkg', name);
if (dirExists(cachePath)) return cachePath;
return null;
}
}