1use std::{
2 fs::{read_dir, read_to_string},
3 path::{Path, PathBuf},
4};
5
6use eyre::Result;
7use openvm_build::{get_in_scope_packages, get_workspace_packages};
8use openvm_sdk::config::{AppConfig, SdkVmConfig};
9#[cfg(feature = "evm-prove")]
10use openvm_sdk::keygen::{AggProvingKey, Halo2ProvingKey};
11use serde::de::DeserializeOwned;
12
13use crate::{
14 commands::RunCargoArgs,
15 default::{default_app_config, DEFAULT_APP_PK_NAME, DEFAULT_APP_VK_NAME},
16};
17
18pub(crate) fn read_to_struct_toml<T: DeserializeOwned>(path: impl AsRef<Path>) -> Result<T> {
19 let toml = read_to_string(path)?;
20 let ret = toml::from_str(&toml)?;
21 Ok(ret)
22}
23
24pub fn read_config_toml_or_default(config: impl AsRef<Path>) -> Result<AppConfig<SdkVmConfig>> {
25 if config.as_ref().exists() {
26 read_to_struct_toml(config)
27 } else {
28 println!(
29 "{:?} not found, using default application configuration",
30 config.as_ref()
31 );
32 Ok(default_app_config())
33 }
34}
35
36#[cfg(feature = "evm-prove")]
37pub fn read_default_agg_and_halo2_pk() -> Result<(AggProvingKey, Halo2ProvingKey)> {
38 use openvm_sdk::fs::read_object_from_file;
39
40 let agg_pk = read_object_from_file(crate::default::default_agg_stark_pk_path())?;
41 let halo2_pk = read_object_from_file(crate::default::default_agg_halo2_pk_path())?;
42 Ok((agg_pk, halo2_pk))
43}
44
45pub fn find_manifest_dir(mut current_dir: PathBuf) -> Result<PathBuf> {
46 current_dir = current_dir.canonicalize()?;
47 while !current_dir.join("Cargo.toml").exists() {
48 current_dir = current_dir
49 .parent()
50 .expect("Could not find Cargo.toml in current directory or any parent directory")
51 .to_path_buf();
52 }
53 Ok(current_dir)
54}
55
56pub fn get_manifest_path_and_dir(manifest_path: &Option<PathBuf>) -> Result<(PathBuf, PathBuf)> {
57 let manifest_dir = if let Some(manifest_path) = &manifest_path {
58 if !manifest_path.ends_with("Cargo.toml") {
59 return Err(eyre::eyre!(
60 "manifest_path must be a path to a Cargo.toml file"
61 ));
62 }
63 manifest_path.parent().unwrap().canonicalize()?
64 } else {
65 find_manifest_dir(PathBuf::from("."))?
66 };
67 let manifest_path = manifest_dir.join("Cargo.toml");
68 Ok((manifest_path.clone(), manifest_dir))
69}
70
71pub fn get_target_dir(target_dir: &Option<PathBuf>, manifest_path: &PathBuf) -> PathBuf {
72 target_dir
73 .clone()
74 .unwrap_or_else(|| openvm_build::get_target_dir(manifest_path))
75}
76
77pub fn get_target_output_dir(target_dir: &Path, profile: &str) -> PathBuf {
78 target_dir.join("openvm").join(profile).to_path_buf()
79}
80
81pub fn get_app_pk_path(target_dir: &Path) -> PathBuf {
82 target_dir.join("openvm").join(DEFAULT_APP_PK_NAME)
83}
84
85pub fn get_app_vk_path(target_dir: &Path) -> PathBuf {
86 target_dir.join("openvm").join(DEFAULT_APP_VK_NAME)
87}
88
89pub fn get_app_commit_path(target_output_dir: &Path, target_name: PathBuf) -> PathBuf {
90 let commit_name = target_name.with_extension("commit.json");
91 target_output_dir.join(commit_name)
92}
93
94pub fn get_single_target_name(cargo_args: &RunCargoArgs) -> Result<PathBuf> {
99 get_single_target_name_raw(
100 &cargo_args.bin,
101 &cargo_args.example,
102 &cargo_args.manifest_path,
103 &cargo_args.package,
104 )
105}
106
107pub fn get_single_target_name_raw(
108 bin: &[String],
109 example: &[String],
110 manifest_path: &Option<PathBuf>,
111 package: &Option<String>,
112) -> Result<PathBuf> {
113 let num_targets = bin.len() + example.len();
114 let single_target_name = if num_targets > 1 {
115 return Err(eyre::eyre!(
116 "`cargo openvm run` can run at most one executable, but multiple were specified"
117 ));
118 } else if num_targets == 0 {
119 let (_, manifest_dir) = get_manifest_path_and_dir(manifest_path)?;
120
121 let packages = if package.is_some() {
122 get_workspace_packages(&manifest_dir)
123 } else {
124 get_in_scope_packages(&manifest_dir)
125 }
126 .into_iter()
127 .filter(|pkg| {
128 if let Some(package) = package {
129 pkg.name == *package
130 } else {
131 true
132 }
133 })
134 .collect::<Vec<_>>();
135
136 let binaries = packages
137 .iter()
138 .flat_map(|pkg| pkg.targets.iter())
139 .filter(|t| t.is_bin())
140 .collect::<Vec<_>>();
141
142 if binaries.len() > 1 {
143 return Err(eyre::eyre!(
144 "Could not determine which binary to run. Use the --bin flag to specify.\n\
145 Available targets: {:?}",
146 binaries.iter().map(|t| t.name.clone()).collect::<Vec<_>>()
147 ));
148 } else if binaries.is_empty() {
149 return Err(eyre::eyre!(
150 "No binaries found. If you would like to run an example, use the --example flag.",
151 ));
152 } else {
153 PathBuf::from(binaries[0].name.clone())
154 }
155 } else if bin.is_empty() {
156 PathBuf::from("examples").join(&example[0])
157 } else {
158 PathBuf::from(bin[0].clone())
159 };
160 Ok(single_target_name)
161}
162
163pub fn get_files_with_ext(dir: &Path, extension: &str) -> Result<Vec<PathBuf>> {
164 let dir = dir.canonicalize()?;
165 let mut files = Vec::new();
166 for entry in read_dir(dir)? {
167 let path = entry?.path();
168 if path.is_file()
169 && path
170 .to_str()
171 .is_some_and(|path_str| path_str.ends_with(extension))
172 {
173 files.push(path);
174 }
175 }
176 Ok(files)
177}