lib/kpm/base_artifact.rb in kpm-0.0.10 vs lib/kpm/base_artifact.rb in kpm-0.0.11

- old
+ new

@@ -33,13 +33,13 @@ KAUI_ARTIFACT_ID = 'kaui-standalone' KAUI_PACKAGING = 'war' KAUI_CLASSIFIER = nil class << self - def pull(logger, group_id, artifact_id, packaging='jar', classifier=nil, version='LATEST', destination_path=nil, overrides={}, ssl_verify=true) + def pull(logger, group_id, artifact_id, packaging='jar', classifier=nil, version='LATEST', destination_path=nil, sha1_file=nil, force_download=false, overrides={}, ssl_verify=true) coordinates = build_coordinates(group_id, artifact_id, packaging, classifier, version) - pull_and_put_in_place(logger, coordinates, destination_path, is_ruby_plugin_and_should_skip_top_dir(group_id, artifact_id), overrides, ssl_verify) + pull_and_put_in_place(logger, coordinates, destination_path, is_ruby_plugin_and_should_skip_top_dir(group_id, artifact_id), sha1_file, force_download, overrides, ssl_verify) end def nexus_remote(overrides={}, ssl_verify=true) nexus_remote ||= NexusCli::RemoteFactory.create(nexus_defaults.merge(overrides || {}), ssl_verify) end @@ -51,74 +51,117 @@ } end protected - def pull_and_put_in_place(logger, coordinates, destination_path=nil, skip_top_dir=true, overrides={}, ssl_verify=true) + def pull_and_put_in_place(logger, coordinates, destination_path=nil, skip_top_dir=true, sha1_file=nil, force_download=false, overrides={}, ssl_verify=true) destination_path = KPM::root if destination_path.nil? # Create the destination directory if path_looks_like_a_directory(destination_path) destination_dir = destination_path else destination_dir = File.dirname(destination_path) end FileUtils.mkdir_p(destination_dir) + # Build artifact info + artifact_info = artifact_info(coordinates, destination_path, overrides, ssl_verify) + if !force_download && skip_if_exists(artifact_info, coordinates, sha1_file) + logger.info "Skipping installation of #{coordinates} to #{artifact_info[:file_path]}, file already exists" + artifact_info[:skipped] = true + return artifact_info + end + # Download the artifact in a temporary directory in case of failures - info = {} Dir.mktmpdir do |tmp_destination_dir| logger.info " Starting download of #{coordinates} to #{tmp_destination_dir}" - info = pull_and_verify(logger, coordinates, tmp_destination_dir, overrides, ssl_verify) - - # Move the file to the final destination, unpacking if necessary - is_tgz = info[:file_path].end_with?('.tar.gz') || info[:file_path].end_with?('.tgz') - if is_tgz - Utils.unpack_tgz(info[:file_path], destination_path, skip_top_dir) - FileUtils.rm info[:file_path] + downloaded_artifact_info = pull_and_verify(logger, artifact_info[:sha1], coordinates, tmp_destination_dir, sha1_file, overrides, ssl_verify) + if artifact_info[:is_tgz] + Utils.unpack_tgz(downloaded_artifact_info[:file_path], destination_path, skip_top_dir) + FileUtils.rm downloaded_artifact_info[:file_path] else - FileUtils.mv info[:file_path], destination_path + FileUtils.mv downloaded_artifact_info[:file_path], destination_path + artifact_info[:size] = downloaded_artifact_info[:size] end + logger.info "Successful installation of #{coordinates} to #{artifact_info[:file_path]}" + end + artifact_info + end - # Update the info hash with the real destination - if File.directory?(destination_path) && !is_tgz - destination = File.join(File.expand_path(destination_path), info[:file_name]) - else - destination = destination_path - end - info[:file_path] = File.expand_path(destination) + def skip_if_exists(artifact_info, coordinates, sha1_file) - if is_tgz - info[:file_name] = nil - info[:size] = nil - else - info[:file_name] = File.basename(destination) - end + # Unclear if this is even possible + return false if artifact_info[:sha1].nil? - logger.info "Successful installation of #{coordinates} to #{info[:file_path]}" + # Check entry in sha1_file if exists + if sha1_file && File.exists?(sha1_file) + sha1_checker = Sha1Checker.from_file(sha1_file) + local_sha1 = sha1_checker.sha1(coordinates) + return true if local_sha1 == artifact_info[:sha1] end + + # If not using sha1_file mechanism, exit early if file_path odes not exist or is a directory + if !File.exists?(artifact_info[:file_path]) || + File.directory?(artifact_info[:file_path]) + return false + end + + # Finally check if remote_sha1 matches what we have locally + local_sha1 = Digest::SHA1.file(artifact_info[:file_path]).hexdigest + local_sha1 == artifact_info[:sha1] + end + + + def artifact_info(coordinates, destination_path, overrides={}, ssl_verify=true) + + info = {} + nexus_info = nexus_remote(overrides, ssl_verify).get_artifact_info(coordinates) + + xml = REXML::Document.new(nexus_info) + repository_path = xml.elements['//repositoryPath'].text unless xml.elements['//repositoryPath'].nil? + sha1 = xml.elements['//sha1'].text unless xml.elements['//sha1'].nil? + version = xml.elements['//version'].text unless xml.elements['//version'].nil? + + info[:sha1] = sha1 + info[:version] = version + info[:is_tgz] = repository_path.end_with?('.tar.gz') || repository_path.end_with?('.tgz') + if File.directory?(destination_path) && !info[:is_tgz] + destination = File.join(File.expand_path(destination_path), File.basename(repository_path)) + info[:file_name] = File.basename(repository_path) + else + # The destination was a fully specified path or this is an archive and we keep the directory + destination = destination_path + info[:file_name] = File.basename(destination_path) if !info[:is_tgz] + end + info[:file_path] = File.expand_path(destination) + info[:skipped] = false info end - def pull_and_verify(logger, coordinates, destination_dir, overrides={}, ssl_verify=true) + + def pull_and_verify(logger, remote_sha1, coordinates, destination_dir, sha1_file, overrides={}, ssl_verify=true) info = nexus_remote(overrides, ssl_verify).pull_artifact(coordinates, destination_dir) - raise ArtifactCorruptedException unless verify(logger, coordinates, info[:file_path], overrides, ssl_verify) + raise ArtifactCorruptedException unless verify(logger, info[:file_path], remote_sha1) + + if sha1_file + sha1_checker = Sha1Checker.from_file(sha1_file) + sha1_checker.add_or_modify_entry!(coordinates, remote_sha1) + end + info end - def verify(logger, coordinates, file_path, overrides={}, ssl_verify=true) - artifact_info = nexus_remote(overrides, ssl_verify).get_artifact_info(coordinates) - sha1_element = REXML::Document.new(artifact_info).elements['//sha1'] + def verify(logger, file_path, remote_sha1) # Can't check :( - if sha1_element.nil? - logger.warn("Unable to find sha1 in Nexus repo for #{coordinates}. Artifact info: #{artifact_info.inspect}") + if remote_sha1.nil? + logger.warn("Unable to verify sha1 for #{coordinates}. Artifact info: #{artifact_info.inspect}") return true end local_sha1 = Digest::SHA1.file(file_path).hexdigest - sha1 = sha1_element.text - local_sha1 == sha1 + local_sha1 == remote_sha1 end def build_coordinates(group_id, artifact_id, packaging, classifier, version=nil) if classifier.nil? if version.nil?