1use crate::errors::*;
2use serde::{Deserialize, Serialize};
3use std::path::Path;
4use tokio::fs;
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub struct Lockfile {
8 pub container: ContainerLock,
9 #[serde(default, rename = "package", skip_serializing_if = "Vec::is_empty")]
10 pub packages: Vec<PackageLock>,
11}
12
13impl Lockfile {
14 pub fn deserialize(buf: &str) -> Result<Self> {
15 let lockfile = toml::from_str(buf)?;
16 Ok(lockfile)
17 }
18
19 pub fn serialize(&self) -> Result<String> {
20 let toml = toml::to_string_pretty(self)?;
21 Ok(toml)
22 }
23
24 pub async fn read_from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
25 let path = path.as_ref();
26 let buf = fs::read_to_string(&path)
27 .await
28 .with_context(|| anyhow!("Failed to read dependency lockfile: {path:?}"))?;
29 let lockfile = Self::deserialize(&buf)?;
30 trace!("Loaded dependency lockfile from file: {lockfile:?}");
31 Ok(lockfile)
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
36pub struct ContainerLock {
37 pub image: String,
38}
39
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
41pub struct PackageLock {
42 pub name: String,
43 pub version: String,
44 pub system: String,
45 pub url: String,
46 #[serde(default, skip_serializing_if = "Vec::is_empty")]
47 pub provides: Vec<String>,
48 pub sha256: String,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub signature: Option<String>,
51 #[serde(default, skip_serializing_if = "is_false")]
55 pub installed: bool,
56}
57
58fn is_false(value: &bool) -> bool {
59 !value
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 pub fn test_serialize_archlinux() -> Result<()> {
68 let lockfile = Lockfile {
69 container: ContainerLock {
70 image:
71 "docker.io/library/archlinux@sha256:6568d3f1f278827a4a7d8537f80c2ae36982829a0c6bccff4cec081774025472"
72 .to_string(),
73 },
74 packages: vec![
75 PackageLock {
76 name: "archlinux-keyring".to_string(),
77 version: "20230704-1".to_string(),
78 system: "archlinux".to_string(),
79 url: "https://archive.archlinux.org/packages/a/archlinux-keyring/archlinux-keyring-20230704-1-any.pkg.tar.zst".to_string(),
80 provides: vec![],
81 sha256: "6a3d2acaa396c4bd72fe3f61a3256d881e3fc2cf326113cf331f168e36dd9a3c".to_string(),
82 signature: Some(
83"iHUEABYIAB0WIQQEKYl95fO9rFN6MGltQr3RFuAGjwUCZKPPXgAKCRBtQr3RFuAGj9oXAP94RQ1sKD53/RxVYlVEEOjKHvOmrWvDkt1veMYygnlnIgD+MLg/TT6d71kE8F08+JH+EcnG7wQow5Xr/qBo1VPLdgQ=".to_string()),
84 installed: false,
85 },
86 PackageLock {
87 name: "binutils".to_string(),
88 version: "2.40-6".to_string(),
89 system: "archlinux".to_string(),
90 url: "https://archive.archlinux.org/packages/b/binutils/binutils-2.40-6-x86_64.pkg.tar.zst".to_string(),
91 provides: vec![],
92 sha256: "b65fd16001578e10b602e577a8031cbfffc1164caf47ed9ba00c60d804519430".to_string(),
93 signature: Some(
94"iNUEABYKAH0WIQQFx3danouXdAf+COadTFqhVCbaCgUCZG6Rg18UgAAAAAAuAChpc3N1ZXItZnByQG5vdGF0aW9ucy5vcGVucGdwLmZpZnRoaG9yc2VtYW4ubmV0MDVDNzc3NUE5RThCOTc3NDA3RkUwOEU2OUQ0QzVBQTE1NDI2REEwQQAKCRCdTFqhVCbaCge2AQD/LGBeHRaeO8xh4E/bAYfqd1O/OFqk2DrQBJ73cdKl2gD9EC8p4U/cXQK8V774m6LSS50usH5pxcQWEq/H0SF+FgM=".to_string()),
95 installed: false,
96 }
97 ],
98 };
99
100 let toml = lockfile.serialize()?;
101
102 assert_eq!(
103 toml,
104 r#"[container]
105image = "docker.io/library/archlinux@sha256:6568d3f1f278827a4a7d8537f80c2ae36982829a0c6bccff4cec081774025472"
106
107[[package]]
108name = "archlinux-keyring"
109version = "20230704-1"
110system = "archlinux"
111url = "https://archive.archlinux.org/packages/a/archlinux-keyring/archlinux-keyring-20230704-1-any.pkg.tar.zst"
112sha256 = "6a3d2acaa396c4bd72fe3f61a3256d881e3fc2cf326113cf331f168e36dd9a3c"
113signature = "iHUEABYIAB0WIQQEKYl95fO9rFN6MGltQr3RFuAGjwUCZKPPXgAKCRBtQr3RFuAGj9oXAP94RQ1sKD53/RxVYlVEEOjKHvOmrWvDkt1veMYygnlnIgD+MLg/TT6d71kE8F08+JH+EcnG7wQow5Xr/qBo1VPLdgQ="
114
115[[package]]
116name = "binutils"
117version = "2.40-6"
118system = "archlinux"
119url = "https://archive.archlinux.org/packages/b/binutils/binutils-2.40-6-x86_64.pkg.tar.zst"
120sha256 = "b65fd16001578e10b602e577a8031cbfffc1164caf47ed9ba00c60d804519430"
121signature = "iNUEABYKAH0WIQQFx3danouXdAf+COadTFqhVCbaCgUCZG6Rg18UgAAAAAAuAChpc3N1ZXItZnByQG5vdGF0aW9ucy5vcGVucGdwLmZpZnRoaG9yc2VtYW4ubmV0MDVDNzc3NUE5RThCOTc3NDA3RkUwOEU2OUQ0QzVBQTE1NDI2REEwQQAKCRCdTFqhVCbaCge2AQD/LGBeHRaeO8xh4E/bAYfqd1O/OFqk2DrQBJ73cdKl2gD9EC8p4U/cXQK8V774m6LSS50usH5pxcQWEq/H0SF+FgM="
122"#
123 );
124
125 let deserialized = Lockfile::deserialize(&toml)?;
126 assert_eq!(deserialized, lockfile);
127
128 Ok(())
129 }
130
131 #[test]
132 pub fn test_serialize_debian() -> Result<()> {
133 let lockfile = Lockfile {
134 container: ContainerLock {
135 image:
136 "debian@sha256:3d868b5eb908155f3784317b3dda2941df87bbbbaa4608f84881de66d9bb297b"
137 .to_string(),
138 },
139 packages: vec![
140 PackageLock {
141 name: "binutils".to_string(),
142 version: "2.40-2".to_string(),
143 system: "debian".to_string(),
144 url: "https://snapshot.debian.org/archive/debian/20230115T211934Z/pool/main/b/binutils/binutils_2.40-2_amd64.deb".to_string(),
145 provides: vec![],
146 sha256: "83c3e20b53e1fbd84d764c3ba27d26a0376e361ae5d7fb37120196934dd87424".to_string(),
147 signature: None,
148 installed: false,
149 },
150 PackageLock {
151 name: "binutils-common".to_string(),
152 version: "2.40-2".to_string(),
153 system: "debian".to_string(),
154 url: "https://snapshot.debian.org/archive/debian/20230115T211934Z/pool/main/b/binutils/binutils-common_2.40-2_amd64.deb".to_string(),
155 provides: vec![],
156 sha256: "ab314134f43a0891a48f69a9bc33d825da748fa5e0ba2bebb7a5c491b026f1a0".to_string(),
157 signature: None,
158 installed: false,
159 }
160 ],
161 };
162
163 let toml = lockfile.serialize()?;
164
165 assert_eq!(
166 toml,
167 r#"[container]
168image = "debian@sha256:3d868b5eb908155f3784317b3dda2941df87bbbbaa4608f84881de66d9bb297b"
169
170[[package]]
171name = "binutils"
172version = "2.40-2"
173system = "debian"
174url = "https://snapshot.debian.org/archive/debian/20230115T211934Z/pool/main/b/binutils/binutils_2.40-2_amd64.deb"
175sha256 = "83c3e20b53e1fbd84d764c3ba27d26a0376e361ae5d7fb37120196934dd87424"
176
177[[package]]
178name = "binutils-common"
179version = "2.40-2"
180system = "debian"
181url = "https://snapshot.debian.org/archive/debian/20230115T211934Z/pool/main/b/binutils/binutils-common_2.40-2_amd64.deb"
182sha256 = "ab314134f43a0891a48f69a9bc33d825da748fa5e0ba2bebb7a5c491b026f1a0"
183"#
184 );
185
186 let deserialized = Lockfile::deserialize(&toml)?;
187 assert_eq!(deserialized, lockfile);
188
189 Ok(())
190 }
191}