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