From 77b60f675a99ebef4672583af68ce3f7c1f2d89c Mon Sep 17 00:00:00 2001 From: David Terry Date: Tue, 21 Jun 2022 17:59:44 +0200 Subject: [PATCH 1/4] automatically patch binaries for nixos --- src/error.rs | 2 ++ src/lib.rs | 22 +++++++++++++++++++++- src/platform.rs | 4 ++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 7593c0c..1858577 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,6 +15,8 @@ pub enum SolcVmError { ChecksumMismatch(String), #[error("Install step for solc version {0} timed out after {1} seconds")] Timeout(String, u64), + #[error("Unable to patch solc binary for nixos. stdout: {0}. stderr: {1}")] + CouldNotPatchForNixOs(String, String), #[error(transparent)] IoError(#[from] std::io::Error), #[error(transparent)] diff --git a/src/lib.rs b/src/lib.rs index fb1d3c2..da65317 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ use std::{ fs, io::{Cursor, Write}, path::PathBuf, + process::Command, }; use std::time::Duration; @@ -68,7 +69,26 @@ impl Installer { let mut content = Cursor::new(&self.binbytes); std::io::copy(&mut content, &mut f)?; - Ok(solc_path) + // patch the binaries to use the correct dynamic linker if we're on nixos + if platform::is_nixos() { + let output = Command::new("nix-shell") + .arg("-p") + .arg("patchelf") + .arg("--run") + .arg(format!("patchelf --set-interpreter \"$(cat $NIX_CC/nix-support/dynamic-linker)\" {}", solc_path.display())) + .output() + .expect("Failed to execute command"); + + match output.status.success() { + true => Ok(solc_path), + false => Err(SolcVmError::CouldNotPatchForNixOs( + String::from_utf8(output.stdout).expect("Found invalid UTF-8 when parsing stdout"), + String::from_utf8(output.stderr).expect("Found invalid UTF-8 when parsing stderr"), + )), + } + } else { + Ok(solc_path) + } } } diff --git a/src/platform.rs b/src/platform.rs index 6ca995f..40b379a 100644 --- a/src/platform.rs +++ b/src/platform.rs @@ -42,6 +42,10 @@ impl FromStr for Platform { } } +pub fn is_nixos() -> bool { + std::path::Path::new("/etc/NIXOS").exists() +} + /// Read the current machine's platform. pub fn platform() -> Platform { match (env::consts::OS, env::consts::ARCH) { From ec5a535470c9a977e1bff4912672402b9da5345e Mon Sep 17 00:00:00 2001 From: David Terry Date: Wed, 22 Jun 2022 16:20:54 +0200 Subject: [PATCH 2/4] seperate nixoos patching routine into a separate function --- src/lib.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index da65317..f4c78f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,29 +69,36 @@ impl Installer { let mut content = Cursor::new(&self.binbytes); std::io::copy(&mut content, &mut f)?; - // patch the binaries to use the correct dynamic linker if we're on nixos if platform::is_nixos() { - let output = Command::new("nix-shell") - .arg("-p") - .arg("patchelf") - .arg("--run") - .arg(format!("patchelf --set-interpreter \"$(cat $NIX_CC/nix-support/dynamic-linker)\" {}", solc_path.display())) - .output() - .expect("Failed to execute command"); - - match output.status.success() { - true => Ok(solc_path), - false => Err(SolcVmError::CouldNotPatchForNixOs( - String::from_utf8(output.stdout).expect("Found invalid UTF-8 when parsing stdout"), - String::from_utf8(output.stderr).expect("Found invalid UTF-8 when parsing stderr"), - )), - } + patch_for_nixos(solc_path) } else { Ok(solc_path) } } } +/// Patch the given binary to use the dynamic linker provided by nixos +pub fn patch_for_nixos(bin: PathBuf) -> Result { + let output = Command::new("nix-shell") + .arg("-p") + .arg("patchelf") + .arg("--run") + .arg(format!( + "patchelf --set-interpreter \"$(cat $NIX_CC/nix-support/dynamic-linker)\" {}", + bin.display() + )) + .output() + .expect("Failed to execute command"); + + match output.status.success() { + true => Ok(bin), + false => Err(SolcVmError::CouldNotPatchForNixOs( + String::from_utf8(output.stdout).expect("Found invalid UTF-8 when parsing stdout"), + String::from_utf8(output.stderr).expect("Found invalid UTF-8 when parsing stderr"), + )), + } +} + /// Derive path to a specific Solc version's binary. pub fn version_path(version: &str) -> PathBuf { let mut version_path = SVM_HOME.to_path_buf(); From 03e5153f4412fd607cfb57414686a5332cf525aa Mon Sep 17 00:00:00 2001 From: David Terry Date: Wed, 22 Jun 2022 16:29:47 +0200 Subject: [PATCH 3/4] nixos: only patch if version is 0.8+ --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index f4c78f8..1a53eed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,7 @@ impl Installer { let mut content = Cursor::new(&self.binbytes); std::io::copy(&mut content, &mut f)?; - if platform::is_nixos() { + if platform::is_nixos() && self.version.major == 0 && self.version.minor >= 8 { patch_for_nixos(solc_path) } else { Ok(solc_path) From 84687f2eccbf0c5633f8e33ec15f9d0830b9587b Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Thu, 23 Jun 2022 10:12:51 +0200 Subject: [PATCH 4/4] chore: refactor version req check for NixOS patching --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1a53eed..75734ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ use once_cell::sync::Lazy; -use semver::Version; +use semver::{Version, VersionReq}; use sha2::Digest; use std::{ @@ -44,6 +44,9 @@ pub static SVM_HOME: Lazy = Lazy::new(|| { /// The timeout to use for requests to the source const REQUEST_TIMEOUT: Duration = Duration::from_secs(60); +/// Version beyond which solc binaries are not fully static, hence need to be patched for NixOS. +static NIXOS_PATCH_REQ: Lazy = Lazy::new(|| VersionReq::parse(">=0.8.0").unwrap()); + // Installer type that copies binary data to the appropriate solc binary file: // 1. create target file to copy binary data // 2. copy data @@ -69,7 +72,7 @@ impl Installer { let mut content = Cursor::new(&self.binbytes); std::io::copy(&mut content, &mut f)?; - if platform::is_nixos() && self.version.major == 0 && self.version.minor >= 8 { + if platform::is_nixos() && NIXOS_PATCH_REQ.matches(&self.version) { patch_for_nixos(solc_path) } else { Ok(solc_path)