Skip to content

Commit 6b2bfea

Browse files
committed
Address comments
1 parent 69ad027 commit 6b2bfea

File tree

3 files changed

+100
-58
lines changed

3 files changed

+100
-58
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@
172172
},
173173
{
174174
"command": "swift.captureDiagnostics",
175-
"title": "Capture VS Code Swift Diagnostic Logs",
175+
"title": "Capture VS Code Swift Diagnostic Bundle",
176176
"category": "Swift"
177177
}
178178
],

src/commands/captureDiagnostics.ts

Lines changed: 84 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,59 +18,94 @@ import * as vscode from "vscode";
1818
import { tmpdir } from "os";
1919
import { exec } from "child_process";
2020
import { Writable } from "stream";
21-
import { SwiftOutputChannel } from "../ui/SwiftOutputChannel";
2221
import { WorkspaceContext } from "../WorkspaceContext";
2322
import { Version } from "../utilities/version";
2423
import { execFileStreamOutput } from "../utilities/utilities";
2524
import configuration from "../configuration";
2625

2726
export async function captureDiagnostics(ctx: WorkspaceContext) {
28-
const diagnosticsDir = path.join(
29-
tmpdir(),
30-
`vscode-diagnostics-${formatDateString(new Date())}`
31-
);
32-
3327
try {
34-
await fs.mkdir(diagnosticsDir);
35-
await writeLogFile(diagnosticsDir, "logs.txt", extensionLogs(ctx));
36-
await writeLogFile(diagnosticsDir, "environment.txt", environmentLogs(ctx));
37-
38-
if (ctx.swiftVersion.isGreaterThanOrEqual(new Version(6, 0, 0))) {
39-
// sourcekit-lsp diagnose command is only available in 6.0 and higher.
40-
// await writeLogFile(diagnosticsDir, "sourcekit-lsp.txt", );
41-
await sourcekitDiagnose(ctx, diagnosticsDir);
42-
} else {
43-
await writeLogFile(diagnosticsDir, "sourcekit-lsp.txt", sourceKitLogs(ctx));
44-
}
28+
const captureMode = await captureDiagnosticsMode(ctx);
4529

46-
await writeLogFile(diagnosticsDir, "diagnostics.txt", diagnosticLogs());
30+
const diagnosticsDir = path.join(
31+
tmpdir(),
32+
`vscode-diagnostics-${formatDateString(new Date())}`
33+
);
4734

48-
ctx.outputChannel.log(`Saved diagnostics to ${diagnosticsDir}`);
35+
await fs.mkdir(diagnosticsDir);
36+
await writeLogFile(diagnosticsDir, "extension-logs.txt", extensionLogs(ctx));
37+
await writeLogFile(diagnosticsDir, "environment-logs.txt", environmentLogs(ctx));
38+
await writeLogFile(diagnosticsDir, "diagnostics.txt", diagnosticLogs());
4939

50-
const showInFinderButton = `Show In ${showCommandType()}`;
51-
const copyPath = "Copy Path to Clipboard";
52-
const result = await vscode.window.showInformationMessage(
53-
`Saved diagnostic logs to ${diagnosticsDir}`,
54-
showInFinderButton,
55-
copyPath
56-
);
57-
if (result === copyPath) {
58-
vscode.env.clipboard.writeText(diagnosticsDir);
59-
} else if (result === showInFinderButton) {
60-
exec(showDirectoryCommand(diagnosticsDir), error => {
61-
// Opening the explorer on windows returns an exit code of 1 despite opening successfully.
62-
if (error && process.platform !== "win32") {
63-
vscode.window.showErrorMessage(
64-
`Failed to open ${showCommandType()}: ${error.message}`
65-
);
66-
}
67-
});
40+
if (captureMode === "Full") {
41+
// The `sourcekit-lsp diagnose` command is only available in 6.0 and higher.
42+
if (ctx.swiftVersion.isGreaterThanOrEqual(new Version(6, 0, 0))) {
43+
await sourcekitDiagnose(ctx, diagnosticsDir);
44+
} else {
45+
await writeLogFile(diagnosticsDir, "sourcekit-lsp.txt", sourceKitLogs(ctx));
46+
}
6847
}
48+
49+
ctx.outputChannel.log(`Saved diagnostics to ${diagnosticsDir}`);
50+
await showCapturedDiagnosticsResults(diagnosticsDir);
6951
} catch (error) {
7052
vscode.window.showErrorMessage(`Unable to capture diagnostic logs: ${error}`);
7153
}
7254
}
7355

56+
async function captureDiagnosticsMode(ctx: WorkspaceContext): Promise<"Minimal" | "Full"> {
57+
if (
58+
ctx.swiftVersion.isGreaterThanOrEqual(new Version(6, 0, 0)) ||
59+
vscode.workspace.getConfiguration("sourcekit-lsp").get<string>("trace.server", "off") !==
60+
"off"
61+
) {
62+
const fullButton = "Capture Full Diagnostics";
63+
const minimalButton = "Capture Minimal Diagnostics";
64+
const fullCaptureResult = await vscode.window.showInformationMessage(
65+
`A Diagnostic Bundle collects information that helps the developers of the VS Code Swift extension diagnose and fix issues.
66+
67+
This information contains:
68+
- Extension logs
69+
- Versions of Swift installed on your system
70+
- Crash logs from SourceKit
71+
- Log messages emitted by SourceKit
72+
- If possible, a minimized project that caused SourceKit to crash
73+
- If possible, a minimized project that caused the Swift compiler to crash`,
74+
{
75+
modal: true,
76+
detail: `If you wish to omit potentially sensitive information choose "${minimalButton}"`,
77+
},
78+
fullButton,
79+
minimalButton
80+
);
81+
return fullCaptureResult === fullButton ? "Full" : "Minimal";
82+
} else {
83+
return "Minimal";
84+
}
85+
}
86+
87+
async function showCapturedDiagnosticsResults(diagnosticsDir: string) {
88+
const showInFinderButton = `Show In ${showCommandType()}`;
89+
const copyPath = "Copy Path to Clipboard";
90+
const result = await vscode.window.showInformationMessage(
91+
`Saved diagnostic logs to ${diagnosticsDir}`,
92+
showInFinderButton,
93+
copyPath
94+
);
95+
if (result === copyPath) {
96+
vscode.env.clipboard.writeText(diagnosticsDir);
97+
} else if (result === showInFinderButton) {
98+
exec(showDirectoryCommand(diagnosticsDir), error => {
99+
// Opening the explorer on windows returns an exit code of 1 despite opening successfully.
100+
if (error && process.platform !== "win32") {
101+
vscode.window.showErrorMessage(
102+
`Failed to open ${showCommandType()}: ${error.message}`
103+
);
104+
}
105+
});
106+
}
107+
}
108+
74109
async function writeLogFile(dir: string, name: string, logs: string) {
75110
if (logs.length === 0) {
76111
return;
@@ -83,13 +118,7 @@ function extensionLogs(ctx: WorkspaceContext): string {
83118
}
84119

85120
function environmentLogs(ctx: WorkspaceContext): string {
86-
const environmentOutputChannel = new SwiftOutputChannel("Swift", false);
87-
ctx.toolchain.logDiagnostics(environmentOutputChannel);
88-
environmentOutputChannel.log("Extension Settings:");
89-
environmentOutputChannel.log(
90-
JSON.stringify(vscode.workspace.getConfiguration("swift"), null, 2)
91-
);
92-
return environmentOutputChannel.logs.join("\n");
121+
return ctx.toolchain.diagnostics;
93122
}
94123

95124
function diagnosticLogs(): string {
@@ -123,21 +152,28 @@ async function sourcekitDiagnose(ctx: WorkspaceContext, dir: string) {
123152
location: vscode.ProgressLocation.Notification,
124153
},
125154
async progress => {
126-
progress.report({ message: "Capturing Diagnostics..." });
155+
progress.report({ message: "Generating Diagnostic Bundle..." });
127156
const writableStream = progressUpdatingWritable(percent =>
128-
progress.report({ message: `Capturing Diagnostics: ${percent}%` })
157+
progress.report({ message: `Generating Diagnostic Bundle: ${percent}%` })
129158
);
130159

131160
await execFileStreamOutput(
132161
serverPath,
133-
["diagnose", "--bundle-output-path", sourcekitDiagnosticDir],
162+
[
163+
"diagnose",
164+
"--bundle-output-path",
165+
sourcekitDiagnosticDir,
166+
"--toolchain",
167+
ctx.toolchain.toolchainPath,
168+
],
134169
writableStream,
135170
writableStream,
136171
null,
137172
{
138173
env: { ...process.env, ...configuration.swiftEnvironmentVariables },
139174
maxBuffer: 16 * 1024 * 1024,
140-
}
175+
},
176+
ctx.currentFolder ?? undefined
141177
);
142178
}
143179
);

src/toolchain/toolchain.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -392,25 +392,31 @@ export class SwiftToolchain {
392392
return path.join(base, "Library/Frameworks");
393393
}
394394

395-
logDiagnostics(channel: SwiftOutputChannel) {
396-
channel.logDiagnostic(this.swiftVersionString);
397-
channel.logDiagnostic(`Swift Path: ${this.swiftFolderPath}`);
398-
channel.logDiagnostic(`Toolchain Path: ${this.toolchainPath}`);
395+
get diagnostics(): string {
396+
let str = "";
397+
str += this.swiftVersionString;
398+
str += `\nSwift Path: ${this.swiftFolderPath}`;
399+
str += `\nToolchain Path: ${this.toolchainPath}`;
399400
if (this.runtimePath) {
400-
channel.logDiagnostic(`Runtime Library Path: ${this.runtimePath}`);
401+
str += `\nRuntime Library Path: ${this.runtimePath}`;
401402
}
402403
if (this.defaultTarget) {
403-
channel.logDiagnostic(`Default Target: ${this.defaultTarget}`);
404+
str += `\nDefault Target: ${this.defaultTarget}`;
404405
}
405406
if (this.defaultSDK) {
406-
channel.logDiagnostic(`Default SDK: ${this.defaultSDK}`);
407+
str += `\nDefault SDK: ${this.defaultSDK}`;
407408
}
408409
if (this.customSDK) {
409-
channel.logDiagnostic(`Custom SDK: ${this.customSDK}`);
410+
str += `\nCustom SDK: ${this.customSDK}`;
410411
}
411412
if (this.xcTestPath) {
412-
channel.logDiagnostic(`XCTest Path: ${this.xcTestPath}`);
413+
str += `\nXCTest Path: ${this.xcTestPath}`;
413414
}
415+
return str;
416+
}
417+
418+
logDiagnostics(channel: SwiftOutputChannel) {
419+
channel.logDiagnostic(this.diagnostics);
414420
}
415421

416422
private static async getSwiftFolderPath(): Promise<string> {

0 commit comments

Comments
 (0)