@@ -190,6 +190,8 @@ func doDownloadPluginFromHub(ctx context.Context, logger zerolog.Logger, c *clou
190190 return errors .New ("failed to get plugin metadata from hub: empty location from response" )
191191 }
192192 pluginZipPath := ops .LocalPath + ".zip"
193+ defer os .Remove (pluginZipPath )
194+
193195 writtenChecksum , err := downloadFile (ctx , pluginZipPath , location , dops )
194196 if err != nil {
195197 return fmt .Errorf ("failed to download plugin: %w" , err )
@@ -201,29 +203,46 @@ func doDownloadPluginFromHub(ctx context.Context, logger zerolog.Logger, c *clou
201203 return fmt .Errorf ("checksum mismatch: expected %s, got %s" , pluginAsset .Checksum , writtenChecksum )
202204 }
203205
204- archive , err := zip .OpenReader (pluginZipPath )
206+ pathInArchive := fmt .Sprintf ("plugin-%s-%s-%s-%s" , ops .PluginName , ops .PluginVersion , runtime .GOOS , runtime .GOARCH )
207+ return extractPluginBinary (pluginZipPath , pathInArchive , ops .LocalPath )
208+ }
209+
210+ // extractPluginBinary writes the binary to a temporary file and renames it into
211+ // place, so a failure part way through never leaves a truncated binary that the
212+ // next run treats as a cached plugin.
213+ func extractPluginBinary (archivePath , pathInArchive , localPath string ) error {
214+ archive , err := zip .OpenReader (archivePath )
205215 if err != nil {
206216 return fmt .Errorf ("failed to open plugin archive: %w" , err )
207217 }
208218 defer archive .Close ()
209219
210- fileInArchive , err := archive .Open (fmt . Sprintf ( "plugin-%s-%s-%s-%s" , ops . PluginName , ops . PluginVersion , runtime . GOOS , runtime . GOARCH ) )
220+ fileInArchive , err := archive .Open (pathInArchive )
211221 if err != nil {
212- return fmt .Errorf ("failed to open plugin archive: %w" , err )
222+ return fmt .Errorf ("failed to open plugin archive %s : %w" , pathInArchive , err )
213223 }
224+ defer fileInArchive .Close ()
214225
215- out , err := os .OpenFile ( ops . LocalPath , os . O_RDWR | os . O_CREATE | os . O_TRUNC , 0744 )
226+ out , err := os .CreateTemp ( filepath . Dir ( localPath ), filepath . Base ( localPath ) + ".tmp" )
216227 if err != nil {
217- return fmt .Errorf ("failed to create file %s: %w" , ops . LocalPath , err )
228+ return fmt .Errorf ("failed to create file %s: %w" , localPath , err )
218229 }
219- _ , err = io .Copy (out , fileInArchive )
220- if err != nil {
230+ tmpPath := out .Name ()
231+ defer os .Remove (tmpPath )
232+
233+ if _ , err := io .Copy (out , fileInArchive ); err != nil {
234+ out .Close ()
221235 return fmt .Errorf ("failed to copy body to file: %w" , err )
222236 }
223- err = out .Close ()
224- if err != nil {
237+ if err := out .Close (); err != nil {
225238 return fmt .Errorf ("failed to close file: %w" , err )
226239 }
240+ if err := os .Chmod (tmpPath , 0744 ); err != nil {
241+ return fmt .Errorf ("failed to set permissions on %s: %w" , localPath , err )
242+ }
243+ if err := os .Rename (tmpPath , localPath ); err != nil {
244+ return fmt .Errorf ("failed to move plugin binary to %s: %w" , localPath , err )
245+ }
227246 return nil
228247}
229248
@@ -284,16 +303,12 @@ func doDownloadPluginFromGithub(ctx context.Context, logger zerolog.Logger, loca
284303 return fmt .Errorf ("failed to get plugin url: %w" , err )
285304 }
286305 logger .Debug ().Msg (fmt .Sprintf ("Downloading %s" , downloadURL ))
306+ defer os .Remove (pluginZipPath )
307+
287308 if _ , err := downloadFile (ctx , pluginZipPath , downloadURL , dops ); err != nil {
288309 return fmt .Errorf ("failed to download plugin: %w" , err )
289310 }
290311
291- archive , err := zip .OpenReader (pluginZipPath )
292- if err != nil {
293- return fmt .Errorf ("failed to open plugin archive: %w" , err )
294- }
295- defer archive .Close ()
296-
297312 var pathInArchive string
298313 switch {
299314 case strings .HasPrefix (downloadURL , "https://github.com/cloudquery/cloudquery/releases/download/plugins-plugin" ):
@@ -312,24 +327,7 @@ func doDownloadPluginFromGithub(ctx context.Context, logger zerolog.Logger, loca
312327 return fmt .Errorf ("unknown GitHub %s" , downloadURL )
313328 }
314329
315- pathInArchive = WithBinarySuffix (pathInArchive )
316- fileInArchive , err := archive .Open (pathInArchive )
317- if err != nil {
318- return fmt .Errorf ("failed to open plugin archive plugins/source/%s: %w" , name , err )
319- }
320- out , err := os .OpenFile (localPath , os .O_RDWR | os .O_CREATE | os .O_TRUNC , 0744 )
321- if err != nil {
322- return fmt .Errorf ("failed to create file %s: %w" , localPath , err )
323- }
324- _ , err = io .Copy (out , fileInArchive )
325- if err != nil {
326- return fmt .Errorf ("failed to copy body to file: %w" , err )
327- }
328- err = out .Close ()
329- if err != nil {
330- return fmt .Errorf ("failed to close file: %w" , err )
331- }
332- return nil
330+ return extractPluginBinary (pluginZipPath , WithBinarySuffix (pathInArchive ), localPath )
333331}
334332
335333func downloadFile (ctx context.Context , localPath string , downloadURL string , dops DownloaderOptions ) (string , error ) {
0 commit comments