@@ -12,6 +12,7 @@ use deno_core::error::AnyError;
1212use deno_core:: resolve_url_or_path;
1313use deno_graph:: GraphKind ;
1414use deno_terminal:: colors;
15+ use rand:: Rng ;
1516use std:: path:: Path ;
1617use std:: path:: PathBuf ;
1718use std:: sync:: Arc ;
@@ -97,8 +98,20 @@ pub async fn compile(
9798 ) ;
9899 validate_output_path ( & output_path) ?;
99100
100- let mut file = std:: fs:: File :: create ( & output_path)
101- . with_context ( || format ! ( "Opening file '{}'" , output_path. display( ) ) ) ?;
101+ let mut temp_filename = output_path. file_name ( ) . unwrap ( ) . to_owned ( ) ;
102+ temp_filename. push ( format ! (
103+ ".tmp-{}" ,
104+ faster_hex:: hex_encode(
105+ & rand:: thread_rng( ) . gen :: <[ u8 ; 8 ] >( ) ,
106+ & mut [ 0u8 ; 16 ]
107+ )
108+ . unwrap( )
109+ ) ) ;
110+ let temp_path = output_path. with_file_name ( temp_filename) ;
111+
112+ let mut file = std:: fs:: File :: create ( & temp_path) . with_context ( || {
113+ format ! ( "Opening temporary file '{}'" , temp_path. display( ) )
114+ } ) ?;
102115 let write_result = binary_writer
103116 . write_bin (
104117 & mut file,
@@ -108,20 +121,38 @@ pub async fn compile(
108121 cli_options,
109122 )
110123 . await
111- . with_context ( || format ! ( "Writing {}" , output_path. display( ) ) ) ;
124+ . with_context ( || {
125+ format ! ( "Writing temporary file '{}'" , temp_path. display( ) )
126+ } ) ;
112127 drop ( file) ;
113- if let Err ( err) = write_result {
114- // errored, so attempt to remove the output path
115- let _ = std:: fs:: remove_file ( output_path) ;
116- return Err ( err) ;
117- }
118128
119129 // set it as executable
120130 #[ cfg( unix) ]
121- {
131+ let write_result = write_result . and_then ( |_| {
122132 use std:: os:: unix:: fs:: PermissionsExt ;
123- let perms = std:: fs:: Permissions :: from_mode ( 0o777 ) ;
124- std:: fs:: set_permissions ( output_path, perms) ?;
133+ let perms = std:: fs:: Permissions :: from_mode ( 0o755 ) ;
134+ std:: fs:: set_permissions ( & temp_path, perms) . with_context ( || {
135+ format ! (
136+ "Setting permissions on temporary file '{}'" ,
137+ temp_path. display( )
138+ )
139+ } )
140+ } ) ;
141+
142+ let write_result = write_result. and_then ( |_| {
143+ std:: fs:: rename ( & temp_path, & output_path) . with_context ( || {
144+ format ! (
145+ "Renaming temporary file '{}' to '{}'" ,
146+ temp_path. display( ) ,
147+ output_path. display( )
148+ )
149+ } )
150+ } ) ;
151+
152+ if let Err ( err) = write_result {
153+ // errored, so attempt to remove the temporary file
154+ let _ = std:: fs:: remove_file ( temp_path) ;
155+ return Err ( err) ;
125156 }
126157
127158 Ok ( ( ) )
0 commit comments