Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
radicle-desktop crates radicle-tauri src commands repo.rs
use std::collections::BTreeSet;
use std::str::FromStr;

use radicle::git;
use radicle::identity::project::ProjectName;
use radicle::identity::{doc, Project, RepoId, Visibility};
use radicle::rad::InitError;
use radicle::storage::git::Repository;
use radicle::storage::refs::branch_of;
use radicle::storage::{SignRepository, WriteRepository};
use radicle_types as types;
use radicle_types::error::Error;
use radicle_types::traits::repo::{Repo, Show};

use crate::AppState;

#[tauri::command]
pub fn list_repos(
    ctx: tauri::State<AppState>,
    show: Show,
) -> Result<Vec<types::repo::RepoInfo>, Error> {
    ctx.list_repos(show)
}

#[tauri::command]
pub fn list_repos_summary(
    ctx: tauri::State<AppState>,
) -> Result<Vec<types::repo::RepoSummary>, Error> {
    ctx.list_repos_summary()
}

#[tauri::command]
pub fn repo_count(ctx: tauri::State<AppState>) -> Result<types::repo::RepoCount, Error> {
    ctx.repo_count()
}

#[tauri::command]
pub fn repo_by_id(
    ctx: tauri::State<AppState>,
    rid: RepoId,
) -> Result<types::repo::RepoInfo, Error> {
    ctx.repo_by_id(rid)
}

#[tauri::command]
pub fn repo_readme(
    ctx: tauri::State<AppState>,
    rid: RepoId,
    sha: Option<git::Oid>,
) -> Result<Option<types::repo::Readme>, Error> {
    ctx.repo_readme(rid, sha)
}

#[tauri::command]
pub fn repo_tree(
    ctx: tauri::State<AppState>,
    rid: RepoId,
    path: std::path::PathBuf,
) -> Result<types::source::tree::Tree, Error> {
    ctx.repo_tree(rid, path)
}

#[tauri::command]
pub fn repo_blob(
    ctx: tauri::State<AppState>,
    rid: RepoId,
    path: std::path::PathBuf,
) -> Result<types::source::blob::Blob, Error> {
    ctx.repo_blob(rid, path)
}

#[tauri::command]
pub async fn diff_stats(
    ctx: tauri::State<'_, AppState>,
    rid: RepoId,
    base: git::Oid,
    head: git::Oid,
) -> Result<types::diff::Stats, Error> {
    ctx.diff_stats(rid, base, head)
}

#[tauri::command]
pub async fn list_commits(
    ctx: tauri::State<'_, AppState>,
    rid: RepoId,
    base: String,
    head: String,
) -> Result<Vec<types::repo::Commit>, Error> {
    ctx.list_commits(rid, base, head)
}

#[tauri::command]
pub async fn get_commit_diff(
    ctx: tauri::State<'_, AppState>,
    rid: RepoId,
    sha: git::Oid,
    unified: Option<u32>,
    highlight: Option<bool>,
) -> Result<types::diff::Diff, Error> {
    ctx.get_commit_diff(rid, sha, unified, highlight)
}

#[tauri::command]
pub async fn list_repo_commits(
    ctx: tauri::State<'_, AppState>,
    rid: RepoId,
    head: Option<git::Oid>,
    skip: Option<usize>,
    take: Option<usize>,
) -> Result<types::cobs::PaginatedQuery<Vec<types::repo::Commit>>, Error> {
    ctx.list_repo_commits(rid, head, skip, take)
}

#[tauri::command]
pub fn repo_commit_count(
    ctx: tauri::State<AppState>,
    rid: RepoId,
    head: git::Oid,
) -> Result<usize, Error> {
    ctx.repo_commit_count(rid, head)
}

#[tauri::command]
pub fn repo_commit(
    ctx: tauri::State<AppState>,
    rid: RepoId,
    sha: git::Oid,
) -> Result<types::repo::Commit, Error> {
    ctx.repo_commit(rid, sha)
}

#[tauri::command]
pub(crate) async fn create_repo(
    ctx: tauri::State<'_, AppState>,
    name: String,
    description: String,
) -> Result<(), Error> {
    let profile = &ctx.profile;
    let storage = &profile.storage;
    let signer = ctx.profile.signer()?;
    let config = git2::Config::open_default()?;
    // SAFETY: "master" is always a valid RefString
    let default_branch = git::fmt::RefString::try_from(
        config
            .get_string("init.defaultBranch")
            .unwrap_or("master".to_owned()),
    )
    .unwrap();

    let name = ProjectName::from_str(&name)?;
    if description.len() > doc::MAX_STRING_LENGTH {
        return Err(Error::ProjectError(
            radicle::identity::project::ProjectError::Description("Cannot exceed 255 characters."),
        ));
    }

    let visibility = Visibility::Private {
        allow: BTreeSet::default(),
    };

    let proj = Project::new(name, description, default_branch.clone()).map_err(|errs| {
        InitError::ProjectPayload(
            errs.into_iter()
                .map(|err| err.to_string())
                .collect::<Vec<_>>()
                .join(", "),
        )
    })?;
    let doc = radicle::identity::Doc::initial(proj, profile.public_key.into(), visibility);
    let (project, identity) = Repository::init(&doc, &storage, &signer)?;

    let tree_id = {
        let mut index = project.backend.index()?;

        index.write_tree()
    }?;
    let sig = project.backend.signature()?;
    let tree = project.backend.find_tree(tree_id)?;

    project.set_remote_identity_root_to(signer.public_key(), identity)?;
    project.set_identity_head_to(identity)?;

    let base = project
        .backend
        .commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])?;

    let ns_head = branch_of(&ctx.profile.public_key, &default_branch);
    project
        .backend
        .reference(ns_head.as_str(), base, false, "Created namespace ref")?;

    project.set_head()?;
    project.sign_refs(&signer)?;

    Ok(())
}

#[tauri::command]
pub fn seed(ctx: tauri::State<AppState>, rid: RepoId) -> Result<(), Error> {
    ctx.seed(rid)
}

#[tauri::command]
pub fn unseed(ctx: tauri::State<AppState>, rid: RepoId) -> Result<(), Error> {
    ctx.unseed(rid)
}

#[tauri::command]
pub fn seeded_not_replicated(ctx: tauri::State<AppState>) -> Result<Vec<RepoId>, Error> {
    ctx.seeded_not_replicated()
}