binstalk_manifests/
crates_manifests.rs1use std::{
2 collections::BTreeMap,
3 fs,
4 io::{self, Seek},
5 path::Path,
6};
7
8use fs_lock::FileLock;
9use miette::Diagnostic;
10use thiserror::Error as ThisError;
11
12use crate::{
13 binstall_crates_v1::{Error as BinstallCratesV1Error, Records as BinstallCratesV1Records},
14 cargo_crates_v1::{CratesToml, CratesTomlParseError},
15 crate_info::CrateInfo,
16 helpers::create_if_not_exist,
17 CompactString, Version,
18};
19
20#[derive(Debug, Diagnostic, ThisError)]
21#[non_exhaustive]
22pub enum ManifestsError {
23 #[error("failed to parse binstall crates-v1 manifest: {0}")]
24 #[diagnostic(transparent)]
25 BinstallCratesV1(#[from] BinstallCratesV1Error),
26
27 #[error("failed to parse cargo v1 manifest: {0}")]
28 #[diagnostic(transparent)]
29 CargoManifestV1(#[from] CratesTomlParseError),
30
31 #[error("I/O error: {0}")]
32 Io(#[from] io::Error),
33}
34
35pub struct Manifests {
36 binstall: BinstallCratesV1Records,
37 cargo_crates_v1: FileLock,
38}
39
40impl Manifests {
41 pub fn open_exclusive(cargo_roots: &Path) -> Result<Self, ManifestsError> {
42 let metadata_path = cargo_roots.join("binstall/crates-v1.json");
44 fs::create_dir_all(metadata_path.parent().unwrap())?;
45
46 let binstall = BinstallCratesV1Records::load_from_path(&metadata_path)?;
47
48 let manifest_path = cargo_roots.join(".crates.toml");
50
51 let cargo_crates_v1 = create_if_not_exist(&manifest_path)?;
52
53 Ok(Self {
54 binstall,
55 cargo_crates_v1,
56 })
57 }
58
59 fn rewind_cargo_crates_v1(&mut self) -> Result<(), ManifestsError> {
60 self.cargo_crates_v1.rewind().map_err(ManifestsError::from)
61 }
62
63 pub fn load_installed_crates(
68 &mut self,
69 ) -> Result<BTreeMap<CompactString, Version>, ManifestsError> {
70 self.rewind_cargo_crates_v1()?;
71
72 CratesToml::load_from_reader(&mut self.cargo_crates_v1)
73 .and_then(CratesToml::collect_into_crates_versions)
74 .map_err(ManifestsError::from)
75 }
76
77 pub fn update(mut self, metadata_vec: Vec<CrateInfo>) -> Result<(), ManifestsError> {
78 self.rewind_cargo_crates_v1()?;
79
80 CratesToml::append_to_file(&mut self.cargo_crates_v1, &metadata_vec)?;
81
82 for metadata in metadata_vec {
83 self.binstall.replace(metadata);
84 }
85 self.binstall.overwrite()?;
86
87 Ok(())
88 }
89}