@@ -5,10 +5,12 @@ use std::path::PathBuf;
5
5
use std:: sync:: Arc ;
6
6
7
7
use anyhow:: { anyhow, bail, ensure, Result } ;
8
+ use async_process:: { Command , Stdio } ;
8
9
use async_std:: fs;
9
10
use async_std:: task:: { spawn, spawn_blocking, JoinHandle } ;
10
- use async_process :: { Command , Stdio } ;
11
+ use console :: Emoji ;
11
12
use futures:: stream:: { FuturesUnordered , StreamExt } ;
13
+ use indicatif:: ProgressBar ;
12
14
use nipper:: Document ;
13
15
use serde:: { Serialize , Deserialize } ;
14
16
@@ -25,25 +27,28 @@ const HREF_ATTR: &str = "href";
25
27
/// build routines can be cleanly abstracted away form any specific CLI endpoints.
26
28
pub struct BuildSystem {
27
29
/// The `Cargo.toml` manifest of the app being built.
28
- pub manifest : CargoManifest ,
30
+ manifest : CargoManifest ,
29
31
/// The path to the source HTML document from which the output `index.html` will be built.
30
- pub target_html_path : Arc < PathBuf > ,
32
+ target_html_path : Arc < PathBuf > ,
31
33
/// The parent directory of `target_html_path`.
32
- pub target_html_dir : Arc < PathBuf > ,
34
+ target_html_dir : Arc < PathBuf > ,
33
35
/// Build in release mode.
34
- pub release : bool ,
36
+ release : bool ,
35
37
/// The output dir for all final assets.
36
- pub dist : Arc < PathBuf > ,
38
+ dist : Arc < PathBuf > ,
37
39
/// The public URL from which assets are to be served.
38
40
public_url : String ,
39
41
40
42
/// The output dir of the wasm-bindgen execution.
41
- pub bindgen_out : Arc < PathBuf > ,
43
+ bindgen_out : Arc < PathBuf > ,
42
44
/// The path to the app's output WASM.
43
- pub app_target_wasm : Arc < PathBuf > ,
45
+ app_target_wasm : Arc < PathBuf > ,
44
46
45
47
/// A stream of asset pipelines.
46
- pub pipelines : FuturesUnordered < JoinHandle < Result < AssetPipelineOutput > > > ,
48
+ pipelines : FuturesUnordered < JoinHandle < Result < AssetPipelineOutput > > > ,
49
+
50
+ /// The object used for writing data to stdout, stderr & controlling the progress spinner.
51
+ progress : ProgressBar ,
47
52
}
48
53
49
54
impl BuildSystem {
@@ -76,11 +81,30 @@ impl BuildSystem {
76
81
bindgen_out : Arc :: new ( bindgen_out) ,
77
82
app_target_wasm : Arc :: new ( app_target_wasm) ,
78
83
pipelines : FuturesUnordered :: new ( ) ,
84
+ progress : ProgressBar :: new_spinner ( ) ,
79
85
} )
80
86
}
81
87
88
+ /// Get a handle to the progress / terminal system.
89
+ pub fn get_progress_handle ( & self ) -> ProgressBar {
90
+ self . progress . clone ( )
91
+ }
92
+
82
93
/// Build the application described in the given build data.
83
94
pub async fn build_app ( & mut self ) -> Result < ( ) > {
95
+ self . progress . reset ( ) ;
96
+ self . progress . enable_steady_tick ( 100 ) ;
97
+ let res = self . build_app_internal ( ) . await ;
98
+ self . progress . disable_steady_tick ( ) ;
99
+ if let Err ( err) = res {
100
+ self . progress . finish_with_message ( & format ! ( "{}build finished with errors" , Emoji ( "❌ " , "" ) ) ) ;
101
+ return Err ( err) ;
102
+ }
103
+ self . progress . finish_with_message ( & format ! ( "{}build completed successfully" , Emoji ( "✅ " , "" ) ) ) ;
104
+ Ok ( ( ) )
105
+ }
106
+
107
+ async fn build_app_internal ( & mut self ) -> Result < ( ) > {
84
108
// Update the contents of the source HTML.
85
109
let target_html_raw = fs:: read_to_string ( self . target_html_path . as_ref ( ) ) . await ?;
86
110
let mut target_html = Document :: from ( & target_html_raw) ;
@@ -117,7 +141,7 @@ impl BuildSystem {
117
141
let asset = match asset_res {
118
142
Ok ( asset) => asset,
119
143
Err ( err) => {
120
- eprintln ! ( "{}" , err) ;
144
+ self . progress . println ( format ! ( "{}" , err) ) ;
121
145
continue ;
122
146
}
123
147
} ;
@@ -154,7 +178,7 @@ impl BuildSystem {
154
178
if self . release {
155
179
args. push ( "--release" ) ;
156
180
}
157
- println ! ( "starting cargo build on {}" , & self . manifest. package. name) ; // TODO: pin down logging.
181
+ self . progress . set_message ( & format ! ( "{} starting cargo build on {}" , Emoji ( "📦 " , "" ) , & self . manifest. package. name) ) ;
158
182
let app_target_wasm = self . app_target_wasm . clone ( ) ;
159
183
spawn ( async move {
160
184
// Spawn the cargo build process.
@@ -187,7 +211,7 @@ impl BuildSystem {
187
211
fn spawn_wasm_bindgen_build ( & self , file_name : String ) -> JoinHandle < Result < WasmBindgenOutput > > {
188
212
let ( dist, bindgen_out, app_target_wasm) = ( self . dist . clone ( ) , self . bindgen_out . clone ( ) , self . app_target_wasm . clone ( ) ) ;
189
213
190
- println ! ( "starting wasm-bindgen build" ) ; // TODO: pin down logging.
214
+ self . progress . set_message ( & format ! ( "{} starting wasm-bindgen build" , Emoji ( "📦 " , "" ) ) ) ;
191
215
spawn ( async move {
192
216
let arg_out_path = format ! ( "--out-dir={}" , bindgen_out. display( ) ) ;
193
217
let arg_out_name = format ! ( "--out-name={}" , & file_name) ;
@@ -232,7 +256,7 @@ impl BuildSystem {
232
256
/// for the asset is finished, it will be able to update the DOM correctly based on its own
233
257
/// ID. All of these trunk specific IDs will be removed from the DOM before it is written.
234
258
async fn spawn_asset_pipelines ( & mut self , target_html : & mut Document ) -> Result < ( ) > {
235
- println ! ( "spawning asset pipelines" ) ;
259
+ self . progress . set_message ( & format ! ( "{} spawning asset pipelines" , Emoji ( "📦 " , "" ) ) ) ;
236
260
237
261
// Accumulate assets declared in HTML head section links for processing.
238
262
let asset_links = target_html. select ( r#"html head link"# )
@@ -254,7 +278,7 @@ impl BuildSystem {
254
278
let path = self . target_html_dir . join ( href. as_ref ( ) ) ;
255
279
let rel = node. attr_or ( "rel" , "" ) . to_string ( ) . to_lowercase ( ) ;
256
280
let id = format ! ( "link-{}" , idx) ;
257
- let asset = match AssetFile :: new ( path, AssetType :: Link { rel} , id) . await {
281
+ let asset = match AssetFile :: new ( path, AssetType :: Link { rel} , id, & self . progress ) . await {
258
282
Ok ( asset) => asset,
259
283
Err ( _) => continue ,
260
284
} ;
@@ -291,8 +315,7 @@ impl BuildSystem {
291
315
292
316
/// Spawn a concurrent build pipeline for a SASS/SCSS asset.
293
317
fn spawn_sass_pipeline ( & mut self , asset : AssetFile ) -> JoinHandle < Result < AssetPipelineOutput > > {
294
- let dist = self . dist . clone ( ) ;
295
- let release = self . release ;
318
+ let ( dist, release, progress) = ( self . dist . clone ( ) , self . release , self . progress . clone ( ) ) ;
296
319
spawn ( async move {
297
320
// Compile the target SASS/SCSS file.
298
321
let path_str = asset. path . to_string_lossy ( ) . to_string ( ) ;
@@ -304,7 +327,7 @@ impl BuildSystem {
304
327
match sass_rs:: compile_file ( & path_str, opts) {
305
328
Ok ( css) => Ok ( css) ,
306
329
Err ( err) => {
307
- eprintln ! ( "{}" , err) ;
330
+ progress . println ( format ! ( "{}" , err) ) ;
308
331
Err ( anyhow ! ( "error compiling sass for {}" , & path_str) )
309
332
}
310
333
}
@@ -377,13 +400,13 @@ impl AssetFile {
377
400
///
378
401
/// Any errors returned from this constructor indicate that one of these invariants was not
379
402
/// upheld.
380
- pub async fn new ( path : PathBuf , atype : AssetType , id : String ) -> Result < Self > {
403
+ pub async fn new ( path : PathBuf , atype : AssetType , id : String , progress : & ProgressBar ) -> Result < Self > {
381
404
// Take the path to referenced resource, if it is actually an FS path, then we continue.
382
405
let path = match fs:: canonicalize ( & path) . await {
383
406
Ok ( path) => path,
384
407
Err ( _) => {
385
408
if !path. to_string_lossy ( ) . contains ( "://" ) {
386
- eprintln ! ( "skipping invalid path: {}" , path. to_string_lossy( ) ) ;
409
+ progress . println ( format ! ( "{} skipping invalid path: {}" , Emoji ( "︎🚫 " , "" ) , path. to_string_lossy( ) ) ) ;
387
410
}
388
411
return Err ( anyhow ! ( "skipping asset which is not a valid path" ) ) ;
389
412
}
0 commit comments