dev_scope/models/
core.rs

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    /// File path for the resource, generated automatically.
16    pub file_path: Option<String>,
17    #[serde(rename = "scope.github.com/file-dir")]
18    #[schemars(skip)]
19    /// Directory containing the resource, generated automatically.
20    pub file_dir: Option<String>,
21    #[serde(rename = "scope.github.com/bin-path")]
22    /// When running commands, additional paths that should be paced at the _beginning_ of the `PATH`.
23    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    /// Name of the resource, needs to be unique across `kinds`. When two resources share a name,
76    /// the one "closest" to the current working directory will take precedence.
77    pub name: String,
78
79    #[serde(default = "default_description")]
80    /// Description of this resource, used when listing resources and helpful to inform users why
81    /// the resource exists.
82    pub description: String,
83
84    #[serde(default)]
85    /// Annotations attach arbitrary non-identifying metadata to objects.
86    pub annotations: ModelMetadataAnnotations,
87
88    #[serde(default)]
89    /// Key/value pairs, allows resources to be easily filtered from the CLI.
90    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}