1use std::collections::BTreeMap;
13use std::fmt::Write;
14
15use super::fetch::FetchPlan;
16use super::manifest::{Extension, Lib};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Lockfile {
20 pub assay: Option<String>,
21 pub extensions: Vec<LockExtension>,
22 pub libs: Vec<LockLib>,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct LockExtension {
27 pub name: String,
28 pub version: String,
29 pub url: String,
30 pub sha256: BTreeMap<String, String>,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct LockLib {
36 pub name: String,
37 pub version: String,
38 pub url: String,
39 pub sha256: String,
40}
41
42impl LockExtension {
43 pub fn new(ext: &Extension, plan: &FetchPlan) -> Self {
44 let sha256 = ext
45 .sha256
46 .iter()
47 .map(|(k, v)| (k.clone(), v.clone()))
48 .collect();
49 LockExtension {
50 name: ext.name.clone(),
51 version: ext.version.clone(),
52 url: plan.url.clone(),
53 sha256,
54 }
55 }
56}
57
58impl LockLib {
59 pub fn new(lib: &Lib, plan: &FetchPlan) -> Self {
60 LockLib {
61 name: lib.name.clone(),
62 version: lib.version.clone(),
63 url: plan.url.clone(),
64 sha256: lib.sha256.clone(),
65 }
66 }
67}
68
69impl Lockfile {
70 pub fn to_lua(&self) -> String {
72 let mut out = String::with_capacity(256);
73 out.push_str("-- Generated by `assay install`. Do not edit by hand.\n");
74 out.push_str("return {\n");
75
76 if let Some(v) = &self.assay {
77 writeln!(out, " assay = {},", lua_string(v)).unwrap();
78 }
79
80 out.push_str(" extensions = {\n");
81 for e in &self.extensions {
82 writeln!(out, " {{").unwrap();
83 writeln!(out, " name = {},", lua_string(&e.name)).unwrap();
84 writeln!(out, " version = {},", lua_string(&e.version)).unwrap();
85 writeln!(out, " url = {},", lua_string(&e.url)).unwrap();
86 out.push_str(" sha256 = {");
87 let mut first = true;
88 for (arch, hash) in &e.sha256 {
89 if !first {
90 out.push(',');
91 }
92 write!(out, " {arch} = {}", lua_string(hash)).unwrap();
93 first = false;
94 }
95 out.push_str(" },\n");
96 writeln!(out, " }},").unwrap();
97 }
98 out.push_str(" },\n");
99
100 out.push_str(" libs = {\n");
101 for l in &self.libs {
102 writeln!(out, " {{").unwrap();
103 writeln!(out, " name = {},", lua_string(&l.name)).unwrap();
104 writeln!(out, " version = {},", lua_string(&l.version)).unwrap();
105 writeln!(out, " url = {},", lua_string(&l.url)).unwrap();
106 writeln!(out, " sha256 = {},", lua_string(&l.sha256)).unwrap();
107 writeln!(out, " }},").unwrap();
108 }
109 out.push_str(" },\n");
110
111 out.push_str("}\n");
112 out
113 }
114}
115
116fn lua_string(s: &str) -> String {
117 let mut out = String::with_capacity(s.len() + 2);
118 out.push('"');
119 for c in s.chars() {
120 match c {
121 '\\' => out.push_str("\\\\"),
122 '"' => out.push_str("\\\""),
123 '\n' => out.push_str("\\n"),
124 '\r' => out.push_str("\\r"),
125 '\t' => out.push_str("\\t"),
126 c if (c as u32) < 0x20 => write!(out, "\\{}", c as u32).unwrap(),
127 c => out.push(c),
128 }
129 }
130 out.push('"');
131 out
132}