git-gemini-forge 0.5.2

A simple Gemini server that serves a read-only view of public repositories from a Git forge.
use super::converters::{GitLabProjectContents, GitLabProjectContentsType};
use super::GitLabApi;
use crate::network::error;
use crate::network::get::{call, ApiEndpoint};
use crate::network::ForgeApi;
use std::cmp::Ordering;
use url::Url;

/// See https://docs.gitlab.com/ee/api/repositories.html#list-repository-tree
struct ContentsEndpoint {
	base_url: Url,
	project_id: String,
}

impl ApiEndpoint<Vec<GitLabProjectContents>> for ContentsEndpoint {
	fn url(&self) -> Url {
		let project_id = &self.project_id;
		return self
			.base_url
			.join(&format!("projects/{project_id}/repository/tree"))
			.unwrap();
	}
}

/// Retrieves a list of files for the given repository from the given API.
pub fn get_file_tree(
	api: &GitLabApi,
	project_id: String,
) -> Result<Vec<GitLabProjectContents>, error::Error> {
	let base_url = api.base_url().clone();
	let endpoint = ContentsEndpoint {
		base_url,
		project_id,
	};

	let mut contents = call(&endpoint)?;
	contents.sort_by(|a, b| {
		// Sort (file; alphabetically) before (dir; alphabetically)
		match a.kind {
			GitLabProjectContentsType::Blob => {
				match b.kind {
					GitLabProjectContentsType::Tree => return Ordering::Greater,
					GitLabProjectContentsType::Blob => {
						return a.name.to_lowercase().cmp(&b.name.to_lowercase())
					}
				};
			}
			GitLabProjectContentsType::Tree => {
				match b.kind {
					GitLabProjectContentsType::Blob => return Ordering::Less,
					GitLabProjectContentsType::Tree => {
						return a.name.to_lowercase().cmp(&b.name.to_lowercase())
					}
				};
			}
		};
	});
	return Ok(contents);
}