@@ -95,21 +95,41 @@ pub async fn ensure_esbuild(
9595 package_folder. join ( "bin" ) . join ( "esbuild" )
9696 } ;
9797
98- std:: fs:: create_dir_all ( esbuild_path. parent ( ) . unwrap ( ) ) . with_context (
99- || {
100- format ! (
101- "failed to create directory {}" ,
102- esbuild_path. parent( ) . unwrap( ) . display( )
103- )
104- } ,
105- ) ?;
106- std:: fs:: copy ( & path, & esbuild_path) . with_context ( || {
98+ let esbuild_dir = esbuild_path. parent ( ) . unwrap ( ) ;
99+ std:: fs:: create_dir_all ( esbuild_dir) . with_context ( || {
100+ format ! ( "failed to create directory {}" , esbuild_dir. display( ) )
101+ } ) ?;
102+ // Install the binary atomically: copy to a temporary file in the same
103+ // directory and then rename it into place. The rename is atomic, so a
104+ // concurrent `deno bundle` process never observes (via the `exists()`
105+ // check above) and tries to execute a half-written binary, which would
106+ // otherwise fail with ETXTBSY ("text file busy") on Linux.
107+ let tmp_path =
108+ esbuild_dir. join ( format ! ( ".esbuild-{}.tmp" , std:: process:: id( ) ) ) ;
109+ std:: fs:: copy ( & path, & tmp_path) . with_context ( || {
107110 format ! (
108111 "failed to copy esbuild binary from {} to {}" ,
109112 path. display( ) ,
110- esbuild_path . display( )
113+ tmp_path . display( )
111114 )
112115 } ) ?;
116+ match std:: fs:: rename ( & tmp_path, & esbuild_path) {
117+ Ok ( ( ) ) => { }
118+ // Another process won the race and installed the binary already; our
119+ // copy is redundant, so just discard it.
120+ Err ( _) if esbuild_path. exists ( ) => {
121+ let _ = std:: fs:: remove_file ( & tmp_path) ;
122+ }
123+ Err ( err) => {
124+ let _ = std:: fs:: remove_file ( & tmp_path) ;
125+ return Err ( err) . with_context ( || {
126+ format ! (
127+ "failed to move esbuild binary into place at {}" ,
128+ esbuild_path. display( )
129+ )
130+ } ) ;
131+ }
132+ }
113133
114134 if !existed {
115135 let _ = std:: fs:: remove_dir_all ( & package_folder) . inspect_err ( |e| {
0 commit comments