multiversx_sc_meta_lib/contract/generate_snippets/
snippet_crate_gen.rs1use colored::Colorize;
2use std::{
3 fs::{self, File, OpenOptions},
4 io::Write,
5 path::{Path, PathBuf},
6};
7
8use crate::version_history;
9
10static SNIPPETS_SOURCE_FILE_NAME: &str = "interactor_main.rs";
11static LIB_SOURCE_FILE_NAME: &str = "interact.rs";
12static SC_CONFIG_FILE_NAME: &str = "sc-config.toml";
13static CONFIG_TOML_PATH: &str = "config.toml";
14static CONFIG_SOURCE_FILE_NAME: &str = "config.rs";
15static INTERACTOR_CS_TEST_FILE_NAME: &str = "interact_cs_tests.rs";
16static INTERACTOR_TEST_FILE_NAME: &str = "interact_tests.rs";
17
18pub(crate) fn create_snippets_folder(snippets_folder_path: &PathBuf) {
19 let _ = fs::create_dir(snippets_folder_path);
20}
21
22pub(crate) fn create_snippets_gitignore(snippets_folder_path: &Path, overwrite: bool) {
23 let gitignore_path = snippets_folder_path.join(".gitignore");
24 let mut file = if overwrite {
25 File::create(&gitignore_path).unwrap()
26 } else {
27 match File::options()
28 .create_new(true)
29 .write(true)
30 .open(&gitignore_path)
31 {
32 Ok(f) => f,
33 Err(_) => return,
34 }
35 };
36
37 writeln!(
38 &mut file,
39 "# Pem files are used for interactions, but shouldn't be committed
40*.pem"
41 )
42 .unwrap();
43}
44
45pub(crate) fn create_snippets_cargo_toml(
46 snippets_folder_path: &Path,
47 contract_crate_name: &str,
48 overwrite: bool,
49) {
50 let contract_deps = contract_crate_name.replace("_", "-");
51 let cargo_toml_path = snippets_folder_path.join("Cargo.toml");
52 let mut file = if overwrite {
53 File::create(&cargo_toml_path).unwrap()
54 } else {
55 match File::options()
56 .create_new(true)
57 .write(true)
58 .open(&cargo_toml_path)
59 {
60 Ok(f) => f,
61 Err(_) => return,
62 }
63 };
64
65 let last_release_version = &version_history::LAST_VERSION;
66
67 writeln!(
68 &mut file,
69 r#"[package]
70name = "rust-interact"
71version = "0.0.0"
72authors = ["you"]
73edition = "2024"
74publish = false
75
76[[bin]]
77name = "rust-interact"
78path = "src/{SNIPPETS_SOURCE_FILE_NAME}"
79
80[lib]
81path = "src/{LIB_SOURCE_FILE_NAME}"
82
83[dependencies.{contract_deps}]
84path = ".."
85
86[dependencies.multiversx-sc-snippets]
87version = "{last_release_version}"
88
89[dependencies.multiversx-sc]
90version = "{last_release_version}"
91
92[dependencies]
93clap = {{ version = "4.4.7", features = ["derive"] }}
94serde = {{ version = "1.0", features = ["derive"] }}
95toml = "0.9"
96
97[features]
98chain-simulator-tests = []
99"#
100 )
101 .unwrap();
102}
103
104pub(crate) fn create_src_folder(snippets_folder_path: &Path) {
105 let src_folder_path = snippets_folder_path.join("src");
107 let _ = fs::create_dir(src_folder_path);
108}
109
110#[must_use]
111pub(crate) fn create_and_get_lib_file(snippets_folder_path: &Path, overwrite: bool) -> File {
112 let lib_path = snippets_folder_path.join("src").join(LIB_SOURCE_FILE_NAME);
113 if overwrite {
114 File::create(&lib_path).unwrap()
115 } else {
116 match File::options().create_new(true).write(true).open(&lib_path) {
117 Ok(f) => f,
118 Err(_) => {
119 println!(
120 "{}",
121 format!(
122 "{lib_path:#?} file already exists, --overwrite option was not provided",
123 )
124 .yellow()
125 );
126 File::options().write(true).open(&lib_path).unwrap()
127 }
128 }
129 }
130}
131
132pub(crate) fn create_main_file(snippets_folder_path: &Path, contract_crate_name: &str) {
133 let lib_path = snippets_folder_path
134 .join("src")
135 .join(SNIPPETS_SOURCE_FILE_NAME);
136
137 let mut file = File::create(lib_path).unwrap();
138
139 writeln!(
140 &mut file,
141 r#"
142use multiversx_sc_snippets::imports::*;
143use rust_interact::{contract_crate_name}_cli;
144
145#[tokio::main]
146async fn main() {{
147 {contract_crate_name}_cli().await;
148}}
149"#
150 )
151 .unwrap();
152}
153
154pub(crate) fn create_test_folder_and_get_files(snippets_folder_path: &Path) -> (File, File) {
155 let folder_path = snippets_folder_path.join("tests");
156
157 if !Path::new(&folder_path).exists() {
158 fs::create_dir_all(&folder_path).expect("Failed to create tests directory");
159 }
160
161 let interactor_file_path = folder_path.join(INTERACTOR_TEST_FILE_NAME);
162 let interactor_cs_file_path = folder_path.join(INTERACTOR_CS_TEST_FILE_NAME);
163
164 let interactor_file =
165 File::create(interactor_file_path).expect("Failed to create interact_tests.rs file");
166 let interactor_cs_file =
167 File::create(interactor_cs_file_path).expect("Failed to create interact_cs_tests.rs file");
168
169 (interactor_file, interactor_cs_file)
170}
171
172pub(crate) fn create_sc_config_file(overwrite: bool, contract_crate_name: &str) {
173 let sc_config_path = Path::new("..").join(SC_CONFIG_FILE_NAME);
174 let proxy_name = format!("{}_proxy.rs", contract_crate_name.replace("-", "_"),);
175
176 let mut file = if overwrite || !sc_config_path.exists() {
178 File::create(sc_config_path).unwrap()
179 } else {
180 let mut file = OpenOptions::new()
182 .read(true)
183 .append(true)
184 .open(&sc_config_path)
185 .unwrap();
186
187 if file_contains_proxy_path(&sc_config_path, &proxy_name).unwrap_or(false) {
188 return;
189 }
190
191 writeln!(&mut file).unwrap();
192
193 file
194 };
195
196 let full_proxy_entry = r#"[[proxy]]
199path = "interactor/src"#;
200
201 writeln!(&mut file, "{full_proxy_entry}/{proxy_name}\"").unwrap();
203}
204
205pub(crate) fn create_config_toml_file(snippets_folder_path: &Path) {
206 let config_path = snippets_folder_path.join(CONFIG_TOML_PATH);
207 let mut file = File::create(config_path).unwrap();
208
209 writeln!(
210 &mut file,
211 r#"# chain_type = 'simulator'
212# gateway_uri = 'http://localhost:8085'
213
214chain_type = 'real'
215gateway_uri = 'https://devnet-gateway.multiversx.com'"#
216 )
217 .unwrap();
218}
219
220pub(crate) fn create_config_rust_file(snippets_folder_path: &Path) -> File {
221 let lib_path = snippets_folder_path
222 .join("src")
223 .join(CONFIG_SOURCE_FILE_NAME);
224
225 File::create(lib_path).unwrap()
226}
227
228fn file_contains_proxy_path(file_path: &PathBuf, proxy_name: &str) -> std::io::Result<bool> {
229 let file_content = fs::read_to_string(file_path)?;
230
231 let proxy_path = Path::new("interactor").join("src").join(proxy_name);
232 let proxy_entry = format!("path = \"{}\"", &proxy_path.to_string_lossy());
233
234 Ok(file_content.contains(&proxy_entry))
235}