diff options
author | Veetaha <[email protected]> | 2020-06-21 13:58:34 +0100 |
---|---|---|
committer | Veetaha <[email protected]> | 2020-07-07 21:30:11 +0100 |
commit | f92bfb580780cda02f9ba8a935538f984d8a4c0d (patch) | |
tree | fbf0e24250cc36eaa122904e78cd7cb50fe1c665 | |
parent | 980a67f44629ed67a54b603aaf9d015a81d61f7a (diff) |
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
-rw-r--r-- | Cargo.lock | 22 | ||||
-rw-r--r-- | Cargo.toml | 5 | ||||
-rw-r--r-- | editors/code/src/main.ts | 17 | ||||
-rw-r--r-- | editors/code/src/net.ts | 16 | ||||
-rw-r--r-- | xtask/Cargo.toml | 1 | ||||
-rw-r--r-- | xtask/src/dist.rs | 31 |
6 files changed, 68 insertions, 24 deletions
diff --git a/Cargo.lock b/Cargo.lock index 916fc53e0..108403ce6 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -208,6 +208,15 @@ dependencies = [ | |||
208 | ] | 208 | ] |
209 | 209 | ||
210 | [[package]] | 210 | [[package]] |
211 | name = "crc32fast" | ||
212 | version = "1.2.0" | ||
213 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
214 | checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" | ||
215 | dependencies = [ | ||
216 | "cfg-if", | ||
217 | ] | ||
218 | |||
219 | [[package]] | ||
211 | name = "crossbeam-channel" | 220 | name = "crossbeam-channel" |
212 | version = "0.4.2" | 221 | version = "0.4.2" |
213 | source = "registry+https://github.com/rust-lang/crates.io-index" | 222 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -341,6 +350,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
341 | checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" | 350 | checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" |
342 | 351 | ||
343 | [[package]] | 352 | [[package]] |
353 | name = "flate2" | ||
354 | version = "1.0.16" | ||
355 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
356 | checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" | ||
357 | dependencies = [ | ||
358 | "cfg-if", | ||
359 | "crc32fast", | ||
360 | "libc", | ||
361 | "miniz_oxide", | ||
362 | ] | ||
363 | |||
364 | [[package]] | ||
344 | name = "flycheck" | 365 | name = "flycheck" |
345 | version = "0.1.0" | 366 | version = "0.1.0" |
346 | dependencies = [ | 367 | dependencies = [ |
@@ -1993,6 +2014,7 @@ name = "xtask" | |||
1993 | version = "0.1.0" | 2014 | version = "0.1.0" |
1994 | dependencies = [ | 2015 | dependencies = [ |
1995 | "anyhow", | 2016 | "anyhow", |
2017 | "flate2", | ||
1996 | "pico-args", | 2018 | "pico-args", |
1997 | "proc-macro2", | 2019 | "proc-macro2", |
1998 | "quote", | 2020 | "quote", |
diff --git a/Cargo.toml b/Cargo.toml index 189f4ea2b..612e6809f 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -29,6 +29,11 @@ opt-level = 0 | |||
29 | [profile.release.package.xtask] | 29 | [profile.release.package.xtask] |
30 | opt-level = 0 | 30 | opt-level = 0 |
31 | 31 | ||
32 | # Gzipping the artifacts is up to 10 times faster with optimizations (`cargo xtask dist`). | ||
33 | # `miniz_oxide` is the direct dependency of `flate2` which does all the heavy lifting | ||
34 | [profile.dev.package.miniz_oxide] | ||
35 | opt-level = 3 | ||
36 | |||
32 | [patch.'crates-io'] | 37 | [patch.'crates-io'] |
33 | # rowan = { path = "../rowan" } | 38 | # rowan = { path = "../rowan" } |
34 | 39 | ||
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index eda95ae5c..bd99d696a 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -274,13 +274,13 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
274 | }; | 274 | }; |
275 | if (config.package.releaseTag === null) return "rust-analyzer"; | 275 | if (config.package.releaseTag === null) return "rust-analyzer"; |
276 | 276 | ||
277 | let binaryName: string | undefined = undefined; | 277 | let platform: string | undefined; |
278 | if (process.arch === "x64" || process.arch === "ia32") { | 278 | if (process.arch === "x64" || process.arch === "ia32") { |
279 | if (process.platform === "linux") binaryName = "rust-analyzer-linux"; | 279 | if (process.platform === "linux") platform = "linux"; |
280 | if (process.platform === "darwin") binaryName = "rust-analyzer-mac"; | 280 | if (process.platform === "darwin") platform = "mac"; |
281 | if (process.platform === "win32") binaryName = "rust-analyzer-windows.exe"; | 281 | if (process.platform === "win32") platform = "windows"; |
282 | } | 282 | } |
283 | if (binaryName === undefined) { | 283 | if (platform === undefined) { |
284 | vscode.window.showErrorMessage( | 284 | vscode.window.showErrorMessage( |
285 | "Unfortunately we don't ship binaries for your platform yet. " + | 285 | "Unfortunately we don't ship binaries for your platform yet. " + |
286 | "You need to manually clone rust-analyzer repository and " + | 286 | "You need to manually clone rust-analyzer repository and " + |
@@ -291,8 +291,8 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
291 | ); | 291 | ); |
292 | return undefined; | 292 | return undefined; |
293 | } | 293 | } |
294 | 294 | const ext = platform === "windows" ? ".exe" : ""; | |
295 | const dest = path.join(config.globalStoragePath, binaryName); | 295 | const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); |
296 | const exists = await fs.stat(dest).then(() => true, () => false); | 296 | const exists = await fs.stat(dest).then(() => true, () => false); |
297 | if (!exists) { | 297 | if (!exists) { |
298 | await state.updateServerVersion(undefined); | 298 | await state.updateServerVersion(undefined); |
@@ -309,7 +309,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
309 | } | 309 | } |
310 | 310 | ||
311 | const release = await fetchRelease(config.package.releaseTag); | 311 | const release = await fetchRelease(config.package.releaseTag); |
312 | const artifact = release.assets.find(artifact => artifact.name === binaryName); | 312 | const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`); |
313 | assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); | 313 | assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); |
314 | 314 | ||
315 | // Unlinking the exe file before moving new one on its place should prevent ETXTBSY error. | 315 | // Unlinking the exe file before moving new one on its place should prevent ETXTBSY error. |
@@ -321,6 +321,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
321 | url: artifact.browser_download_url, | 321 | url: artifact.browser_download_url, |
322 | dest, | 322 | dest, |
323 | progressTitle: "Downloading rust-analyzer server", | 323 | progressTitle: "Downloading rust-analyzer server", |
324 | gunzip: true, | ||
324 | mode: 0o755 | 325 | mode: 0o755 |
325 | }); | 326 | }); |
326 | 327 | ||
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts index 866092882..53c9e91cd 100644 --- a/editors/code/src/net.ts +++ b/editors/code/src/net.ts | |||
@@ -3,6 +3,7 @@ import * as vscode from "vscode"; | |||
3 | import * as stream from "stream"; | 3 | import * as stream from "stream"; |
4 | import * as crypto from "crypto"; | 4 | import * as crypto from "crypto"; |
5 | import * as fs from "fs"; | 5 | import * as fs from "fs"; |
6 | import * as zlib from "zlib"; | ||
6 | import * as util from "util"; | 7 | import * as util from "util"; |
7 | import * as path from "path"; | 8 | import * as path from "path"; |
8 | import { log, assert } from "./util"; | 9 | import { log, assert } from "./util"; |
@@ -65,6 +66,7 @@ interface DownloadOpts { | |||
65 | url: string; | 66 | url: string; |
66 | dest: string; | 67 | dest: string; |
67 | mode?: number; | 68 | mode?: number; |
69 | gunzip?: boolean; | ||
68 | } | 70 | } |
69 | 71 | ||
70 | export async function download(opts: DownloadOpts) { | 72 | export async function download(opts: DownloadOpts) { |
@@ -82,7 +84,7 @@ export async function download(opts: DownloadOpts) { | |||
82 | }, | 84 | }, |
83 | async (progress, _cancellationToken) => { | 85 | async (progress, _cancellationToken) => { |
84 | let lastPercentage = 0; | 86 | 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) => { |
86 | const newPercentage = (readBytes / totalBytes) * 100; | 88 | const newPercentage = (readBytes / totalBytes) * 100; |
87 | progress.report({ | 89 | progress.report({ |
88 | message: newPercentage.toFixed(0) + "%", | 90 | message: newPercentage.toFixed(0) + "%", |
@@ -97,16 +99,11 @@ export async function download(opts: DownloadOpts) { | |||
97 | await fs.promises.rename(tempFile, opts.dest); | 99 | await fs.promises.rename(tempFile, opts.dest); |
98 | } | 100 | } |
99 | 101 | ||
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 | */ | ||
106 | async function downloadFile( | 102 | async function downloadFile( |
107 | url: string, | 103 | url: string, |
108 | destFilePath: fs.PathLike, | 104 | destFilePath: fs.PathLike, |
109 | mode: number | undefined, | 105 | mode: number | undefined, |
106 | gunzip: boolean, | ||
110 | onProgress: (readBytes: number, totalBytes: number) => void | 107 | onProgress: (readBytes: number, totalBytes: number) => void |
111 | ): Promise<void> { | 108 | ): Promise<void> { |
112 | const res = await fetch(url); | 109 | const res = await fetch(url); |
@@ -130,7 +127,10 @@ async function downloadFile( | |||
130 | }); | 127 | }); |
131 | 128 | ||
132 | const destFileStream = fs.createWriteStream(destFilePath, { mode }); | 129 | 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 | |||
134 | await new Promise<void>(resolve => { | 134 | await new Promise<void>(resolve => { |
135 | destFileStream.on("close", resolve); | 135 | destFileStream.on("close", resolve); |
136 | destFileStream.destroy(); | 136 | destFileStream.destroy(); |
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index a8b9b010d..8045a98ea 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml | |||
@@ -14,3 +14,4 @@ pico-args = "0.3.1" | |||
14 | quote = "1.0.2" | 14 | quote = "1.0.2" |
15 | proc-macro2 = "1.0.8" | 15 | proc-macro2 = "1.0.8" |
16 | anyhow = "1.0.26" | 16 | anyhow = "1.0.26" |
17 | flate2 = "1.0" | ||
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index aef68089e..b8f68027c 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -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 | }; | ||
2 | 8 | ||
3 | use anyhow::Result; | 9 | use anyhow::Result; |
4 | 10 | ||
@@ -16,7 +22,7 @@ pub fn run_dist(nightly: bool, client_version: Option<String>) -> Result<()> { | |||
16 | let release_tag = if nightly { "nightly".to_string() } else { date_iso()? }; | 22 | let release_tag = if nightly { "nightly".to_string() } else { date_iso()? }; |
17 | dist_client(&version, &release_tag)?; | 23 | dist_client(&version, &release_tag)?; |
18 | } | 24 | } |
19 | dist_server(nightly)?; | 25 | dist_server()?; |
20 | Ok(()) | 26 | Ok(()) |
21 | } | 27 | } |
22 | 28 | ||
@@ -46,17 +52,14 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { | |||
46 | Ok(()) | 52 | Ok(()) |
47 | } | 53 | } |
48 | 54 | ||
49 | fn dist_server(nightly: bool) -> Result<()> { | 55 | fn dist_server() -> Result<()> { |
50 | if cfg!(target_os = "linux") { | 56 | if cfg!(target_os = "linux") { |
51 | std::env::set_var("CC", "clang"); | 57 | env::set_var("CC", "clang"); |
52 | run!( | 58 | run!( |
53 | "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" | 59 | "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" |
54 | // We'd want to add, but that requires setting the right linker somehow | 60 | // We'd want to add, but that requires setting the right linker somehow |
55 | // --features=jemalloc | 61 | // --features=jemalloc |
56 | )?; | 62 | )?; |
57 | if !nightly { | ||
58 | run!("strip ./target/release/rust-analyzer")?; | ||
59 | } | ||
60 | } else { | 63 | } else { |
61 | run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; | 64 | run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; |
62 | } | 65 | } |
@@ -71,8 +74,20 @@ fn dist_server(nightly: bool) -> Result<()> { | |||
71 | panic!("Unsupported OS") | 74 | panic!("Unsupported OS") |
72 | }; | 75 | }; |
73 | 76 | ||
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 | } | ||
75 | 85 | ||
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()?; | ||
76 | Ok(()) | 91 | Ok(()) |
77 | } | 92 | } |
78 | 93 | ||