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