golem_cli/model/deploy_diff/
component.rs1use crate::model::app::AppComponentName;
16use crate::model::component::Component;
17use crate::model::deploy_diff::DiffSerialize;
18use crate::model::text::component::is_sensitive_env_var_name;
19use crate::model::ComponentName;
20use golem_client::model::{DynamicLinkedInstance, DynamicLinking};
21use golem_common::model::{ComponentFilePermissions, ComponentType};
22use serde::{Deserialize, Serialize};
23use std::collections::{BTreeMap, HashMap};
24
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
26#[serde(rename_all = "camelCase")]
27pub struct DiffableComponentFile {
28 pub hash: String,
29 pub permissions: ComponentFilePermissions,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
33#[serde(rename_all = "camelCase")]
34pub struct DiffableComponent {
35 pub component_name: ComponentName,
36 pub component_hash: String,
37 pub component_type: ComponentType,
38 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
39 pub files: BTreeMap<String, DiffableComponentFile>,
40 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
41 pub dynamic_linking: BTreeMap<String, BTreeMap<String, String>>,
42 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
43 pub env: BTreeMap<String, String>,
44}
45
46impl DiffableComponent {
47 pub fn from_server(
48 show_sensitive: bool,
49 component: &Component,
50 component_hash: String,
51 files: BTreeMap<String, DiffableComponentFile>,
52 ) -> anyhow::Result<Self> {
53 Ok(Self {
54 component_name: component.component_name.clone(),
55 component_hash,
56 component_type: component.component_type,
57 files,
58 dynamic_linking: component
59 .metadata
60 .dynamic_linking
61 .iter()
62 .map(|(name, link)| {
63 (
64 name.clone(),
65 match link {
66 golem_common::model::component_metadata::DynamicLinkedInstance::WasmRpc(links) => links
67 .targets
68 .iter()
69 .map(|(resource, target)| {
70 (resource.clone(), target.interface_name.clone())
71 })
72 .collect::<BTreeMap<String, String>>(),
73 },
74 )
75 })
76 .collect(),
77 env: masked_env(show_sensitive, &component.env),
78 })
79 }
80
81 pub fn from_manifest(
82 show_sensitive: bool,
83 component_name: &AppComponentName,
84 component_hash: String,
85 component_type: ComponentType,
86 files: BTreeMap<String, DiffableComponentFile>,
87 dynamic_linking: Option<&DynamicLinking>,
88 env: Option<&HashMap<String, String>>,
89 ) -> anyhow::Result<Self> {
90 Ok(DiffableComponent {
91 component_name: component_name.as_str().into(),
92 component_hash,
93 component_type,
94 files,
95 dynamic_linking: dynamic_linking
96 .iter()
97 .flat_map(|dl| {
98 dl.dynamic_linking.iter().map(|(name, instance)| {
99 (
100 name.clone(),
101 match instance {
102 DynamicLinkedInstance::WasmRpc(links) => links
103 .targets
104 .iter()
105 .map(|(resource, target)| {
106 (resource.clone(), target.interface_name.clone())
107 })
108 .collect::<BTreeMap<_, _>>(),
109 },
110 )
111 })
112 })
113 .collect(),
114 env: env
115 .map(|env| masked_env(show_sensitive, env))
116 .unwrap_or_default(),
117 })
118 }
119}
120
121impl DiffSerialize for DiffableComponent {
122 fn to_diffable_string(&self) -> anyhow::Result<String> {
123 Ok(serde_yaml::to_string(&self)?)
124 }
125}
126
127fn masked_env<'a, I: IntoIterator<Item = (&'a String, &'a String)>>(
128 show_sensitive: bool,
129 env: I,
130) -> BTreeMap<String, String> {
131 env.into_iter()
132 .map(|(k, v)| {
133 (
134 k.clone(),
135 if is_sensitive_env_var_name(show_sensitive, k) {
136 format!("<hashed-value:{}>", blake3::hash(v.as_bytes()).to_hex())
137 } else {
138 v.clone()
139 },
140 )
141 })
142 .collect()
143}