diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2024-02-13 21:52:30 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-13 21:52:30 +0530 |
commit | a68eb3fcc3997fce8680f87edce46f6450e79635 (patch) | |
tree | 6839607033226fdfb2ce1be3187ef93791096507 /cli/standalone/binary.rs | |
parent | 492a9fbb9194a24a1f9223f797b4f4df9efde2bd (diff) |
feat: denort binary for `deno compile` (#22205)
This introduces the `denort` binary - a slim version of deno without
tooling. The binary is used as the default for `deno compile`.
Improves `deno compile` final size by ~2.5x (141 MB -> 61 MB) on Linux
x86_64.
Diffstat (limited to 'cli/standalone/binary.rs')
-rw-r--r-- | cli/standalone/binary.rs | 80 |
1 files changed, 76 insertions, 4 deletions
diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs index f8bb1e21c..f9d65fdaa 100644 --- a/cli/standalone/binary.rs +++ b/cli/standalone/binary.rs @@ -2,12 +2,14 @@ use std::collections::BTreeMap; use std::env::current_exe; +use std::fs; use std::io::Read; use std::io::Seek; use std::io::SeekFrom; use std::io::Write; use std::path::Path; use std::path::PathBuf; +use std::process::Command; use deno_ast::ModuleSpecifier; use deno_core::anyhow::bail; @@ -337,6 +339,71 @@ fn u64_from_bytes(arr: &[u8]) -> Result<u64, AnyError> { Ok(u64::from_be_bytes(*fixed_arr)) } +pub fn unpack_into_dir( + exe_name: &str, + archive_name: &str, + archive_data: Vec<u8>, + is_windows: bool, + temp_dir: &tempfile::TempDir, +) -> Result<PathBuf, AnyError> { + let temp_dir_path = temp_dir.path(); + let exe_ext = if is_windows { "exe" } else { "" }; + let archive_path = temp_dir_path.join(exe_name).with_extension("zip"); + let exe_path = temp_dir_path.join(exe_name).with_extension(exe_ext); + assert!(!exe_path.exists()); + + let archive_ext = Path::new(archive_name) + .extension() + .and_then(|ext| ext.to_str()) + .unwrap(); + let unpack_status = match archive_ext { + "zip" if cfg!(windows) => { + fs::write(&archive_path, &archive_data)?; + Command::new("tar.exe") + .arg("xf") + .arg(&archive_path) + .arg("-C") + .arg(temp_dir_path) + .spawn() + .map_err(|err| { + if err.kind() == std::io::ErrorKind::NotFound { + std::io::Error::new( + std::io::ErrorKind::NotFound, + "`tar.exe` was not found in your PATH", + ) + } else { + err + } + })? + .wait()? + } + "zip" => { + fs::write(&archive_path, &archive_data)?; + Command::new("unzip") + .current_dir(temp_dir_path) + .arg(&archive_path) + .spawn() + .map_err(|err| { + if err.kind() == std::io::ErrorKind::NotFound { + std::io::Error::new( + std::io::ErrorKind::NotFound, + "`unzip` was not found in your PATH, please install `unzip`", + ) + } else { + err + } + })? + .wait()? + } + ext => bail!("Unsupported archive type: '{ext}'"), + }; + if !unpack_status.success() { + bail!("Failed to unpack archive."); + } + assert!(exe_path.exists()); + fs::remove_file(&archive_path)?; + Ok(exe_path) +} pub struct DenoCompileBinaryWriter<'a> { file_fetcher: &'a FileFetcher, client: &'a HttpClient, @@ -404,13 +471,16 @@ impl<'a> DenoCompileBinaryWriter<'a> { &self, compile_flags: &CompileFlags, ) -> Result<Vec<u8>, AnyError> { - if compile_flags.target.is_none() { - let path = std::env::current_exe()?; + // Used for testing. + // + // Phase 2 of the 'min sized' deno compile RFC talks + // about adding this as a flag. + if let Some(path) = std::env::var_os("DENORT_BIN") { return Ok(std::fs::read(path)?); } let target = compile_flags.resolve_target(); - let binary_name = format!("deno-{target}.zip"); + let binary_name = format!("denort-{target}.zip"); let binary_path_suffix = if crate::version::is_canary() { format!("canary/{}/{}", crate::version::GIT_COMMIT_HASH, binary_name) @@ -429,7 +499,9 @@ impl<'a> DenoCompileBinaryWriter<'a> { let archive_data = std::fs::read(binary_path)?; let temp_dir = tempfile::TempDir::new()?; - let base_binary_path = crate::tools::upgrade::unpack_into_dir( + let base_binary_path = unpack_into_dir( + "denort", + &binary_name, archive_data, target.contains("windows"), &temp_dir, |