1use anyhow::{bail, Result};
2use async_recursion::async_recursion;
3use indexmap::IndexSet;
4use semver::VersionReq;
5use std::fs;
6use warg_protocol::package::{Release, ReleaseState};
7use warg_protocol::registry::PackageName;
8use wasm_encoder::{
9 Component, ComponentImportSection, ComponentSectionId, ComponentTypeRef, RawSection,
10};
11use wasmparser::{Chunk, ComponentImportSectionReader, Parser, Payload};
12
13use super::Client;
14use crate::storage::{ContentStorage, NamespaceMapStorage, PackageInfo, RegistryStorage};
15use crate::version_util::{DependencyImportParser, Import, ImportKind};
16pub struct LockListBuilder {
20 pub lock_list: IndexSet<Import>,
22}
23
24impl Default for LockListBuilder {
25 fn default() -> Self {
27 Self {
28 lock_list: IndexSet::new(),
29 }
30 }
31}
32
33impl LockListBuilder {
34 fn parse_import(
35 &self,
36 parser: &ComponentImportSectionReader,
37 imports: &mut Vec<String>,
38 ) -> Result<()> {
39 let clone = parser.clone();
40 for import in clone.into_iter_with_offsets() {
41 let (_, imp) = import?;
42 imports.push(imp.name.0.to_string());
43 }
44 Ok(())
45 }
46
47 #[async_recursion]
48 async fn parse_package<R, C, N>(
49 &mut self,
50 client: &Client<R, C, N>,
51 mut bytes: &[u8],
52 ) -> Result<()>
53 where
54 R: RegistryStorage,
55 C: ContentStorage,
56 N: NamespaceMapStorage,
57 {
58 let mut parser = Parser::new(0);
59 let mut imports: Vec<String> = Vec::new();
60 loop {
61 let payload = match parser.parse(bytes, true)? {
62 Chunk::NeedMoreData(_) => unreachable!(),
63 Chunk::Parsed { payload, consumed } => {
64 bytes = &bytes[consumed..];
65 payload
66 }
67 };
68 match payload {
69 Payload::ComponentImportSection(s) => {
70 self.parse_import(&s, &mut imports)?;
71 }
72 Payload::CodeSectionStart {
73 count: _,
74 range: _,
75 size: _,
76 } => {
77 parser.skip_section();
78 }
79 Payload::ModuleSection { range, .. } => {
80 let offset = range.end - range.start;
81 if offset > bytes.len() {
82 bail!("invalid module or component section range");
83 }
84 bytes = &bytes[offset..];
85 }
86 Payload::ComponentSection { range, .. } => {
87 let offset = range.end - range.start;
88 if offset > bytes.len() {
89 bail!("invalid module or component section range");
90 }
91 bytes = &bytes[offset..];
92 }
93 Payload::End(_) => {
94 break;
95 }
96 _ => {}
97 }
98 }
99 for import in imports {
100 let mut resolver = DependencyImportParser {
101 next: &import,
102 offset: 0,
103 };
104
105 let import = resolver.parse()?;
106 match import.kind {
107 ImportKind::Locked(_) | ImportKind::Unlocked => {
108 let id = PackageName::new(import.name.clone())?;
109 let registry_domain = client.get_warg_registry(id.namespace()).await?;
110 if let Some(info) = client
111 .registry()
112 .load_package(registry_domain.as_ref(), &id)
113 .await?
114 {
115 let release = info.state.releases().last();
116 if let Some(r) = release {
117 if let Some(bytes) = self.release_bytes(r, client)? {
118 self.parse_package(client, &bytes).await?;
119 }
120 }
121 self.lock_list.insert(import);
122 } else {
123 client.download(&id, &VersionReq::STAR).await?;
124 if let Some(info) = client
125 .registry()
126 .load_package(
127 client.get_warg_registry(id.namespace()).await?.as_ref(),
128 &id,
129 )
130 .await?
131 {
132 let release = info.state.releases().last();
133 if let Some(r) = release {
134 if let Some(bytes) = self.release_bytes(r, client)? {
135 self.parse_package(client, &bytes).await?;
136 }
137 }
138 self.lock_list.insert(import);
139 }
140 }
141 }
142 ImportKind::Interface(_) => {}
143 }
144 }
145 Ok(())
146 }
147
148 fn release_bytes<R: RegistryStorage, C: ContentStorage, N: NamespaceMapStorage>(
149 &self,
150 release: &Release,
151 client: &Client<R, C, N>,
152 ) -> Result<Option<Vec<u8>>> {
153 let state = &release.state;
154 if let ReleaseState::Released { content } = state {
155 let path = client.content().content_location(content);
156 if let Some(p) = path {
157 return Ok(Some(fs::read(p)?));
158 }
159 }
160 Ok(None)
161 }
162
163 #[async_recursion]
165 pub async fn build_list<R, C, N>(
166 &mut self,
167 client: &Client<R, C, N>,
168 info: &PackageInfo,
169 ) -> Result<()>
170 where
171 R: RegistryStorage,
172 C: ContentStorage,
173 N: NamespaceMapStorage,
174 {
175 let release = info.state.releases().last();
176 if let Some(r) = release {
177 let state = &r.state;
178 if let ReleaseState::Released { content } = state {
179 let path = client.content().content_location(content);
180 if let Some(p) = path {
181 let bytes = fs::read(p)?;
182 self.parse_package(client, &bytes).await?;
183 }
184 }
185 }
186 Ok(())
187 }
188}
189
190pub struct Bundler<'a, R, C, N>
192where
193 R: RegistryStorage,
194 C: ContentStorage,
195 N: NamespaceMapStorage,
196{
197 client: &'a Client<R, C, N>,
199}
200
201impl<'a, R, C, N> Bundler<'a, R, C, N>
202where
203 R: RegistryStorage,
204 C: ContentStorage,
205 N: NamespaceMapStorage,
206{
207 pub fn new(client: &'a Client<R, C, N>) -> Self {
209 Self { client }
210 }
211
212 async fn parse_imports(
213 &mut self,
214 parser: ComponentImportSectionReader<'a>,
215 component: &mut Component,
216 ) -> Result<Vec<u8>> {
217 let mut imports = ComponentImportSection::new();
218 for import in parser.into_iter_with_offsets() {
219 let (_, imp) = import?;
220 let mut dep_parser = DependencyImportParser {
221 next: imp.name.0,
222 offset: 0,
223 };
224 let parsed_imp = dep_parser.parse()?;
225 if !parsed_imp.name.contains('/') {
226 let pkg_id = PackageName::new(parsed_imp.name)?;
227 if let Some(info) = self
228 .client
229 .registry()
230 .load_package(
231 self.client
232 .get_warg_registry(pkg_id.namespace())
233 .await?
234 .as_ref(),
235 &pkg_id,
236 )
237 .await?
238 {
239 let release = if parsed_imp.req != VersionReq::STAR {
240 info.state
241 .releases()
242 .filter(|r| parsed_imp.req.matches(&r.version))
243 .last()
244 } else {
245 info.state.releases().last()
246 };
247 if let Some(r) = release {
248 let release_state = &r.state;
249 if let ReleaseState::Released { content } = release_state {
250 let path = self.client.content().content_location(content);
251 if let Some(p) = path {
252 let bytes = fs::read(p)?;
253 component.section(&RawSection {
254 id: ComponentSectionId::Component.into(),
255 data: &bytes,
256 });
257 }
258 }
259 }
260 }
261 } else if let wasmparser::ComponentTypeRef::Instance(i) = imp.ty {
262 imports.import(imp.name.0, ComponentTypeRef::Instance(i));
263 }
264 }
265 component.section(&imports);
266 Ok(Vec::new())
267 }
268
269 pub async fn parse(&mut self, mut bytes: &'a [u8]) -> Result<Component> {
271 let constant = bytes;
272 let mut parser = Parser::new(0);
273 let mut component = Component::new();
274 loop {
275 let payload = match parser.parse(bytes, true)? {
276 Chunk::NeedMoreData(_) => unreachable!(),
277 Chunk::Parsed { payload, consumed } => {
278 bytes = &bytes[consumed..];
279 payload
280 }
281 };
282 match payload {
283 Payload::ComponentImportSection(s) => {
284 self.parse_imports(s, &mut component).await?;
285 }
286 Payload::ModuleSection { range, .. } => {
287 let offset = range.end - range.start;
288 component.section(&RawSection {
289 id: 1,
290 data: &constant[range],
291 });
292 if offset > bytes.len() {
293 panic!();
294 }
295 bytes = &bytes[offset..];
296 }
297 Payload::End(_) => {
298 break;
299 }
300 _ => {
301 if let Some((id, range)) = payload.as_section() {
302 component.section(&RawSection {
303 id,
304 data: &constant[range],
305 });
306 }
307 }
308 }
309 }
310 Ok(component)
311 }
312}