1use {
2 crate::error_codes::{ErrorCode::UnsupportedRunner, ErrorResponse},
3 serde::{Deserialize, Serialize},
4 serde_repr::{Deserialize_repr, Serialize_repr},
5 std::{
6 fmt::{self, Display, Formatter},
7 fs,
8 path::PathBuf,
9 },
10};
11
12#[derive(Debug, Deserialize_repr, Serialize_repr, Clone, Copy, PartialEq, Default)]
13#[repr(u8)]
14#[tsync::tsync]
15pub enum Runner {
16 #[default]
17 NodeJs = 0,
18 Static = 1,
21 Ruby = 2,
22 Swift = 3,
23 Monorepo = 255,
24}
25
26impl Display for Runner {
27 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
28 match self {
29 Runner::NodeJs => write!(f, "NodeJs"),
30 Runner::Static => write!(f, "Static"),
31 Runner::Ruby => write!(f, "Ruby"),
32 Runner::Swift => write!(f, "Swift"),
33 Runner::Monorepo => write!(f, "Monorepo"),
34 }
35 }
36}
37
38#[derive(Debug, Serialize, Deserialize)]
39#[tsync::tsync]
40pub enum NodeJsFramework {
41 NextJs,
42 Astro,
43}
44
45#[derive(Debug, Serialize, Deserialize)]
46#[tsync::tsync]
47pub enum RubyFramework {
48 Rails,
49}
50
51#[derive(Debug, Serialize, Deserialize)]
52#[tsync::tsync]
53pub enum SwiftFramework {
54 Vapor,
55}
56
57impl Runner {
58 pub fn from(repo_path: &PathBuf) -> Result<Runner, ErrorResponse> {
59 if repo_path.join("package.json").exists()
61 && (next_config_exists(repo_path) || astro_config_exists(repo_path))
62 {
63 return Ok(Runner::NodeJs);
64 }
65
66 if repo_path.join("Gemfile").exists() {
67 return Ok(Runner::Ruby);
68 }
69 if repo_path.join("Package.swift").exists() {
70 return Ok(Runner::Swift);
71 }
72 non_framework_runner()
74 }
75
76 pub fn git_host(&self) -> String {
77 format!("git@{}.smbcloud.xyz", self.api())
78 }
79
80 pub fn rsync_host(&self) -> String {
83 format!("{}.smbcloud.xyz", self.api())
84 }
85
86 fn api(&self) -> &str {
87 match self {
88 Runner::Monorepo => "monorepo",
89 Runner::NodeJs | Runner::Static => "api",
91 Runner::Ruby | Runner::Swift => "api-1",
92 }
93 }
94}
95
96fn non_framework_runner() -> Result<Runner, ErrorResponse> {
97 Err(ErrorResponse::Error {
98 error_code: UnsupportedRunner,
99 message: UnsupportedRunner.message(None).to_string(),
100 })
101}
102
103fn next_config_exists(repo_path: &PathBuf) -> bool {
105 if let Ok(entries) = fs::read_dir(repo_path) {
106 for entry in entries.flatten() {
107 let filename = entry.file_name();
108 let filename_str = filename.to_string_lossy();
109 if filename_str.starts_with("next.config.") {
110 return true;
111 }
112 }
113 }
114 false
115}
116
117fn astro_config_exists(repo_path: &PathBuf) -> bool {
119 if let Ok(entries) = fs::read_dir(repo_path) {
120 for entry in entries.flatten() {
121 let filename = entry.file_name();
122 let filename_str = filename.to_string_lossy();
123 if filename_str.starts_with("astro.config.") {
124 return true;
125 }
126 }
127 }
128 false
129}