1use std::{
4 collections::BTreeMap,
5 io::{Cursor, Write},
6};
7
8use zip::write::{FileOptions, ZipWriter};
9
10use crate::{
11 manifest::{Manifest, Package, Realm},
12 package_contents::PackageContents,
13 package_id::PackageId,
14 package_req::PackageReq,
15};
16
17pub struct PackageBuilder {
18 manifest: Manifest,
19 files: BTreeMap<String, String>,
20}
21
22impl PackageBuilder {
23 pub fn new<S>(identity: S) -> Self
24 where
25 S: AsRef<str>,
26 {
27 let id: PackageId = identity.as_ref().parse().expect("invalid PackageId");
28 let (name, version) = id.into_parts();
29
30 let manifest = Manifest {
31 package: Package {
32 name,
33 version,
34 registry: String::new(),
35 realm: Realm::Shared,
36 description: None,
37 license: None,
38 authors: Vec::new(),
39 include: Vec::new(),
40 exclude: Vec::new(),
41 private: false,
42 },
43 place: Default::default(),
44 dependencies: Default::default(),
45 server_dependencies: Default::default(),
46 dev_dependencies: Default::default(),
47 };
48
49 Self {
50 manifest,
51 files: BTreeMap::new(),
52 }
53 }
54
55 pub fn with_realm(mut self, realm: Realm) -> Self {
56 self.manifest.package.realm = realm;
57 self
58 }
59
60 pub fn with_dep<A, R>(mut self, alias: A, package_req: R) -> Self
61 where
62 A: Into<String>,
63 R: AsRef<str>,
64 {
65 let req: PackageReq = package_req.as_ref().parse().expect("invalid PackageReq");
66
67 self.manifest.dependencies.insert(alias.into(), req);
68 self
69 }
70
71 pub fn with_server_dep<A, R>(mut self, alias: A, package_req: R) -> Self
72 where
73 A: Into<String>,
74 R: AsRef<str>,
75 {
76 let req: PackageReq = package_req.as_ref().parse().expect("invalid PackageReq");
77
78 self.manifest.server_dependencies.insert(alias.into(), req);
79 self
80 }
81
82 pub fn with_file<P, C>(mut self, path: P, contents: C) -> Self
83 where
84 P: Into<String>,
85 C: Into<String>,
86 {
87 self.files.insert(path.into(), contents.into());
88 self
89 }
90
91 pub fn into_manifest(self) -> Manifest {
92 self.manifest
93 }
94
95 pub fn manifest(&self) -> &Manifest {
96 &self.manifest
97 }
98
99 pub fn contents(&self) -> PackageContents {
100 let mut buffer = Vec::new();
101 let mut archive = ZipWriter::new(Cursor::new(&mut buffer));
102
103 for (path, contents) in &self.files {
104 archive.start_file(path, FileOptions::default()).unwrap();
105 archive.write_all(contents.as_bytes()).unwrap();
106 }
107
108 let encoded_manifest = toml::to_string_pretty(&self.manifest).unwrap();
109 archive
110 .start_file("wally.toml", FileOptions::default())
111 .unwrap();
112 archive.write_all(encoded_manifest.as_bytes()).unwrap();
113
114 archive.finish().unwrap();
115 drop(archive);
116
117 let contents = PackageContents::from_buffer(buffer);
118 contents
119 }
120
121 pub fn package(self) -> (Manifest, PackageContents) {
122 let contents = self.contents();
123 (self.manifest, contents)
124 }
125}