Merge pull request #467 from RedBrogdon/nomono
Updates compilation and analysis to use an unforked version of the Flutter SDK
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..1f2e1eb
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,4 @@
+# Docker should ignore the local copy of Flutter and install its own,
+# since the Docker container is likely running a different OS than the
+# developer's machine.
+flutter
diff --git a/.gitmodules b/.gitmodules
index d9a07c4..37aa38f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,3 @@
-[submodule "flutter_web"]
- path = flutter_web
- url = https://github.com/flutter/flutter_web.git
- branch = master
+[submodule "flutter"]
+ path = flutter
+ url = https://github.com/flutter/flutter.git
diff --git a/.travis.yml b/.travis.yml
index 9215045..9762685 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,4 +14,11 @@
branches:
only: [master]
+before_script:
+ - git submodule init
+ - git submodule update
+ - export PATH=$PATH:$PWD/flutter/bin
+ - flutter doctor
+ - flutter config --enable-web
+ - flutter precache --web --no-android --no-ios --no-linux --no-windows --no-macos --no-fuchsia
script: ./tool/travis.sh
diff --git a/Dockerfile b/Dockerfile
index 195f826..fed533c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,12 +1,16 @@
# Keep aligned with min SDK in pubspec.yaml and Dart test version in .travis.yml
FROM google/dart:2.6.0
+# The specific commit that dart-services should use. This should be kept
+# in sync with the flutter submodule in the dart-services repo.
+# (run `git rev-parse HEAD` from the flutter submodule to retrieve this value.
+ARG FLUTTER_COMMIT=fbabb264e0ab3e090d6ec056e0744aaeb1586735
+
WORKDIR /app
ADD tool/dart_run.sh /dart_runtime/
RUN chmod 755 /dart_runtime/dart_run.sh && \
chown root:root /dart_runtime/dart_run.sh
ADD pubspec.* /app/
-ADD third_party /app/third_party
RUN find -name "*" -print
RUN pub get
ADD . /app
@@ -16,12 +20,37 @@
# docker image diff small.
RUN apt-get update && \
apt-get install -y unzip && \
- cp -a third_party/pkg ../pkg && \
rm -rf /var/lib/apt/lists/*
+# The Flutter tool won't perform its actions when run as root.
+RUN groupadd --system dart && \
+ useradd --no-log-init --system --home /home/dart --create-home -g dart dart
+
+RUN mkdir flutter && chown dart:dart flutter
+
+# Switch to a new, non-root user to use the flutter tool.
+USER dart
+
+ENV PATH="/home/dart/.pub-cache/bin:${PATH}"
+
+# Clone the flutter repo and set it to the same commit as the flutter submodule.
+RUN git clone https://github.com/flutter/flutter.git
+RUN cd flutter && git checkout $FLUTTER_COMMIT
+
+# Set the Flutter SDK up for web compilation.
+RUN flutter/bin/flutter doctor
+RUN flutter/bin/flutter config --enable-web
+RUN flutter/bin/flutter precache --web --no-android --no-ios --no-linux \
+ --no-windows --no-macos --no-fuchsia
+RUN cat flutter/bin/cache/dart-sdk/version
+
EXPOSE 8080 8181 5858
# Clear out any arguments the base images might have set and ensure we start
# the Dart app using custom script enabling debug modes.
CMD []
+
+# Switch back to root to run the application.
+USER root
+
ENTRYPOINT /bin/bash /dart_runtime/dart_run.sh
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 425f5e2..80e87de 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -7,4 +7,4 @@
- 'dart-sdk/**'
- 'third_party/**'
- 'doc/generated/**'
- - 'flutter_web/**'
+ - 'flutter/**'
diff --git a/benchmark/bench.dart b/benchmark/bench.dart
index 84c234a..88b9f23 100644
--- a/benchmark/bench.dart
+++ b/benchmark/bench.dart
@@ -6,6 +6,7 @@
import 'dart:async';
+import 'package:dart_services/src/sdk_manager.dart';
import 'package:logging/logging.dart';
import 'package:dart_services/src/analysis_server.dart';
@@ -19,10 +20,12 @@
final BenchmarkHarness harness = BenchmarkHarness(asJson: json);
- final FlutterWebManager flutterWebManager = FlutterWebManager(sdkPath);
+ final FlutterWebManager flutterWebManager =
+ FlutterWebManager(SdkManager.flutterSdk);
await flutterWebManager.initFlutterWeb();
- var compiler = Compiler(sdkPath, flutterWebManager);
+ var compiler =
+ Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
Logger.root.level = Level.WARNING;
Logger.root.onRecord.listen((LogRecord record) {
diff --git a/bin/server.dart b/bin/server.dart
index 49bc5ab..5750d57 100644
--- a/bin/server.dart
+++ b/bin/server.dart
@@ -15,6 +15,7 @@
// Ensure the Dart SDK is downloaded (if already up-to-date, no work is
// performed).
await SdkManager.sdk.init();
+ await SdkManager.flutterSdk.init();
server.main(args);
}
diff --git a/bin/server_dev.dart b/bin/server_dev.dart
index 50799e0..79ae125 100644
--- a/bin/server_dev.dart
+++ b/bin/server_dev.dart
@@ -12,6 +12,7 @@
Future<void> main(List<String> args) async {
await SdkManager.sdk.init();
+ await SdkManager.flutterSdk.init();
services_dev.main(args);
}
diff --git a/flutter b/flutter
new file mode 160000
index 0000000..fbabb26
--- /dev/null
+++ b/flutter
@@ -0,0 +1 @@
+Subproject commit fbabb264e0ab3e090d6ec056e0744aaeb1586735
diff --git a/flutter_web b/flutter_web
deleted file mode 160000
index c04fb50..0000000
--- a/flutter_web
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit c04fb502b842859de07e36954a9390465a5426c0
diff --git a/lib/services_dev.dart b/lib/services_dev.dart
index 3483203..842ee24 100644
--- a/lib/services_dev.dart
+++ b/lib/services_dev.dart
@@ -10,6 +10,7 @@
import 'dart:io';
import 'package:args/args.dart';
+import 'package:dart_services/src/sdk_manager.dart';
import 'package:logging/logging.dart';
import 'package:rpc/rpc.dart';
import 'package:shelf/shelf.dart';
@@ -50,7 +51,7 @@
if (result['relay'] as bool) {
EndpointsServer.generateRelayDiscovery(sdk, serverUrl).then(printExit);
} else {
- EndpointsServer.generateDiscovery(sdk, serverUrl).then(printExit);
+ EndpointsServer.generateDiscovery(SdkManager.flutterSdk, serverUrl).then(printExit);
}
return;
}
@@ -79,8 +80,8 @@
}
static Future<String> generateDiscovery(
- String sdkPath, String serverUrl) async {
- FlutterWebManager flutterWebManager = FlutterWebManager(sdkPath);
+ FlutterSdk flutterSdk, String serverUrl) async {
+ FlutterWebManager flutterWebManager = FlutterWebManager(flutterSdk);
CommonServer commonServer =
CommonServer(sdkPath, flutterWebManager, _ServerContainer(), _Cache());
await commonServer.init();
@@ -124,7 +125,7 @@
EndpointsServer._(String sdkPath, this.port) {
discoveryEnabled = false;
- flutterWebManager = FlutterWebManager(sdkPath);
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
commonServer =
CommonServer(sdkPath, flutterWebManager, _ServerContainer(), _Cache());
commonServer.init();
diff --git a/lib/services_gae.dart b/lib/services_gae.dart
index e3c11fc..887a1d4 100644
--- a/lib/services_gae.dart
+++ b/lib/services_gae.dart
@@ -8,6 +8,7 @@
import 'dart:io' as io;
import 'package:appengine/appengine.dart' as ae;
+import 'package:dart_services/src/sdk_manager.dart';
import 'package:logging/logging.dart';
import 'package:rpc/rpc.dart' as rpc;
@@ -42,7 +43,7 @@
io.stdout.write(out);
}
});
- log.info('''Initializing dart-services:
+ log.info('''Initializing dart-services:
port: $gaePort
sdkPath: $sdkPath
REDIS_SERVER_URI: ${io.Platform.environment['REDIS_SERVER_URI']}
@@ -70,7 +71,7 @@
discoveryEnabled = false;
fileRelayServer = FileRelayServer();
- flutterWebManager = FlutterWebManager(sdkPath);
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
commonServer = CommonServer(
sdkPath,
flutterWebManager,
diff --git a/lib/src/analysis_server.dart b/lib/src/analysis_server.dart
index 952d874..416c449 100644
--- a/lib/src/analysis_server.dart
+++ b/lib/src/analysis_server.dart
@@ -66,7 +66,7 @@
'--client-id=DartPad',
'--client-version=$_sdkVersion'
];
- _logger.info('About to start with server with args: $serverArgs');
+ _logger.info('About to start with server with SDK path `$sdkPath` and args: $serverArgs');
_init = AnalysisServer.create(
onRead: onRead,
@@ -94,6 +94,8 @@
await _sendRemoveOverlays();
return analysisServer;
+ }).catchError((err, st) {
+ _logger.severe('Error starting analysis server ($sdkPath): $err.\n$st');
});
}
diff --git a/lib/src/common.dart b/lib/src/common.dart
index 876289a..760abd2 100644
--- a/lib/src/common.dart
+++ b/lib/src/common.dart
@@ -9,6 +9,25 @@
import 'sdk_manager.dart';
const kMainDart = 'main.dart';
+const kBootstrapDart = 'bootstrap.dart';
+
+const kBootstrapFlutterCode = r'''
+import 'dart:ui' as ui;
+import 'main.dart' as user_code;
+
+void main() async {
+ await ui.webOnlyInitializePlatform();
+ user_code.main();
+}
+''';
+
+const kBootstrapDartCode = r'''
+import 'main.dart' as user_code;
+
+void main() {
+ user_code.main();
+}
+''';
const sampleCode = '''
void main() {
@@ -25,6 +44,28 @@
}
""";
+const sampleCodeFlutter = '''
+import 'package:flutter/material.dart';
+
+void main() async {
+ runApp(
+ MaterialApp(
+ debugShowCheckedModeBanner: false,
+ home: Scaffold(
+ appBar: AppBar(
+ title: Text('Hey there, boo!'),
+ ),
+ body: Center(
+ child: Text(
+ 'You are pretty okay.',
+ ),
+ ),
+ ),
+ ),
+ );
+}
+''';
+
const sampleCodeMultiFoo = """
import 'bar.dart';
@@ -74,16 +115,6 @@
}
""";
-const sampleDart2OK = """
-class Foo {
- String toString() => 'hello';
-}
-
-void main(List<String> argv) {
- print (Foo());
-}
-""";
-
const sampleDart2Error = '''
class Foo {
final bool isAlwaysNull;
diff --git a/lib/src/common_server.dart b/lib/src/common_server.dart
index 8fb3b85..297c32b 100644
--- a/lib/src/common_server.dart
+++ b/lib/src/common_server.dart
@@ -155,12 +155,13 @@
});
}
- /// Build a key that includes the server version, and Dart SDK Version.
+ /// Build a key that includes the server version, Dart SDK version, and
+ /// Flutter SDK version.
///
- /// We don't use the existing key directly so that different AppEngine versions
- /// using the same redis cache do not have collisions.
+ /// We don't use the existing key directly so that different AppEngine
+ /// versions using the same redis cache do not have collisions.
String _genKey(String key) =>
- 'server:$serverVersion:dart:${SdkManager.sdk.versionFull}+$key';
+ 'server:$serverVersion:dart:${SdkManager.sdk.versionFull}:flutter:${SdkManager.flutterSdk.versionFull}+$key';
@override
Future<String> get(String key) async {
@@ -268,6 +269,7 @@
Compiler compiler;
AnalysisServerWrapper analysisServer;
+ AnalysisServerWrapper flutterAnalysisServer;
CommonServer(
this.sdkPath,
@@ -280,10 +282,19 @@
}
Future<void> init() async {
+ log.info('Beginning CommonServer init().');
analysisServer = AnalysisServerWrapper(sdkPath, flutterWebManager);
- compiler = Compiler(sdkPath, flutterWebManager);
+ flutterAnalysisServer = AnalysisServerWrapper(
+ flutterWebManager.flutterSdk.sdkPath, flutterWebManager);
+
+ compiler =
+ Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
await analysisServer.init();
+ log.info('Dart analysis server initialized.');
+
+ await flutterAnalysisServer.init();
+ log.info('Flutter analysis server initialized.');
unawaited(analysisServer.onExit.then((int code) {
log.severe('analysisServer exited, code: $code');
@@ -291,12 +302,20 @@
exit(code);
}
}));
+
+ unawaited(flutterAnalysisServer.onExit.then((int code) {
+ log.severe('flutterAnalysisServer exited, code: $code');
+ if (code != 0) {
+ exit(code);
+ }
+ }));
}
Future<void> warmup({bool useHtml = false}) async {
await flutterWebManager.warmup();
await compiler.warmup(useHtml: useHtml);
await analysisServer.warmup(useHtml: useHtml);
+ await flutterAnalysisServer.warmup(useHtml: useHtml);
}
Future<void> restart() async {
@@ -313,6 +332,7 @@
Future<dynamic> shutdown() {
return Future.wait(<Future<dynamic>>[
analysisServer.shutdown(),
+ flutterAnalysisServer.shutdown(),
compiler.dispose(),
Future<dynamic>.sync(cache.shutdown)
]);
@@ -420,7 +440,8 @@
try {
final Stopwatch watch = Stopwatch()..start();
- AnalysisResults results = await analysisServer.analyze(source);
+ AnalysisResults results =
+ await getCorrectAnalysisServer(source).analyze(source);
int lineCount = source.split('\n').length;
int ms = watch.elapsedMilliseconds;
log.info('PERF: Analyzed $lineCount lines of Dart in ${ms}ms.');
@@ -554,7 +575,7 @@
Stopwatch watch = Stopwatch()..start();
try {
Map<String, String> docInfo =
- await analysisServer.dartdoc(source, offset);
+ await getCorrectAnalysisServer(source).dartdoc(source, offset);
docInfo ??= <String, String>{};
log.info('PERF: Computed dartdoc in ${watch.elapsedMilliseconds}ms.');
return DocumentResponse(docInfo);
@@ -584,7 +605,8 @@
Stopwatch watch = Stopwatch()..start();
try {
- CompleteResponse response = await analysisServer.complete(source, offset);
+ CompleteResponse response =
+ await getCorrectAnalysisServer(source).complete(source, offset);
log.info('PERF: Computed completions in ${watch.elapsedMilliseconds}ms.');
return response;
} catch (e, st) {
@@ -605,7 +627,8 @@
await _checkPackageReferencesInitFlutterWeb(source);
Stopwatch watch = Stopwatch()..start();
- FixesResponse response = await analysisServer.getFixes(source, offset);
+ FixesResponse response =
+ await getCorrectAnalysisServer(source).getFixes(source, offset);
log.info('PERF: Computed fixes in ${watch.elapsedMilliseconds}ms.');
return response;
}
@@ -621,7 +644,8 @@
await _checkPackageReferencesInitFlutterWeb(source);
Stopwatch watch = Stopwatch()..start();
- var response = await analysisServer.getAssists(source, offset);
+ var response =
+ await getCorrectAnalysisServer(source).getAssists(source, offset);
log.info('PERF: Computed assists in ${watch.elapsedMilliseconds}ms.');
return response;
}
@@ -634,7 +658,8 @@
Stopwatch watch = Stopwatch()..start();
- FormatResponse response = await analysisServer.format(source, offset);
+ FormatResponse response =
+ await getCorrectAnalysisServer(source).format(source, offset);
log.info('PERF: Computed format in ${watch.elapsedMilliseconds}ms.');
return response;
}
@@ -646,7 +671,7 @@
/// Check that the set of packages referenced is valid.
///
- /// If there are uses of package:flutter_web, ensure that support there is
+ /// If there are uses of package:flutter, ensure that support there is
/// initialized.
Future<void> _checkPackageReferencesInitFlutterWeb(String source) async {
Set<String> imports = getAllImportsFor(source);
@@ -660,11 +685,18 @@
try {
await flutterWebManager.initFlutterWeb();
} catch (e) {
- log.warning('unable to init package:flutter_web');
+ log.warning('unable to init package:flutter: $e');
return;
}
}
}
+
+ AnalysisServerWrapper getCorrectAnalysisServer(String source) {
+ Set<String> imports = getAllImportsFor(source);
+ return flutterWebManager.usesFlutterWeb(imports)
+ ? flutterAnalysisServer
+ : analysisServer;
+ }
}
String _printCompileProblem(CompilationProblem problem) => problem.message;
diff --git a/lib/src/compiler.dart b/lib/src/compiler.dart
index ada8d87..b2898814 100644
--- a/lib/src/compiler.dart
+++ b/lib/src/compiler.dart
@@ -22,27 +22,23 @@
/// An interface to the dart2js compiler. A compiler object can process one
/// compile at a time.
class Compiler {
- final String sdkPath;
- final FlutterWebManager flutterWebManager;
-
+ final Sdk _sdk;
+ final FlutterSdk _flutterSdk;
+ final FlutterWebManager _flutterWebManager;
+ final String _dartdevcPath;
final BazelWorkerDriver _ddcDriver;
- String _sdkVersion;
- Compiler(this.sdkPath, this.flutterWebManager)
- : _ddcDriver = BazelWorkerDriver(
- () => Process.start(path.join(sdkPath, 'bin', 'dartdevc'),
- <String>['--persistent_worker']),
- maxWorkers: 1) {
- _sdkVersion = SdkManager.sdk.version;
- }
+ Compiler(this._sdk, this._flutterSdk, this._flutterWebManager)
+ : _dartdevcPath = path.join(_flutterSdk.sdkPath, 'bin', 'dartdevc'),
+ _ddcDriver = BazelWorkerDriver(
+ () => Process.start(
+ path.join(_flutterSdk.sdkPath, 'bin', 'dartdevc'),
+ <String>['--persistent_worker'],
+ ),
+ maxWorkers: 1);
bool importsOkForCompile(Set<String> imports) {
- return !flutterWebManager.hasUnsupportedImport(imports);
- }
-
- /// The version of the SDK this copy of dart2js is based on.
- String get version {
- return File(path.join(sdkPath, 'version')).readAsStringSync().trim();
+ return !_flutterWebManager.hasUnsupportedImport(imports);
}
Future<CompilationResults> warmup({bool useHtml = false}) {
@@ -58,23 +54,23 @@
if (!importsOkForCompile(imports)) {
return CompilationResults(problems: <CompilationProblem>[
CompilationProblem._(
- 'unsupported import: ${flutterWebManager.getUnsupportedImport(imports)}',
+ 'unsupported import: ${_flutterWebManager.getUnsupportedImport(imports)}',
),
]);
}
Directory temp = await Directory.systemTemp.createTemp('dartpad');
+ _logger.info('Temp directory created: ${temp.path}');
try {
List<String> arguments = <String>[
'--suppress-hints',
'--terse',
+ if (!returnSourceMap) '--no-source-maps',
+ '--packages=${_flutterWebManager.packagesFilePath}',
+ ...['-o', '$kMainDart.js'],
+ kMainDart,
];
- if (!returnSourceMap) arguments.add('--no-source-maps');
-
- arguments.add('--packages=${flutterWebManager.packagesFilePath}');
- arguments.add('-o$kMainDart.js');
- arguments.add(kMainDart);
String compileTarget = path.join(temp.path, kMainDart);
File mainDart = File(compileTarget);
@@ -83,7 +79,7 @@
File mainJs = File(path.join(temp.path, '$kMainDart.js'));
File mainSourceMap = File(path.join(temp.path, '$kMainDart.js.map'));
- final String dart2JSPath = path.join(sdkPath, 'bin', 'dart2js');
+ final String dart2JSPath = path.join(_sdk.sdkPath, 'bin', 'dart2js');
_logger.info('About to exec: $dart2JSPath $arguments');
ProcessResult result = await Process.run(dart2JSPath, arguments,
@@ -121,38 +117,48 @@
if (!importsOkForCompile(imports)) {
return DDCCompilationResults.failed(<CompilationProblem>[
CompilationProblem._(
- 'unsupported import: ${flutterWebManager.getUnsupportedImport(imports)}',
+ 'unsupported import: ${_flutterWebManager.getUnsupportedImport(imports)}',
),
]);
}
Directory temp = await Directory.systemTemp.createTemp('dartpad');
+ _logger.info('Temp directory created: ${temp.path}');
try {
+ final usingFlutter = _flutterWebManager.usesFlutterWeb(imports);
+
+ final mainPath = path.join(temp.path, kMainDart);
+ final bootstrapPath = path.join(temp.path, kBootstrapDart);
+ final bootstrapContents =
+ usingFlutter ? kBootstrapFlutterCode : kBootstrapDartCode;
+
+ await File(bootstrapPath).writeAsString(bootstrapContents);
+ await File(mainPath).writeAsString(input);
+
List<String> arguments = <String>[
'--modules=amd',
+ if (usingFlutter) ...[
+ '-k',
+ '-s',
+ _flutterWebManager.summaryFilePath,
+ '-s',
+ '${_flutterSdk.flutterBinPath}/cache/flutter_web_sdk/flutter_web_sdk/kernel/flutter_ddc_sdk.dill'
+ ],
+ ...['-o', path.join(temp.path, '$kMainDart.js')],
+ '--single-out-file',
+ ...['--module-name', 'dartpad_main'],
+ bootstrapPath,
+ '--packages=${_flutterWebManager.packagesFilePath}',
];
- if (flutterWebManager.usesFlutterWeb(imports)) {
- arguments.addAll(<String>['-s', flutterWebManager.summaryFilePath]);
- }
-
- String compileTarget = path.join(temp.path, kMainDart);
- File mainDart = File(compileTarget);
- await mainDart.writeAsString(input);
-
- arguments.addAll(<String>['-o', path.join(temp.path, '$kMainDart.js')]);
- arguments.add('--single-out-file');
- arguments.addAll(<String>['--module-name', 'dartpad_main']);
- arguments.add(compileTarget);
- arguments.addAll(<String>['--library-root', temp.path]);
-
File mainJs = File(path.join(temp.path, '$kMainDart.js'));
- _logger.info('About to exec dartdevc with: $arguments');
+ _logger.info('About to exec "$_dartdevcPath ${arguments.join(' ')}"');
+ _logger.info('Compiling: $input');
- final WorkResponse response =
- await _ddcDriver.doWork(WorkRequest()..arguments.addAll(arguments));
+ final WorkResponse response = await _ddcDriver
+ .doWork(WorkRequest()..arguments.addAll(arguments));
if (response.exitCode != 0) {
return DDCCompilationResults.failed(<CompilationProblem>[
@@ -162,7 +168,7 @@
final DDCCompilationResults results = DDCCompilationResults(
compiledJS: await mainJs.readAsString(),
modulesBaseUrl: 'https://storage.googleapis.com/'
- 'compilation_artifacts/$_sdkVersion/',
+ 'compilation_artifacts/${_flutterSdk.versionFull}/',
);
return results;
}
@@ -218,6 +224,7 @@
/// This is true if there were no errors.
bool get success => problems.isEmpty;
+
@override
String toString() => success
? 'CompilationResults: Success'
diff --git a/lib/src/flutter_web.dart b/lib/src/flutter_web.dart
index 612a015..90d3561 100644
--- a/lib/src/flutter_web.dart
+++ b/lib/src/flutter_web.dart
@@ -15,13 +15,13 @@
/// Handle provisioning package:flutter_web and related work.
class FlutterWebManager {
- final String sdkPath;
+ final FlutterSdk flutterSdk;
Directory _projectDirectory;
bool _initedFlutterWeb = false;
- FlutterWebManager(this.sdkPath) {
+ FlutterWebManager(this.flutterSdk) {
_projectDirectory = Directory.systemTemp.createTempSync('dartpad');
_init();
}
@@ -36,7 +36,7 @@
void _init() {
// create a pubspec.yaml file
- String pubspec = createPubspec(false);
+ String pubspec = createPubspec(true);
File(path.join(_projectDirectory.path, 'pubspec.yaml'))
.writeAsStringSync(pubspec);
@@ -71,26 +71,29 @@
await _runPubGet();
- final String sdkVersion = SdkManager.sdk.version;
+ final String sdkVersion = flutterSdk.versionFull;
- // download and save the flutter_web.sum file
+ // Download and save the flutter_web.dill file.
String url = 'https://storage.googleapis.com/compilation_artifacts/'
- '$sdkVersion/flutter_web.sum';
+ '$sdkVersion/flutter_web.dill';
+
+ _logger.info('Attempting download of $url');
+
Uint8List summaryContents = await http.readBytes(url);
- await File(path.join(_projectDirectory.path, 'flutter_web.sum'))
+ await File(path.join(_projectDirectory.path, 'flutter_web.dill'))
.writeAsBytes(summaryContents);
+ _logger.info('Wrote flutter_web.dill');
+
_initedFlutterWeb = true;
}
String get summaryFilePath {
- return path.join(_projectDirectory.path, 'flutter_web.sum');
+ return path.join(_projectDirectory.path, 'flutter_web.dill');
}
static final Set<String> _flutterWebImportPrefixes = <String>{
- 'package:flutter_web',
- 'package:flutter_web_ui',
- 'package:flutter_web_test',
+ 'package:flutter',
};
bool usesFlutterWeb(Set<String> imports) {
@@ -106,9 +109,6 @@
}
String getUnsupportedImport(Set<String> imports) {
- // TODO(devoncarew): Should we support a white-listed set of package:
- // imports?
-
for (String import in imports) {
// All dart: imports are ok;
if (import.startsWith('dart:')) {
@@ -133,24 +133,62 @@
}
Future<void> _runPubGet() async {
- _logger.info('running pub get (${_projectDirectory.path})');
+ _logger.info('running flutter pub get (${_projectDirectory.path})');
- ProcessResult result = await Process.run(
- path.join(sdkPath, 'bin', 'pub'),
- <String>['get', '--no-precompile'],
+ final observatoryPort = await _findFreePort();
+
+ // The DART_VM_OPTIONS flag is included here to override the one sent by the
+ // Dart SDK during tests. Without the flag, the Flutter tool will attempt to
+ // spin up its own observatory on the same port as the one already
+ // instantiated by the Dart SDK running the test, causing a hang.
+ //
+ // The value should be an available port number.
+ final result = await Process.start(
+ path.join(flutterSdk.flutterBinPath, 'flutter'),
+ ['pub', 'get'],
workingDirectory: _projectDirectory.path,
+ environment: {'DART_VM_OPTIONS': '--enable-vm-service=$observatoryPort'},
);
_logger.info('${result.stdout}'.trim());
- if (result.exitCode != 0) {
+ final code = await result.exitCode;
+
+ if (code != 0) {
_logger.warning('pub get failed: ${result.exitCode}');
_logger.warning(result.stderr);
- throw 'pub get failed: ${result.exitCode}';
+ throw 'pub get failed: ${result.exitCode}: ${result.stderr}';
}
}
+ Future<int> _findFreePort({bool ipv6 = false}) async {
+ var port = 0;
+ ServerSocket serverSocket;
+ final InternetAddress loopback =
+ ipv6 ? InternetAddress.loopbackIPv6 : InternetAddress.loopbackIPv4;
+
+ try {
+ serverSocket = await ServerSocket.bind(loopback, 0);
+ port = serverSocket.port;
+ } on SocketException catch (e) {
+ // If ipv4 loopback bind fails, try ipv6.
+ if (!ipv6) {
+ return _findFreePort(ipv6: true);
+ }
+ _logger.severe('Could not find free port for `pub get`: $e');
+ } catch (e) {
+ // Failures are signaled by a return value of 0 from this function.
+ _logger.severe('Could not find free port for `pub get`: $e');
+ } finally {
+ if (serverSocket != null) {
+ await serverSocket.close();
+ }
+ }
+
+ return port;
+ }
+
static const String _samplePackageName = 'dartpad_sample';
static String createPubspec(bool includeFlutterWeb) {
@@ -161,25 +199,10 @@
if (includeFlutterWeb) {
content += '''
dependencies:
- flutter_web:
- git:
- url: https://github.com/flutter/flutter_web
- path: packages/flutter_web
- flutter_web_test:
- git:
- url: https://github.com/flutter/flutter_web
- path: packages/flutter_web_test
- flutter_web_ui:
- git:
- url: https://github.com/flutter/flutter_web
- path: packages/flutter_web_ui
-dependency_overrides:
- flutter_web:
- path: ${Directory.current.path}/flutter_web/packages/flutter_web
- flutter_web_test:
- path: ${Directory.current.path}/flutter_web/packages/flutter_web_test
- flutter_web_ui:
- path: ${Directory.current.path}/flutter_web/packages/flutter_web_ui
+ flutter:
+ sdk: flutter
+ flutter_test:
+ sdk: flutter
''';
}
diff --git a/lib/src/sdk_manager.dart b/lib/src/sdk_manager.dart
index be63403..b1757f7 100644
--- a/lib/src/sdk_manager.dart
+++ b/lib/src/sdk_manager.dart
@@ -11,11 +11,21 @@
class SdkManager {
static Sdk get sdk => _sdk ?? (_sdk = PlatformSdk());
+ static FlutterSdk get flutterSdk => _flutterSdk ?? (_flutterSdk = FlutterSdk());
+
static void setSdk(Sdk value) {
_sdk = sdk;
}
+ static void setFlutterSdk(FlutterSdk value) {
+ _flutterSdk = value;
+ }
+
+ // The installed Dart SDK.
static Sdk _sdk;
+
+ // The installed Flutter SDK.
+ static FlutterSdk _flutterSdk;
}
abstract class Sdk {
@@ -37,6 +47,7 @@
String get sdkPath;
}
+/// Represents a Dart SDK present on the server.
class PlatformSdk extends Sdk {
String _versionFull = '';
@@ -44,7 +55,6 @@
Future<void> init() async {
_versionFull =
(await File(path.join(sdkPath, 'version')).readAsString()).trim();
- return;
}
@override
@@ -53,3 +63,25 @@
@override
String get sdkPath => path.dirname(path.dirname(Platform.resolvedExecutable));
}
+
+/// Represents a Flutter SDK installation (which includes its own version of the
+/// Dart SDK) present on the server.
+///
+/// This class assumes the Flutter SDK is available at `./flutter`.
+class FlutterSdk extends Sdk {
+ String _versionFull = '';
+
+ @override
+ Future<void> init() async {
+ _versionFull =
+ (await File(path.join(sdkPath, 'version')).readAsString()).trim();
+ }
+
+ @override
+ String get sdkPath => path.join(flutterBinPath, 'cache/dart-sdk');
+
+ String get flutterBinPath => path.join(Directory.current.path, 'flutter/bin');
+
+ @override
+ String get versionFull => _versionFull;
+}
diff --git a/pubspec.lock b/pubspec.lock
index d5985f6..0e3a5f9 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -548,4 +548,4 @@
source: hosted
version: "2.2.0"
sdks:
- dart: ">=2.6.0-dev.8.2 <3.0.0"
+ dart: ">=2.6.0 <3.0.0"
diff --git a/test/analysis_server_test.dart b/test/analysis_server_test.dart
index cd749bd..0f7bda2 100644
--- a/test/analysis_server_test.dart
+++ b/test/analysis_server_test.dart
@@ -8,6 +8,7 @@
import 'package:dart_services/src/api_classes.dart';
import 'package:dart_services/src/common.dart';
import 'package:dart_services/src/flutter_web.dart';
+import 'package:dart_services/src/sdk_manager.dart';
import 'package:test/test.dart';
const completionCode = r'''
@@ -63,9 +64,9 @@
AnalysisServerWrapper analysisServer;
FlutterWebManager flutterWebManager;
- group('analysis_server', () {
+ group('Platform SDK analysis_server', () {
setUp(() async {
- flutterWebManager = FlutterWebManager(sdkPath);
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
analysisServer = AnalysisServerWrapper(sdkPath, flutterWebManager);
await analysisServer.init();
});
@@ -179,18 +180,6 @@
expect(issue.kind, 'error');
});
- test('analyze dart-2', () async {
- await analysisServer.shutdown();
-
- flutterWebManager = FlutterWebManager(sdkPath);
-
- analysisServer = AnalysisServerWrapper(sdkPath, flutterWebManager);
- await analysisServer.init();
-
- AnalysisResults results = await analysisServer.analyze(sampleDart2OK);
- expect(results.issues, hasLength(0));
- });
-
test('filter completions', () async {
// just after A
var idx = 61;
@@ -204,6 +193,26 @@
expect(completionsContains(results, 'ZZ'), false);
});
});
+
+ group('Flutter cached SDK analysis_server', () {
+ setUp(() async {
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
+ analysisServer = AnalysisServerWrapper(SdkManager.flutterSdk.sdkPath, flutterWebManager);
+ await analysisServer.init();
+ });
+
+ tearDown(() => analysisServer.shutdown());
+
+ test('analyze working Dart code', () async {
+ AnalysisResults results = await analysisServer.analyze(sampleCode);
+ expect(results.issues, isEmpty);
+ });
+
+ test('analyze working Flutter code', () async {
+ AnalysisResults results = await analysisServer.analyze(sampleCode);
+ expect(results.issues, isEmpty);
+ });
+ });
}
bool completionsContains(CompleteResponse response, String completion) =>
diff --git a/test/common_server_test.dart b/test/common_server_test.dart
index a299cd1..284bf20 100644
--- a/test/common_server_test.dart
+++ b/test/common_server_test.dart
@@ -298,7 +298,7 @@
setUpAll(() async {
container = MockContainer();
cache = MockCache();
- flutterWebManager = FlutterWebManager(sdkPath);
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
server = CommonServer(sdkPath, flutterWebManager, container, cache);
await server.init();
@@ -338,16 +338,26 @@
tearDown(log.clearListeners);
- test('analyze', () async {
+ test('analyze Dart', () async {
var jsonData = {'source': sampleCode};
var response =
- await _sendPostRequest('dartservices/v1/analyze', jsonData);
+ await _sendPostRequest('dartservices/v1/analyze', jsonData);
expect(response.status, 200);
var data = await response.body.first;
expect(
json.decode(utf8.decode(data)), {'issues': [], 'packageImports': []});
});
+ test('analyze Flutter', () async {
+ var jsonData = {'source': sampleCodeFlutter};
+ var response =
+ await _sendPostRequest('dartservices/v1/analyze', jsonData);
+ expect(response.status, 200);
+ var data = await response.body.first;
+ expect(
+ json.decode(utf8.decode(data)), {'issues': [], 'packageImports': ['flutter']});
+ });
+
test('analyze errors', () async {
var jsonData = {'source': sampleCodeError};
var response =
diff --git a/test/compiler_test.dart b/test/compiler_test.dart
index ba27522..a9afa97 100644
--- a/test/compiler_test.dart
+++ b/test/compiler_test.dart
@@ -7,6 +7,7 @@
import 'package:dart_services/src/common.dart';
import 'package:dart_services/src/compiler.dart';
import 'package:dart_services/src/flutter_web.dart';
+import 'package:dart_services/src/sdk_manager.dart';
import 'package:test/test.dart';
void main() => defineTests();
@@ -17,9 +18,14 @@
group('compiler', () {
setUpAll(() async {
- flutterWebManager = FlutterWebManager(sdkPath);
+ await SdkManager.sdk.init();
+ await SdkManager.flutterSdk.init();
- compiler = Compiler(sdkPath, flutterWebManager);
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
+ await flutterWebManager.initFlutterWeb();
+
+ compiler =
+ Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
});
tearDownAll(() async {
@@ -60,6 +66,20 @@
});
});
+ test('compileDDC with Flutter', () {
+ return compiler
+ .compileDDC(sampleCodeFlutter)
+ .then((DDCCompilationResults result) {
+ print(result.problems);
+
+ expect(result.success, true);
+ expect(result.compiledJS, isNotEmpty);
+ expect(result.modulesBaseUrl, isNotEmpty);
+
+ expect(result.compiledJS, contains("define('dartpad_main', ["));
+ });
+ });
+
test('compileDDC with async', () {
return compiler
.compileDDC(sampleCodeAsync)
@@ -113,8 +133,6 @@
return compiler
.compile(sampleCode, returnSourceMap: true)
.then((CompilationResults result) {
- expect(compiler.version, isNotNull);
- expect(compiler.version, startsWith('2.'));
expect(result.sourceMap, isNotNull);
expect(result.sourceMap, isNotEmpty);
});
diff --git a/test/flutter_web_test.dart b/test/flutter_web_test.dart
index 3c5839f..069842e 100644
--- a/test/flutter_web_test.dart
+++ b/test/flutter_web_test.dart
@@ -4,7 +4,6 @@
import 'dart:io';
-import 'package:dart_services/src/common.dart';
import 'package:dart_services/src/flutter_web.dart';
import 'package:dart_services/src/sdk_manager.dart';
import 'package:test/test.dart';
@@ -17,7 +16,8 @@
setUp(() async {
await SdkManager.sdk.init();
- flutterWebManager = FlutterWebManager(sdkPath);
+ await SdkManager.flutterSdk.init();
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
});
tearDown(() {
@@ -53,7 +53,9 @@
FlutterWebManager flutterWebManager;
setUpAll(() async {
- flutterWebManager = FlutterWebManager(sdkPath);
+ await SdkManager.sdk.init();
+ await SdkManager.flutterSdk.init();
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
await flutterWebManager.initFlutterWeb();
});
@@ -67,7 +69,7 @@
File file = File(packagesPath);
List<String> lines = file.readAsLinesSync();
- expect(lines, anyElement(startsWith('flutter_web:file://')));
+ expect(lines, anyElement(startsWith('flutter:file://')));
});
test('summaryFilePath', () {
diff --git a/third_party/pkg/README b/third_party/pkg/README
deleted file mode 100644
index db43505..0000000
--- a/third_party/pkg/README
+++ /dev/null
@@ -1,2 +0,0 @@
-Place dependency overrides here if it is necessary
-to deploy a dart-services with them.
diff --git a/tool/fuzz_driver.dart b/tool/fuzz_driver.dart
index 01cfe5e..3d6471e 100644
--- a/tool/fuzz_driver.dart
+++ b/tool/fuzz_driver.dart
@@ -18,6 +18,7 @@
import 'package:dart_services/src/common_server.dart';
import 'package:dart_services/src/compiler.dart' as comp;
import 'package:dart_services/src/flutter_web.dart';
+import 'package:dart_services/src/sdk_manager.dart';
import 'package:rpc/rpc.dart';
bool _SERVER_BASED_CALL = false;
@@ -123,7 +124,7 @@
print('SdKPath: $sdkPath');
- FlutterWebManager flutterWebManager = FlutterWebManager(sdkPath);
+ FlutterWebManager flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
container = MockContainer();
cache = MockCache();
@@ -140,7 +141,7 @@
await analysisServer.warmup();
print('Warming up compiler');
- compiler = comp.Compiler(sdkPath, flutterWebManager);
+ compiler = comp.Compiler(SdkManager.sdk, SdkManager.flutterSdk, flutterWebManager);
await compiler.warmup();
print('SetupTools done');
}
diff --git a/tool/grind.dart b/tool/grind.dart
index c080350..437dc5f 100644
--- a/tool/grind.dart
+++ b/tool/grind.dart
@@ -12,9 +12,11 @@
import 'package:grinder/grinder.dart';
import 'package:grinder/grinder_files.dart';
import 'package:http/http.dart' as http;
+import 'package:path/path.dart' as path;
Future<void> main(List<String> args) async {
await SdkManager.sdk.init();
+ await SdkManager.flutterSdk.init();
return grind(args);
}
@@ -33,7 +35,7 @@
@Task()
void serve() {
// You can run the `grind serve` command, or just run
- // `dart bin/server_dev.dart --port 8002` locally.
+ // `dart bin/server_dev.dart --port 8082` locally.
Process.runSync(
Platform.executable, ['bin/server_dev.dart', '--port', '8082']);
@@ -59,13 +61,13 @@
final List<String> compilationArtifacts = [
'dart_sdk.js',
'flutter_web.js',
- 'flutter_web.sum',
+ 'flutter_web.dill',
];
@Task('validate that we have the correct compilation artifacts available in '
'google storage')
void validateStorageArtifacts() async {
- String version = SdkManager.sdk.version;
+ String version = SdkManager.flutterSdk.versionFull;
const String urlBase =
'https://storage.googleapis.com/compilation_artifacts/';
@@ -89,7 +91,7 @@
@Task('build the sdk compilation artifacts for upload to google storage')
void buildStorageArtifacts() {
- // build and copy dart_sdk.js, flutter_web.js, and flutter_web.sum
+ // build and copy dart_sdk.js, flutter_web.js, and flutter_web.dill
final Directory temp =
Directory.systemTemp.createTempSync('flutter_web_sample');
@@ -101,18 +103,20 @@
}
void _buildStorageArtifacts(Directory dir) {
+ final flutterSdkPath =
+ Directory(path.join(Directory.current.path, 'flutter'));
String pubspec = FlutterWebManager.createPubspec(true);
joinFile(dir, ['pubspec.yaml']).writeAsStringSync(pubspec);
- // run pub get
- Pub.get(workingDirectory: dir.path);
+ // run flutter pub get
+ run(
+ path.join(flutterSdkPath.path, 'bin/flutter'),
+ arguments: ['pub', 'get'],
+ workingDirectory: dir.path,
+ );
// locate the artifacts
- final List<String> flutterPackages = [
- 'flutter_web',
- 'flutter_web_ui',
- 'flutter_web_test',
- ];
+ final List<String> flutterPackages = ['flutter', 'flutter_test'];
List<String> flutterLibraries = [];
List<String> packageLines = joinFile(dir, ['.packages']).readAsLinesSync();
@@ -139,34 +143,56 @@
}
}
- // build the artifacts using DDC
- // dartdevc --modules=amd -o flutter_web.js package:flutter_web/animation.dart ...
+ // Make sure flutter/bin/cache/flutter_web_sdk/flutter_web_sdk/kernel/flutter_ddc_sdk.dill
+ // is installed.
run(
- 'dartdevc',
- arguments: [
- '--modules=amd',
- '-o',
- 'flutter_web.js',
- ]..addAll(flutterLibraries),
+ path.join(flutterSdkPath.path, 'bin/flutter'),
+ arguments: ['precache', '--web'],
workingDirectory: dir.path,
);
- // copy them to the project dir
- Directory artifactsDir = getDir('artifacts');
+ // Build the artifacts using DDC:
+ // dart-sdk/bin/dartdevc -k -s kernel/flutter_ddc_sdk.dill
+ // --modules=amd package:flutter_web/animation.dart ...
+ final compilerPath =
+ path.join(flutterSdkPath.path, 'bin/cache/dart-sdk/bin/dartdevc');
+ final dillPath = path.join(flutterSdkPath.path,
+ 'bin/cache/flutter_web_sdk/flutter_web_sdk/kernel/flutter_ddc_sdk.dill');
+
+ var args = [
+ '-k',
+ '-s',
+ dillPath,
+ '--modules=amd',
+ '-o',
+ 'flutter_web.js',
+ ...flutterLibraries
+ ];
+
+ run(
+ compilerPath,
+ arguments: args,
+ workingDirectory: dir.path,
+ );
+
+ // Copy both to the project directory.
+ final artifactsDir = getDir('artifacts');
artifactsDir.create();
- copy(getFile('${SdkManager.sdk.sdkPath}/lib/dev_compiler/amd/dart_sdk.js'),
- artifactsDir);
- copy(joinFile(dir, ['flutter_web.js']), artifactsDir);
- copy(joinFile(dir, ['flutter_web.sum']), artifactsDir);
+ final sdkJsPath = path.join(flutterSdkPath.path,
+ 'bin/cache/flutter_web_sdk/flutter_web_sdk/kernel/amd/dart_sdk.js');
- // emit some good google storage upload instructions
- final String version = SdkManager.sdk.version;
+ copy(getFile(sdkJsPath), artifactsDir);
+ copy(joinFile(dir, ['flutter_web.js']), artifactsDir);
+ copy(joinFile(dir, ['flutter_web.dill']), artifactsDir);
+
+ // Emit some good google storage upload instructions.
+ final String version = SdkManager.flutterSdk.versionFull;
log('\nFrom the dart-services project root dir, run:');
log(' gsutil -h "Cache-Control:public, max-age=86400" cp -z js '
'artifacts/*.js gs://compilation_artifacts/$version/');
- log(' gsutil -h "Cache-Control:public, max-age=86400" cp -z sum '
- 'artifacts/*.sum gs://compilation_artifacts/$version/');
+ log(' gsutil -h "Cache-Control:public, max-age=86400" cp -z dill '
+ 'artifacts/*.dill gs://compilation_artifacts/$version/');
}
@Task()