1 require 'osdn/cli/command/frs_base'
4 module OSDN; module CLI; module Command
5 class Relfile < FrsBase
6 attr_accessor :target_proj, :target_package, :target_release, :visibility, :force_digest, :show_progress
9 puts "#{$0} relfile [opts] [list]"
10 puts "#{$0} relfile [opts] create <target-file> [target-files...]"
11 puts "#{$0} relfile [opts] update <numeric-file-id>"
12 puts "#{$0} relfile [opts] delete <numeric-file-id>"
14 puts " -f --format=<pretty|json> Set output format"
15 puts " -p --project=<project> Target project (numeric id or name)"
16 puts " --package=<package-id> Target package (numeric id)"
17 puts " --release=<release-id> Target release (numeric id)"
18 puts " -v --visibility=<public|private|hidden>"
19 puts " --force-digest Calc local file digest forcely"
20 puts " --progress Force to show upload progress"
21 puts " --no-progress Force to hide upload progress"
22 puts " --bwlimit=RATE Limit bandwidth (in KB)"
26 "Manipulate frs files of project"
30 opts = GetoptLong.new(
31 [ '--format', '-f', GetoptLong::REQUIRED_ARGUMENT ],
32 [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ],
33 [ '--package', GetoptLong::REQUIRED_ARGUMENT ],
34 [ '--release', GetoptLong::REQUIRED_ARGUMENT ],
35 [ '--visibility', '-v', GetoptLong::REQUIRED_ARGUMENT ],
36 [ '--force-digest', GetoptLong::NO_ARGUMENT],
37 [ '--progress', GetoptLong::NO_ARGUMENT],
38 [ '--no-progress', GetoptLong::NO_ARGUMENT],
39 [ '--bwlimit', GetoptLong::REQUIRED_ARGUMENT ],
41 opts.each do |opt, arg|
58 unless %w(public private hidden).member?(arg)
59 logger.fatal "Invalid visibility status: #{arg}"
66 @show_progress = false
69 OSDN::CLI._rate_limit = arg.to_i * 1024
75 release = api.get_release target_proj, target_package, target_release
78 puts list.map{|i| i.to_hash}.to_json
87 if ARGV.empty? || ARGV.first == ""
88 logger.fatal "Target filename is missing."
98 def calc_file_digest(filename)
99 file = Pathname('.') + filename
100 vars = load_variables(file.dirname)
102 if !@force_digest && vars.local_file_info &&
103 vars.local_file_info[file.basename.to_s]
104 finfo = vars.local_file_info[file.basename.to_s]
105 if finfo.filesize == file.size && finfo.mtime == file.mtime
106 digests = vars.local_file_info[file.basename.to_s].digests
111 logger.info "Calculating digest for #{file}..."
113 sha256: hexdigest(Digest::SHA256, file),
114 sha1: hexdigest(Digest::SHA1, file),
115 md5: hexdigest(Digest::MD5, file),
117 update_variables file.dirname, {local_file_info: {file.basename.to_s => {digests: digests, mtime: file.mtime, filesize: file.size}}}
121 def create_one(filename)
122 file = Pathname('.') + filename
123 calc_file_digest file
124 vars = load_variables(file.dirname)
126 logger.level <= Logger::INFO && @show_progress != false || @show_progress and
127 OSDN::CLI._show_progress = true
128 logger.info "Starting upload #{file} (#{file.size} bytes)..."
134 remote_file = api.create_release_file target_proj, target_package, target_release, fio, visibility: @visibility
135 rescue OSDNClient::ApiError => e
136 if max_upload_tries - upload_tries <= 0
137 logger.error "Max upload attempts (#{max_upload_tries}) has been exceeded, give up!"
139 elsif [0, 100, 502].member?(e.code.to_i)
141 logger.error "Upload error (#{e.code} #{e.message}), retrying (#{upload_tries}/#{max_upload_tries})..."
149 OSDN::CLI._show_progress = false
152 if vars.local_file_info[file.basename.to_s].digests.find { |type, dig| rd = remote_file.send("digest_#{type}"); rd && rd != '' && rd != dig }
153 logger.error "File digest mismatch! Uploaded file #{file} may be broken! Please check."
154 elsif file.size != remote_file.size
155 logger.error "File size mismatch! Uploaded file #{file} may be broken! Please check."
157 logger.info "Upload complete."
159 puts format_file(remote_file)
164 target_id = ARGV.shift
166 logger.fatal "Target file ID is missing."
171 logger.fatal "Visibility status is missing. Use '-v <public|private|hidden>'."
174 f = api.update_release_file target_proj, target_package, target_release, target_id, visibility: @visibility
175 logger.info "file #{target_id} has been updated."
180 target_id = ARGV.shift
182 logger.fatal "Target file ID is missing."
186 f = api.delete_release_file target_proj, target_package, target_release, target_id
187 logger.info "file #{target_id} has been deleted."