diff --git a/Cargo.lock b/Cargo.lock index bcffc30..09008e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.12.0" @@ -101,6 +110,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -110,6 +128,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "dagger-rs" version = "0.1.1" @@ -117,11 +145,26 @@ dependencies = [ "clap", "dirs", "eyre", + "flate2", + "hex", + "hex-literal", "platform-info", "reqwest", + "sha2", + "tar", "tempfile", ] +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dirs" version = "4.0.0" @@ -191,6 +234,18 @@ dependencies = [ "instant", ] +[[package]] +name = "filetime" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + [[package]] name = "flate2" version = "1.0.25" @@ -198,6 +253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", + "libz-sys", "miniz_oxide", ] @@ -292,6 +348,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.8" @@ -337,6 +403,18 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + [[package]] name = "http" version = "0.2.8" @@ -498,6 +576,17 @@ version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -833,6 +922,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "slab" version = "0.4.7" @@ -869,6 +969,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.3.0" @@ -1000,6 +1111,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + [[package]] name = "unicode-bidi" version = "0.3.10" @@ -1038,6 +1155,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "want" version = "0.3.0" @@ -1239,3 +1362,12 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] diff --git a/Cargo.toml b/Cargo.toml index ec1548b..6c79191 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,11 @@ description = "A dagger sdk for rust, written in rust" clap = "4.1.4" dirs = "4.0.0" eyre = "0.6.8" +flate2 = { version = "1.0.25", features = ["zlib"] } +hex = "0.4.3" +hex-literal = "0.3.4" platform-info = "1.0.2" reqwest = { version = "0.11.14", features = ["stream", "blocking", "deflate"] } +sha2 = "0.10.6" +tar = "0.4.38" tempfile = "3.3.0" diff --git a/src/downloader.rs b/src/downloader.rs index 84caaec..5c1d815 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -1,11 +1,16 @@ use std::{ fs::File, - io::{BufWriter, Read, Write}, + io::{copy, BufReader, BufWriter, Read, Write}, + os::unix::prelude::PermissionsExt, path::PathBuf, }; use eyre::Context; +use flate2::read::GzDecoder; +use hex_literal::hex; use platform_info::Uname; +use sha2::Digest; +use tar::Archive; use tempfile::{tempfile, NamedTempFile}; #[allow(dead_code)] @@ -141,16 +146,24 @@ impl Downloader { Ok(cli_bin_path) } - fn download(&self, _path: PathBuf) -> eyre::Result { + fn download(&self, path: PathBuf) -> eyre::Result { let expected_checksum = self.expected_checksum()?; - let (actual_hash, _tempbin) = self.extract_cli_archive()?; + let mut bytes = vec![]; + let actual_hash = self.extract_cli_archive(&mut bytes)?; if expected_checksum != actual_hash { eyre::bail!("downloaded CLI binary checksum doesn't match checksum from checksums.txt") } - todo!(); + let mut file = std::fs::File::create(&path)?; + let meta = file.metadata()?; + let mut perm = meta.permissions(); + perm.set_mode(0o700); + file.set_permissions(perm)?; + file.write_all(bytes.as_slice())?; + + Ok(path) } fn expected_checksum(&self) -> eyre::Result { @@ -178,35 +191,63 @@ impl Downloader { eyre::bail!("could not find a matching version or binary in checksums.txt") } - pub fn extract_cli_archive(&self) -> eyre::Result<(String, File)> { + pub fn extract_cli_archive(&self, dest: &mut Vec) -> eyre::Result { let archive_url = self.archive_url(); let resp = reqwest::blocking::get(&archive_url)?; let mut resp = resp.error_for_status()?; - let temp = NamedTempFile::new()?; - let mut buf_writer = BufWriter::new(temp); let mut bytes = vec![]; - let _ = resp.read_to_end(&mut bytes)?; - buf_writer.write_all(bytes.as_slice())?; + let lines = resp.read_to_end(&mut bytes)?; + if lines == 0 { + eyre::bail!("nothing was downloaded") + } + let mut hasher = sha2::Sha256::new(); + hasher.update(bytes.as_slice()); + let res = hasher.finalize(); + + println!("{}", hex::encode(&res)); if archive_url.ends_with(".zip") { // TODO: Nothing for now + todo!() } else { - //self.extract_from_tar(&temp)?; + self.extract_from_tar(bytes.as_slice(), dest)?; } - todo!() + + Ok(hex::encode(res)) + } + + fn extract_from_tar(&self, temp: &[u8], output: &mut Vec) -> eyre::Result<()> { + let decompressed_temp = GzDecoder::new(temp); + let mut archive = Archive::new(decompressed_temp); + + for entry in archive.entries()? { + let mut entry = entry?; + let path = entry.path()?; + + println!("path: {:?}", path); + + if path.ends_with("dagger") { + copy(&mut entry, output)?; + + return Ok(()); + } + } + + eyre::bail!("could not find a matching file") } } #[cfg(test)] mod test { - use std::path::PathBuf; - use super::Downloader; #[test] fn download() { let cli_path = Downloader::new("0.3.10".into()).unwrap().get_cli().unwrap(); - assert_eq!(PathBuf::from("/"), cli_path) + assert_eq!( + Some("dagger-0.3.10"), + cli_path.file_name().and_then(|s| s.to_str()) + ) } }