GitRoot

Craft your forge, Build your project, Grow your community freely
  1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
  2//
  3// SPDX-License-Identifier: MIT
  4
  5use std::{
  6    collections::HashMap,
  7    sync::{OnceLock, RwLock},
  8};
  9
 10use crate::{
 11    fs::{Fs, FsBase},
 12    httpclient::HttpClient,
 13    imports::{self, call, can_call},
 14    model::{Call, Commit, Exec, ExecStatus, ForgeConf, PluginRun, ReportLevel, ReportToGitroot},
 15};
 16
 17pub type CallbackFn =
 18    Box<dyn Fn(HashMap<String, String>) -> Result<HashMap<String, String>, String> + Send + Sync>;
 19
 20pub struct Server {
 21    pub run: Vec<PluginRun>,
 22    exported_funcs: RwLock<HashMap<String, CallbackFn>>,
 23    worktree_fs: OnceLock<Fs>,
 24    webcontent_fs: OnceLock<Fs>,
 25    cache_fs: OnceLock<Fs>,
 26}
 27
 28impl Server {
 29    pub fn new(run: Vec<PluginRun>) -> Self {
 30        Server {
 31            run,
 32            exported_funcs: RwLock::new(HashMap::new()),
 33            worktree_fs: OnceLock::new(),
 34            webcontent_fs: OnceLock::new(),
 35            cache_fs: OnceLock::new(),
 36        }
 37    }
 38
 39    pub fn forge_conf(&self) -> Result<ForgeConf, String> {
 40        imports::forge_conf()
 41    }
 42
 43    pub fn worktree(&self) -> &Fs {
 44        self.worktree_fs.get_or_init(|| Fs::new(FsBase::WORKTREE))
 45    }
 46
 47    pub fn webcontent(&self) -> &Fs {
 48        self.webcontent_fs
 49            .get_or_init(|| Fs::new(FsBase::WEBCONTENT))
 50    }
 51
 52    pub fn cache(&self) -> &Fs {
 53        self.cache_fs.get_or_init(|| Fs::new(FsBase::CACHE))
 54    }
 55
 56    pub fn commit_all_if_needed(&self, message: String) {
 57        imports::commit_all(message);
 58    }
 59
 60    pub fn diff_with_parent(
 61        &self,
 62        hash: String,
 63        old_filepath: String,
 64        new_filepath: String,
 65    ) -> Result<String, String> {
 66        imports::diff_with_parent(hash, old_filepath, new_filepath)
 67    }
 68
 69    pub fn log<S>(&self, message: S)
 70    where
 71        S: AsRef<str>,
 72    {
 73        imports::log(message.as_ref());
 74    }
 75
 76    pub fn log_error<S, K>(&self, message: S, err: K)
 77    where
 78        S: AsRef<str>,
 79        K: AsRef<str>,
 80    {
 81        imports::log_error(message.as_ref(), err.as_ref());
 82    }
 83
 84    pub fn merge(&self, from: String, to: String) {
 85        imports::merge(from, to);
 86    }
 87
 88    pub fn commits(&self, from: String, to: String) -> Result<Vec<Commit>, String> {
 89        imports::commits(from, to)
 90    }
 91
 92    pub fn exec(&self, cmd: &Exec) -> Result<ExecStatus, String> {
 93        imports::exec(cmd)
 94    }
 95
 96    pub fn report(&self, level: ReportLevel, content: Vec<String>) {
 97        imports::report_to_gitroot(ReportToGitroot { level, content })
 98    }
 99
100    pub fn export_func<S, F>(&self, name: S, callback: F)
101    where
102        S: Into<String>,
103        F: Fn(HashMap<String, String>) -> Result<HashMap<String, String>, String>
104            + Send
105            + Sync
106            + 'static,
107    {
108        let mut cb_map = self.exported_funcs.write().unwrap();
109        cb_map.insert(name.into(), Box::new(callback));
110    }
111
112    pub(crate) fn call_internal_func(&self, c: Call) -> Result<HashMap<String, String>, String> {
113        let cb_map = self.exported_funcs.read().unwrap();
114        match cb_map.get(&c.name) {
115            Some(func) => func(c.args),
116            None => Err("func not found".to_string()),
117        }
118    }
119
120    pub fn can_call_func(&self, c: Call) -> bool {
121        can_call(&c) != 0
122    }
123
124    pub fn call_func(&self, c: Call) -> Result<HashMap<String, String>, String> {
125        call(&c).map(|r| r.res)
126    }
127
128    pub fn http_client(&self, header: HashMap<String, Vec<String>>) -> HttpClient {
129        return HttpClient::new(header);
130    }
131}