yast/yast-migration

View on GitHub
src/lib/migration/proposal_client.rb

Summary

Maintainability
A
0 mins
Test Coverage

# ------------------------------------------------------------------------------
# Copyright (c) 2015 SUSE LLC
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# ------------------------------------------------------------------------------
#

require "installation/proposal_client"
require "migration/repository_checker"
require "y2packager/resolvable"

module Migration
  # The proposal client for online migration
  class ProposalClient < ::Installation::ProposalClient
    include Yast
    include Yast::I18n

    # ID prefix used in the proposal links
    LINK_PREFIX = "migration--disable_repository_".freeze

    def initialize
      Yast.import "Pkg"
      Yast.import "HTML"
      Yast.import "Packages"
      Yast.import "SpaceCalculation"
      Yast.import "Update"

      textdomain "migration"
    end

    # propose migration - return migration summary
    # @return [Hash] proposal result
    def make_proposal(_attrs)
      # report dependency issues in the Packages proposal
      Pkg.PkgSolve(true)
      Update.solve_errors = Pkg.PkgSolveErrors

      # recalculate the disk space usage data
      SpaceCalculation.GetPartitionInfo

      products = Y2Packager::Resolvable.find(kind: :product)

      ret = {
        "preformatted_proposal" => product_summary(products),
        "help"                  => help
      }

      add_warnings(ret, products)

      ret
    end

    # handle the user feedback
    # @param [Hash] param proposal parameters
    # @return [Hash] proposal result
    def ask_user(param)
      chosen_id = param["chosen_id"]

      # handle the link clicked in the migratin proposal
      if chosen_id && chosen_id.start_with?(LINK_PREFIX)
        disable_repo(chosen_id)
        { "workflow_sequence" => :next }
      else
        # run the repository manager, refresh enabled repositories so they
        # are up-to-date
        ret = WFM.call("repositories", ["refresh-enabled"])
        { "workflow_sequence" => ret }
      end
    end

    # the proposal description
    # @return [Hash] proposal result
    def description
      {
        # TRANSLATORS: a summary heading
        "rich_text_title" => _("Migration Summary"),
        # TRANSLATORS: a menu entry
        "menu_title"      => _("&Migration Summary"),
        "id"              => "migration_proposal"
      }
    end

  private

    # check the current products for possible issues, add product warnings
    # to the proposal summary
    # @param [Hash] proposal the proposal summary (the value is modified)
    # @param [Array<Y2Packager::Resolvable>] products list of the current products
    def add_warnings(proposal, products)
      package_warnings = Packages.product_update_warning(products)
      repo_warnings = check_repositories(products)

      # merge the warnings
      warning = package_warnings["warning"].to_s + repo_warnings["warning"].to_s
      return if warning.empty?

      proposal["warning"] = warning

      warning_level = package_warnings["warning_level"] ||
        repo_warnings["warning_level"]
      proposal["warning_level"] = warning_level if warning_level

      links = repo_warnings["links"]
      proposal["links"] = links if links
    end

    # create a product summary for migration proposal
    # @param [Array<Y2Packager::Resolvable>] products the current libzypp products
    # @return [String] product summary text (RichText)
    def product_summary(products)
      summary_text = Packages.product_update_summary(products).map do |item|
        "<li>#{item}</li>"
      end

      HTML.ListStart + summary_text.join + HTML.ListEnd
    end

    # check for obsolete repositories
    # @param [Array<Y2Packager::Resolvable>] products the current libzypp products
    # @return [Hash] warning for the proposal summary, an empty Hash is returned
    #   if everything is OK
    def check_repositories(products)
      warnings = []
      links = []

      checker = RepositoryChecker.new(products)
      checker.obsolete_product_repos.each do |repo|
        msg, link = warning_for_repo(repo)
        warnings << msg
        links << link
      end

      proposal_warning(warnings, links)
    end

    # create a warning masse for an obsolete repository
    # @param [Fixnum] repo the repository ID
    # @return [Array] a pair [message, link_name]
    def warning_for_repo(repo)
      repo_data = Pkg.SourceGeneralData(repo)
      link = "#{LINK_PREFIX}#{repo}"

      # TRANSLATORS: A warning message displayed in the migration proposal
      # %{name} is a repository name, %{link} is a hidden internal identifier
      msg = _("Warning: Repository <b>%{name}</b> is obsolete and should be excluded " \
          "from migration.<br>It is highly recommended to disable this repository. "\
          "(<a href=\"%{link}\">Disable</a>)") % { name: repo_data["name"], link: link }

      [msg, link]
    end

    # create proposal warning
    # @return [Hash] hash for the proposal summary
    def proposal_warning(warnings, links)
      return {} if warnings.empty?

      {
        "warning"       => warnings.join,
        "warning_level" => :warning,
        "links"         => links
      }
    end

    # handle clicking the "Disable" link
    # @param [String] link clicked link ID
    def disable_repo(link)
      log.info "Activated link: #{link}"

      link =~ /^#{LINK_PREFIX}(\d+)/
      repo = Regexp.last_match(1).to_i

      log.info "Disabling repository #{repo}"
      Pkg.SourceSetEnabled(repo, false)

      # disable the old repo permanently to not possibly mess the system later
      Pkg.SourceSaveAll
    end

    # proposal help text
    # @return [String] help text
    def help
      # TRANSLATORS: help text
      _(
        "<p>This is an overview of the product migration.</p>\n"
      )
    end
  end
end