soldeer_core/lock/
forge.rs1use log::debug;
6use serde::{Deserialize, Serialize};
7use std::{
8 collections::HashMap,
9 fs,
10 path::{Path, PathBuf},
11};
12
13use crate::errors::LockError;
14
15use super::Result;
16
17pub const FOUNDRY_LOCK: &str = "foundry.lock";
18
19pub type DepMap = HashMap<PathBuf, DepIdentifier>;
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct Lockfile {
25 #[serde(flatten)]
27 deps: DepMap,
28 #[serde(skip)]
30 lockfile_path: PathBuf,
31}
32
33impl Lockfile {
34 pub fn new(project_root: &Path) -> Self {
40 Self { deps: HashMap::default(), lockfile_path: project_root.join(FOUNDRY_LOCK) }
41 }
42
43 pub fn read(&mut self) -> Result<()> {
47 if !self.lockfile_path.exists() {
48 return Err(LockError::FoundryLockMissing);
49 }
50
51 let lockfile_str = fs::read_to_string(&self.lockfile_path)?;
52
53 self.deps = serde_json::from_str(&lockfile_str)?;
54
55 debug!(lockfile:? = self.deps; "loaded lockfile");
56
57 Ok(())
58 }
59
60 pub fn get(&self, path: &Path) -> Option<&DepIdentifier> {
62 self.deps.get(path)
63 }
64
65 pub fn len(&self) -> usize {
67 self.deps.len()
68 }
69
70 pub fn is_empty(&self) -> bool {
72 self.deps.is_empty()
73 }
74
75 pub fn iter(&self) -> impl Iterator<Item = (&PathBuf, &DepIdentifier)> {
77 self.deps.iter()
78 }
79
80 pub fn exists(&self) -> bool {
81 self.lockfile_path.exists()
82 }
83}
84
85#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
93pub enum DepIdentifier {
94 #[serde(rename = "branch")]
96 Branch { name: String, rev: String },
97
98 #[serde(rename = "tag")]
100 Tag { name: String, rev: String },
101
102 #[serde(rename = "rev", untagged)]
104 Rev { rev: String },
105}
106
107impl DepIdentifier {
108 pub fn rev(&self) -> &str {
110 match self {
111 Self::Branch { rev, .. } => rev,
112 Self::Tag { rev, .. } => rev,
113 Self::Rev { rev, .. } => rev,
114 }
115 }
116
117 pub fn name(&self) -> &str {
121 match self {
122 Self::Branch { name, .. } => name,
123 Self::Tag { name, .. } => name,
124 Self::Rev { rev, .. } => rev,
125 }
126 }
127
128 pub fn checkout_id(&self) -> &str {
130 match self {
131 Self::Branch { name, .. } => name,
132 Self::Tag { name, .. } => name,
133 Self::Rev { rev, .. } => rev,
134 }
135 }
136
137 pub fn is_branch(&self) -> bool {
139 matches!(self, Self::Branch { .. })
140 }
141}
142
143impl std::fmt::Display for DepIdentifier {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 match self {
146 Self::Branch { name, rev, .. } => write!(f, "branch={name}@{rev}"),
147 Self::Tag { name, rev, .. } => write!(f, "tag={name}@{rev}"),
148 Self::Rev { rev, .. } => write!(f, "rev={rev}"),
149 }
150 }
151}