1use crate::error::Result;
4use serde::{Deserialize, Serialize};
5use std::path::Path;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct InstallReceipt {
10 pub homebrew_version: String,
11 pub installed_as_dependency: bool,
12 pub installed_on_request: bool,
13 pub install_time: u64,
14 pub source: ReceiptSource,
15 #[serde(default)]
16 pub runtime_dependencies: Vec<RuntimeDependency>,
17 #[serde(default)]
18 pub poured_from_bottle: bool,
19 #[serde(default)]
20 pub built_as_bottle: bool,
21 #[serde(default)]
22 pub changed_files: Vec<String>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ReceiptSource {
27 pub tap: String,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub path: Option<String>,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct RuntimeDependency {
34 pub full_name: String,
35 pub version: String,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub revision: Option<u32>,
38}
39
40impl InstallReceipt {
41 pub fn new_bottle(tap: &str, on_request: bool, dependencies: Vec<RuntimeDependency>) -> Self {
43 let now = std::time::SystemTime::now()
44 .duration_since(std::time::UNIX_EPOCH)
45 .unwrap()
46 .as_secs();
47
48 Self {
49 homebrew_version: "4.0.0".to_string(), installed_as_dependency: !on_request,
51 installed_on_request: on_request,
52 install_time: now,
53 source: ReceiptSource {
54 tap: tap.to_string(),
55 path: None,
56 },
57 runtime_dependencies: dependencies,
58 poured_from_bottle: true,
59 built_as_bottle: true,
60 changed_files: Vec::new(),
61 }
62 }
63
64 pub fn new_source(tap: &str, on_request: bool, dependencies: Vec<RuntimeDependency>) -> Self {
66 let now = std::time::SystemTime::now()
67 .duration_since(std::time::UNIX_EPOCH)
68 .unwrap()
69 .as_secs();
70
71 Self {
72 homebrew_version: "4.0.0".to_string(),
73 installed_as_dependency: !on_request,
74 installed_on_request: on_request,
75 install_time: now,
76 source: ReceiptSource {
77 tap: tap.to_string(),
78 path: None,
79 },
80 runtime_dependencies: dependencies,
81 poured_from_bottle: false, built_as_bottle: false,
83 changed_files: Vec::new(),
84 }
85 }
86}
87
88pub fn write_receipt(install_path: impl AsRef<Path>, receipt: &InstallReceipt) -> Result<()> {
90 let path = install_path.as_ref().join("INSTALL_RECEIPT.json");
91 let json = serde_json::to_string_pretty(receipt)?;
92 std::fs::write(&path, json)?;
93 Ok(())
94}
95
96#[allow(dead_code)]
98pub fn read_receipt(install_path: impl AsRef<Path>) -> Result<InstallReceipt> {
99 let path = install_path.as_ref().join("INSTALL_RECEIPT.json");
100 let json = std::fs::read_to_string(&path)?;
101 let receipt: InstallReceipt = serde_json::from_str(&json)?;
102 Ok(receipt)
103}