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}