From 201709c360be526dd74fec652ebd3f11fe89d87f Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 28 Sep 2024 14:00:00 -0400 Subject: [PATCH] Construct the response to listing the tree in gitea. --- src/gitea_client/error.rs | 25 +++++++++++++++++++++++ src/gitea_client/mod.rs | 43 +++++++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 src/gitea_client/error.rs diff --git a/src/gitea_client/error.rs b/src/gitea_client/error.rs new file mode 100644 index 0000000..d4c4a84 --- /dev/null +++ b/src/gitea_client/error.rs @@ -0,0 +1,25 @@ +use std::error::Error; + +#[derive(Debug, Clone)] +pub(crate) enum GiteaClientError { + Static(#[allow(dead_code)] &'static str), + String(#[allow(dead_code)] String), + NoTotalCountHeaderInResponse, +} + +impl std::fmt::Display for GiteaClientError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + GiteaClientError::Static(s) => write!(f, "GiteaClientError: {}", s), + GiteaClientError::String(s) => write!(f, "GiteaClientError: {}", s), + GiteaClientError::NoTotalCountHeaderInResponse => { + write!( + f, + "GiteaClientError: No x-total-count header returned in gitea response.", + ) + } + } + } +} + +impl Error for GiteaClientError {} diff --git a/src/gitea_client/mod.rs b/src/gitea_client/mod.rs index 41c051e..68998db 100644 --- a/src/gitea_client/mod.rs +++ b/src/gitea_client/mod.rs @@ -1,5 +1,7 @@ use serde::Deserialize; -use tracing::debug; + +use self::error::GiteaClientError; +pub(crate) mod error; #[derive(Debug, Clone)] pub(crate) struct GiteaClient { @@ -25,6 +27,7 @@ impl GiteaClient { ) -> Result> { let mut files = Vec::new(); let mut page: Option = None; + let mut num_responses: u64 = 0; loop { let url = format!( "{api_root}/v1/repos/{owner}/{repo}/git/trees/{commit}?recursive=true&per_page=10{page}", @@ -41,16 +44,28 @@ impl GiteaClient { .send() .await?; let response = response.error_for_status()?; - let body = response.text().await?; - debug!("Response: {}", body); - let parsed_body: ResponseGetTree = serde_json::from_str(body.as_str())?; - println!("Response: {:#?}", parsed_body); - // TODO: Read response objects + let total_count = response + .headers() + .get("x-total-count") + .ok_or(GiteaClientError::NoTotalCountHeaderInResponse)? + .to_str()? + .parse::()?; + if num_responses == 0 { + files.reserve(total_count as usize); + } - if !parsed_body.truncated { + let body = response.text().await?; + let parsed_body: ResponseGetTree = serde_json::from_str(body.as_str())?; + num_responses += parsed_body.tree.len() as u64; + + files.extend(parsed_body.tree.into_iter().map(|response_object| { + TreeFileReference::new(response_object.path, response_object.url) + })); + + if num_responses >= total_count { break; } - // TODO: Switch to using response headers instead of response body. + page = Some(parsed_body.page + 1); } Ok(Tree::new(files)) @@ -85,7 +100,10 @@ pub(crate) struct Tree { } #[derive(Debug)] -pub(crate) struct TreeFileReference {} +pub(crate) struct TreeFileReference { + path: String, + url: String, +} impl Tree { pub(crate) fn new(files: Vec) -> Tree { @@ -94,7 +112,10 @@ impl Tree { } impl TreeFileReference { - pub(crate) fn new() -> TreeFileReference { - TreeFileReference {} + pub(crate) fn new, U: Into>(path: P, url: U) -> TreeFileReference { + TreeFileReference { + path: path.into(), + url: url.into(), + } } }