Skip to main content

bynk_driver/
contracts_lock.rs

1//! Reading and atomically writing `bynk.contracts.lock` (#2554): the driver's
2//! side of [`CompileOptions::contracts_lock`], beside [`crate::schema_lock`]
3//! and sharing its read and write.
4//!
5//! The pure document (`ContractsLock`, parse, serialize) is
6//! `bynk_project::contracts_lock`; a build only reads the file, and `bynk
7//! deploy --accept-compatible-skew` is what writes it.
8//!
9//! [`CompileOptions::contracts_lock`]: bynk_emit::project::CompileOptions::contracts_lock
10
11use std::io;
12use std::path::{Path, PathBuf};
13
14/// The file at the project root.
15pub const LOCK_FILE: &str = "bynk.contracts.lock";
16
17/// Where the lock lives for a project root, for messages that name the file.
18pub fn lock_path(project_root: &Path) -> PathBuf {
19    project_root.join(LOCK_FILE)
20}
21
22/// The lock's raw content; `Ok(None)` is verified absent, any other failure
23/// is an error. See [`crate::schema_lock::read`] for why the two differ.
24pub fn read(project_root: &Path) -> io::Result<Option<String>> {
25    crate::schema_lock::read_named(project_root, LOCK_FILE)
26}
27
28/// Write the lock atomically; a no-op when the content is unchanged.
29pub fn write(project_root: &Path, content: &str) -> io::Result<()> {
30    crate::schema_lock::write_named(project_root, LOCK_FILE, content)
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn an_absent_lock_is_verified_absent_and_a_written_one_reads_back() {
39        let dir = std::env::temp_dir().join(format!("bynk_2554_lock_{}", std::process::id()));
40        let _ = std::fs::remove_dir_all(&dir);
41        std::fs::create_dir_all(&dir).unwrap();
42        assert_eq!(read(&dir).unwrap(), None);
43        write(&dir, "version = 1\n").unwrap();
44        assert_eq!(read(&dir).unwrap().as_deref(), Some("version = 1\n"));
45        assert!(lock_path(&dir).ends_with("bynk.contracts.lock"));
46        let _ = std::fs::remove_dir_all(&dir);
47    }
48}