140 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # Copyright 2020 Google LLC
 | |
| #
 | |
| # Licensed under the Apache License, Version 2.0 (the "License");
 | |
| # you may not use this file except in compliance with the License.
 | |
| # You may obtain a copy of the License at
 | |
| #
 | |
| #      http://www.apache.org/licenses/LICENSE-2.0
 | |
| #
 | |
| # Unless required by applicable law or agreed to in writing, software
 | |
| # distributed under the License is distributed on an "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| # See the License for the specific language governing permissions and
 | |
| # limitations under the License.
 | |
| 
 | |
| require "gems"
 | |
| 
 | |
| module Google
 | |
|   module Apis
 | |
|     class Generator
 | |
|       # Matches generated files against current files and decides what to update
 | |
|       # @private
 | |
|       class Updater
 | |
|         def initialize
 | |
|           @gems_client = nil
 | |
|           @current_rubygems_versions = {}
 | |
|         end
 | |
| 
 | |
|         def analyze(base_dir, generator_result)
 | |
|           modified_files = {}
 | |
|           version_content = changelog_content = nil
 | |
|           generator_result.files.each do |path, content|
 | |
|             full_path = File.join(base_dir, path)
 | |
|             old_content = File.read(full_path) if File.readable?(full_path)
 | |
|             if path == generator_result.version_path
 | |
|               version_content = old_content || content
 | |
|             elsif path == generator_result.changelog_path
 | |
|               changelog_content = old_content || content
 | |
|             else
 | |
|               modified_files[path] = content unless content == old_content
 | |
|             end
 | |
|           end
 | |
|           unless modified_files.empty?
 | |
|             desired_gem_version = next_rubygems_version(generator_result.gem_name)
 | |
|             version_content, generator_version_change, revision_change =
 | |
|                 update_version_content(version_content, desired_gem_version, generator_result.revision)
 | |
|             changelog_content = update_changelog_content(changelog_content, desired_gem_version, generator_version_change, revision_change)
 | |
|             modified_files[generator_result.version_path] = version_content
 | |
|             modified_files[generator_result.changelog_path] = changelog_content
 | |
|           end
 | |
|           modified_files
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def gems_client
 | |
|           @gems_client ||= Gems::Client.new
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def current_rubygems_version(gem_name)
 | |
|           @current_rubygems_versions[gem_name] ||= begin
 | |
|             gems_client.info(gem_name)["version"]
 | |
|           rescue Gems::NotFound
 | |
|             "0.0.0"
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def next_rubygems_version(gem_name)
 | |
|           major, minor = current_rubygems_version(gem_name).split(".")
 | |
|           "#{major.to_i}.#{minor.to_i + 1}.0"
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def update_version_content(content, desired_gem_version, new_revision)
 | |
|           generator_version_change = revision_change = nil
 | |
|           modified_content = content.dup
 | |
|           modified_content.sub!(/GEM_VERSION = "([\w\.]*)"/) do |*|
 | |
|             "GEM_VERSION = \"#{desired_gem_version}\""
 | |
|           end or raise "gem_version.rb is missing GEM_VERSION"
 | |
|           modified_content.sub!(/GENERATOR_VERSION = "([\w\.]*)"/) do |*|
 | |
|             generator_version_change = Generator::VERSION unless Regexp.last_match[1] == Generator::VERSION
 | |
|             "GENERATOR_VERSION = \"#{Generator::VERSION}\""
 | |
|           end or raise "gem_version.rb is missing GENERATOR_VERSION"
 | |
|           modified_content.sub!(/REVISION = "([\w\.]*)"/) do |*|
 | |
|             revision_change = new_revision unless Regexp.last_match[1] == new_revision
 | |
|             "REVISION = \"#{new_revision}\""
 | |
|           end or raise "gem_version.rb is missing REVISION"
 | |
|           [modified_content, generator_version_change, revision_change]
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def update_changelog_content(content, desired_gem_version, generator_version_change, revision_change)
 | |
|           lines = parse_existing_changelog_entry(content, desired_gem_version)
 | |
|           modify_changelog_lines(lines, generator_version_change, revision_change)
 | |
|           entry = assemble_changelog_entry(lines, desired_gem_version)
 | |
|           replace_changelog_entry(content, desired_gem_version, entry)
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def parse_existing_changelog_entry(content, desired_gem_version)
 | |
|           quoted_gem_version = Regexp.quote(desired_gem_version)
 | |
|           match = /\n+### v#{quoted_gem_version} \([\d-]+\)\n+((?:[^#][^\n]*\n+)*)(?=#|$)/.match content
 | |
|           return [] unless match
 | |
|           match[1].split("\n")
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def modify_changelog_lines(lines, generator_version_change, revision_change)
 | |
|           if generator_version_change
 | |
|             lines.reject! { |line| line =~ /^\* Regenerated using generator version \d[\w\.]+/ }
 | |
|             lines.unshift("* Regenerated using generator version #{generator_version_change}")
 | |
|           end
 | |
|           if revision_change
 | |
|             lines.reject! { |line| line =~ /^\* Regenerated from discovery document revision \d+/ }
 | |
|             lines.unshift("* Regenerated from discovery document revision #{revision_change}")
 | |
|           end
 | |
|           lines << "* Unspecified changes" if lines.empty?
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def assemble_changelog_entry(lines, desired_gem_version)
 | |
|           entry_lines = lines.join("\n")
 | |
|           date = Time.now.strftime("%Y-%m-%d")
 | |
|           "\n\n### v#{desired_gem_version} (#{date})\n\n#{entry_lines}\n\n"
 | |
|         end
 | |
| 
 | |
|         # @private
 | |
|         def replace_changelog_entry(content, desired_gem_version, entry)
 | |
|           quoted_gem_version = Regexp.quote(desired_gem_version)
 | |
|           modified_content = content.dup
 | |
|           modified_content.sub!(/\n+### v#{quoted_gem_version} \([\d-]+\)\n+(?:[^#][^\n]*\n+)*(?=#|$)/, entry) or
 | |
|             modified_content.sub!(/^(\n*# [^\n]+)\n+(?=#|$)/, "\\1#{entry}") or
 | |
|             raise "CHANGELOG doesn't seem to have the expected header"
 | |
|           modified_content
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |