class InvocaGems::Gem WORKING_DIRECTORY = "invoca_gems" include InvocaGems::ShellCommand attr_reader :name, :uri, :sha, :version, :used_by, :dependants, :path, :branch, :presenter def initialize(gem_name, presenter, defer_bundle: false) @presenter = presenter bundle_wrapper = InvocaGems::Bundler.new try_load_from_git_source(bundle_wrapper, gem_name) try_load_from_path_source(bundle_wrapper, gem_name) @name or presenter.stop_with_message("Could not find gem #{gem_name}") @dependants = bundle_wrapper.dependants(gem_name) @defer_bundle = defer_bundle end def edit configure_branch update_gemfile_for_source bundle_install_application end def save(commit_message=nil) if git_repo.unsaved_changes? if commit_message commit_changes(commit_message) else presenter.stop_with_message "unsaved changes found in #{repo_directory}" end else git_repo.push end update_gemfile_for_github(gemfile_path: "Gemfile", gem_name: name, gem_uri: uri, new_version: version, new_sha: git_repo.sha) presenter.set_subtask("now at #{version} #{git_repo.sha[0..6]}") update_dependencies(name, version, git_repo.sha) bundle_install_application end def update_version(new_version, new_sha) presenter.set_subtask "updating #{name} to #{new_version} #{new_sha}" update_gemfile_for_github( gemfile_path: "Gemfile", gem_name: name, gem_uri: uri, new_version: new_version, new_sha: new_sha) update_dependencies(name, new_version, new_sha) bundle_install_application end def update_dependencies(gem_to_update, version, sha) if dependants dependants.uniq.each do |dependant| presenter.set_task "Updating #{dependant} for #{gem_to_update}" gem = self.class.new(dependant, presenter, defer_bundle: true) gem.edit # Dependant gem update gem.update_gemfile_for_github( gemfile_path: gem.repo_directory + '/Gemfile', gem_name: name, gem_uri: uri, new_version: version, new_sha: sha) # Project gem update gem.update_gemfile_for_github( gemfile_path: gem.repo_directory + '/Gemfile', gem_name: name, gem_uri: uri, new_version: version, new_sha: sha) gem.update_gem_gemspec(gem.repo_directory + "/#{gem.name}.gemspec", gem_to_update, version) gem.bundle_install_gem gem.commit_changes("Update #{gem_to_update} to #{version} (#{sha[0..6]})") gem.save # Will nest dependency upudate end end end def update_gem_gemspec(gemspec_path, gem_name, version) presenter.set_subtask "updating #{gemspec_path} for #{gem_name}" gemspec = InvocaGems::Gemspec.new(gemspec_path) gemspec_gem = gemspec.find(gem_name) gemspec_gem.update_version(version) gemspec_gem.save! end def commit_changes(message) git_repo.commit("#{local_branch_name} #{message}") git_repo.push end def update_gemfile_for_github(gemfile_path:, gem_name:, gem_uri:, new_version:, new_sha:) presenter.set_subtask "updating #{gemfile_path} for #{gem_name}" gemfile = InvocaGems::Gemfile.new(gemfile_path) gemfile_gem = gemfile.find(gem_name, allow_missing: true) || gemfile.append(gem_name) gemfile_gem.update_as_github(new_version, gem_uri, new_sha) gemfile_gem.save! end def repo_directory WORKING_DIRECTORY + '/' + name end def repo_exists? File.directory?(repo_directory) end def git_repo create_working_directory unless @git_repo unless repo_exists? presenter.set_subtask "creating #{repo_directory} from #{uri}" InvocaGems::GitRepo.clone(WORKING_DIRECTORY, uri, name, presenter: presenter) end @git_repo = repo_for_path(repo_directory) @git_repo.fetch end @git_repo end def repo_for_path(path) InvocaGems::GitRepo.new(presenter, path) end def configure_branch git_repo.unsaved_changes? and presenter.stop_with_message "Unsaved changes found in #{repo_directory}" if !git_repo.branch_exists?(local_branch_name) presenter.set_subtask "Creating branch #{local_branch_name}" git_repo.create_branch_at(local_branch_name, sha) end presenter.set_subtask "Using branch #{local_branch_name}" git_repo.checkout_branch(local_branch_name) if git_repo.sha != sha presenter.stop_with_message "Commited work not found in gem, use -- mumble mumble to fix." end end def update_gemfile_for_source gemfile = InvocaGems::Gemfile.new('Gemfile') gemfile_gem = gemfile.find(name) gemfile_gem.update_as_path(repo_directory) gemfile_gem.save! end def local_branch_name @local_branch_name ||= repo_for_path('.').branch end def try_load_from_git_source(bundle_wrapper, gem_name) if result = bundle_wrapper.find_git_source(gem_name) @name = result.name @uri = result.uri @version = result.version @sha = result.ref end end def try_load_from_path_source(bundle_wrapper, gem_name) if !@name && result = bundle_wrapper.find_path_source(gem_name) @name = result.name @path = result.path @version = result.version get_git_statistics_from_path(path) end end def get_git_statistics_from_path(path) repo = repo_for_path(path) @uri = repo.uri @sha = repo.sha @branch = repo.branch end def configure_appilication unless @application_configured create_working_directory @application_configured = true end end def create_working_directory if File.read(".gitignore") !~ /#{WORKING_DIRECTORY}/m presenter.set_subtask "updating .gitignore" File.open(".gitignore","a") { |f| f.write("# Invoca Gem support\n#{WORKING_DIRECTORY}/**\n") } end if !File.directory?(WORKING_DIRECTORY) presenter.set_subtask "creating #{WORKING_DIRECTORY}" Dir.mkdir(WORKING_DIRECTORY) end end def bundle_install_application unless @defer_bundle without_ruby_options do shell_command(command: "bundle install --quiet", presenter: presenter) end end end def bundle_install_gem without_ruby_options do shell_command(command: "bundle install --quiet", path: repo_directory, presenter: presenter) end end def without_ruby_options old_opt = ENV.delete("RUBYOPT") yield ensure ENV["RUBYOPT"] = old_opt end end