mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
migrate from fs
to vscode.FileSystem
API
This commit is contained in:
parent
3ca7f61a8d
commit
0448b73646
3 changed files with 35 additions and 44 deletions
|
@ -1,7 +1,5 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as path from "path";
|
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import { promises as fs, PathLike } from "fs";
|
|
||||||
|
|
||||||
import * as commands from './commands';
|
import * as commands from './commands';
|
||||||
import { activateInlayHints } from './inlay_hints';
|
import { activateInlayHints } from './inlay_hints';
|
||||||
|
@ -222,7 +220,7 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
|
||||||
const artifact = latestNightlyRelease.assets.find(artifact => artifact.name === "rust-analyzer.vsix");
|
const artifact = latestNightlyRelease.assets.find(artifact => artifact.name === "rust-analyzer.vsix");
|
||||||
assert(!!artifact, `Bad release: ${JSON.stringify(latestNightlyRelease)}`);
|
assert(!!artifact, `Bad release: ${JSON.stringify(latestNightlyRelease)}`);
|
||||||
|
|
||||||
const dest = path.join(config.globalStorageUri.path, "rust-analyzer.vsix");
|
const dest = vscode.Uri.joinPath(config.globalStorageUri, "rust-analyzer.vsix");
|
||||||
|
|
||||||
await downloadWithRetryDialog(state, async () => {
|
await downloadWithRetryDialog(state, async () => {
|
||||||
await download({
|
await download({
|
||||||
|
@ -233,8 +231,8 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(dest));
|
await vscode.commands.executeCommand("workbench.extensions.installExtension", dest);
|
||||||
await fs.unlink(dest);
|
await vscode.workspace.fs.delete(dest);
|
||||||
|
|
||||||
await state.updateNightlyReleaseId(latestNightlyRelease.id);
|
await state.updateNightlyReleaseId(latestNightlyRelease.id);
|
||||||
await state.updateLastCheck(now);
|
await state.updateLastCheck(now);
|
||||||
|
@ -259,7 +257,7 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise<
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function patchelf(dest: PathLike): Promise<void> {
|
async function patchelf(dest: vscode.Uri): Promise<void> {
|
||||||
await vscode.window.withProgress(
|
await vscode.window.withProgress(
|
||||||
{
|
{
|
||||||
location: vscode.ProgressLocation.Notification,
|
location: vscode.ProgressLocation.Notification,
|
||||||
|
@ -279,11 +277,11 @@ async function patchelf(dest: PathLike): Promise<void> {
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
const origFile = dest + "-orig";
|
const origFile = vscode.Uri.file(dest.path + "-orig");
|
||||||
await fs.rename(dest, origFile);
|
await vscode.workspace.fs.rename(dest, origFile);
|
||||||
progress.report({ message: "Patching executable", increment: 20 });
|
progress.report({ message: "Patching executable", increment: 20 });
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const handle = exec(`nix-build -E - --argstr srcStr '${origFile}' -o '${dest}'`,
|
const handle = exec(`nix-build -E - --argstr srcStr '${origFile.path}' -o '${dest.path}'`,
|
||||||
(err, stdout, stderr) => {
|
(err, stdout, stderr) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
reject(Error(stderr));
|
reject(Error(stderr));
|
||||||
|
@ -294,7 +292,7 @@ async function patchelf(dest: PathLike): Promise<void> {
|
||||||
handle.stdin?.write(expression);
|
handle.stdin?.write(expression);
|
||||||
handle.stdin?.end();
|
handle.stdin?.end();
|
||||||
});
|
});
|
||||||
await fs.unlink(origFile);
|
await vscode.workspace.fs.delete(origFile);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -334,20 +332,20 @@ async function getServer(config: Config, state: PersistentState): Promise<string
|
||||||
platform = "x86_64-unknown-linux-musl";
|
platform = "x86_64-unknown-linux-musl";
|
||||||
}
|
}
|
||||||
const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : "";
|
const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : "";
|
||||||
const dest = path.join(config.globalStorageUri.path, `rust-analyzer-${platform}${ext}`);
|
const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer-${platform}${ext}`);
|
||||||
const exists = await fs.stat(dest).then(() => true, () => false);
|
const exists = await vscode.workspace.fs.stat(dest).then(() => true, () => false);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
await state.updateServerVersion(undefined);
|
await state.updateServerVersion(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.serverVersion === config.package.version) return dest;
|
if (state.serverVersion === config.package.version) return dest.path;
|
||||||
|
|
||||||
if (config.askBeforeDownload) {
|
if (config.askBeforeDownload) {
|
||||||
const userResponse = await vscode.window.showInformationMessage(
|
const userResponse = await vscode.window.showInformationMessage(
|
||||||
`Language server version ${config.package.version} for rust-analyzer is not installed.`,
|
`Language server version ${config.package.version} for rust-analyzer is not installed.`,
|
||||||
"Download now"
|
"Download now"
|
||||||
);
|
);
|
||||||
if (userResponse !== "Download now") return dest;
|
if (userResponse !== "Download now") return dest.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
const releaseTag = config.package.releaseTag;
|
const releaseTag = config.package.releaseTag;
|
||||||
|
@ -374,7 +372,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
|
||||||
}
|
}
|
||||||
|
|
||||||
await state.updateServerVersion(config.package.version);
|
await state.updateServerVersion(config.package.version);
|
||||||
return dest;
|
return dest.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
function serverPath(config: Config): string | null {
|
function serverPath(config: Config): string | null {
|
||||||
|
@ -383,7 +381,7 @@ function serverPath(config: Config): string | null {
|
||||||
|
|
||||||
async function isNixOs(): Promise<boolean> {
|
async function isNixOs(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const contents = await fs.readFile("/etc/os-release");
|
const contents = (await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))).toString();
|
||||||
return contents.indexOf("ID=nixos") !== -1;
|
return contents.indexOf("ID=nixos") !== -1;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -73,14 +73,14 @@ export interface GithubRelease {
|
||||||
assets: Array<{
|
assets: Array<{
|
||||||
name: string;
|
name: string;
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
browser_download_url: string;
|
browser_download_url: vscode.Uri;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DownloadOpts {
|
interface DownloadOpts {
|
||||||
progressTitle: string;
|
progressTitle: string;
|
||||||
url: string;
|
url: vscode.Uri;
|
||||||
dest: string;
|
dest: vscode.Uri;
|
||||||
mode?: number;
|
mode?: number;
|
||||||
gunzip?: boolean;
|
gunzip?: boolean;
|
||||||
httpProxy?: string;
|
httpProxy?: string;
|
||||||
|
@ -90,9 +90,9 @@ export async function download(opts: DownloadOpts) {
|
||||||
// Put artifact into a temporary file (in the same dir for simplicity)
|
// Put artifact into a temporary file (in the same dir for simplicity)
|
||||||
// to prevent partially downloaded files when user kills vscode
|
// to prevent partially downloaded files when user kills vscode
|
||||||
// This also avoids overwriting running executables
|
// This also avoids overwriting running executables
|
||||||
const dest = path.parse(opts.dest);
|
|
||||||
const randomHex = crypto.randomBytes(5).toString("hex");
|
const randomHex = crypto.randomBytes(5).toString("hex");
|
||||||
const tempFile = path.join(dest.dir, `${dest.name}${randomHex}`);
|
const rawDest = path.parse(opts.dest.path);
|
||||||
|
const tempFilePath = vscode.Uri.joinPath(vscode.Uri.file(rawDest.dir), `${rawDest.name}${randomHex}`);
|
||||||
|
|
||||||
await vscode.window.withProgress(
|
await vscode.window.withProgress(
|
||||||
{
|
{
|
||||||
|
@ -102,7 +102,7 @@ export async function download(opts: DownloadOpts) {
|
||||||
},
|
},
|
||||||
async (progress, _cancellationToken) => {
|
async (progress, _cancellationToken) => {
|
||||||
let lastPercentage = 0;
|
let lastPercentage = 0;
|
||||||
await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, opts.httpProxy, (readBytes, totalBytes) => {
|
await downloadFile(opts.url, tempFilePath, opts.mode, !!opts.gunzip, opts.httpProxy, (readBytes, totalBytes) => {
|
||||||
const newPercentage = Math.round((readBytes / totalBytes) * 100);
|
const newPercentage = Math.round((readBytes / totalBytes) * 100);
|
||||||
if (newPercentage !== lastPercentage) {
|
if (newPercentage !== lastPercentage) {
|
||||||
progress.report({
|
progress.report({
|
||||||
|
@ -116,12 +116,12 @@ export async function download(opts: DownloadOpts) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
await fs.promises.rename(tempFile, opts.dest);
|
await vscode.workspace.fs.rename(tempFilePath, opts.dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadFile(
|
async function downloadFile(
|
||||||
url: string,
|
url: vscode.Uri,
|
||||||
destFilePath: fs.PathLike,
|
destFilePath: vscode.Uri,
|
||||||
mode: number | undefined,
|
mode: number | undefined,
|
||||||
gunzip: boolean,
|
gunzip: boolean,
|
||||||
httpProxy: string | null | undefined,
|
httpProxy: string | null | undefined,
|
||||||
|
@ -129,15 +129,15 @@ async function downloadFile(
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const res = await (() => {
|
const res = await (() => {
|
||||||
if (httpProxy) {
|
if (httpProxy) {
|
||||||
log.debug(`Downloading ${url} via proxy: ${httpProxy}`);
|
log.debug(`Downloading ${url.path} via proxy: ${httpProxy}`);
|
||||||
return fetch(url, { agent: new HttpsProxyAgent(httpProxy) });
|
return fetch(url.path, { agent: new HttpsProxyAgent(httpProxy) });
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(url);
|
return fetch(url.path);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
log.error("Error", res.status, "while downloading file from", url);
|
log.error("Error", res.status, "while downloading file from", url.path);
|
||||||
log.error({ body: await res.text(), headers: res.headers });
|
log.error({ body: await res.text(), headers: res.headers });
|
||||||
|
|
||||||
throw new Error(`Got response ${res.status} when trying to download a file.`);
|
throw new Error(`Got response ${res.status} when trying to download a file.`);
|
||||||
|
@ -146,7 +146,7 @@ async function downloadFile(
|
||||||
const totalBytes = Number(res.headers.get('content-length'));
|
const totalBytes = Number(res.headers.get('content-length'));
|
||||||
assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol");
|
assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol");
|
||||||
|
|
||||||
log.debug("Downloading file of", totalBytes, "bytes size from", url, "to", destFilePath);
|
log.debug("Downloading file of", totalBytes, "bytes size from", url.path, "to", destFilePath.path);
|
||||||
|
|
||||||
let readBytes = 0;
|
let readBytes = 0;
|
||||||
res.body.on("data", (chunk: Buffer) => {
|
res.body.on("data", (chunk: Buffer) => {
|
||||||
|
@ -154,7 +154,7 @@ async function downloadFile(
|
||||||
onProgress(readBytes, totalBytes);
|
onProgress(readBytes, totalBytes);
|
||||||
});
|
});
|
||||||
|
|
||||||
const destFileStream = fs.createWriteStream(destFilePath, { mode });
|
const destFileStream = fs.createWriteStream(destFilePath.path, { mode });
|
||||||
const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body;
|
const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body;
|
||||||
|
|
||||||
await pipeline(srcStream, destFileStream);
|
await pipeline(srcStream, destFileStream);
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import * as cp from 'child_process';
|
import * as cp from 'child_process';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as readline from 'readline';
|
import * as readline from 'readline';
|
||||||
import { OutputChannel } from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { execute, log, memoize } from './util';
|
import { execute, log, memoize } from './util';
|
||||||
|
|
||||||
interface CompilationArtifact {
|
interface CompilationArtifact {
|
||||||
|
@ -19,7 +18,7 @@ export interface ArtifactSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Cargo {
|
export class Cargo {
|
||||||
constructor(readonly rootFolder: string, readonly output: OutputChannel) { }
|
constructor(readonly rootFolder: string, readonly output: vscode.OutputChannel) { }
|
||||||
|
|
||||||
// Made public for testing purposes
|
// Made public for testing purposes
|
||||||
static artifactSpec(args: readonly string[]): ArtifactSpec {
|
static artifactSpec(args: readonly string[]): ArtifactSpec {
|
||||||
|
@ -158,9 +157,9 @@ export const getPathForExecutable = memoize(
|
||||||
try {
|
try {
|
||||||
// hmm, `os.homedir()` seems to be infallible
|
// hmm, `os.homedir()` seems to be infallible
|
||||||
// it is not mentioned in docs and cannot be infered by the type signature...
|
// it is not mentioned in docs and cannot be infered by the type signature...
|
||||||
const standardPath = path.join(os.homedir(), ".cargo", "bin", executableName);
|
const standardPath = vscode.Uri.joinPath(vscode.Uri.file(os.homedir()), ".cargo", "bin", executableName);
|
||||||
|
|
||||||
if (isFile(standardPath)) return standardPath;
|
if (isFile(standardPath.path)) return standardPath.path;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error("Failed to read the fs info", err);
|
log.error("Failed to read the fs info", err);
|
||||||
}
|
}
|
||||||
|
@ -181,12 +180,6 @@ function lookupInPath(exec: string): boolean {
|
||||||
return candidates.some(isFile);
|
return candidates.some(isFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFile(suspectPath: string): boolean {
|
async function isFile(path: string): Promise<boolean> {
|
||||||
// It is not mentionned in docs, but `statSync()` throws an error when
|
return ((await vscode.workspace.fs.stat(vscode.Uri.file(path))).type & vscode.FileType.File) != 0;
|
||||||
// the path doesn't exist
|
|
||||||
try {
|
|
||||||
return fs.statSync(suspectPath).isFile();
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue