diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5580c2b8..3b2c904f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -185,9 +185,10 @@ jobs: run: cargo fmt -- --check - name: Prepare binary publish - run: cp - target/${{ matrix.config.target }}/${{ matrix.config.variant }}/gn_out/obj/${{ env.LIB_NAME }}.${{ env.LIB_EXT }} - target/${{ env.LIB_NAME }}_${{ matrix.config.variant }}_${{ matrix.config.target }}.${{ env.LIB_EXT }} + run: gzip -9c + target/${{ matrix.config.target }}/${{ matrix.config.variant }}/gn_out/obj/${{ env.LIB_NAME }}.${{ env.LIB_EXT }} > + target/${{ env.LIB_NAME }}_${{ matrix.config.variant }}_${{ matrix.config.target }}.${{ env.LIB_EXT }}.gz && + ls -l target/${{ env.LIB_NAME }}_${{ matrix.config.variant }}_${{ matrix.config.target }}.${{ env.LIB_EXT }}.gz - name: Binary publish uses: softprops/action-gh-release@v0.1.15 @@ -197,7 +198,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - files: target/${{ env.LIB_NAME }}_${{ matrix.config.variant }}_${{ matrix.config.target }}.${{ env.LIB_EXT }} + files: target/${{ env.LIB_NAME }}_${{ matrix.config.variant }}_${{ matrix.config.target }}.${{ env.LIB_EXT }}.gz # TODO: add clang-format and maybe cpplint. diff --git a/Cargo.lock b/Cargo.lock index 756fa3b0..4d92bb8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.8.11" @@ -301,6 +307,15 @@ dependencies = [ "objc", ] +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "cty" version = "0.2.2" @@ -514,6 +529,15 @@ dependencies = [ "bitflags 2.4.2", ] +[[package]] +name = "gzip-header" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2" +dependencies = [ + "crc32fast", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -721,6 +745,15 @@ dependencies = [ "objc", ] +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.11" @@ -1290,7 +1323,9 @@ dependencies = [ "bitflags 2.4.2", "bytes", "fslock", + "gzip-header", "home", + "miniz_oxide", "once_cell", "trybuild", "which", diff --git a/Cargo.toml b/Cargo.toml index 23d4aa0e..b8dc23b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,11 +84,15 @@ bitflags = "2.4" once_cell = "1.19" [build-dependencies] +miniz_oxide = "0.7.2" +gzip-header = "1.0.0" fslock = "0.2" which = "5" home = "0" [dev-dependencies] +miniz_oxide = "0.7.2" +gzip-header = "1.0.0" bytes = "1" align-data = "0.1.0" fslock = "0.2" diff --git a/build.rs b/build.rs index a72d0333..3c8609b9 100644 --- a/build.rs +++ b/build.rs @@ -1,9 +1,18 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. use fslock::LockFile; +use miniz_oxide::inflate::stream::inflate; +use miniz_oxide::inflate::stream::InflateState; +use miniz_oxide::MZFlush; +use miniz_oxide::MZResult; +use miniz_oxide::MZStatus; +use miniz_oxide::StreamResult; use std::collections::HashSet; use std::env; use std::fs; use std::io; +use std::io::Read; +use std::io::Seek; +use std::io::Write; use std::path::Path; use std::path::PathBuf; use std::process::exit; @@ -322,14 +331,17 @@ fn static_lib_url() -> String { // Note: we always use the release build on windows. if cfg!(target_os = "windows") { - return format!("{}/v{}/rusty_v8_release_{}.lib", base, version, target); + return format!("{}/v{}/rusty_v8_release_{}.lib.gz", base, version, target); } // Use v8 in release mode unless $V8_FORCE_DEBUG=true let profile = match env_bool("V8_FORCE_DEBUG") { true => "debug", _ => "release", }; - format!("{}/v{}/librusty_v8_{}_{}.a", base, version, profile, target) + format!( + "{}/v{}/librusty_v8_{}_{}.a.gz", + base, version, profile, target + ) } fn env_bool(key: &str) -> bool { @@ -418,7 +430,7 @@ fn download_file(url: String, filename: PathBuf) { // Try downloading with python first. Python is a V8 build dependency, // so this saves us from adding a Rust HTTP client dependency. - println!("Downloading {}", url); + println!("Downloading (using Python) {}", url); let status = Command::new(python()) .arg("./tools/download_file.py") .arg("--url") @@ -451,7 +463,9 @@ fn download_file(url: String, filename: PathBuf) { // Write checksum (i.e url) & move file std::fs::write(static_checksum_path(), url).unwrap(); - std::fs::rename(&tmpfile, &filename).unwrap(); + copy_archive(&tmpfile.to_string_lossy(), &filename); + std::fs::remove_file(&tmpfile).unwrap(); + assert!(filename.exists()); assert!(static_checksum_path().exists()); assert!(!tmpfile.exists()); @@ -473,6 +487,57 @@ fn download_static_lib_binaries() { download_file(url, static_lib_path()); } +fn decompress_to_writer(input: &mut R, output: &mut W) -> io::Result<()> +where + R: Read, + W: Write, +{ + let mut inflate_state = InflateState::default(); + let mut input_buffer = [0; 16 * 1024]; + let mut output_buffer = [0; 16 * 1024]; + let mut input_offset = 0; + + // Skip the gzip header + gzip_header::read_gz_header(input).unwrap(); + + loop { + let bytes_read = input.read(&mut input_buffer[input_offset..])?; + let bytes_avail = input_offset + bytes_read; + + let StreamResult { + bytes_consumed, + bytes_written, + status, + } = inflate( + &mut inflate_state, + &input_buffer[..bytes_avail], + &mut output_buffer, + MZFlush::None, + ); + + if status != MZResult::Ok(MZStatus::Ok) + && status != MZResult::Ok(MZStatus::StreamEnd) + { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Decompression error {status:?}"), + )); + } + + output.write_all(&output_buffer[..bytes_written])?; + + // Move remaining bytes to the beginning of the buffer + input_buffer.copy_within(bytes_consumed..bytes_avail, 0); + input_offset = bytes_avail - bytes_consumed; + + if status == MZResult::Ok(MZStatus::StreamEnd) { + break; // End of decompression + } + } + + Ok(()) +} + /// Copy the V8 archive at `url` to `filename`. /// /// This function doesn't use `std::fs::copy` because that would @@ -481,9 +546,21 @@ fn download_static_lib_binaries() { /// This is necessary because the V8 archive could live inside a read-only /// filesystem, and subsequent builds would fail to overwrite it. fn copy_archive(url: &str, filename: &Path) { + println!("Copying {url} to {filename:?}"); let mut src = fs::File::open(url).unwrap(); let mut dst = fs::File::create(filename).unwrap(); - io::copy(&mut src, &mut dst).unwrap(); + + // Allow both GZIP and non-GZIP downloads + let mut header = [0; 2]; + src.read_exact(&mut header).unwrap(); + src.seek(io::SeekFrom::Start(0)).unwrap(); + if header == [0x1f, 0x8b] { + println!("Detected GZIP archive"); + decompress_to_writer(&mut src, &mut dst).unwrap(); + } else { + println!("Not a GZIP archive"); + io::copy(&mut src, &mut dst).unwrap(); + } } fn print_link_flags() {