ab_contracts_tooling/
target_specification.rs1use anyhow::Context;
4use dirs::cache_dir;
5use std::fs::{File, create_dir_all};
6use std::io::{Read, Seek, Write};
7use std::path::{Path, PathBuf};
8
9pub(crate) const TARGET_SPECIFICATION_NAME: &str = "riscv64-unknown-none-abundance";
10const TARGET_SPECIFICATION_FILE_NAME: &str = "riscv64-unknown-none-abundance.json";
11const TARGET_SPECIFICATION: &str = include_str!("riscv64-unknown-none-abundance.json");
12
13#[derive(Debug)]
15pub struct TargetSpecification {
16 path: PathBuf,
17 _file: File,
18}
19
20impl TargetSpecification {
21 pub fn create(base_directory: &Path) -> anyhow::Result<Self> {
25 let path = base_directory.join(TARGET_SPECIFICATION_FILE_NAME);
26 let mut file = File::options()
27 .read(true)
28 .write(true)
29 .create(true)
30 .truncate(false)
31 .open(&path)
32 .context("Failed to open target specification file")?;
33
34 loop {
36 file.lock_shared()
37 .context("Failed to lock target specification file")?;
38
39 let mut actual_target_specification = String::with_capacity(TARGET_SPECIFICATION.len());
40 file.seek(std::io::SeekFrom::Start(0))
41 .context("Failed to seek to start of target specification file")?;
42 file.read_to_string(&mut actual_target_specification)
43 .context("Failed to read target specification file")?;
44
45 if actual_target_specification == TARGET_SPECIFICATION {
46 break;
47 }
48
49 file.unlock()
50 .context("Failed to unlock target specification file")?;
51 file.lock()
52 .context("Failed to lock target specification file")?;
53 file.set_len(0)
54 .context("Failed to truncate target specification file")?;
55 file.seek(std::io::SeekFrom::Start(0))
56 .context("Failed to seek to start of target specification file")?;
57 file.write_all(TARGET_SPECIFICATION.as_bytes())
58 .context("Failed to write target specification file")?;
59 file.sync_all()
60 .context("Failed to sync target specification file")?;
61 file.unlock()
62 .context("Failed to unlock target specification file")?;
63 }
64
65 Ok(Self { path, _file: file })
66 }
67
68 pub fn default_base_dir() -> anyhow::Result<PathBuf> {
71 let app_dir = cache_dir()
72 .context("Failed to get cache directory")?
73 .join("ab-contracts");
74 create_dir_all(&app_dir)
75 .with_context(|| format!("Failed to create cache directory {}", app_dir.display()))?;
76
77 Ok(app_dir)
78 }
79
80 pub fn path(&self) -> &Path {
82 &self.path
83 }
84}