use std::borrow::{Borrow, BorrowMut};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use tf_bindgen_schema::document::{Meta, Metadata, ProviderConfig, Terraform};
use tf_bindgen_schema::Document;
use crate::{L1Construct, Path, Provider, Scope};
#[derive(Clone)]
pub struct Stack {
inner: Rc<InnerStack>,
}
struct InnerStack {
name: String,
provider: RefCell<Vec<Rc<dyn Provider>>>,
resources: RefCell<Vec<Rc<dyn L1Construct>>>,
data_sources: RefCell<Vec<Rc<dyn L1Construct>>>,
}
impl Stack {
pub fn new(name: impl Into<String>) -> Rc<Self> {
Rc::new(Self {
inner: Rc::new(InnerStack {
name: name.into(),
provider: RefCell::new(Vec::new()),
resources: RefCell::new(Vec::new()),
data_sources: RefCell::new(Vec::new()),
}),
})
}
pub fn name(&self) -> &str {
&self.inner.name
}
pub fn add_provider(&self, provider: Rc<dyn Provider>) {
self.inner.provider.borrow_mut().push(provider)
}
pub fn add_resource(&self, resource: Rc<dyn L1Construct>) {
self.inner.resources.borrow_mut().push(resource)
}
pub fn add_data_source(&self, data_source: Rc<dyn L1Construct>) {
self.inner.data_sources.borrow_mut().push(data_source)
}
pub fn to_document(&self) -> Document {
let mut document = Document {
meta: Meta {
metadata: Metadata {
backend: "local".to_string(),
stack_name: self.name().to_string(),
version: tf_bindgen_schema::VERSION.to_string(),
},
outputs: HashMap::default(),
},
terraform: Terraform {
required_providers: HashMap::default(),
},
provider: HashMap::default(),
resource: HashMap::default(),
data: HashMap::default(),
};
for provider in self.inner.provider.borrow().iter() {
let path = provider.path();
let name = path.name();
let local_name = name.split('/').last().unwrap();
let (version, schema) = provider.to_schema();
let config = ProviderConfig {
source: name.to_string(),
version,
};
document
.terraform
.required_providers
.insert(local_name.to_string(), config);
if !document.provider.borrow().contains_key(local_name) {
document
.provider
.borrow_mut()
.insert(local_name.to_string(), Vec::new());
}
document
.provider
.borrow_mut()
.get_mut(local_name)
.unwrap()
.push(schema);
}
for resource in self.inner.resources.borrow().iter() {
let path = resource.path();
let key = path.id();
let (ty, schema) = resource.to_schema();
if !document.resource.contains_key(&ty) {
document.resource.insert(ty.clone(), HashMap::new());
}
if document
.resource
.get_mut(&ty)
.unwrap()
.insert(key, schema)
.is_some()
{
panic!("resource '{path}' already exists");
}
}
for data_source in self.inner.data_sources.borrow().iter() {
let path = data_source.path();
let key = path.id();
let (ty, schema) = data_source.to_schema();
if !document.data.contains_key(&ty) {
document.data.insert(ty.clone(), HashMap::new());
}
if document
.data
.get_mut(&ty)
.unwrap()
.insert(key, schema)
.is_some()
{
panic!("data source '{path}' already exists");
}
}
document
}
}
impl Scope for Stack {
fn stack(&self) -> Stack {
self.clone()
}
fn path(&self) -> crate::Path {
Path::from(self.name().to_string())
}
}