diff --git a/webdev/lib/src/command/configuration.dart b/webdev/lib/src/command/configuration.dart index 51598870e..59cd2cfc5 100644 --- a/webdev/lib/src/command/configuration.dart +++ b/webdev/lib/src/command/configuration.dart @@ -37,6 +37,7 @@ const nullSafetyAuto = 'auto'; const disableDdsFlag = 'disable-dds'; const enableExperimentOption = 'enable-experiment'; const canaryFeaturesFlag = 'canary'; +const offlineFlag = 'offline'; ReloadConfiguration _parseReloadConfiguration(ArgResults argResults) { var auto = argResults.options.contains(autoOption) @@ -107,6 +108,7 @@ class Configuration { final String? _nullSafety; final List? _experiments; final bool? _canaryFeatures; + final bool? _offline; Configuration({ bool? autoRun, @@ -133,6 +135,7 @@ class Configuration { String? nullSafety, List? experiments, bool? canaryFeatures, + bool? offline, }) : _autoRun = autoRun, _chromeDebugPort = chromeDebugPort, _debugExtension = debugExtension, @@ -154,7 +157,8 @@ class Configuration { _verbose = verbose, _nullSafety = nullSafety, _experiments = experiments, - _canaryFeatures = canaryFeatures { + _canaryFeatures = canaryFeatures, + _offline = offline { _validateConfiguration(); } @@ -229,7 +233,8 @@ class Configuration { verbose: other._verbose ?? _verbose, nullSafety: other._nullSafety ?? _nullSafety, experiments: other._experiments ?? _experiments, - canaryFeatures: other._canaryFeatures ?? _canaryFeatures); + canaryFeatures: other._canaryFeatures ?? _canaryFeatures, + offline: other._offline ?? _offline); factory Configuration.noInjectedClientDefaults() => Configuration(autoRun: false, debug: false, debugExtension: false); @@ -284,6 +289,8 @@ class Configuration { bool get canaryFeatures => _canaryFeatures ?? false; + bool get offline => _offline ?? false; + /// Returns a new configuration with values updated from the parsed args. static Configuration fromArgs(ArgResults? argResults, {Configuration? defaultConfiguration}) { @@ -408,6 +415,10 @@ class Configuration { ? argResults[canaryFeaturesFlag] as bool? : defaultConfiguration.canaryFeatures; + var offline = argResults.options.contains(offlineFlag) + ? argResults[offlineFlag] as bool? + : defaultConfiguration.verbose; + return Configuration( autoRun: defaultConfiguration.autoRun, chromeDebugPort: chromeDebugPort, @@ -433,6 +444,7 @@ class Configuration { nullSafety: nullSafety, experiments: experiments, canaryFeatures: canaryFeatures, + offline: offline, ); } } diff --git a/webdev/lib/src/command/shared.dart b/webdev/lib/src/command/shared.dart index e05c31da8..0eeb9ee4e 100644 --- a/webdev/lib/src/command/shared.dart +++ b/webdev/lib/src/command/shared.dart @@ -74,7 +74,11 @@ void addSharedArgs(ArgParser argParser, abbr: 'v', defaultsTo: false, negatable: false, - help: 'Enables verbose logging.'); + help: 'Enables verbose logging.') + ..addFlag(offlineFlag, + defaultsTo: false, + negatable: false, + help: 'Disable feching from pub.dev.'); } /// Parses the provided [Configuration] to return a list of @@ -103,7 +107,9 @@ List buildRunnerArgs(Configuration configuration) { } Future validatePubspecLock(Configuration configuration) async { - final pubspecLock = await PubspecLock.read(); + final pubspecLock = await PubspecLock.read( + offline: configuration.offline + ); await checkPubspecLock(pubspecLock, requireBuildWebCompilers: configuration.requireBuildWebCompilers); } diff --git a/webdev/lib/src/pubspec.dart b/webdev/lib/src/pubspec.dart index 6bcec17b3..d3d79d106 100644 --- a/webdev/lib/src/pubspec.dart +++ b/webdev/lib/src/pubspec.dart @@ -68,8 +68,12 @@ class PubspecLock { PubspecLock(this._packages); - static Future read() async { - await _runPubDeps(); + static Future read({ + bool offline = false + }) async { + if (!offline) { + await _runPubDeps(); + } var dir = p.absolute(p.current); while (true) { final candidate = p.join( diff --git a/webdev/test/installation_test.dart b/webdev/test/installation_test.dart index d79674521..6ac972c4f 100644 --- a/webdev/test/installation_test.dart +++ b/webdev/test/installation_test.dart @@ -30,6 +30,14 @@ void main() { Process? serveProcess; Directory? tempDir0; + final testScript = + File(p.join(p.dirname(Platform.script.toFilePath()), 'test.dart')) + .readAsStringSync(); + final thisScript = File.fromUri(Uri.parse(testScript.substring( + testScript.lastIndexOf('import', testScript.indexOf('as test;')) + 8, + testScript.indexOf('as test;') - 2))); + final packageDir = p.dirname(p.dirname(thisScript.path)); + Future expectStdoutAndCleanExit(Process process, {required String expectedStdout}) async { final stdoutCompleter = _captureOutput( @@ -127,7 +135,7 @@ void main() { // Verify that `dart pub global activate` works: activateProcess = await Process.start( 'dart', - ['pub', 'global', 'activate', 'webdev'], + ['pub', 'global', 'activate', '--source', 'path', packageDir], ); await expectStdoutAndCleanExit( activateProcess!, @@ -141,6 +149,41 @@ void main() { await expectStdoutThenExit(serveProcess!, expectedStdout: 'Serving `web` on'); }); + + test('activate and serve webdev fails with offline', () async { + final tempDir = tempDir0!; + final tempPath = tempDir.path; + + // Verify that we can create a new Dart app: + createProcess = await Process.start( + 'dart', + ['create', '--no-pub', '--template', 'web', 'temp_app'], + workingDirectory: tempPath, + ); + await expectStdoutAndCleanExit( + createProcess!, + expectedStdout: 'Created project temp_app in temp_app!', + ); + final appPath = p.join(tempPath, 'temp_app'); + expect(await Directory(appPath).exists(), isTrue); + + // Verify that `dart pub global activate` works: + activateProcess = await Process.start( + 'dart', + ['pub', 'global', 'activate', '--source', 'path', packageDir], + ); + await expectStdoutAndCleanExit( + activateProcess!, + expectedStdout: 'Activated webdev', + ); + + // Verify that `webdev serve` works for our new app: + serveProcess = await Process.start('dart', + ['pub', 'global', 'run', 'webdev', 'serve', '--offline', 'web:8081'], + workingDirectory: appPath); + await expectStdoutThenExit(serveProcess!, + expectedStdout: 'Cannot open file\n pubspec.lock\n'); + }); } Future _waitForExitOrTimeout(Process process) {