mirror of
https://github.com/kjuulh/dagger-rs.git
synced 2024-11-08 11:01:47 +01:00
Add base sdk
This commit is contained in:
commit
078e2d9c2c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
target/
|
1241
Cargo.lock
generated
Normal file
1241
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "4.1.4"
|
||||||
|
dirs = "4.0.0"
|
||||||
|
eyre = "0.6.8"
|
||||||
|
platform-info = "1.0.2"
|
||||||
|
reqwest = { version = "0.11.14", features = ["stream", "blocking", "deflate"] }
|
||||||
|
tempfile = "3.3.0"
|
22
src/cli.rs
Normal file
22
src/cli.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
pub struct Cli {
|
||||||
|
cmd: clap::Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cli {
|
||||||
|
pub fn new() -> eyre::Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
cmd: clap::Command::new("dagger-rust")
|
||||||
|
.subcommand_required(true)
|
||||||
|
.subcommand(clap::Command::new("generate")),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(self, args: &[&str]) -> eyre::Result<()> {
|
||||||
|
let matches = self.cmd.get_matches_from(args);
|
||||||
|
|
||||||
|
match matches.subcommand() {
|
||||||
|
Some(("generate", args)) => Ok(()),
|
||||||
|
_ => eyre::bail!("command missing"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/dagger.rs
Normal file
21
src/dagger.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub fn connect() -> eyre::Result<Client> {
|
||||||
|
Client::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InnerClient {}
|
||||||
|
|
||||||
|
pub struct Client {
|
||||||
|
inner: Arc<InnerClient>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn new() -> eyre::Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
inner: Arc::new(InnerClient {}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn container(&self) -> Container {}
|
||||||
|
}
|
206
src/downloader.rs
Normal file
206
src/downloader.rs
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufWriter, Read, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use eyre::Context;
|
||||||
|
use platform_info::Uname;
|
||||||
|
use tempfile::{tempfile, NamedTempFile};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Platform {
|
||||||
|
pub os: String,
|
||||||
|
pub arch: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Platform {
|
||||||
|
pub fn from_system() -> eyre::Result<Self> {
|
||||||
|
let platform = platform_info::PlatformInfo::new()?;
|
||||||
|
let os_name = platform.sysname();
|
||||||
|
let arch = platform.machine().to_lowercase();
|
||||||
|
let normalize_arch = match arch.as_str() {
|
||||||
|
"x86_64" => "amd64",
|
||||||
|
"aarch" => "arm64",
|
||||||
|
arch => arch,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
os: os_name.to_lowercase(),
|
||||||
|
arch: normalize_arch.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TempFile {
|
||||||
|
prefix: String,
|
||||||
|
directory: PathBuf,
|
||||||
|
file: File,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TempFile {
|
||||||
|
pub fn new(prefix: &str, directory: &PathBuf) -> eyre::Result<Self> {
|
||||||
|
let prefix = prefix.to_string();
|
||||||
|
let directory = directory.clone();
|
||||||
|
|
||||||
|
let file = tempfile()?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
prefix,
|
||||||
|
directory,
|
||||||
|
file,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CliVersion = String;
|
||||||
|
|
||||||
|
pub struct Downloader {
|
||||||
|
version: CliVersion,
|
||||||
|
platform: Platform,
|
||||||
|
}
|
||||||
|
const DEFAULT_CLI_HOST: &str = "dl.dagger.io";
|
||||||
|
const CLI_BIN_PREFIX: &str = "dagger-";
|
||||||
|
const CLI_BASE_URL: &str = "https://dl.dagger.io/dagger/releases";
|
||||||
|
|
||||||
|
impl Downloader {
|
||||||
|
pub fn new(version: CliVersion) -> eyre::Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
version,
|
||||||
|
platform: Platform::from_system()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn archive_url(&self) -> String {
|
||||||
|
let ext = match self.platform.os.as_str() {
|
||||||
|
"windows" => "zip",
|
||||||
|
_ => "tar.gz",
|
||||||
|
};
|
||||||
|
let version = &self.version;
|
||||||
|
let os = &self.platform.os;
|
||||||
|
let arch = &self.platform.arch;
|
||||||
|
|
||||||
|
format!("{CLI_BASE_URL}/{version}/dagger_v{version}_{os}_{arch}.{ext}")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checksum_url(&self) -> String {
|
||||||
|
let version = &self.version;
|
||||||
|
|
||||||
|
format!("{CLI_BASE_URL}/{version}/checksums.txt")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cache_dir(&self) -> eyre::Result<PathBuf> {
|
||||||
|
let env = std::env::var("XDG_CACHE_HOME").unwrap_or("".into());
|
||||||
|
let env = env.trim();
|
||||||
|
let mut path = match env {
|
||||||
|
"" => dirs::cache_dir().ok_or(eyre::anyhow!(
|
||||||
|
"could not find cache_dir, either in env or XDG_CACHE_HOME"
|
||||||
|
))?,
|
||||||
|
path => PathBuf::from(path),
|
||||||
|
};
|
||||||
|
|
||||||
|
path.push("dagger");
|
||||||
|
|
||||||
|
std::fs::create_dir_all(&path)?;
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cli(&self) -> eyre::Result<PathBuf> {
|
||||||
|
let version = &self.version;
|
||||||
|
let mut cli_bin_path = self.cache_dir()?;
|
||||||
|
cli_bin_path.push(format!("{CLI_BIN_PREFIX}{version}"));
|
||||||
|
if self.platform.os == "windows" {
|
||||||
|
cli_bin_path = cli_bin_path.with_extension("exe")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cli_bin_path.exists() {
|
||||||
|
cli_bin_path = self
|
||||||
|
.download(cli_bin_path)
|
||||||
|
.context("failed to download CLI from archive")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in self.cache_dir()?.read_dir()? {
|
||||||
|
if let Ok(entry) = file {
|
||||||
|
let path = entry.path();
|
||||||
|
if path != cli_bin_path {
|
||||||
|
std::fs::remove_file(path)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cli_bin_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn download(&self, path: PathBuf) -> eyre::Result<PathBuf> {
|
||||||
|
let expected_checksum = self.expected_checksum()?;
|
||||||
|
|
||||||
|
let (actual_hash, tempbin) = self.extract_cli_archive()?;
|
||||||
|
|
||||||
|
if expected_checksum != actual_hash {
|
||||||
|
eyre::bail!("downloaded CLI binary checksum doesn't match checksum from checksums.txt")
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expected_checksum(&self) -> eyre::Result<String> {
|
||||||
|
let archive_url = &self.archive_url();
|
||||||
|
let archive_path = PathBuf::from(&archive_url);
|
||||||
|
let archive_name = archive_path
|
||||||
|
.file_name()
|
||||||
|
.ok_or(eyre::anyhow!("could not get file_name from archive_url"))?;
|
||||||
|
let resp = reqwest::blocking::get(self.checksum_url())?;
|
||||||
|
let resp = resp.error_for_status()?;
|
||||||
|
for line in resp.text()?.lines() {
|
||||||
|
let mut content = line.split_whitespace();
|
||||||
|
let checksum = content
|
||||||
|
.next()
|
||||||
|
.ok_or(eyre::anyhow!("could not find checksum in checksums.txt"))?;
|
||||||
|
let file_name = content
|
||||||
|
.next()
|
||||||
|
.ok_or(eyre::anyhow!("could not find file_name in checksums.txt"))?;
|
||||||
|
|
||||||
|
if file_name == archive_name {
|
||||||
|
return Ok(checksum.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eyre::bail!("could not find a matching version or binary in checksums.txt")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_cli_archive(&self) -> eyre::Result<(String, File)> {
|
||||||
|
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 (file, path) = temp.keep()?;
|
||||||
|
println!("path: {:?}", path);
|
||||||
|
|
||||||
|
let mut buf_writer = BufWriter::new(file);
|
||||||
|
let mut bytes = vec![];
|
||||||
|
let _ = resp.read_to_end(&mut bytes)?;
|
||||||
|
buf_writer.write_all(bytes.as_slice())?;
|
||||||
|
|
||||||
|
if archive_url.ends_with(".zip") {
|
||||||
|
// TODO: Nothing for now
|
||||||
|
} else {
|
||||||
|
//self.extract_from_tar(&temp)?;
|
||||||
|
}
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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)
|
||||||
|
}
|
||||||
|
}
|
4
src/lib.rs
Normal file
4
src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod cli;
|
||||||
|
pub mod dagger;
|
||||||
|
mod downloader;
|
||||||
|
mod schema;
|
0
src/schema.rs
Normal file
0
src/schema.rs
Normal file
18
tests/integration.rs
Normal file
18
tests/integration.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use rust::dagger;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_container() {
|
||||||
|
let client = dagger::connect().unwrap();
|
||||||
|
let alpine = client.container().from("alpine:3.16.2").unwrap();
|
||||||
|
let out = alpine
|
||||||
|
.exec(dagger::ContainerExecOpts {
|
||||||
|
args: vec!["cat", "/etc/alpine-release"],
|
||||||
|
})
|
||||||
|
.stdout()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!("3.16.2", out);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user