-
Notifications
You must be signed in to change notification settings - Fork 102
/
Copy pathexecutor.rs
165 lines (138 loc) · 5 KB
/
executor.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
use anyhow::bail;
use regex::Regex;
use std::io::BufRead;
use std::path::Path;
use std::{
io::BufReader,
path::PathBuf,
process::{Command, Stdio},
thread,
};
#[derive(Debug)]
pub struct Executor {
pub cmd: Command,
pub artifacts: Vec<PathBuf>,
pub test: bool,
}
impl Executor {
pub fn execute(mut self) -> anyhow::Result<Self> {
let mut child = self
.cmd
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("Couldn't spawn child process");
let stdout = BufReader::new(child.stdout.take().expect("Couldn't take stdout of child"));
let stderr = BufReader::new(child.stderr.take().expect("Couldn't take stderr of child"));
let stdout_handle = thread::spawn(move || {
for line in stdout.lines().enumerate().map(|(index, line)| {
line.unwrap_or_else(|e| {
panic!("Couldn't get stdout line: {index}\n with error: {e}")
})
}) {
println!("[docker] {line}");
}
});
for line in stderr.lines().enumerate().map(|(index, line)| {
line.unwrap_or_else(|e| panic!("Couldn't get stderr line: {index}\n with error: {e}"))
}) {
println!("[zkvm-stdout] {line}");
if self.test && line.contains("Executable unittests") {
if let Some(test) = extract_path(&line) {
let Some(artifact) = self
.artifacts
.iter_mut()
.find(|a| file_name(&test).contains(&file_name(a).replace('-', "_")))
else {
bail!("Failed to find test artifact");
};
*artifact = test;
}
}
}
stdout_handle
.join()
.expect("Couldn't wait for stdout handle to finish");
let result = child.wait()?;
if !result.success() {
// Error message is already printed by cargo
std::process::exit(result.code().unwrap_or(1))
}
Ok(self)
}
#[cfg(feature = "sp1")]
pub fn sp1_placement(&self, dest: &str) -> anyhow::Result<()> {
use std::fs;
let root = crate::ROOT_DIR.get().expect("No reference to ROOT_DIR");
let dest = PathBuf::from(dest);
if !dest.exists() {
fs::create_dir_all(&dest).expect("Couldn't create destination directories");
}
for src in &self.artifacts {
let mut name = file_name(src);
if self.test {
name = format!(
"test-{}",
name.split('-').next().expect("Couldn't get test name")
);
}
fs::copy(
root.join(src.to_str().expect("File name is not valid UTF-8")),
&dest.join(&name.replace('_', "-")),
)?;
println!("Write elf from\n {src:?}\nto\n {dest:?}");
}
Ok(())
}
#[cfg(feature = "risc0")]
pub fn risc0_placement(&self, dest: &str) -> anyhow::Result<()> {
use crate::risc0_util::GuestListEntry;
use std::{fs, io::Write};
let root = crate::ROOT_DIR.get().expect("No reference to ROOT_DIR");
let dest_dir = PathBuf::from(dest);
if !dest_dir.exists() {
fs::create_dir_all(&dest_dir).expect("Couldn't create destination directories");
}
println!("#### {:#?}", self.artifacts);
for src in &self.artifacts {
let mut name = file_name(src);
if self.test {
name = format!(
"test-{}",
name.split('-').next().expect("Couldn't get test name")
);
}
let mut dest_file =
fs::File::create(&dest_dir.join(&format!("{}.rs", name.replace('-', "_"))))
.expect("Couldn't create destination file");
let guest = GuestListEntry::build(
&name,
root.join(src).to_str().expect("Path is not valid UTF-8"),
)
.expect("Couldn't build the guest list entry");
dest_file.write_all(
guest
.codegen_consts(
&std::fs::canonicalize(&dest_dir)
.expect("Couldn't canonicalize the destination path"),
)
.as_bytes(),
)?;
println!("Write from\n {src:?}\nto\n {dest_file:?}");
}
Ok(())
}
}
fn file_name(path: &Path) -> String {
path.file_name()
.expect("no filename in path")
.to_str()
.expect("filename is non unicode")
.to_owned()
}
fn extract_path(line: &str) -> Option<PathBuf> {
let re = Regex::new(r"\(([^)]+)\)").expect("Couldn't create regex");
re.captures(line)
.and_then(|caps| caps.get(1).map(|m| m.as_str().to_string()))
.map(PathBuf::from)
}