11b1da577f
For posix paths, replacing the file path during normalization and then swapping it back later works for both paths and URIs, because a file URI just contains the file path verbatim:
file:///foo/bar/baz
However that's not the case for Windows:
C:\foo\bar\baz
file:///c:/foo/bar/baz
So when normalizing, we need to know if we normalized a URI or a file path, so that we can reverse it later.
With this change, we'll use `{{workspaceFolder-0}}` for the URI, and `{{workspaceFolder-0:filePath}}` for the file path. Then when reversing, we can easily put the correct one back.
This also updates the log replace/scenarios to use the LogNormalizer to perform the denormalization so they don't have to have duplicated logic about what to restore.
I've also updated the existing committed scenarios (EDIT: moved this to a separate CL because Gerrit is falling over) - although even with those changes, they all fail for different reasons (invalid git hashes, mismatches in expected vs actual requests) so I think there is still more work to do here.
Fixes https://github.com/dart-lang/sdk/issues/63330
Change-Id: Ib4c4aabe2c7c0d089bd620bdf00de37acde25f52
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/501600
Reviewed-by: Keerti Parthasarathy <keertip@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
89 lines
3.1 KiB
Dart
89 lines
3.1 KiB
Dart
// Copyright (c) 2026, 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' hide File;
|
|
|
|
import 'package:analysis_server/src/server/driver.dart';
|
|
import 'package:analysis_server/src/session_logger/entry_kind.dart';
|
|
import 'package:analysis_server/src/session_logger/log_entry.dart';
|
|
import 'package:analysis_server/src/session_logger/log_normalizer.dart';
|
|
import 'package:analysis_server/src/session_logger/process_id.dart';
|
|
import 'package:analyzer/file_system/physical_file_system.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import 'log.dart';
|
|
import 'server_driver.dart';
|
|
|
|
/// Either reads in a log file and sends messages one at a time to the
|
|
/// analysis server, or reads them from stdin.
|
|
///
|
|
/// Note that a limited number of bytes at a time can be sent manually through
|
|
/// interactive terminals (4096 bytes on linux, 1028 on mac), which limits the
|
|
/// size of the messages that can be sent that way.
|
|
///
|
|
/// This is useful for manually testing the analysis server, or a given log.
|
|
Future<void> main(List<String> args) async {
|
|
print('Starting analysis server...');
|
|
var driver = ServerDriver(
|
|
arguments: [
|
|
'--${Driver.serverProtocolOption}',
|
|
ServerProtocol.lsp.flagValue,
|
|
],
|
|
);
|
|
await driver.start();
|
|
driver.serverMessages.listen((message) {
|
|
print('<<< ${json.encode(message)}');
|
|
});
|
|
|
|
if (args.isEmpty) {
|
|
sendManualMessages(driver);
|
|
} else if (args.length == 1) {
|
|
replayLogFile(args.single, driver);
|
|
} else {
|
|
print('Requires at most a single argument: the path to the log file.');
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void replayLogFile(String path, ServerDriver driver) {
|
|
var logFile = PhysicalResourceProvider.INSTANCE.getFile(p.normalize(path));
|
|
if (!logFile.exists) {
|
|
throw ArgumentError('Log file does not exist: ${logFile.path}');
|
|
}
|
|
print('Replaying log file at: $path with workspace folder: ${p.current}');
|
|
var normalizer = LogNormalizer()
|
|
..addReplacementsForPath(p.current, 'workspaceFolder-0')
|
|
..addReplacementsForPath(p.current, 'rootPath')
|
|
..addReplacementsForPath(p.current, 'rootUri');
|
|
var log = Log.fromFile(logFile, normalizer.denormalize);
|
|
|
|
print('ready, hit enter to send next message');
|
|
var entriesIterator = log.entries.iterator;
|
|
stdin.transform(utf8.decoder).transform(const LineSplitter()).listen((_) {
|
|
while (true) {
|
|
if (!entriesIterator.moveNext()) {
|
|
print('no more entries');
|
|
break;
|
|
}
|
|
var entry = entriesIterator.current;
|
|
if (entry.kind != EntryKind.message ||
|
|
entry.receiver != ProcessId.server) {
|
|
continue;
|
|
} else {
|
|
print('>>> ${json.encode(entry.message)}');
|
|
driver.sendMessageFromIde(entry.message);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void sendManualMessages(ServerDriver driver) {
|
|
print('Enter JSON messages to send to the server, one per line:');
|
|
stdin.transform(utf8.decoder).transform(const LineSplitter()).listen((line) {
|
|
driver.sendMessageFromIde(Message(json.decode(line) as JsonMap));
|
|
});
|
|
}
|