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