1use crate::models::{HelpMetadata, ScopeModel};
2use derive_builder::Builder;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::collections::BTreeMap;
6
7pub const FILE_PATH_ANNOTATION: &str = "scope.github.com/file-path";
8pub const FILE_DIR_ANNOTATION: &str = "scope.github.com/file-dir";
9pub const FILE_EXEC_PATH_ANNOTATION: &str = "scope.github.com/bin-path";
10
11#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Builder, JsonSchema)]
12pub struct ModelMetadataAnnotations {
13 #[serde(rename = "scope.github.com/file-path")]
14 #[schemars(skip)]
15 pub file_path: Option<String>,
17 #[serde(rename = "scope.github.com/file-dir")]
18 #[schemars(skip)]
19 pub file_dir: Option<String>,
21 #[serde(rename = "scope.github.com/bin-path")]
22 pub bin_path: Option<String>,
24 #[serde(flatten)]
25 pub extra: BTreeMap<String, String>,
26}
27
28impl ModelMetadata {
29 pub fn name(&self) -> String {
30 self.name.to_string()
31 }
32
33 pub fn description(&self) -> String {
34 self.description.to_string()
35 }
36
37 pub fn file_path(&self) -> String {
38 match &self.annotations.file_path {
39 Some(v) => v.to_string(),
40 None => "unknown".to_string(),
41 }
42 }
43
44 pub fn containing_dir(&self) -> String {
45 match &self.annotations.file_dir {
46 Some(v) => v.to_string(),
47 None => "unknown".to_string(),
48 }
49 }
50
51 pub fn exec_path(&self) -> String {
52 match &self.annotations.bin_path {
53 Some(v) => {
54 format!(
55 "{}:{}",
56 v,
57 std::env::var("PATH").unwrap_or_else(|_| "".to_string())
58 )
59 }
60 None => std::env::var("PATH").unwrap_or_else(|_| "".to_string()),
61 }
62 }
63
64 pub fn new(name: &str) -> ModelMetadata {
65 Self {
66 name: name.to_string(),
67 ..Default::default()
68 }
69 }
70}
71
72#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Builder, JsonSchema)]
73#[builder(setter(into))]
74pub struct ModelMetadata {
75 pub name: String,
78
79 #[serde(default = "default_description")]
80 pub description: String,
83
84 #[serde(default)]
85 pub annotations: ModelMetadataAnnotations,
87
88 #[serde(default)]
89 pub labels: BTreeMap<String, String>,
91}
92
93fn default_description() -> String {
94 "Description not provided".to_string()
95}
96
97#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Builder)]
98#[builder(setter(into))]
99#[serde(rename_all = "camelCase")]
100pub struct ModelRoot<V> {
101 pub api_version: String,
102 pub kind: String,
103 pub metadata: ModelMetadata,
104 pub spec: V,
105}
106
107impl<S> HelpMetadata for ModelRoot<S> {
108 fn metadata(&self) -> &ModelMetadata {
109 &self.metadata
110 }
111
112 fn full_name(&self) -> String {
113 format!("{}/{}", self.kind, self.name())
114 }
115}
116
117impl<S> ScopeModel<S> for ModelRoot<S> {
118 fn api_version(&self) -> String {
119 self.api_version.to_string()
120 }
121
122 fn kind(&self) -> String {
123 self.kind.to_string()
124 }
125
126 fn spec(&self) -> &S {
127 &self.spec
128 }
129}