Skip to content

Commit 4c7f0c1

Browse files
jakemac53Commit Queue
authored andcommitted
Add some real scenario logs and get them running successfully.
- Move analysis server startup into log_player.dart, parse the protocol from the arguments. - Add {{workspaceRoot}} and {{dartSdk}} root placeholder support to log files. - Create logs of a real sdk scenario (rename the analysis server class), anonymize the logs using the placeholders. Future work: - We should add support for mutating a log to put in these placeholders. - Figure out how we want to support package dependencies in a similar way. - Implement the matching for server responses so the scenarios don't just complete early. Change-Id: Ic0f6ac9c26da9d0a4473d08709aa05e9ff1e8536 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/462620 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Keerti Parthasarathy <[email protected]> Auto-Submit: Jake Macdonald <[email protected]> Commit-Queue: Keerti Parthasarathy <[email protected]>
1 parent fee0f5f commit 4c7f0c1

File tree

9 files changed

+280
-40
lines changed

9 files changed

+280
-40
lines changed

pkg/analysis_server/tool/log_player/log.dart

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,23 @@ class Log {
1414

1515
/// Creates a log by reading the content of the [file] and decoding it as a
1616
/// list of entries.
17-
factory Log.fromFile(File file) {
18-
return Log.fromString(file.readAsStringSync());
17+
factory Log.fromFile(File file, Map<String, String> replacements) {
18+
return Log.fromString(file.readAsStringSync(), replacements);
1919
}
2020

2121
/// Creates a log by decoding the [logContent] as a list of entries.
2222
///
2323
/// The [logContent] should not include the opening and closing delimiters
2424
/// for a Json array ('[' and ']'), but otherwise should be a comma-separated
2525
/// list of json-encoded log entries.
26-
factory Log.fromString(String logContent) {
26+
///
27+
/// Each entry in [replacements] is all occurences of the key replaced with
28+
/// the value.
29+
factory Log.fromString(String logContent, Map<String, String> replacements) {
2730
logContent = logContent.trim();
31+
for (var entry in replacements.entries) {
32+
logContent = logContent.replaceAll(entry.key, entry.value);
33+
}
2834
if (logContent.endsWith(',')) {
2935
logContent = logContent.substring(0, logContent.length - 1);
3036
}

pkg/analysis_server/tool/log_player/log_player.dart

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analysis_server/src/server/driver.dart';
6+
import 'package:analysis_server/src/session_logger/entry_kind.dart';
57
import 'package:analysis_server/src/session_logger/log_entry.dart';
68
import 'package:analysis_server/src/session_logger/process_id.dart';
79

@@ -17,42 +19,68 @@ class LogPlayer {
1719
Log log;
1820

1921
/// The object used to communicate with the running server.
20-
ServerDriver server;
22+
ServerDriver? server;
2123

2224
/// Whether the `shutdown` method has been seen.
2325
bool _hasSeenShutdown = false;
2426

2527
/// Whether the `exit` method has been seen.
2628
bool _hasSeenExit = false;
2729

28-
LogPlayer({required this.log, required this.server});
30+
/// Arg parser equivalent to what the real driver uses, used to extract
31+
/// options from command line arguments.
32+
final driverArgParser = Driver.createArgParser();
33+
34+
LogPlayer({required this.log});
2935

3036
/// Plays the log.
3137
Future<void> play() async {
3238
var entries = log.entries;
3339
var nextIndex = 0;
34-
var entry = entries[nextIndex];
35-
if (entry.isCommandLine) {
36-
server.additionalArguments.addAll(entry.argList);
37-
nextIndex++;
38-
}
3940
while (nextIndex < entries.length) {
4041
// TODO(brianwilkerson): This doesn't currently attempt to retain the same
4142
// timing of messages as was recorded in the log.
4243
var entry = entries[nextIndex];
43-
if (entry.receiver == ProcessId.server) {
44-
await _sendMessageToServer(entry);
45-
} else if (entry.sender == ProcessId.server) {
46-
_handleMessageFromServer(entry);
44+
switch (entry.kind) {
45+
case EntryKind.commandLine:
46+
if (this.server != null) {
47+
throw StateError(
48+
'Analysis server already started, only one instance is allowed.',
49+
);
50+
}
51+
var parsedArgs = driverArgParser.parse(entry.argList);
52+
var protocolOption = parsedArgs.option(Driver.serverProtocolOption);
53+
var protocol = switch (protocolOption) {
54+
Driver.protocolAnalyzer => ServerProtocol.legacy,
55+
Driver.protocolLsp => ServerProtocol.lsp,
56+
_ => throw StateError('Unrecognized protocol $protocolOption'),
57+
};
58+
var server = this.server = ServerDriver(protocol: protocol);
59+
server.additionalArguments.addAll(entry.argList);
60+
await server.start();
61+
case EntryKind.message:
62+
if (entry.receiver == ProcessId.server) {
63+
await _sendMessageToServer(entry);
64+
} else if (entry.sender == ProcessId.server) {
65+
_handleMessageFromServer(entry);
66+
} else {
67+
throw StateError('''
68+
Unexpected sender/reciever for message:
69+
70+
sender: ${entry.sender}
71+
receiver: ${entry.receiver}
72+
''');
73+
}
4774
}
4875
nextIndex++;
4976
}
5077
if (!_hasSeenShutdown) {
51-
server.shutdown();
78+
server?.shutdown();
5279
}
5380
if (!_hasSeenExit) {
54-
server.exit();
81+
server?.exit();
5582
}
83+
server = null;
5684
}
5785

5886
/// Responds to a message sent from the server to some other process.
@@ -86,6 +114,10 @@ class LogPlayer {
86114

87115
/// Sends the message in the [entry] to the server.
88116
Future<void> _sendMessageToServer(LogEntry entry) async {
117+
var server = this.server;
118+
if (server == null) {
119+
throw StateError('Analysis server not started.');
120+
}
89121
var message = entry.message;
90122
switch (entry.sender) {
91123
case ProcessId.dtd:
@@ -104,6 +136,7 @@ class LogPlayer {
104136
_hasSeenShutdown = true;
105137
} else if (message.isExit) {
106138
_hasSeenExit = true;
139+
this.server = null;
107140
}
108141
server.sendMessageFromIde(message);
109142
case ProcessId.plugin:

pkg/analysis_server/tool/log_player/server_driver.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ class ServerDriver {
8383
);
8484
}
8585
_stdinSink?.close();
86+
_stdinSink = null;
8687
_dtdSocket?.close();
88+
_dtdSocket = null;
8789
}
8890

8991
void sendMessageFromDTD(Message message) {
@@ -149,6 +151,12 @@ class ServerDriver {
149151

150152
/// Create and start the server.
151153
Future<void> start() async {
154+
if (_stdinSink != null) {
155+
throw StateError(
156+
'Analysis server already started, only one active instance is allowed '
157+
'at a time.',
158+
);
159+
}
152160
var process = await Process.start(_dartExecutable, [
153161
'language-server',
154162
'--protocol=${_protocol.flagValue}',

pkg/analysis_server/tool/performance/project_generator/git_worktree_project_generator.dart

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,22 @@ class GitWorktreeProjectGenerator implements ProjectGenerator {
2525
@override
2626
Future<Directory> setUp() async {
2727
var projectDir = await Directory.systemTemp.createTemp('as_git_worktree');
28-
await runGitCommand(['worktree', 'add', projectDir.path], originalRepo);
28+
await runGitCommand([
29+
'worktree',
30+
'add',
31+
'-d',
32+
projectDir.path,
33+
], originalRepo);
2934
return projectDir;
3035
}
3136

3237
@override
3338
Future<void> tearDown(Directory projectDir) async {
34-
await runGitCommand(['worktree', 'remove', projectDir.path], originalRepo);
39+
await runGitCommand([
40+
'worktree',
41+
'remove',
42+
'-f',
43+
projectDir.path,
44+
], originalRepo);
3545
}
3646
}

pkg/analysis_server/tool/performance/scenarios/logs/empty.json

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{"time":1763408263553,"kind":"commandLine","argList":["--protocol=lsp","--port=0","--client-id=VS-Code","--client-version=3.122.0","--with-fine-dependencies"]},
2+
{"time":1763408263573,"kind":"message","sender":"ide","receiver":"server","message":{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":2053633,"clientInfo":{"name":"code-server","version":"1.98.2"},"locale":"en","rootPath":"{{workspaceRoot}}","rootUri":"file://{{workspaceRoot}}","capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional","normalizesLineEndings":true,"changeAnnotationSupport":{"groupsOnLabel":true}},"configuration":true,"didChangeWatchedFiles":{"dynamicRegistration":true,"relativePatternSupport":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"tagSupport":{"valueSet":[1]},"resolveSupport":{"properties":["location.range"]}},"codeLens":{"refreshSupport":true},"executeCommand":{"dynamicRegistration":true},"didChangeConfiguration":{"dynamicRegistration":true},"workspaceFolders":true,"semanticTokens":{"refreshSupport":true},"fileOperations":{"dynamicRegistration":true,"didCreate":true,"didRename":true,"didDelete":true,"willCreate":true,"willRename":true,"willDelete":true},"inlineValue":{"refreshSupport":true},"inlayHint":{"refreshSupport":true},"diagnostics":{"refreshSupport":true}},"textDocument":{"publishDiagnostics":{"relatedInformation":true,"versionSupport":false,"tagSupport":{"valueSet":[1,2]},"codeDescriptionSupport":true,"dataSupport":true},"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true,"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true,"resolveSupport":{"properties":["documentation","detail","additionalTextEdits"]},"insertTextModeSupport":{"valueSet":[1,2]},"labelDetailsSupport":true},"insertTextMode":2,"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]},"completionList":{"itemDefaults":["commitCharacters","editRange","insertTextFormat","insertTextMode"]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["markdown","plaintext"],"parameterInformation":{"labelOffsetSupport":true},"activeParameterSupport":true},"contextSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"hierarchicalDocumentSymbolSupport":true,"tagSupport":{"valueSet":[1]},"labelSupport":true},"codeAction":{"dynamicRegistration":true,"isPreferredSupport":true,"disabledSupport":true,"dataSupport":true,"resolveSupport":{"properties":["edit"]},"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"honorsChangeAnnotations":false},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true,"prepareSupportDefaultBehavior":1,"honorsChangeAnnotations":true},"documentLink":{"dynamicRegistration":true,"tooltipSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true,"foldingRangeKind":{"valueSet":["comment","imports","region"]},"foldingRange":{"collapsedText":false}},"declaration":{"dynamicRegistration":true,"linkSupport":true},"selectionRange":{"dynamicRegistration":true},"callHierarchy":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator","decorator"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary"],"formats":["relative"],"requests":{"range":true,"full":{"delta":true}},"multilineTokenSupport":false,"overlappingTokenSupport":false,"serverCancelSupport":true,"augmentsSyntaxTokens":true},"linkedEditingRange":{"dynamicRegistration":true},"typeHierarchy":{"dynamicRegistration":true},"inlineValue":{"dynamicRegistration":true},"inlayHint":{"dynamicRegistration":true,"resolveSupport":{"properties":["tooltip","textEdits","label.tooltip","label.location","label.command"]}},"diagnostic":{"dynamicRegistration":true,"relatedDocumentSupport":false}},"window":{"showMessage":{"messageActionItem":{"additionalPropertiesSupport":true}},"showDocument":{"support":true},"workDoneProgress":true},"general":{"staleRequestSupport":{"cancel":true,"retryOnContentModified":["textDocument/semanticTokens/full","textDocument/semanticTokens/range","textDocument/semanticTokens/full/delta"]},"regularExpressions":{"engine":"ECMAScript","version":"ES2020"},"markdown":{"parser":"marked","version":"1.1.0","allowedTags":["ul","li","p","code","blockquote","ol","h1","h2","h3","h4","h5","h6","hr","em","pre","table","thead","tbody","tr","th","td","div","del","a","strong","br","img","span"]},"positionEncodings":["utf-16"]},"notebookDocument":{"synchronization":{"dynamicRegistration":true,"executionSummarySupport":true}},"experimental":{"supportsWindowShowMessageRequest":true,"commands":["dart.goToLocation"],"dartCodeAction":{"commandParameterSupport":{"supportedKinds":["saveUri"]}},"snippetTextEdit":true,"supportsDartTextDocumentContentProvider":true,"supportsDartTextDocumentContentProviderEXP1":true}},"initializationOptions":{"allowOpenUri":true,"appHost":"server-distro","closingLabels":true,"flutterOutline":false,"hostKind":"server-distro","onlyAnalyzeProjectsWithOpenFiles":false,"outline":true,"previewSurveys":true,"suggestFromUnimportedLibraries":true,"useInEditorDartFixPrompt":true},"trace":"off","workspaceFolders":[{"uri":"{{workspaceRoot}}","name":"sdk"}]},"clientRequestTime":1763408262903}},
3+
{"time":1763408263726,"kind":"message","sender":"ide","receiver":"server","message":{"jsonrpc":"2.0","method":"initialized","params":{},"clientRequestTime":1763408263726}},

0 commit comments

Comments
 (0)