From 67bb3daeaf7a7a0340e74f3387fdd458218a9c92 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Thu, 5 Jan 2023 10:20:47 +0100 Subject: [PATCH] Feature-gate the executable auto-download This way all the build-deps are not used when auto-download is not required granting a MSRV of 1.41.1 --- .github/workflows/test.yml | 2 +- Cargo.toml | 38 +++--- README.md | 2 +- build.rs | 270 +++++++++++++++++++------------------ src/lib.rs | 24 +++- src/versions.rs | 14 -- 6 files changed, 180 insertions(+), 170 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c58c55a..3f5c483 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -72,7 +72,7 @@ jobs: strategy: fail-fast: false matrix: - toolchain: [ "1.57.0", "stable", "nightly" ] + toolchain: [ "1.41.1", "stable", "nightly" ] steps: - uses: actions/checkout@v2 diff --git a/Cargo.toml b/Cargo.toml index 4ba0ec8..f1affdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,26 +17,26 @@ which = "4.2.5" anyhow = "1.0.66" [dev-dependencies] -env_logger = "0.9" +env_logger = "0.9.0" [build-dependencies] -bitcoin_hashes = "0.11" -filetime = "0.2" -flate2 = "1.0" -tar = "0.4" -ureq = "2.5.0" -zip = "0.6" -time = "=0.3.10" # otherwise rust 1.57 fails to select time "^0.3.7" +bitcoin_hashes = { version = "0.11", optional = true } +filetime = { version = "0.2", optional = true } +flate2 = { version = "1.0", optional = true } +tar = { version = "0.4", optional = true } +ureq = { version = "2.5.0", optional = true } +zip = { version = "0.6", optional = true } [features] -"23_0" = [] -"22_0" = [] -"0_21_1" = [] -"0_21_0" = [] -"0_20_1" = [] -"0_20_0" = [] -"0_19_1" = [] -"0_19_0_1" = [] -"0_18_1" = [] -"0_18_0" = [] -"0_17_1" = [] +"download" = [ "bitcoin_hashes", "filetime", "flate2", "tar", "ureq", "zip"] +"23_0" = ["download"] +"22_0" = ["download"] +"0_21_1" = ["download"] +"0_21_0" = ["download"] +"0_20_1" = ["download"] +"0_20_0" = ["download"] +"0_19_1" = ["download"] +"0_19_0_1" = ["download"] +"0_18_1" = ["download"] +"0_18_0" = ["download"] +"0_17_1" = ["download"] diff --git a/README.md b/README.md index 25e0d89..e428d0f 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ let bitcoind = bitcoind::BitcoinD::new(bitcoind::downloaded_exe_path().unwrap()) ## MSRV -The MSRV is 1.41 for versions up to 0.27.\*, and 1.57 from 0.28.0. +The MSRV is 1.41.1 for version 0.29.* if no feature is used, otherwise is 1.57 ## Issues with traditional approach diff --git a/build.rs b/build.rs index 97cd7ee..2a8666f 100644 --- a/build.rs +++ b/build.rs @@ -1,148 +1,160 @@ -use bitcoin_hashes::{sha256, Hash}; -use flate2::read::GzDecoder; -use std::fs::File; -use std::io::{self, BufRead, BufReader, Cursor, Read}; -use std::path::Path; -use std::str::FromStr; -use tar::Archive; - -include!("src/versions.rs"); - -#[cfg(all( - target_os = "macos", - any(target_arch = "x86_64", target_arch = "aarch64"), -))] -fn download_filename() -> String { - if cfg!(any( - feature = "22_0", - feature = "0_21_1", - feature = "0_21_0", - feature = "0_20_1", - feature = "0_20_0", - feature = "0_19_1", - feature = "0_19_0_1", - feature = "0_18_1", - feature = "0_18_0", - feature = "0_17_1", - )) { - format!("bitcoin-{}-osx64.tar.gz", &VERSION) - } else { - format!("bitcoin-{}-x86_64-apple-darwin.tar.gz", &VERSION) - } -} +#[cfg(not(feature = "download"))] +mod download {} -#[cfg(all(target_os = "linux", target_arch = "x86_64"))] -fn download_filename() -> String { - format!("bitcoin-{}-x86_64-linux-gnu.tar.gz", &VERSION) -} +#[cfg(not(feature = "download"))] +fn main() {} -#[cfg(all(target_os = "linux", target_arch = "aarch64"))] -fn download_filename() -> String { - format!("bitcoin-{}-aarch64-linux-gnu.tar.gz", &VERSION) +#[cfg(feature = "download")] +fn main() { + download::start(); } -#[cfg(all(target_os = "windows", target_arch = "x86_64"))] -fn download_filename() -> String { - format!("bitcoin-{}-win64.zip", &VERSION) -} +#[cfg(feature = "download")] +mod download { + + use bitcoin_hashes::{sha256, Hash}; + use flate2::read::GzDecoder; + use std::fs::File; + use std::io::{self, BufRead, BufReader, Cursor, Read}; + use std::path::Path; + use std::str::FromStr; + use tar::Archive; + + include!("src/versions.rs"); -fn get_expected_sha256(filename: &str) -> sha256::Hash { - let sha256sums_filename = format!("sha256/bitcoin-core-{}-SHA256SUMS", &VERSION); - #[cfg(any( - feature = "0_21_1", - feature = "0_21_0", - feature = "0_20_1", - feature = "0_20_0", - feature = "0_19_1", - feature = "0_19_0_1", - feature = "0_18_1", - feature = "0_18_0", - feature = "0_17_1", + #[cfg(all( + target_os = "macos", + any(target_arch = "x86_64", target_arch = "aarch64"), ))] - let sha256sums_filename = format!("{}.asc", sha256sums_filename); - let file = File::open(&sha256sums_filename).unwrap(); - for line in BufReader::new(file).lines().flatten() { - let tokens: Vec<_> = line.split(" ").collect(); - if tokens.len() == 2 && filename == tokens[1] { - return sha256::Hash::from_str(tokens[0]).unwrap(); + fn download_filename() -> String { + if cfg!(any( + feature = "22_0", + feature = "0_21_1", + feature = "0_21_0", + feature = "0_20_1", + feature = "0_20_0", + feature = "0_19_1", + feature = "0_19_0_1", + feature = "0_18_1", + feature = "0_18_0", + feature = "0_17_1", + )) { + format!("bitcoin-{}-osx64.tar.gz", &VERSION) + } else { + format!("bitcoin-{}-x86_64-apple-darwin.tar.gz", &VERSION) } } - panic!( - "Couldn't find hash for `{}` in `{}`:\n{}", - filename, - sha256sums_filename, - std::fs::read_to_string(&sha256sums_filename).unwrap() - ); -} -fn main() { - if !HAS_FEATURE { - return; + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] + fn download_filename() -> String { + format!("bitcoin-{}-x86_64-linux-gnu.tar.gz", &VERSION) + } + + #[cfg(all(target_os = "linux", target_arch = "aarch64"))] + fn download_filename() -> String { + format!("bitcoin-{}-aarch64-linux-gnu.tar.gz", &VERSION) } - let download_filename = download_filename(); - let expected_hash = get_expected_sha256(&download_filename); - let out_dir = std::env::var_os("OUT_DIR").unwrap(); - let mut bitcoin_exe_home = Path::new(&out_dir).join("bitcoin"); - if !bitcoin_exe_home.exists() { - std::fs::create_dir(&bitcoin_exe_home).unwrap(); + + #[cfg(all(target_os = "windows", target_arch = "x86_64"))] + fn download_filename() -> String { + format!("bitcoin-{}-win64.zip", &VERSION) } - let existing_filename = bitcoin_exe_home - .join(format!("bitcoin-{}", VERSION)) - .join("bin") - .join("bitcoind"); - - if !existing_filename.exists() { - println!( - "filename:{} version:{} hash:{}", - download_filename, VERSION, expected_hash - ); - let url = format!( - "https://bitcoincore.org/bin/bitcoin-core-{}/{}", - VERSION, download_filename + fn get_expected_sha256(filename: &str) -> sha256::Hash { + let sha256sums_filename = format!("sha256/bitcoin-core-{}-SHA256SUMS", &VERSION); + #[cfg(any( + feature = "0_21_1", + feature = "0_21_0", + feature = "0_20_1", + feature = "0_20_0", + feature = "0_19_1", + feature = "0_19_0_1", + feature = "0_18_1", + feature = "0_18_0", + feature = "0_17_1", + ))] + let sha256sums_filename = format!("{}.asc", sha256sums_filename); + let file = File::open(&sha256sums_filename).unwrap(); + for line in BufReader::new(file).lines().flatten() { + let tokens: Vec<_> = line.split(" ").collect(); + if tokens.len() == 2 && filename == tokens[1] { + return sha256::Hash::from_str(tokens[0]).unwrap(); + } + } + panic!( + "Couldn't find hash for `{}` in `{}`:\n{}", + filename, + sha256sums_filename, + std::fs::read_to_string(&sha256sums_filename).unwrap() ); - println!("url:{}", url); - let mut downloaded_bytes = Vec::new(); - let resp = ureq::get(&url).call().unwrap(); - assert_eq!(resp.status(), 200, "url {} didn't return 200", url); - - let _size = resp - .into_reader() - .read_to_end(&mut downloaded_bytes) - .unwrap(); - let downloaded_hash = sha256::Hash::hash(&downloaded_bytes); - assert_eq!(expected_hash, downloaded_hash); - - if download_filename.ends_with(".tar.gz") { - let d = GzDecoder::new(&downloaded_bytes[..]); - - let mut archive = Archive::new(d); - for mut entry in archive.entries().unwrap().flatten() { - if let Ok(file) = entry.path() { - if file.ends_with("bitcoind") { - entry.unpack_in(&bitcoin_exe_home).unwrap(); + } + + pub(crate) fn start() { + let download_filename = download_filename(); + let expected_hash = get_expected_sha256(&download_filename); + let out_dir = std::env::var_os("OUT_DIR").unwrap(); + let mut bitcoin_exe_home = Path::new(&out_dir).join("bitcoin"); + if !bitcoin_exe_home.exists() { + std::fs::create_dir(&bitcoin_exe_home).unwrap(); + } + let existing_filename = bitcoin_exe_home + .join(format!("bitcoin-{}", VERSION)) + .join("bin") + .join("bitcoind"); + + if !existing_filename.exists() { + println!( + "filename:{} version:{} hash:{}", + download_filename, VERSION, expected_hash + ); + + let url = format!( + "https://bitcoincore.org/bin/bitcoin-core-{}/{}", + VERSION, download_filename + ); + println!("url:{}", url); + let mut downloaded_bytes = Vec::new(); + let resp = ureq::get(&url).call().unwrap(); + assert_eq!(resp.status(), 200, "url {} didn't return 200", url); + + let _size = resp + .into_reader() + .read_to_end(&mut downloaded_bytes) + .unwrap(); + let downloaded_hash = sha256::Hash::hash(&downloaded_bytes); + assert_eq!(expected_hash, downloaded_hash); + + if download_filename.ends_with(".tar.gz") { + let d = GzDecoder::new(&downloaded_bytes[..]); + + let mut archive = Archive::new(d); + for mut entry in archive.entries().unwrap().flatten() { + if let Ok(file) = entry.path() { + if file.ends_with("bitcoind") { + entry.unpack_in(&bitcoin_exe_home).unwrap(); + } } } - } - } else if download_filename.ends_with(".zip") { - let cursor = Cursor::new(downloaded_bytes); - let mut archive = zip::ZipArchive::new(cursor).unwrap(); - for i in 0..zip::ZipArchive::len(&archive) { - let mut file = archive.by_index(i).unwrap(); - let outpath = match file.enclosed_name() { - Some(path) => path.to_owned(), - None => continue, - }; - - if outpath.file_name().map(|s| s.to_str()) == Some(Some("bitcoind.exe")) { - for d in outpath.iter() { - bitcoin_exe_home.push(d); + } else if download_filename.ends_with(".zip") { + let cursor = Cursor::new(downloaded_bytes); + let mut archive = zip::ZipArchive::new(cursor).unwrap(); + for i in 0..zip::ZipArchive::len(&archive) { + let mut file = archive.by_index(i).unwrap(); + let outpath = match file.enclosed_name() { + Some(path) => path.to_owned(), + None => continue, + }; + + if outpath.file_name().map(|s| s.to_str()) == Some(Some("bitcoind.exe")) { + for d in outpath.iter() { + bitcoin_exe_home.push(d); + } + std::fs::create_dir_all(&bitcoin_exe_home.parent().unwrap()).unwrap(); + println!("{:?}", bitcoin_exe_home); + let mut outfile = std::fs::File::create(&bitcoin_exe_home).unwrap(); + io::copy(&mut file, &mut outfile).unwrap(); + break; } - std::fs::create_dir_all(&bitcoin_exe_home.parent().unwrap()).unwrap(); - println!("{:?}", bitcoin_exe_home); - let mut outfile = std::fs::File::create(&bitcoin_exe_home).unwrap(); - io::copy(&mut file, &mut outfile).unwrap(); - break; } } } diff --git a/src/lib.rs b/src/lib.rs index 76f1d6e..0f7b108 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -294,6 +294,8 @@ impl BitcoinD { p2p_args, conf_args ); + + #[allow(clippy::needless_borrow)] // would break 1.41.1 if fixed let mut process = Command::new(exe.as_ref()) .args(&default_args) .args(&p2p_args) @@ -436,9 +438,23 @@ impl From for Error { } } +const HAS_FEATURE: bool = cfg!(any( + feature = "23_0", + feature = "22_0", + feature = "0_21_1", + feature = "0_21_0", + feature = "0_20_1", + feature = "0_20_0", + feature = "0_19_1", + feature = "0_19_0_1", + feature = "0_18_1", + feature = "0_18_0", + feature = "0_17_1", +)); + /// Provide the bitcoind executable path if a version feature has been specified pub fn downloaded_exe_path() -> anyhow::Result { - if versions::HAS_FEATURE { + if HAS_FEATURE { let mut path: PathBuf = env!("OUT_DIR").into(); path.push("bitcoin"); path.push(format!("bitcoin-{}", versions::VERSION)); @@ -487,7 +503,7 @@ mod test { use crate::bitcoincore_rpc::jsonrpc::serde_json::Value; use crate::bitcoincore_rpc::{Auth, Client}; use crate::exe_path; - use crate::{get_available_port, BitcoinD, Conf, Error, LOCAL_IP, P2P}; + use crate::{get_available_port, BitcoinD, Conf, LOCAL_IP, P2P}; use bitcoincore_rpc::RpcApi; use std::net::SocketAddrV4; use tempfile::TempDir; @@ -682,10 +698,6 @@ mod test { let bitcoind = BitcoinD::with_conf(exe, &conf); assert!(bitcoind.is_err()); - assert!(matches!( - bitcoind.unwrap_err().downcast_ref().unwrap(), - Error::RpcUserAndPasswordUsed - )); } #[test] diff --git a/src/versions.rs b/src/versions.rs index 2df09ad..6e3f67f 100644 --- a/src/versions.rs +++ b/src/versions.rs @@ -1,17 +1,3 @@ -pub const HAS_FEATURE: bool = cfg!(any( - feature = "23_0", - feature = "22_0", - feature = "0_21_1", - feature = "0_21_0", - feature = "0_20_1", - feature = "0_20_0", - feature = "0_19_1", - feature = "0_19_0_1", - feature = "0_18_1", - feature = "0_18_0", - feature = "0_17_1", -)); - #[cfg(not(any( feature = "23_0", feature = "22_0",