1 module OSDN; module CLI; module Command
4 puts "#{$0} frs_upload [opts] [target_dir]"
6 puts " -n --dry-run Do noting (use with global -v to inspect)"
7 puts " -p --project=<project> Target project (numeric id or name)"
8 puts " --package=<package-id> Target package (numeric id)"
9 puts " --release=<release-id> Target release (numeric id)"
10 puts " -v --visibility=<public|private|hidden>"
11 puts " Default visibility for newly created items"
12 puts " --force-digest Calc local file digest forcely"
17 opts = GetoptLong.new(
18 [ '--dry-run', '-n', GetoptLong::NO_ARGUMENT ],
19 [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ],
20 [ '--package', GetoptLong::REQUIRED_ARGUMENT ],
21 [ '--release', GetoptLong::REQUIRED_ARGUMENT ],
22 [ '--visibility', '-v', GetoptLong::REQUIRED_ARGUMENT ],
23 [ '--force-digest', GetoptLong::NO_ARGUMENT],
25 opts.each do |opt, arg|
37 unless %w(public private hidden).member?(arg)
38 logger.fatal "Invalid visibility status: #{arg}"
49 @target_dir = Pathname.new(ARGV.shift || '.')
50 proj_info = api.get_project target_proj # check project existance
52 vars = load_variables(@target_dir)
54 if @target_release || vars.release_id
55 process_release(@target_dir)
56 elsif @target_package || vars.package_id
57 process_package(@target_dir)
59 Pathname.glob(@target_dir+'*').sort.each do |pdir|
66 "Upload local file tree and create package/release implicitly."
69 def process_package(pdir)
70 if cur_pkgid = load_variables(pdir).package_id
71 # check package existance on server
73 api.get_package target_proj, target_package(pdir)
74 rescue OSDNClient::ApiError => e
76 err = JSON.parse(e.response_body)
80 if err['status'] == 404
81 logger.warn "Package ##{cur_pkgid} has been deleted on server and local directory '#{pdir}' remains. You can delete the local directory or delete '#{pdir}/.osdn.vars' file to create a package again with new ID."
87 logger.info "Createing new package '#{pdir.basename}'"
89 pinfo = Hashie::Mash.new id: '(dry-run)', name: pdir.basename, url: '(dry-run)'
91 pinfo = api.create_package target_proj, pdir.basename, visibility: @visibility
92 update_variables pdir, package_id: pinfo.id
94 $stdout.puts "New package '#{pinfo.name}' has been created; #{pinfo.url}"
97 Pathname.glob(pdir + '*').sort.each do |rdir|
102 def process_release(rdir)
104 logger.warn "Skip normal file '#{rdir}' in release level"
108 vars = load_variables(rdir)
112 rinfo = api.get_release target_proj, target_package(rdir), target_release(rdir)
113 rescue OSDNClient::ApiError => e
115 err = JSON.parse(e.response_body)
119 if err['status'] == 404
120 logger.warn "Release ##{vars.release_id} has been deleted on server and local directory '#{rdir}' remains. You can delete the local directory or delete '#{rdir}/.osdn.vars' file to create a release again with new ID."
126 logger.info "Createing new release '#{rdir.basename}'"
128 rinfo = Hashie::Mash.new id: '(dry-run)', name: rdir.basename, url: '(dry-run)', files: []
130 rinfo = api.create_release target_proj, target_package(rdir), rdir.basename, visibility: @visibility
131 update_variables rdir, release_id: rinfo.id
133 $stdout.puts "New release '#{rinfo.name}' has been created; #{rinfo.url}"
135 Pathname.glob(rdir + '*').sort.each do |file|
136 process_file(file, rdir, rinfo)
140 def process_file(file, rdir, rinfo)
142 logger.error "Skip direcotry #{file}"
146 vars = load_variables(rdir)
148 if !@force_digest && vars.local_file_info &&
149 vars.local_file_info[file.basename.to_s]
150 finfo = vars.local_file_info[file.basename.to_s]
151 if finfo[:size] == file.size && finfo.mtime == file.mtime
152 digests = vars.local_file_info[file.basename.to_s].digests
157 logger.info "Calculating digest for #{file}..."
159 sha256: hexdigest(Digest::SHA256, file),
160 sha1: hexdigest(Digest::SHA1, file),
161 md5: hexdigest(Digest::MD5, file),
163 update_variables rdir, {local_file_info: {file.basename.to_s => {digests: digests, mtime: file.mtime, size: file.size}}}
165 if remote_f = rinfo.files.find { |f| f.name == file.basename.to_s }
166 if digests.find { |type, dig| dig != remote_f.send("digest_#{type}") }
167 logger.error "#{file} was changed from remote file! Please delete remote file before uploading new one."
169 logger.info "Skip already uploaded file '#{file}'"
173 logger.info "Uploading file #{file} (#{file.size} bytes)"
175 finfo = Hashie::Mash.new id: '(dry-run)', url: '(dry-run)'
177 logger.level <= Logger::INFO and
178 OSDN::CLI._show_progress = true
180 logger.info "Starting upload #{file}..."
181 finfo = api.create_release_file target_proj, target_package(rdir), target_release(rdir), fio, visibility: @visibility
183 OSDN::CLI._show_progress = false
184 if digests.find { |type, dig| dig != finfo.send("digest_#{type}") }
185 logger.error "File digests are mismatch! Upload file #{file} may be broken! Please check."
187 logger.info "Upload complete."
190 $stdout.puts "New file '#{file}' has been uploaded; #{finfo.url}"
195 @target_proj and return @target_proj
196 vars = load_variables(@target_dir)
197 vars.project && !vars.project.empty? and
199 logger.fatal "No target project is specified."
203 def target_package(dir)
204 @target_package and return @target_package
205 vars = load_variables(dir)
206 vars.package_id && !vars.package_id.to_s.empty? and
207 return vars.package_id
208 logger.fatal "No target package is specified."
212 def target_release(dir)
213 @target_release and return @target_release
214 vars = load_variables(dir)
215 vars.release_id && !vars.release_id.to_s.empty? and
216 return vars.release_id
217 logger.fatal "No target release is specified."
222 OSDNClient::ProjectApi.new