OSDN Git Service

Show progress and check file digest after upload.
[osdn-codes/osdn-cli.git] / lib / osdn / cli / command / frs_upload.rb
index a40ace3..e9aaa54 100644 (file)
@@ -1,3 +1,46 @@
+require 'digest'
+require 'ethon'
+
+module OSDN; module CLI; module Command
+  class FrsUpload < Base
+    @@_show_progress = false
+    def self._show_progress
+      @@_show_progress
+    end
+    def self._show_progress=(v)
+      need_reset = (!!@@_show_progress != !!v)
+      @@_show_progress = v
+      need_reset and _reset_all_typhoeus_pool
+    end
+
+    def self._reset_all_typhoeus_pool
+      first_easyid = nil
+      while true
+        e = Typhoeus::Pool.get
+        Typhoeus::Pool.release(e)
+        e.__id__ == first_easyid and break
+        first_easyid ||= e.__id__
+      end
+    end
+  end
+end; end; end
+
+module Ethon
+  class Easy
+    module Callbacks
+      alias_method :set_callbacks_orig, :set_callbacks
+      def set_callbacks
+        set_callbacks_orig
+        if OSDN::CLI::Command::FrsUpload._show_progress
+          Curl.set_option(:noprogress, false, handle)
+        else
+          Curl.set_option(:noprogress, true, handle)
+        end
+      end
+    end
+  end
+end
+
 module OSDN; module CLI; module Command
   class FrsUpload < Base
     def help
@@ -47,8 +90,12 @@ module OSDN; module CLI; module Command
       Pathname.glob(@target_dir+'*').each do |pdir|
         unless load_variables(pdir).package_id
           logger.info "Createing new package '#{pdir.basename}'"
-          pinfo = api.create_package target_proj, pdir.basename, visibility: @visibility
-          update_variables pdir, package_id: pinfo.id
+          if @dry_run
+            pinfo = Hashie::Mash.new id: '(dry-run)', name: pdir.basename, url: '(dry-run)'
+          else
+            pinfo = api.create_package target_proj, pdir.basename, visibility: @visibility
+            update_variables pdir, package_id: pinfo.id
+          end
           $stdout.puts "New package '#{pinfo.name}' has been created; #{pinfo.url}"
         end
 
@@ -59,13 +106,12 @@ module OSDN; module CLI; module Command
             rinfo = api.get_release target_proj, target_package(rdir), target_release(rdir)
           else vars.release_id
             logger.info "Createing new release '#{rdir.basename}'"
-            rinfo = nil
-            if api.respond_to? :create_reelase # TODO: remove, just typo...
-              rinfo = api.create_reelase target_proj, target_package(rdir), rdir.basename, visibility: @visibility
+            if @dry_run
+              rinfo = Hashie::Mash.new id: '(dry-run)', name: rdir.basename, url: '(dry-run)', files: []
             else
               rinfo = api.create_release target_proj, target_package(rdir), rdir.basename, visibility: @visibility
+              update_variables rdir, release_id: rinfo.id
             end
-            update_variables rdir, release_id: rinfo.id
             $stdout.puts "New release '#{rinfo.name}' has been created; #{rinfo.url}"
           end
           
@@ -75,13 +121,35 @@ module OSDN; module CLI; module Command
               next
             end
 
-            if rinfo.files.find { |f| f.name == file.basename.to_s }
+            logger.debug "Calculating digest for #{file}..."
+            digests = {
+              sha256: hexdigest(Digest::SHA256, file),
+              sha1:   hexdigest(Digest::SHA1, file),
+              md5:    hexdigest(Digest::MD5, file),
+            }
+            if remote_f = rinfo.files.find { |f| f.name == file.basename.to_s }
+              if digests.find { |type, dig| dig != remote_f.send("digest_#{type}") }
+                logger.error "#{file} was changed from remote file! Please delete remote file before uploading new one."
+              end
               logger.warn "Skip already uploaded file '#{file}'"
             else
               logger.info "Uploading file #{file} (#{file.size} bytes)"
-              # TODO: show progress bar!
-              finfo = api.create_release_file target_proj, target_package(rdir), target_release(rdir), file.open, visibility: @visibility
-              logger.info "Upload completed."
+              if @dry_run
+                finfo = Hashie::Mash.new id: '(dry-run)', url: '(dry-run)'
+              else
+                logger.level <= Logger::INFO and
+                  self.class._show_progress = true
+                fio = file.open
+                logger.info "Starting upload #{file}..."
+                finfo = api.create_release_file target_proj, target_package(rdir), target_release(rdir), fio, visibility: @visibility
+                fio.close
+                self.class._show_progress = false
+                if digests.find { |type, dig| dig != finfo.send("digest_#{type}") }
+                  logger.error "File digests are mismatch! Upload file #{file} may be broken! Please check."
+                else
+                  logger.info "Upload completed."
+                end
+              end
               $stdout.puts "New file '#{file}' has been uploaded; #{finfo.url}"
             end
           end
@@ -124,5 +192,16 @@ module OSDN; module CLI; module Command
     def api
       OSDNClient::ProjectApi.new
     end
+
+    def hexdigest(klass, file)
+      fio = file.open
+      dig = klass.new
+      while buf = fio.read(1024*1024) and buf.length > 0
+        dig << buf
+      end
+      fio.close
+      dig.hexdigest
+    end
+
   end
 end; end; end