lib/cicd/builder/mixlib/repo/S3.rb in cicd-builder-0.9.43 vs lib/cicd/builder/mixlib/repo/S3.rb in cicd-builder-0.9.44
- old
+ new
@@ -123,59 +123,39 @@
obj
rescue Aws::S3::Errors::NotFound
nil
rescue Aws::S3::Errors::NoSuchKey
nil
+ rescue Aws::S3::Errors::Forbidden
+ nil
+ rescue Exception => e
+ nil
end
+ # noinspection RubyUnnecessaryReturnValue
s3_obj
end
# ---------------------------------------------------------------------------------------------------------------
- def takeInventory()
- def _update(hash, key, value)
- h = {}
- i = -1
- hash[key].each { |v| h[v] = i+=1 }
- unless h.has_key?(value)
- h[value] = h.keys.size # No -1 because this is evaluated BEFORE we make the addition!
- end
- s = h.sort_by { |_, v| v }
- s = s.map { |v| v[0] }
- hash[key] = s
- h[value]
+ def _update(hash, key, value)
+ h = {}
+ i = -1
+ hash[key].each { |v| h[v] = i+=1 }
+ unless h.has_key?(value)
+ h[value] = h.keys.size # No -1 because this is evaluated BEFORE we make the addition!
end
+ s = h.sort_by { |_, v| v }
+ s = s.map { |v| v[0] }
+ hash[key] = s
+ h[value]
+ end
- # Read and parse in JSON
- json_s = ''
- json = nil
+ # ---------------------------------------------------------------------------------------------------------------
+ def takeInventory()
varianth = nil
-
- key = "#{@vars[:project_name]}/INVENTORY.json"
- s3_obj = maybeS3Object(key)
- # If the inventory has started then add to it else create a new one
- if s3_obj.nil?
- # Start a new inventory
- over = true
- else
- resp = s3_obj.get()
- body = resp.body
- if body.is_a?(String)
- json_s = resp.data
- else
- body.rewind
- json_s = body.read()
- end
- json = Yajl::Parser.parse(json_s)
- over = false
- # Is the inventory format up to date ...
- constraint = ::Semverse::Constraint.new "<= #{@options[:gen]}"
- version = ::Semverse::Version.new(json['gen'])
- # raise CiCd::Builder::Errors::InvalidVersion.new "The constraint failed: #{json['gen']} #{constraint}"
-
- unless constraint.satisfies?(version)
- raise CiCd::Builder::Errors::InvalidVersion.new "The inventory generation is newer than I can manage: #{version} <=> #{@options[:gen]}"
- end
+ # Read and parse in JSON
+ key, json, over = pullInventory()
+ unless json.nil?
if json['container'] and json['container']['variants']
# but does not have our variant then add it
variants = json['container']['variants']
unless variants[@vars[:variant]]
variants[@vars[:variant]] = {}
@@ -229,22 +209,11 @@
}
end
varianth['builds'] << filing
end
build_lst = (varianth['builds'].size-1)
- build_rel = build_lst
- i = -1
- varianth['builds'].each{ |h|
- i += 1
- convert_build(h)
- convert_build(varianth['builds'][build_rel])
- if h['release'].to_i > varianth['builds'][build_rel]['release'].to_i
- build_rel = i
- elsif h['release'] == varianth['builds'][build_rel]['release']
- build_rel = i if h['build_number'].to_i > varianth['builds'][build_rel]['build_number'].to_i
- end
- }
+ build_rel = _getLatestRelease(build_lst, varianth)
# Add new branch ...
build_bra = _update(varianth, 'branches', @vars[:build_bra])
# Add new version ...
build_ver = _update(varianth, 'versions', @vars[:build_ver])
@@ -257,18 +226,22 @@
release: build_rel,
}
json['gen'] = @options[:gen]
json_s = JSON.pretty_generate( json, { indent: "\t", space: ' '})
end
+ pushInventory(json_s, key)
+ end
+
+ def pushInventory(json_s, key)
begin
md5 = Digest::MD5.hexdigest(json_s)
# [:'x-amz-meta-digest'] = "md5=#{md5}"
- resp = getS3.put_object( bucket: ENV['AWS_S3_BUCKET'],
- key: key,
- body: json_s,
- # acl: 'authenticated-read',
- metadata: {checksum: md5, digest: "md5=#{md5}"},
+ resp = getS3.put_object(bucket: ENV['AWS_S3_BUCKET'],
+ key: key,
+ body: json_s,
+ # acl: 'authenticated-read',
+ metadata: {checksum: md5, digest: "md5=#{md5}"},
)
s3_obj = maybeS3Object(key)
# s3_obj.etag
@logger.info "Inventory URL: #{s3_obj.presigned_url(:get, expires_in: 86400)}"
return 0
@@ -276,10 +249,118 @@
@logger.error("Exception: #{e.class.name}: #{e.message}\n#{e.backtrace.ai}")
return Errors::INVENTORY_UPLOAD_EXCEPTION
end
end
+ # ---------------------------------------------------------------------------------------------------------------
+ def _getLatestRelease(build_lst, varianth)
+ build_rel = build_lst
+ i = -1
+ varianth['builds'].each { |h|
+ i += 1
+ convert_build(h)
+ convert_build(varianth['builds'][build_rel])
+ if h['release'].to_f > varianth['builds'][build_rel]['release'].to_f
+ build_rel = i
+ elsif h['release'] == varianth['builds'][build_rel]['release']
+ build_rel = i if h['build_number'].to_i > varianth['builds'][build_rel]['build_number'].to_i
+ end
+ }
+ build_rel
+ end
+
+ # ---------------------------------------------------------------------------------------------------------------
+ def _getLatestBranch(build_lst, varianth)
+ # noinspection RubyHashKeysTypesInspection
+ map = Hash[varianth['branches'].map.with_index.to_a]
+ build_bra = map[_getBranch(@vars, varianth['builds'][build_lst])]
+
+ i = -1
+ varianth['builds'].each { |h|
+ i += 1
+ convert_build(h)
+ brah = _getBranch(@vars, h)
+ bral = _getBranch(@vars, varianth['builds'][build_bra])
+ if map[brah] > map[bral]
+ build_bra = map[brah]
+ end
+ }
+ build_bra
+ end
+
+ # ---------------------------------------------------------------------------------------------------------------
+ def _getLatestVersion(build_lst, varianth)
+ # noinspection RubyHashKeysTypesInspection
+ map = Hash[varianth['versions'].map.with_index.to_a]
+ build_ver = map[_getVersion(@vars, varianth['builds'][build_lst])]
+
+ verl = _getVersion(@vars, varianth['builds'][build_ver])
+ gt = ::Semverse::Constraint.new "> #{verl}"
+ eq = ::Semverse::Constraint.new "= #{verl}"
+
+ i = -1
+ varianth['builds'].each { |h|
+ i += 1
+ convert_build(h)
+ verh = _getVersion(@vars, h)
+ version = ::Semverse::Version.new(verh)
+ if gt.satisfies?(version)
+ build_ver = map[verh]
+ build_lst = i
+ gt = ::Semverse::Constraint.new "> #{verh}"
+ eq = ::Semverse::Constraint.new "= #{verh}"
+ elsif eq.satisfies?(version)
+ if h['build_number'].to_i > varianth['builds'][build_lst]['build_number'].to_i
+ build_ver = map[verh]
+ build_lst = i
+ gt = ::Semverse::Constraint.new "> #{verh}"
+ eq = ::Semverse::Constraint.new "= #{verh}"
+ end
+ end
+ }
+ build_ver
+ end
+
+ # ---------------------------------------------------------------------------------------------------------------
+ def pullInventory()
+ json = nil
+ key, s3_obj = checkForInventory()
+ # If the inventory has started then add to it else create a new one
+ if s3_obj.nil?
+ # Start a new inventory
+ over = true
+ else
+ resp = s3_obj.get()
+ body = resp.body
+ if body.is_a?(String)
+ json_s = resp.data
+ else
+ body.rewind
+ json_s = body.read()
+ end
+ json = Yajl::Parser.parse(json_s)
+ over = false
+ # Is the inventory format up to date ...
+ constraint = ::Semverse::Constraint.new "<= #{@options[:gen]}"
+ version = ::Semverse::Version.new(json['gen'])
+ # raise CiCd::Builder::Errors::InvalidVersion.new "The constraint failed: #{json['gen']} #{constraint}"
+
+ unless constraint.satisfies?(version)
+ raise CiCd::Builder::Errors::InvalidVersion.new "The inventory generation is newer than I can manage: #{version} <=> #{@options[:gen]}"
+ end
+ end
+ return key, json, over
+ end
+
+ # ---------------------------------------------------------------------------------------------------------------
+ def checkForInventory
+ key = "#{@vars[:project_name]}/INVENTORY.json"
+ s3_obj = maybeS3Object(key)
+ return key, s3_obj
+ end
+
+ # ---------------------------------------------------------------------------------------------------------------
def convert_build(h)
if h.has_key?('number')
h['build_number'] = h['number']
h.delete 'number'
elsif h.has_key?('build_number')
@@ -351,9 +432,245 @@
else
@vars[:return_code] = Errors::NO_ARTIFACTS
end
@vars[:return_code]
end
+
+ # noinspection RubyHashKeysTypesInspection,RubyHashKeysTypesInspection
+ # @param Hash args
+ def _getMatches(args, name, match)
+ args = args.dup
+ args[:version] = '[0-9\.]+'
+ args[:release] = '[0-9\.]+'
+ args[:branch] = '[^-]+'
+ args[:build] = '\d+'
+ map = [ :product,:version,:branch,:build ]
+ matches = name.match(/^(#{args[:product]})-(#{args[:version]})-(#{args[:branch]})-build-(\d+)$/)
+ unless matches
+ map = [ :product,:version,:branch,:variant,:build ]
+ matches = name.match(/^(#{args[:product]})-(#{args[:version]})-(#{args[:branch]})-(#{args[:variant]})-build-(\d+)$/)
+ unless matches
+ map = [ :product,:version,:release,:branch,:variant,:build ]
+ matches = name.match(/^(#{args[:product]})-(#{args[:version]})-release-(#{args[:release]})-(#{args[:branch]})-(#{args[:variant]})-build-(\d+)$/)
+ unless matches
+ name = name.dup
+ map.each { |key|
+ if key == match
+ break
+ elsif key == :release
+ name.gsub!(/^release-/, '')
+ elsif key == :build
+ name.gsub!(/^build-/, '')
+ end
+ name.gsub!(/^#{args[key]}-/, '')
+ }
+ map.reverse.each { |key|
+ if key == match
+ break
+ end
+ name.gsub!(/-#{args[key]}$/, '')
+ if key == :release
+ name.gsub!(/-release$/, '')
+ elsif key == :build
+ name.gsub!(/-build$/, '')
+ end
+ }
+ return name
+ end
+ end
+ end
+ if matches
+ map = Hash[map.map.with_index.to_a]
+ if map.has_key? match
+ matches[map[match]+1] # 0 is the whole thing
+ else
+ nil
+ end
+ else
+ nil
+ end
+ end
+
+ def _getBuildNumber(args,drawer, naming = nil)
+ name = drawer['build_name'] rescue drawer['build']
+ drawer['build_number'] || _getMatches(args, name, :build)
+ end
+
+ def _getVersion(args,drawer, naming = nil)
+ name = drawer['build_name'] rescue drawer['build']
+ drawer['version'] || _getMatches(args, name, :version)
+ end
+
+ def _getRelease(args,drawer, naming = nil)
+ name = drawer['build_name'] rescue drawer['build']
+ drawer['release'] || _getMatches(args, name, :release)
+ end
+
+ def _getBranch(args,drawer, naming = nil)
+ name = drawer['build_name'] rescue drawer['build']
+ drawer['branch'] || _getMatches(args, name, :branch)
+ end
+
+ def first(builds, pruner)
+ raise "Bad syntax: #{__method__}{ #{pruner.join(' ')}" unless pruner.size == 1
+ count = pruner[0].to_i
+ count > 0 ? builds[0..(count-1)] : []
+ end
+
+ def last(builds, pruner)
+ raise "Bad syntax: #{__method__} #{pruner.join(' ')}" unless pruner.size == 1
+ count = pruner[0].to_i
+ count > 0 ? builds[(-1-count+1)..-1] : []
+ end
+
+ def keep(builds, pruner)
+ prune builds, pruner
+ end
+
+ def drop(builds, pruner)
+ raise "Bad syntax: drop #{pruner.join(' ')}" unless pruner.size == 2
+ case pruner[0]
+ when 'first'
+ prune builds, [ 'keep', 'last', pruner[-1] ]
+ when 'last'
+ prune builds, [ 'keep', 'first', builds.size-pruner[-1].to_i ]
+ when /\d+/
+ prune builds, [ 'keep', pruner[-2], pruner[-1] ]
+ else
+ raise "Bad syntax: drop #{pruner.join(' ')}"
+ end
+ end
+
+ # ---------------------------------------------------------------------------------------------------------------
+ def prune(builds, pruner)
+ if pruner.size > 0
+ blds = builds.dup
+ eval("blds = #{pruner[0]} blds, #{pruner[1..-1]}")
+ blds
+ else
+ builds
+ end
+ end
+
+ # ---------------------------------------------------------------------------------------------------------------
+ def pruneRepo()
+ @logger.step __method__.to_s
+ # Read and parse in JSON
+ key, json, over = pullInventory()
+ if json.nil?
+ @logger.error "Bad repo/inventory specified. s3://#{ENV['AWS_S3_BUCKET']}/#{key}"
+ @vars[:return_code] = Errors::PRUNE_BAD_REPO
+ else
+ if @vars[:variant]
+ if @vars[:tree]
+ if @vars[:pruner]
+ if json['container'] and json['container']['variants']
+ # but does not have our variant ...
+ variants = json['container']['variants']
+ if variants[@vars[:variant]]
+ varianth = variants[@vars[:variant]]
+ # If the inventory 'latest' format is up to date ...
+ if varianth['latest'] and varianth['latest'].is_a?(Hash)
+ builds = varianth['builds']
+ branches = varianth['branches']
+ versions = varianth['versions']
+ case @vars[:tree]
+ when %r'variants?'
+ variants.delete(@vars[:pruner])
+ when %r'versions?'
+ if varianth['versions'].include?(@vars[:pruner])
+ survivors = builds.select{ |drawer|
+ ver = _getVersion(@vars, drawer)
+ ver != @vars[:pruner]
+ }
+ varianth['builds'] = survivors
+ varianth['versions'] = varianth['versions'].select{|ver| ver != @vars[:pruner] }
+ else
+ @logger.error "Cannot prune the version '#{@vars[:pruner]}' from variant '#{@vars[:variant]}'"
+ @vars[:return_code] = Errors::PRUNE_BAD_VERSION
+ end
+ when %r'branch(|es)'
+ if varianth['branches'].include?(@vars[:pruner])
+ survivors = builds.select{ |drawer|
+ bra = _getBranch(@vars, drawer)
+ bra != @vars[:pruner]
+ }
+ varianth['builds'] = survivors
+ varianth['branches'] = varianth['branches'].select{|bra| bra != @vars[:pruner] }
+ else
+ @logger.error "Cannot prune the branch '#{@vars[:pruner]}' from variant '#{@vars[:variant]}'"
+ @vars[:return_code] = Errors::PRUNE_BAD_BRANCH
+ end
+ when %r'builds?'
+ # noinspection RubyHashKeysTypesInspection
+ begin
+ builds = prune(builds, @vars[:pruner].split(/\s+/))
+ varianth['builds'] = builds
+ branches = builds.map{ |bld|
+ _getBranch(@vars, bld)
+ }
+ varianth['branches'] = Hash[branches.map.with_index.to_a].keys
+ versions = builds.map{ |bld|
+ _getVersion(@vars, bld)
+ }
+ varianth['versions'] = Hash[versions.map.with_index.to_a].keys
+ rescue Exception => e
+ @logger.error "Cannot prune the builds '#{e.message}'"
+ @vars[:return_code] = Errors::PRUNE_BAD_PRUNER
+ end
+ else
+ @logger.error "Bad 'TREE' specified. Only 'branches', 'builds', 'versions' and 'variant' can be pruned"
+ @vars[:return_code] = Errors::PRUNE_NO_TREE
+ end
+ if 0 == @vars[:return_code]
+ build_lst = (varianth['builds'].size-1)
+ build_rel = _getLatestRelease(build_lst, varianth)
+ # Latest branch ...
+ build_bra = _getLatestBranch(build_lst, varianth)
+ # Latest version ...
+ build_ver = _getLatestVersion(build_lst, varianth)
+
+ # Set latest
+ varianth['latest'] = {
+ branch: build_bra,
+ version: build_ver,
+ build: build_lst,
+ release: build_rel,
+ }
+ json_s = JSON.pretty_generate( json, { indent: "\t", space: ' '})
+ pushInventory(json_s, key)
+ end
+ else
+ # Start over ... too old/ incompatible
+ @logger.error 'Repo too old or incompatible to prune. No [container][variants][VARIANT][latest].'
+ @vars[:return_code] = Errors::PRUNE_TOO_OLD
+ end
+ else
+ @logger.error "Variant '#{@vars[:variant]}' not present."
+ @vars[:return_code] = Errors::PRUNE_VARIANT_MIA
+ end
+ else
+ # Start over ... too old/ incompatible
+ @logger.error 'Repo too old or incompatible to prune. No [container][variants].'
+ @vars[:return_code] = Errors::PRUNE_TOO_OLD
+ end
+ else
+ @logger.error "No 'PRUNER' specified"
+ @vars[:return_code] = Errors::PRUNE_NO_PRUNER
+ end
+ else
+ @logger.error "No 'TREE' specified"
+ @vars[:return_code] = Errors::PRUNE_NO_TREE
+ end
+ else
+ @logger.error "No 'VARIANT' specified"
+ @vars[:return_code] = Errors::PRUNE_NO_VARIANT
+ end
+ end
+ @vars[:return_code]
+ end
+
+ private :_update, :checkForInventory, :pullInventory
end
end
end
end
\ No newline at end of file