op_primitives/
monorepo.rs1use eyre::Result;
2use serde::{Deserialize, Serialize};
3use std::{
4 path::{Path, PathBuf},
5 process::Command,
6};
7
8#[macro_export]
11macro_rules! path_to_str {
12 ($path:expr) => {
13 $path
14 .to_str()
15 .ok_or_else(|| eyre::eyre!("Failed to convert path to string: {:?}", $path))
16 };
17}
18
19#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
21pub struct MonorepoConfig {
22 pub directory_name: String,
24 pub source: MonorepoSource,
26 pub git_url: String,
28 pub tarball_url: String,
30 pub force: bool,
32}
33
34impl Default for MonorepoConfig {
35 fn default() -> Self {
36 Self {
37 source: MonorepoSource::Git,
38 directory_name: "optimism".to_string(),
39 git_url: "git@github.com:ethereum-optimism/optimism.git".to_string(),
40 tarball_url: "https://github.com/ethereum-optimism/optimism/archive/develop.tar.gz"
41 .to_string(),
42 force: false,
43 }
44 }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
49#[serde(rename_all = "lowercase")]
50pub enum MonorepoSource {
51 #[default]
53 Git,
54 Tarball,
56}
57
58#[derive(Debug, Default, Clone, PartialEq)]
60pub struct Monorepo {
61 pwd: PathBuf,
63 config: MonorepoConfig,
65}
66
67impl Monorepo {
68 pub fn with_config(config: MonorepoConfig) -> Result<Self> {
74 Ok(Self {
75 pwd: std::env::current_dir()?,
76 config,
77 })
78 }
79
80 pub fn path(&self) -> PathBuf {
82 self.pwd.join(&self.config.directory_name)
83 }
84
85 pub fn devnet(&self) -> PathBuf {
87 self.path().join(".devnet")
88 }
89
90 pub fn l1_genesis(&self) -> PathBuf {
92 self.devnet().join("genesis-l1.json")
93 }
94
95 pub fn l2_genesis(&self) -> PathBuf {
97 self.devnet().join("genesis-l2.json")
98 }
99
100 pub fn contracts(&self) -> PathBuf {
102 self.path().join("packages/contracts-bedrock")
103 }
104
105 pub fn deploy_config(&self) -> PathBuf {
107 self.contracts().join("deploy-config/devnetL1.json")
108 }
109
110 pub fn deployments(&self) -> PathBuf {
112 self.contracts().join("deployments")
113 }
114
115 pub fn devnet_deploys(&self) -> PathBuf {
117 self.deployments().join("devnetL1")
118 }
119
120 pub fn allocs(&self) -> PathBuf {
122 self.devnet().join("allocs-l1.json")
123 }
124
125 pub fn addresses_json(&self) -> PathBuf {
127 self.devnet().join("addresses.json")
128 }
129
130 pub fn op_node_dir(&self) -> PathBuf {
132 self.path().join("op-node")
133 }
134
135 pub fn genesis_rollup(&self) -> PathBuf {
137 self.devnet().join("rollup.json")
138 }
139}
140
141impl Monorepo {
142 pub fn obtain_from_source(&self) -> Result<()> {
146 if self.path().exists() && !self.config.force {
147 tracing::warn!(target: "monorepo", "Monorepo already exists, skipping...");
148 return Ok(());
149 }
150
151 match self.config.source {
152 MonorepoSource::Git => self.git_clone(),
153 MonorepoSource::Tarball => self.download(),
154 }
155 }
156
157 fn git_clone(&self) -> Result<()> {
159 tracing::info!(target: "monorepo", "Cloning optimism monorepo (this may take a while)...");
160 git_clone(&self.pwd, &self.config.git_url)
161 }
162
163 fn download(&self) -> Result<()> {
173 tracing::info!(target: "monorepo", "Downloading optimism monorepo...");
174 let archive_file_name = "optimism_monorepo.tar.gz";
175
176 download_file(&self.pwd, &self.config.tarball_url, archive_file_name)?;
177 unzip_tarball(&self.pwd, archive_file_name)?;
178 mv_dir(&self.pwd, "optimism-develop", &self.config.directory_name)?;
179 std::fs::remove_file(archive_file_name)?;
180 Ok(())
181 }
182}
183
184pub(crate) fn git_clone(pwd: &Path, repo: &str) -> Result<()> {
186 let out = Command::new("git")
187 .arg("clone")
188 .arg("--recursive")
189 .arg("--depth")
190 .arg("1")
191 .arg(repo)
192 .current_dir(pwd)
193 .output()?;
194 if !out.status.success() {
195 eyre::bail!(
196 "Failed to clone {} in {:?}: {}",
197 repo,
198 pwd,
199 String::from_utf8_lossy(&out.stderr)
200 )
201 }
202
203 Ok(())
204}
205
206pub(crate) fn download_file(pwd: &Path, url: &str, name: &str) -> Result<()> {
208 let out = Command::new("curl")
209 .arg("-L")
210 .arg("--output")
211 .arg(name)
212 .arg(url)
213 .current_dir(pwd)
214 .output()?;
215 if !out.status.success() {
216 eyre::bail!(
217 "Failed to download {} in {:?}: {}",
218 url,
219 pwd,
220 String::from_utf8_lossy(&out.stderr)
221 )
222 }
223
224 Ok(())
225}
226
227pub(crate) fn unzip_tarball(pwd: &Path, name: &str) -> Result<()> {
229 let out = Command::new("tar")
230 .arg("-xvf")
231 .arg(name)
232 .current_dir(pwd)
233 .output()?;
234 if !out.status.success() {
235 eyre::bail!(
236 "Failed to unzip {} in {:?}: {}",
237 name,
238 pwd,
239 String::from_utf8_lossy(&out.stderr)
240 )
241 }
242
243 Ok(())
244}
245
246pub(crate) fn mv_dir(pwd: &Path, src: &str, dst: &str) -> Result<()> {
248 let out = Command::new("mv")
249 .arg(src)
250 .arg(dst)
251 .current_dir(pwd)
252 .output()?;
253 if !out.status.success() {
254 eyre::bail!(
255 "Failed to move {} to {} in {:?}: {}",
256 src,
257 dst,
258 pwd,
259 String::from_utf8_lossy(&out.stderr)
260 )
261 }
262
263 Ok(())
264}