Skip to content

Commit 97f6f8c

Browse files
committed
Gzip artifacts
Co-authored-by: bjorn3 <[email protected]> Override miniz_oxide to build it with optimizations Building this crate with optimizations decreases the gzipping part of `cargo xtask dist` from `30-40s` down to `3s`, the overhead for `rustc` to apply optimizations is miserable on this background
1 parent 8943c2c commit 97f6f8c

File tree

6 files changed

+84
-25
lines changed

6 files changed

+84
-25
lines changed

Cargo.lock

Lines changed: 38 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ opt-level = 0
2727
[profile.release.package.xtask]
2828
opt-level = 0
2929

30+
# Gzipping the artifacts is up to 10 times faster with optimizations (`cargo xtask dist`).
31+
# `miniz_oxide` is the direct dependency of `flate2` which does all the heavy lifting
32+
[profile.dev.package.miniz_oxide]
33+
opt-level = 3
34+
3035
[patch.'crates-io']
3136
# rowan = { path = "../rowan" }
3237

editors/code/src/main.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,13 @@ async function getServer(config: Config, state: PersistentState): Promise<string
261261
};
262262
if (config.package.releaseTag === null) return "rust-analyzer";
263263

264-
let binaryName: string | undefined = undefined;
264+
let platform: string | undefined;
265265
if (process.arch === "x64" || process.arch === "ia32") {
266-
if (process.platform === "linux") binaryName = "rust-analyzer-linux";
267-
if (process.platform === "darwin") binaryName = "rust-analyzer-mac";
268-
if (process.platform === "win32") binaryName = "rust-analyzer-windows.exe";
266+
if (process.platform === "linux") platform = "linux";
267+
if (process.platform === "darwin") platform = "mac";
268+
if (process.platform === "win32") platform = "windows";
269269
}
270-
if (binaryName === undefined) {
270+
if (platform === undefined) {
271271
vscode.window.showErrorMessage(
272272
"Unfortunately we don't ship binaries for your platform yet. " +
273273
"You need to manually clone rust-analyzer repository and " +
@@ -278,8 +278,8 @@ async function getServer(config: Config, state: PersistentState): Promise<string
278278
);
279279
return undefined;
280280
}
281-
282-
const dest = path.join(config.globalStoragePath, binaryName);
281+
const ext = platform === "windows" ? ".exe" : "";
282+
const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`);
283283
const exists = await fs.stat(dest).then(() => true, () => false);
284284
if (!exists) {
285285
await state.updateServerVersion(undefined);
@@ -296,7 +296,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
296296
}
297297

298298
const release = await fetchRelease(config.package.releaseTag);
299-
const artifact = release.assets.find(artifact => artifact.name === binaryName);
299+
const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`);
300300
assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
301301

302302
// Unlinking the exe file before moving new one on its place should prevent ETXTBSY error.
@@ -308,6 +308,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
308308
url: artifact.browser_download_url,
309309
dest,
310310
progressTitle: "Downloading rust-analyzer server",
311+
gunzip: true,
311312
mode: 0o755
312313
});
313314

editors/code/src/net.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as vscode from "vscode";
33
import * as stream from "stream";
44
import * as crypto from "crypto";
55
import * as fs from "fs";
6+
import * as zlib from "zlib";
67
import * as util from "util";
78
import * as path from "path";
89
import { log, assert } from "./util";
@@ -65,6 +66,7 @@ interface DownloadOpts {
6566
url: string;
6667
dest: string;
6768
mode?: number;
69+
gunzip?: boolean;
6870
}
6971

7072
export async function download(opts: DownloadOpts) {
@@ -82,7 +84,7 @@ export async function download(opts: DownloadOpts) {
8284
},
8385
async (progress, _cancellationToken) => {
8486
let lastPercentage = 0;
85-
await downloadFile(opts.url, tempFile, opts.mode, (readBytes, totalBytes) => {
87+
await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, (readBytes, totalBytes) => {
8688
const newPercentage = (readBytes / totalBytes) * 100;
8789
progress.report({
8890
message: newPercentage.toFixed(0) + "%",
@@ -97,16 +99,11 @@ export async function download(opts: DownloadOpts) {
9799
await fs.promises.rename(tempFile, opts.dest);
98100
}
99101

100-
/**
101-
* Downloads file from `url` and stores it at `destFilePath` with `mode` (unix permissions).
102-
* `onProgress` callback is called on recieveing each chunk of bytes
103-
* to track the progress of downloading, it gets the already read and total
104-
* amount of bytes to read as its parameters.
105-
*/
106102
async function downloadFile(
107103
url: string,
108104
destFilePath: fs.PathLike,
109105
mode: number | undefined,
106+
gunzip: boolean,
110107
onProgress: (readBytes: number, totalBytes: number) => void
111108
): Promise<void> {
112109
const res = await fetch(url);
@@ -130,7 +127,10 @@ async function downloadFile(
130127
});
131128

132129
const destFileStream = fs.createWriteStream(destFilePath, { mode });
133-
await pipeline(res.body, destFileStream);
130+
const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body;
131+
132+
await pipeline(srcStream, destFileStream);
133+
134134
await new Promise<void>(resolve => {
135135
destFileStream.on("close", resolve);
136136
destFileStream.destroy();

xtask/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ pico-args = "0.3.1"
1414
quote = "1.0.2"
1515
proc-macro2 = "1.0.8"
1616
anyhow = "1.0.26"
17+
flate2 = "1.0"

xtask/src/dist.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
use std::path::PathBuf;
1+
use flate2::{write::GzEncoder, Compression};
2+
use std::{
3+
env,
4+
fs::File,
5+
io,
6+
path::{Path, PathBuf},
7+
};
28

39
use anyhow::Result;
410

@@ -16,7 +22,7 @@ pub fn run_dist(nightly: bool, client_version: Option<String>) -> Result<()> {
1622
let release_tag = if nightly { "nightly".to_string() } else { date_iso()? };
1723
dist_client(&version, &release_tag)?;
1824
}
19-
dist_server(nightly)?;
25+
dist_server()?;
2026
Ok(())
2127
}
2228

@@ -46,17 +52,14 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
4652
Ok(())
4753
}
4854

49-
fn dist_server(nightly: bool) -> Result<()> {
55+
fn dist_server() -> Result<()> {
5056
if cfg!(target_os = "linux") {
51-
std::env::set_var("CC", "clang");
57+
env::set_var("CC", "clang");
5258
run!(
5359
"cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release"
5460
// We'd want to add, but that requires setting the right linker somehow
5561
// --features=jemalloc
5662
)?;
57-
if !nightly {
58-
run!("strip ./target/release/rust-analyzer")?;
59-
}
6063
} else {
6164
run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?;
6265
}
@@ -71,8 +74,20 @@ fn dist_server(nightly: bool) -> Result<()> {
7174
panic!("Unsupported OS")
7275
};
7376

74-
fs2::copy(src, dst)?;
77+
let src = Path::new(src);
78+
let dst = Path::new(dst);
79+
80+
fs2::copy(&src, &dst)?;
81+
gzip(&src, &dst.with_extension("gz"))?;
82+
83+
Ok(())
84+
}
7585

86+
fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
87+
let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
88+
let mut input = io::BufReader::new(File::open(src_path)?);
89+
io::copy(&mut input, &mut encoder)?;
90+
encoder.finish()?;
7691
Ok(())
7792
}
7893

0 commit comments

Comments
 (0)