FIX: Make site tasks work with duplicated uploads (#13972)

FIX: Make site tasks work with duplicated uploads (#13972)

Uploads can be reused between site settings. This change allows the same upload to be exported only once and then the same file is reused. The same applies to import.

diff --git a/lib/tasks/site.rake b/lib/tasks/site.rake
index 87ac822..ba984bd 100644
--- a/lib/tasks/site.rake
+++ b/lib/tasks/site.rake
@@ -8,6 +8,7 @@ class ZippedSiteStructure
 
   def initialize(path, create: false)
     @zip = Zip::File.open(path, create)
+    @uploads = {}
   end
 
   def close
@@ -41,26 +42,53 @@ class ZippedSiteStructure
       return nil
     end
 
+    if @uploads[upload.id].present?
+      puts "  - Already exported upload #{upload_or_id_or_url} to #{@uploads[upload.id][:path]}"
+      return @uploads[upload.id]
+    end
+
     local_path = upload.local? ? Discourse.store.path_for(upload) : Discourse.store.download(upload).path
     zip_path = File.join('uploads', File.basename(local_path))
+    zip_path = get_unique_path(zip_path)
 
     puts "  - Exporting upload #{upload_or_id_or_url} to #{zip_path}"
     @zip.add(zip_path, local_path)
 
-    { filename: upload.original_filename, path: zip_path }
+    @uploads[upload.id] ||= { filename: upload.original_filename, path: zip_path }
   end
 
   def get_upload(upload, opts = {})
     return nil if upload.blank?
 
+    if @uploads[upload['path']].present?
+      puts "  - Already imported upload #{upload['filename']} from #{upload['path']}"
+      return @uploads[upload['path']]
+    end
+
     puts "  - Importing upload #{upload['filename']} from #{upload['path']}"
 
     tempfile = Tempfile.new(upload['filename'], binmode: true)
     tempfile.write(@zip.get_input_stream(upload['path']).read)
     tempfile.rewind
 
-    UploadCreator.new(tempfile, upload['filename'], opts)
-      .create_for(Discourse::SYSTEM_USER_ID)
+    @uploads[upload['path']] ||= UploadCreator.new(tempfile, upload['filename'], opts).create_for(Discourse::SYSTEM_USER_ID)
+  end
+
+  private
+
+  def get_unique_path(path)
+    return path if @zip.find_entry(path).blank?
+
+    extname = File.extname(path)
+    basename = File.basename(path, extname)
+    dirname = File.dirname(path)
+
+    i = 0
+    loop do
+      i += 1
+      path = File.join(dirname, "#{basename}_#{i}#{extname}")
+      return path if @zip.find_entry(path).blank?
+    end
   end
 end
 

GitHub sha: 4380ba34d5d83ee05cb8bf2057882de9efde1362

This commit appears in #13972 which was approved by eviltrout. It was merged by nbianca.