lib/cicd/builder/mixlib/repo/artifactory.rb in cicd-builder-0.9.48 vs lib/cicd/builder/mixlib/repo/artifactory.rb in cicd-builder-0.9.50
- old
+ new
@@ -1,7 +1,64 @@
require 'artifactory'
+require 'artifactory/version'
+require 'parallel'
+require 'ruby-progressbar'
+raise "Need to check compatibility of monkey patch for Artifactory.VERSION == #{::Artifactory::VERSION}" unless ::Artifactory::VERSION == '2.2.1'
+module Artifactory
+ module Defaults
+ class << self
+ #
+ # Reset all configuration options to their default values.
+ #
+ # @example Reset all settings
+ # Artifactory.reset!
+ #
+ # @return [self]
+ #
+ def reset!
+ @_options = nil
+ options
+ end
+ alias_method :setup, :reset!
+ #
+ # Number of seconds to wait for a response from Artifactory
+ #
+ # @return [Integer, nil]
+ #
+ def read_timeout
+ ENV['ARTIFACTORY_READ_TIMEOUT'].to_s.to_i || 120
+ end
+ end
+ end
+end
+
+module Artifactory
+ #
+ # A re-usable class containing configuration information for the {Client}. See
+ # {Defaults} for a list of default values.
+ #
+ module Configurable
+ #
+ # Reset all configuration options to their default values.
+ #
+ # @example Reset all settings
+ # Artifactory.reset!
+ #
+ # @return [self]
+ #
+ def reset!
+ Defaults.reset!
+ Artifactory::Configurable.keys.each do |key|
+ instance_variable_set(:"@#{key}", Defaults.options[key])
+ end
+ self
+ end
+ alias_method :setup, :reset!
+ end
+end
+
module CiCd
module Builder
module Repo
class Artifactory < CiCd::Builder::Repo::Base
# include ::Artifactory::Resource
@@ -46,10 +103,20 @@
# # config.proxy_username = 'user'
# # config.proxy_password = 'password'
# # config.proxy_address = 'my.proxy.server'
# # config.proxy_port = '8080'
# end
+ if ENV['ARTIFACTORY_READ_TIMEOUT']
+ # [2015-04-29 Christo] Sometimes you just have to shake your head ...
+ # a) The Artifactory object does it's setup and read ENV variables during require phase ...
+ # b) They do not check if the passed value is valid ( in range or even a number at all ) and they don't convert it to an int
+ # c) ENV does not allow one to do this: ENV['ARTIFACTORY_READ_TIMEOUT'] = ENV['ARTIFACTORY_READ_TIMEOUT'].to_s.to_i
+ # d) ::Artifactory.setup and ::Artifactory.reset! does not reread those options!!!! OMG!
+ # Only resort: Open ::Artifactory class and override the method with the code it should have had ... %)
+ ::Artifactory.setup
+ end
+
@client = ::Artifactory::Client.new()
end
# ---------------------------------------------------------------------------------------------------------------
def method_missing(name, *args)
@@ -84,11 +151,11 @@
data[:sha1] = Digest::SHA1.file(data[:file]).hexdigest
data[:md5] = Digest::MD5.file(data[:file]).hexdigest
else
raise 'Artifact does not have file or data?'
end
- file_name, file_ext = get_artifact_file_name_ext(data)
+ file_name, file_ext = (data[:file_name] and data[:file_ext]) ? [data[:file_name], data[:file_ext]] : get_artifact_file_name_ext(data)
if file_name =~ %r'\.+'
raise "Unable to parse out file name in #{data[:file]}"
end
unless file_name.empty?
file_name = '_'+file_name.gsub(%r'^(\.|-|)(\w)', '\2').gsub(%r'(\.|-)+', '_')
@@ -208,40 +275,107 @@
# ---------------------------------------------------------------------------------------------------------------
def maybeArtifactoryObject(artifact_name,artifact_version,wide=true)
begin
# Get a list of matching artifacts in this repository
- result = @client.artifact_gavc_search(group: artifactory_org_path(), name: artifact_name, version: "#{artifact_version}", repos: [artifactory_repo()])
- if result.size > 0
- @logger.info "Artifactory gavc_search match g=#{artifactory_org_path()},a=#{artifact_name},v=#{artifact_version},r=#{artifactory_repo()}: #{result}"
- # raise "GAVC started working: #{result.ai}"
+ @logger.info "Artifactory gavc_search g=#{artifactory_org_path()},a=#{artifact_name},v=#{artifact_version},r=#{artifactory_repo()}"
+ @arti_search_result = []
+ # results = ::Parallel.map([:search,:progress], preserve_results: true, in_threads: 2) { |task|
+ # if task == :search
+ # @logger.debug 'searching ... '
+ # @arti_search_result = @client.artifact_gavc_search(group: artifactory_org_path(), name: artifact_name, version: "#{artifact_version}", repos: [artifactory_repo()])
+ # @logger.debug 'searching complete!'
+ # raise ::Parallel::Kill
+ # # raise ::Parallel::Break # -> stops after all current items are finished
+ # else
+ # progressbar = ::ProgressBar.create(:title => 'artifact_gavc_search', progress_mark: '=', length: 30, remainder_mark: '.')
+ # 30.times { |i|
+ # @logger.debug i
+ # sleep 1
+ # progressbar.increment
+ # }
+ # raise ::Parallel::Kill
+ # end
+ # }
+ monitor(30, 'artifact_gavc_search'){
+ @arti_search_result = @client.artifact_gavc_search(group: artifactory_org_path(), name: artifact_name, version: "#{artifact_version}", repos: [artifactory_repo()])
+ }
+ # noinspection RubyScope
+ if @arti_search_result.size > 0
+ @logger.info "\tresult: #{@arti_search_result}"
elsif wide
@logger.warn 'GAVC search came up empty!'
- result = @client.artifact_search(name: artifact_name, repos: [artifactory_repo()])
- @logger.info "Artifactory search match a=#{artifact_name},r=#{artifactory_repo()}: #{result}"
+ @arti_search_result = @client.artifact_search(name: artifact_name, repos: [artifactory_repo()])
+ @logger.info "Artifactory search match a=#{artifact_name},r=#{artifactory_repo()}: #{@arti_search_result}"
end
- result
+ @arti_search_result
rescue Exception => e
@logger.error "Artifactory error: #{e.class.name} #{e.message}"
raise e
end
end
+ def monitor(limit,title='Progress')
+ raise 'Must have a block' unless block_given?
+ thread = Thread.new(){
+ yield
+ }
+ progressbar = ::ProgressBar.create({title: title, progress_mark: '=', starting_at: 0, total: limit, remainder_mark: '.', throttle_rate: 0.5})
+ limit.times do
+ res = thread.join(1)
+ progressbar.increment
+ progressbar.total = limit
+ unless thread.alive? #or thread.stop?
+ puts ''
+ break
+ end
+ end
+ thread.kill if thread.alive? or thread.stop?
+ end
+
def uploadArtifact(artifact_module, artifact_version, artifact_path, data)
data[:size] = File.size(data[:file])
artifact = ::Artifactory::Resource::Artifact.new(local_path: data[:file], client: @client)
# noinspection RubyStringKeysInHashInspection
artifact.checksums = {
'md5' => data[:md5],
'sha1' => data[:sha1],
}
artifact.size = data[:size]
@logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S %z')}] Start upload #{artifact_path} = #{data[:size]} bytes"
- result = artifact.upload(artifactory_repo(), "#{artifact_path}", data[:properties] || {})
- @logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S %z')}] Uploaded: #{result.attributes.select { |k, _| k != :client }.ai}"
- artifact.upload_checksum(artifactory_repo(), "#{artifact_path}", :sha1, data[:sha1])
- artifact.upload_checksum(artifactory_repo(), "#{artifact_path}", :md5, data[:md5])
+ monitor(30, 'upload') {
+ @arti_upload_result = artifact.upload(artifactory_repo(), "#{artifact_path}", data[:properties] || {})
+ }
+ @logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S %z')}] Uploaded: #{@arti_upload_result.attributes.select { |k, _| k != :client }.ai}"
+ 3.times{
+ @arti_upload_checksum = false
+ monitor(30, 'upload_checksum') {
+ begin
+ artifact.upload_checksum(artifactory_repo(), "#{artifact_path}", :sha1, data[:sha1])
+ @arti_upload_checksum = true
+ rescue Exception => e
+ @logger.fatal "Failed to upload #{artifact_path}: #{e.class.name} #{e.message}"
+ raise e
+ end
+ }
+ break if @arti_upload_checksum
+ }
+ raise "Failed to upload SHA1 for #{artifact_path}" unless @arti_upload_checksum
+ 3.times{
+ @arti_upload_checksum = false
+ monitor(30, 'upload_checksum') {
+ begin
+ artifact.upload_checksum(artifactory_repo(), "#{artifact_path}", :md5, data[:md5])
+ @arti_upload_checksum = true
+ rescue Exception => e
+ @logger.fatal "Failed to upload #{artifact_path}: #{e.class.name} #{e.message}"
+ raise e
+ end
+ }
+ break if @arti_upload_checksum
+ }
+ raise "Failed to upload MD5 for #{artifact_path}" unless @arti_upload_checksum
attempt = 0
objects = []
while attempt < 3
objects = maybeArtifactoryObject(artifact_module, artifact_version, false)
break if objects.size > 0
@@ -256,12 +390,21 @@
begin
if artifact.attributes[:uri].eql?(File.join(artifactory_endpoint, artifactory_repo, artifact_path))
@logger.info "Not copying (identical artifact): #{artifact_path}"
else
@logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S %z')}] Start copy #{artifact_path} = #{artifact.attributes[:size]} bytes"
- result = artifact.copy("#{artifactory_repo()}/#{artifact_path}")
- @logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S %z')}] Copied: #{result.ai}"
+ copied = false
+ 3.times{
+ copied = false
+ monitor(30){
+ result = artifact.copy("#{artifactory_repo()}/#{artifact_path}")
+ @logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S %z')}] Copied: #{result.ai}"
+ copied = true
+ }
+ break if copied
+ }
+ raise "Failed to copy #{artifact_path}" unless copied
end
objects = maybeArtifactoryObject(artifact_module, artifact_version, false)
unless objects.size > 0
sleep 10
objects = maybeArtifactoryObject(artifact_module, artifact_version, false)
@@ -274,11 +417,11 @@
end
end
# ---------------------------------------------------------------------------------------------------------------
def uploadBuildArtifacts()
- @logger.step __method__.to_s
+ @logger.step CLASS+'::'+__method__.to_s
if @vars.has_key?(:build_dir) and @vars.has_key?(:build_pkg)
begin
artifacts = @vars[:artifacts] rescue []
key = getKey()
@@ -310,9 +453,25 @@
end
else
@vars[:return_code] = Errors::NO_ARTIFACTS
end
@vars[:return_code]
+ end
+
+ # ---------------------------------------------------------------------------------------------------------------
+ def cleanupTempFiles
+ @vars[:artifacts].each do |art|
+ if art[:data][:temp].is_a?(FalseClass)
+ if File.exists?(art[:data][:file])
+ File.unlink(art[:data][:file]) if File.exists?(art[:data][:file])
+ art[:data].delete(:file)
+ art[:data].delete(:temp)
+ else
+ @logger.warn "Temporary file disappeared: #{data.ai}"
+ @vars[:return_code] = Errors::TEMP_FILE_MISSING
+ end
+ end
+ end
end
end
end
end
\ No newline at end of file