monerochan_cli/commands/
build_toolchain.rs1use anyhow::{Context, Result};
2use clap::Parser;
3use std::{path::PathBuf, process::Command};
4
5use crate::{
6 get_target, CommandExecutor, LATEST_SUPPORTED_TOOLCHAIN_VERSION_TAG, RUSTUP_TOOLCHAIN_NAME,
7};
8
9#[derive(Parser)]
10#[command(name = "build-toolchain", about = "Build the cargo-monerochan toolchain.")]
11pub struct BuildToolchainCmd {}
12
13impl BuildToolchainCmd {
14 pub fn run(&self) -> Result<()> {
15 let github_access_token = std::env::var("GITHUB_ACCESS_TOKEN");
17 let build_dir = std::env::var("MONEROCHAN_BUILD_DIR");
18
19 let rust_dir = match build_dir {
21 Ok(build_dir) => {
22 println!("Detected MONEROCHAN_BUILD_DIR, skipping cloning rust.");
23 PathBuf::from(build_dir).join("rust")
24 }
25 Err(_) => {
26 let temp_dir = std::env::temp_dir();
27 let dir = temp_dir.join("monerochan-rust");
28 if dir.exists() {
29 std::fs::remove_dir_all(&dir)?;
30 }
31
32 println!("No MONEROCHAN_BUILD_DIR detected, cloning rust.");
33 let repo_url = match github_access_token {
34 Ok(github_access_token) => {
35 println!("Detected GITHUB_ACCESS_TOKEN, using it to clone rust.");
36 format!(
37 "https://{github_access_token}@github.com/monerochanorg/monerochan-rust"
38 )
39 }
40 Err(_) => {
41 println!("No GITHUB_ACCESS_TOKEN detected. If you get throttled by Github, set it to bypass the rate limit.");
42 "https://github.com/monerochanorg/monerochan-rust".to_string()
43 }
44 };
45
46 Command::new("git")
48 .args([
49 "clone",
50 &repo_url,
51 "--depth=1",
52 "--single-branch",
53 &format!("--branch={LATEST_SUPPORTED_TOOLCHAIN_VERSION_TAG}"),
54 "monerochan-rust",
55 ])
56 .current_dir(&temp_dir)
57 .run()
58 .with_context(|| format!("Failed to clone repository from {repo_url}. Make sure the repository exists and you have access to it."))?;
59
60 if !dir.exists() {
62 return Err(anyhow::anyhow!("Clone completed but directory {} does not exist", dir.display()));
63 }
64
65 Command::new("git")
67 .args(["reset", "--hard"])
68 .current_dir(&dir)
69 .run()
70 .with_context(|| format!("Failed to reset repository in {}", dir.display()))?;
71
72 Command::new("git")
74 .args(["submodule", "update", "--init", "--recursive", "--progress"])
75 .current_dir(&dir)
76 .run()
77 .with_context(|| format!("Failed to update submodules in {}", dir.display()))?;
78
79 dir
80 }
81 };
82
83 let bootstrap_toml = include_str!("bootstrap.toml");
85 let bootstrap_file = rust_dir.join("bootstrap.toml");
86 std::fs::write(&bootstrap_file, bootstrap_toml)
87 .with_context(|| format!("while writing configuration to {bootstrap_file:?}"))?;
88
89 let temp_dir = std::env::temp_dir().join("rustc-targets");
92 if !temp_dir.exists() {
93 std::fs::create_dir_all(&temp_dir)?;
94 }
95 std::fs::File::create(temp_dir.join("riscv32im-succinct-zkvm-elf.json"))?;
96
97 Command::new("python3")
99 .env("RUST_TARGET_PATH", &temp_dir)
100 .env("CARGO_TARGET_RISCV32IM_SUCCINCT_ZKVM_ELF_RUSTFLAGS", "-Cpasses=lower-atomic")
101 .args([
102 "x.py",
103 "build",
104 "--stage",
105 "2",
106 "compiler/rustc",
107 "library",
108 "--target",
109 &format!("riscv32im-succinct-zkvm-elf,{}", get_target()),
110 ])
111 .current_dir(&rust_dir)
112 .run()?;
113
114 match Command::new("rustup").args(["toolchain", "remove", RUSTUP_TOOLCHAIN_NAME]).run() {
116 Ok(_) => println!("Successfully removed existing toolchain."),
117 Err(_) => println!("No existing toolchain to remove."),
118 }
119
120 let mut toolchain_dir = None;
122 for wentry in std::fs::read_dir(rust_dir.join("build"))? {
123 let entry = wentry?;
124 let toolchain_dir_candidate = entry.path().join("stage2");
125 if toolchain_dir_candidate.is_dir() {
126 toolchain_dir = Some(toolchain_dir_candidate);
127 break;
128 }
129 }
130 let toolchain_dir = toolchain_dir.unwrap();
131 println!(
132 "Found built toolchain directory at {}.",
133 toolchain_dir.as_path().to_str().unwrap()
134 );
135
136 Command::new("rustup")
138 .args(["toolchain", "link", RUSTUP_TOOLCHAIN_NAME])
139 .arg(&toolchain_dir)
140 .run()?;
141 println!("Successfully linked the toolchain to rustup.");
142
143 let target = get_target();
145 let tar_gz_path = format!("rust-toolchain-{target}.tar.gz");
146 Command::new("tar")
147 .args([
148 "--exclude",
149 "lib/rustlib/src",
150 "--exclude",
151 "lib/rustlib/rustc-src",
152 "-hczvf",
153 &tar_gz_path,
154 "-C",
155 toolchain_dir.to_str().unwrap(),
156 ".",
157 ])
158 .run()?;
159 println!("Successfully compressed the toolchain to {tar_gz_path}.");
160
161 Ok(())
162 }
163}