1use std::{
2 fs::{read_dir, read_to_string},
3 path::{Path, PathBuf},
4};
5
6use eyre::{Context, Result};
7use openvm_build::{get_in_scope_packages, get_workspace_packages};
8use openvm_sdk::config::AppConfig;
9use openvm_sdk_config::SdkVmConfig;
10use serde::de::DeserializeOwned;
11
12use crate::{
13 commands::RunCargoArgs,
14 default::{
15 default_app_config, BASELINE_JSON_EXT, COMMIT_JSON_EXT, DEFAULT_AGG_PREFIX_PK_NAME,
16 DEFAULT_APP_PK_NAME, DEFAULT_APP_VK_NAME,
17 },
18};
19
20pub fn evm_verifier_version_dir() -> String {
25 format!("v{}-base", openvm_sdk::OPENVM_VERSION)
26}
27
28pub(crate) fn read_to_struct_toml<T: DeserializeOwned>(path: impl AsRef<Path>) -> Result<T> {
29 let path = path.as_ref();
30 let toml = read_to_string(path)
31 .with_context(|| format!("failed to read config file {}", path.display()))?;
32 let ret = toml::from_str(&toml)
33 .with_context(|| format!("failed to parse TOML from {}", path.display()))?;
34 Ok(ret)
35}
36
37pub fn read_config_toml_or_default(config: impl AsRef<Path>) -> Result<AppConfig<SdkVmConfig>> {
38 if config.as_ref().exists() {
39 read_to_struct_toml(config)
40 } else {
41 println!(
42 "{:?} not found, using default application configuration",
43 config.as_ref()
44 );
45 Ok(default_app_config())
46 }
47}
48
49pub fn find_manifest_dir(mut current_dir: PathBuf) -> Result<PathBuf> {
50 current_dir = current_dir.canonicalize()?;
51 while !current_dir.join("Cargo.toml").exists() {
52 current_dir = current_dir
53 .parent()
54 .ok_or_else(|| {
55 eyre::eyre!(
56 "could not find Cargo.toml in current directory or any parent directory"
57 )
58 })?
59 .to_path_buf();
60 }
61 Ok(current_dir)
62}
63
64pub fn get_manifest_path_and_dir(manifest_path: &Option<PathBuf>) -> Result<(PathBuf, PathBuf)> {
65 let manifest_dir = if let Some(manifest_path) = &manifest_path {
66 if !manifest_path.ends_with("Cargo.toml") {
67 return Err(eyre::eyre!(
68 "manifest_path must be a path to a Cargo.toml file"
69 ));
70 }
71 manifest_path.parent().unwrap().canonicalize()?
72 } else {
73 find_manifest_dir(PathBuf::from("."))?
74 };
75 let manifest_path = manifest_dir.join("Cargo.toml");
76 Ok((manifest_path.clone(), manifest_dir))
77}
78
79pub fn get_target_dir(target_dir: &Option<PathBuf>, manifest_path: &PathBuf) -> PathBuf {
80 target_dir
81 .clone()
82 .unwrap_or_else(|| openvm_build::get_target_dir(manifest_path))
83}
84
85pub fn get_target_output_dir(target_dir: &Path, profile: &str) -> PathBuf {
86 get_openvm_dir(target_dir).join(profile)
87}
88
89pub fn get_openvm_dir(target_dir: &Path) -> PathBuf {
90 target_dir.parent().unwrap_or(target_dir).join("openvm")
91}
92
93pub fn get_app_pk_path(target_dir: &Path) -> PathBuf {
94 get_openvm_dir(target_dir).join(DEFAULT_APP_PK_NAME)
95}
96
97pub fn get_app_vk_path(target_dir: &Path) -> PathBuf {
98 get_openvm_dir(target_dir).join(DEFAULT_APP_VK_NAME)
99}
100
101pub fn get_agg_prefix_pk_path(target_dir: &Path) -> PathBuf {
102 get_openvm_dir(target_dir).join(DEFAULT_AGG_PREFIX_PK_NAME)
103}
104
105pub fn get_app_commit_path(target_output_dir: &Path, target_name: PathBuf) -> PathBuf {
106 let commit_name = target_name.with_extension(COMMIT_JSON_EXT);
107 target_output_dir.join(commit_name)
108}
109
110pub fn get_app_baseline_path(target_output_dir: &Path, target_name: PathBuf) -> PathBuf {
111 let baseline_name = target_name.with_extension(BASELINE_JSON_EXT);
112 target_output_dir.join(baseline_name)
113}
114
115pub fn get_single_target_name(cargo_args: &RunCargoArgs) -> Result<PathBuf> {
120 get_single_target_name_raw(
121 &cargo_args.bin,
122 &cargo_args.example,
123 &cargo_args.manifest.manifest_path,
124 &cargo_args.package,
125 )
126}
127
128pub fn get_single_target_name_raw(
129 bin: &[String],
130 example: &[String],
131 manifest_path: &Option<PathBuf>,
132 package: &Option<String>,
133) -> Result<PathBuf> {
134 let num_targets = bin.len() + example.len();
135 let single_target_name = if num_targets > 1 {
136 return Err(eyre::eyre!(
137 "`cargo openvm run` can run at most one executable, but multiple were specified"
138 ));
139 } else if num_targets == 0 {
140 let (_, manifest_dir) = get_manifest_path_and_dir(manifest_path)?;
141
142 let packages = if package.is_some() {
143 get_workspace_packages(&manifest_dir)
144 } else {
145 get_in_scope_packages(&manifest_dir)
146 }
147 .into_iter()
148 .filter(|pkg| {
149 if let Some(package) = package {
150 pkg.name == *package
151 } else {
152 true
153 }
154 })
155 .collect::<Vec<_>>();
156
157 let binaries = packages
158 .iter()
159 .flat_map(|pkg| pkg.targets.iter())
160 .filter(|t| t.is_bin())
161 .collect::<Vec<_>>();
162
163 if binaries.len() > 1 {
164 return Err(eyre::eyre!(
165 "Could not determine which binary to run. Use the --bin flag to specify.\n\
166 Available targets: {:?}",
167 binaries.iter().map(|t| t.name.clone()).collect::<Vec<_>>()
168 ));
169 } else if binaries.is_empty() {
170 return Err(eyre::eyre!(
171 "No binaries found. If you would like to run an example, use the --example flag.",
172 ));
173 } else {
174 PathBuf::from(binaries[0].name.clone())
175 }
176 } else if bin.is_empty() {
177 PathBuf::from("examples").join(&example[0])
178 } else {
179 PathBuf::from(bin[0].clone())
180 };
181 Ok(single_target_name)
182}
183
184pub fn resolve_proof_path(proof: &Option<PathBuf>, extension: &str) -> Result<PathBuf> {
185 if let Some(proof) = proof {
186 return Ok(proof.clone());
187 }
188 let files = get_files_with_ext(Path::new("."), extension)?;
189 if files.len() > 1 {
190 return Err(eyre::eyre!(
191 "multiple .{extension} files found, please specify the path using option --proof"
192 ));
193 } else if files.is_empty() {
194 return Err(eyre::eyre!(
195 "no .{extension} file found, please specify the path using option --proof"
196 ));
197 }
198 Ok(files[0].clone())
199}
200
201pub fn get_files_with_ext(dir: &Path, extension: &str) -> Result<Vec<PathBuf>> {
202 let dir = dir.canonicalize()?;
203 let mut files = Vec::new();
204 for entry in read_dir(dir)? {
205 let path = entry?.path();
206 if path.is_file()
207 && path
208 .to_str()
209 .is_some_and(|path_str| path_str.ends_with(extension))
210 {
211 files.push(path);
212 }
213 }
214 Ok(files)
215}