1use anyhow::Result;
2use rustc_hash::FxHashSet;
3use tracing::Instrument;
4use turbo_tasks::{
5 ResolvedVc, TryFlatJoinIterExt, ValueToString, Vc,
6 graph::{AdjacencyMap, GraphTraversal},
7};
8use turbo_tasks_fs::{FileSystemPath, rebase};
9use turbopack_core::{
10 asset::Asset,
11 output::{OutputAsset, OutputAssets},
12};
13
14#[turbo_tasks::function]
20pub async fn emit_all_assets(
21 assets: Vc<OutputAssets>,
22 node_root: Vc<FileSystemPath>,
23 client_relative_path: Vc<FileSystemPath>,
24 client_output_path: Vc<FileSystemPath>,
25) -> Result<()> {
26 let _ = emit_assets(
27 all_assets_from_entries(assets),
28 node_root,
29 client_relative_path,
30 client_output_path,
31 )
32 .resolve()
33 .await?;
34 Ok(())
35}
36
37#[turbo_tasks::function]
43pub async fn emit_assets(
44 assets: Vc<OutputAssets>,
45 node_root: Vc<FileSystemPath>,
46 client_relative_path: Vc<FileSystemPath>,
47 client_output_path: Vc<FileSystemPath>,
48) -> Result<()> {
49 let _: Vec<Vc<()>> = assets
50 .await?
51 .iter()
52 .copied()
53 .map(|asset| async move {
54 let path = asset.path();
55 let span = tracing::info_span!("emit asset", name = %path.to_string().await?);
56 async move {
57 let path = path.await?;
58 Ok(if path.is_inside_ref(&*node_root.await?) {
59 Some(emit(*asset))
60 } else if path.is_inside_ref(&*client_relative_path.await?) {
61 Some(emit_rebase(
65 *asset,
66 client_relative_path,
67 client_output_path,
68 ))
69 } else {
70 None
71 })
72 }
73 .instrument(span)
74 .await
75 })
76 .try_flat_join()
77 .await?;
78 Ok(())
79}
80
81#[turbo_tasks::function]
82async fn emit(asset: Vc<Box<dyn OutputAsset>>) -> Result<()> {
83 let _ = asset.content().write(asset.path()).resolve().await?;
84 Ok(())
85}
86
87#[turbo_tasks::function]
88async fn emit_rebase(
89 asset: Vc<Box<dyn OutputAsset>>,
90 from: Vc<FileSystemPath>,
91 to: Vc<FileSystemPath>,
92) -> Result<()> {
93 let path = rebase(asset.path(), from, to);
94 let content = asset.content();
95 let _ = content
96 .resolve()
97 .await?
98 .write(path.resolve().await?)
99 .resolve()
100 .await?;
101 Ok(())
102}
103
104#[turbo_tasks::function]
107pub async fn all_assets_from_entries(entries: Vc<OutputAssets>) -> Result<Vc<OutputAssets>> {
108 Ok(Vc::cell(
109 AdjacencyMap::new()
110 .skip_duplicates()
111 .visit(entries.await?.iter().copied(), get_referenced_assets)
112 .await
113 .completed()?
114 .into_inner()
115 .into_postorder_topological()
116 .collect::<FxHashSet<_>>()
117 .into_iter()
118 .collect(),
119 ))
120}
121
122async fn get_referenced_assets(
124 asset: ResolvedVc<Box<dyn OutputAsset>>,
125) -> Result<impl Iterator<Item = ResolvedVc<Box<dyn OutputAsset>>> + Send> {
126 Ok(asset
127 .references()
128 .await?
129 .iter()
130 .copied()
131 .collect::<Vec<_>>()
132 .into_iter())
133}