OSDN Git Service

Update to compat API change (no digest infomation when file uploaded).
[osdn-codes/osdn-cli.git] / lib / osdn / cli / command / relfile.rb
index aeb389f..7ba54da 100644 (file)
@@ -3,18 +3,23 @@ require 'pathname'
 
 module OSDN; module CLI; module Command
   class Relfile < FrsBase
+    attr_accessor :target_proj, :target_package, :target_release, :visibility, :force_digest, :show_progress
+
     def help
       puts "#{$0} relfile [opts] [list]"
-      puts "#{$0} relfile [opts] create <target-file>"
+      puts "#{$0} relfile [opts] create <target-file> [target-files...]"
       puts "#{$0} relfile [opts] update <numeric-file-id>"
       puts "#{$0} relfile [opts] delete <numeric-file-id>"
       puts "Options:"
       puts "  -f --format=<pretty|json>  Set output format"
       puts "  -p --project=<project>     Target project (numeric id or name)"
-      puts "     --package=<project>     Target package (numeric id)"
-      puts "     --release=<project>     Target release (numeric id)"
+      puts "     --package=<package-id>  Target package (numeric id)"
+      puts "     --release=<release-id>  Target release (numeric id)"
       puts "  -v --visibility=<public|private|hidden>"
       puts "      --force-digest         Calc local file digest forcely"
+      puts "      --progress             Force to show upload progress"
+      puts "      --no-progress          Force to hide upload progress"
+      puts "      --bwlimit=RATE         Limit bandwidth (in KB)"
     end
 
     def self.description
@@ -29,6 +34,9 @@ module OSDN; module CLI; module Command
         [ '--release', GetoptLong::REQUIRED_ARGUMENT ],
         [ '--visibility', '-v', GetoptLong::REQUIRED_ARGUMENT ],
         [ '--force-digest', GetoptLong::NO_ARGUMENT],
+        [ '--progress', GetoptLong::NO_ARGUMENT],
+        [ '--no-progress', GetoptLong::NO_ARGUMENT],
+        [ '--bwlimit', GetoptLong::REQUIRED_ARGUMENT ],
       )
       opts.each do |opt, arg|
         case opt
@@ -52,6 +60,13 @@ module OSDN; module CLI; module Command
             exit
           end
           @visibility = arg
+        when '--progress'
+          @show_progress = true
+        when '--no-progress'
+          @show_progress = false
+        when '--bwlimit'
+          arg.to_i != 0 and
+            OSDN::CLI._rate_limit = arg.to_i * 1024
         end
       end
     end
@@ -69,21 +84,25 @@ module OSDN; module CLI; module Command
     end
 
     def create
-      filename = ARGV.shift
-      if !filename
+      if ARGV.empty? || ARGV.first == ""
         logger.fatal "Target filename is missing."
         help
         return
       end
-      file = Pathname('.') + filename
-      logger.debug "Calculating digest for #{file}..."
 
+      ARGV.each do |f|
+        create_one(f)
+      end
+    end
+
+    def calc_file_digest(filename)
+      file = Pathname('.') + filename
       vars = load_variables(file.dirname)
       digests = nil
       if !@force_digest && vars.local_file_info &&
-         vars.local_file_info[file.basename.to_s]
+        vars.local_file_info[file.basename.to_s]
         finfo = vars.local_file_info[file.basename.to_s]
-        if finfo[:size] == file.size && finfo.mtime == file.mtime
+        if finfo.filesize == file.size && finfo.mtime == file.mtime
           digests = vars.local_file_info[file.basename.to_s].digests
         end
       end
@@ -95,22 +114,50 @@ module OSDN; module CLI; module Command
           sha1:   hexdigest(Digest::SHA1, file),
           md5:    hexdigest(Digest::MD5, file),
         }
-        update_variables file.dirname, {local_file_info: {file.basename.to_s => {digests: digests, mtime: file.mtime, size: file.size}}}
+        update_variables file.dirname, {local_file_info: {file.basename.to_s => {digests: digests, mtime: file.mtime, filesize: file.size}}}
       end
+    end
 
+    def create_one(filename)
+      file = Pathname('.') + filename
+      calc_file_digest file
+      vars = load_variables(file.dirname)
       fio = file.open
-      logger.level <= Logger::INFO and
+      logger.level <= Logger::INFO && @show_progress != false || @show_progress and
         OSDN::CLI._show_progress = true
-      logger.info "Starting upload #{file}..."
-      f = api.create_release_file target_proj, target_package, target_release, fio, visibility: @visibility
-      fio.close
-      OSDN::CLI._show_progress = false
-      if digests.find { |type, dig| dig != f.send("digest_#{type}") }
-        logger.error "File digests are mismatch! Upload file #{file} may be broken! Please check."
+      logger.info "Starting upload #{file} (#{file.size} bytes)..."
+      max_upload_tries = 5
+      upload_tries = 0
+      remote_file = nil
+      begin
+        upload_tries += 1
+        remote_file = api.create_release_file target_proj, target_package, target_release, fio, visibility: @visibility
+      rescue OSDNClient::ApiError => e
+        if max_upload_tries - upload_tries <= 0 
+          logger.error "Max upload attempts (#{max_upload_tries}) has been exceeded, give up!"
+          raise e
+        elsif [0, 100, 502].member?(e.code.to_i)
+          fio.rewind
+          logger.error "Upload error (#{e.code} #{e.message}), retrying (#{upload_tries}/#{max_upload_tries})..."
+          sleep 10
+          retry
+        else
+          raise e
+        end
+      ensure
+        fio.close
+        OSDN::CLI._show_progress = false
+      end
+      
+      if vars.local_file_info[file.basename.to_s].digests.find { |type, dig| rd = remote_file.send("digest_#{type}"); rd && rd != '' && rd != dig }
+        logger.error "File digest mismatch! Uploaded file #{file} may be broken! Please check."
+      elsif file.size != remote_file.size
+        logger.error "File size mismatch! Uploaded file #{file} may be broken! Please check."
       else
         logger.info "Upload complete."
       end
-      puts format_file(f)
+      puts format_file(remote_file)
+      remote_file
     end
 
     def update