tfschema_bindgen/lib.rs
1//! This crate aims to compile schemas extracted from Terraform providers into Serde type definitions.
2//!
3//! ## Quick Start
4//!
5//! A Terraform schema is required for generating Rust types responsible of deserialization and serialization.
6//! It can either be exported from your Terraform configuration or manually generated.
7//! We'll take the latter approach, therefore defining a reference schema with just one provider type having one attribute:
8//!
9//! ```json
10//!{
11//! "provider_schemas": {
12//! "test_provider": {
13//! "provider": {
14//! "version": 0,
15//! "block": {
16//! "attributes": {
17//! "base_url": {
18//! "type": "string",
19//! "description": "The url.",
20//! "optional": true
21//! }
22//! }
23//! }
24//! }
25//! }
26//! },
27//! "format_version": "0.1"
28//!}
29//! ```
30//!
31//! In addition to a Rust library, this crate provides a binary tool `tfbindgen` to process Terraform schemas
32//! saved on disk.
33//! Outside of this repository, you may install the tool with:
34//!
35//! ```bash
36//! cargo install tfschema-bindgen
37//! ```
38//!
39//! Then use `$HOME/.cargo/bin/tfbindgen`.
40//!
41//! We're going to use this tool assuming that we're inside the repository.
42//!
43//! The following command will generate Serde bindings from the previous definitions, outputting those to `test.rs` module:
44//!
45//! ```bash
46//! cargo run --bin tfbindgen -- test.json > test.rs
47//! ```
48//!
49//! The following is a Rust example snippet comprising the previously generated bindings and a main function building on these in order
50//! deserialize a configuration descriptor adhering to our Terraform schema:
51//!
52//! ```
53//! #![allow(unused_imports, non_snake_case, non_camel_case_types, non_upper_case_globals)]
54//! use std::collections::BTreeMap as Map;
55//! use serde::{Serialize, Deserialize};
56//! use serde_bytes::ByteBuf as Bytes;
57//!
58//! #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize, Default)]
59//! pub struct config {
60//! #[serde(skip_serializing_if = "Option::is_none")]
61//! pub data: Option<Vec<data_root>>,
62//! #[serde(skip_serializing_if = "Option::is_none")]
63//! pub provider: Option<Vec<provider_root>>,
64//! #[serde(skip_serializing_if = "Option::is_none")]
65//! pub resource: Option<Vec<resource_root>>,
66//! }
67//!
68//! #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
69//! pub enum data_root {
70//! }
71//!
72//! #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
73//! pub enum provider_root {
74//! test_provider(Vec<test_provider_details>),
75//! }
76//!
77//! #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
78//! pub enum resource_root {
79//! }
80//!
81//! #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize, Default)]
82//! pub struct test_provider_details {
83//! #[serde(skip_serializing_if = "Option::is_none")]
84//! pub base_url: Option<String>,
85//! }
86//!
87//! const TF_JSON_CONFIG: &str = r#"{
88//! "provider": [
89//! {
90//! "test_provider": [
91//! {
92//! "base_url": "https://acme.com/foo"
93//! }
94//! ]
95//! }
96//! ]
97//! }"#;
98//!
99//! fn main() -> Result<(), std::io::Error> {
100//! let res: config = serde_json::from_str(TF_JSON_CONFIG).unwrap();
101//!
102//! assert_eq!(res.provider.as_ref().map(|x| x.is_empty()), Some(false));
103//! assert_eq!(
104//! res.provider.as_ref().map(|x| x.get(0).is_none()),
105//! Some(false)
106//! );
107//! let prv = res
108//! .provider
109//! .as_ref()
110//! .and_then(|x| x.get(0))
111//! .and_then(|x| match x {
112//! provider_root::test_provider(p) => p.get(0),
113//! });
114//! assert_eq!(prv.is_none(), false);
115//! assert_eq!(
116//! prv.and_then(|x| x.base_url.to_owned()),
117//! Some("https://acme.com/foo".to_owned())
118//! );
119//! print!("success!\n");
120//! Ok(())
121//! }
122//! ```
123//! ## Quickstart Example
124//!
125//! In addition to a Rust library and generation tool, this crate provides the above example which
126//! can be executed using the following command:
127//!
128//! ```bash
129//! cargo run --example quickstart
130//! ```
131//!
132//! ## Consuming third-party Terraform schemas
133//!
134//! In order to operate on Terraform configuration descriptors of third-party providers, Rust bindings have to be generated using the
135//! provided schema descriptor in the JSON format.
136//!
137//! Firstly, create a minimal Terraform configuration declaring the target provider. The following is an example for enabling
138//! the Amazon Web Services (AWS) Terraform provider:
139//!
140//! ```code
141//! provider "aws" {
142//! version = ">= 2.31.0, < 3.0"
143//!}
144//! ```
145//!
146//! Initialize Terraform so that configured providers are installed in the local environment:
147//!
148//! ```bash
149//! terraform init
150//! ```
151//!
152//! Secondly, extract the schema for the providers defined in the Terraform configuration, AWS in this case:
153//!
154//! ```bash
155//! terraform providers schema -json > aws-provider-schema.json
156//! ```
157//!
158//! Finally, generate the Rust (de)serialization types for the given provider using the following command (assuming you are inside the repository):
159//!
160//! ```bash
161//! cargo run --bin tfbindgen -- aws-provider-schema.json > aws_provider_schema.rs
162//! ```
163//!
164//! In order do (de)serialize provider's configuration, import the generated module in your application.
165//!
166
167// registry creation
168pub mod binding;
169
170// code generator
171pub mod emit;
172
173// configuraiton support for code generation
174pub mod config;
175
176/// Utility functions to help testing code generators.
177#[doc(hidden)]
178pub mod test_utils;