yast/yast-yast2

View on GitHub
library/packages/src/modules/PackageLock.rb

Summary

Maintainability
C
1 day
Test Coverage
# ***************************************************************************
#
# Copyright (c) 2002 - 2012 Novell, Inc.
# All Rights Reserved.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact Novell, Inc.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com
#
# ***************************************************************************
# File:  modules/PackageLock.ycp
# Package:  yast2
# Summary:  Packages manipulation (system)
# Authors:  Martin Vidner <mvidner@suse.cz>
#
# $Id$
#
# This should be used everywhere before Pkg is first used. #160319
require "yast"

module Yast
  class PackageLockClass < Module
    def main
      Yast.import "Pkg"
      textdomain "base"

      Yast.import "Popup"
      Yast.import "Label"
      Yast.import "PackageKit"

      @have_lock = nil
      @aborted = false
      # display a different message in the first PackageKit quit confirmation
      @packagekit_asked = false
    end

    # Ask whether to quit PackageKit if it is running
    # @return [Boolean] true if PackageKit was asked to quit
    def AskPackageKit
      ret = false

      if PackageKit.IsRunning
        # ask to send quit signal to PackageKit
        msg = if @packagekit_asked
          _(
            "PackageKit is still running (probably busy).\nAsk PackageKit to quit again?"
          )
        else
          _(
            "PackageKit is blocking software management.\n" \
            "This happens when the updater applet or another software management\n" \
            "application is running.\n" \
            "\n" \
            "Ask PackageKit to quit?"
          )
        end

        @packagekit_asked = true

        if Popup.YesNo(msg)
          PackageKit.SuggestQuit
          ret = true
        end
      end

      ret
    end

    # Tries to acquire the packager (zypp) lock.
    # Reports an error if another process has the lock already.
    # Will only report once even if called multiple times.
    # @return true if we can continue
    def Check
      # we already have a lock
      return @have_lock if !@have_lock.nil?

      # just to allow 'Retry', see more in bug #280383
      try_again = true

      # while not having a lock and user wants to try again
      while try_again
        # Invoke a cheap call that accesses the zypp lock
        @have_lock = Pkg.Connect == true # nil guard
        break if @have_lock == true

        if @have_lock != true
          if AskPackageKit()
            # let the PackageKit quit before retrying
            Builtins.sleep(2000)
            next
          end

          try_again = Popup.AnyQuestion(
            # TRANSLATORS: a popup headline
            _("Accessing the Software Management Failed"),
            Ops.add(
              Ops.add(Pkg.LastError, "\n\n"),
              # TRANSLATORS: an error message with question
              _(
                "Would you like to continue without having access\nto the software management or retry to access it?\n"
              )
            ),
            Label.ContinueButton,
            Label.RetryButton,
            # 'Continue' instead of 'Retry'
            :focus_yes
          ) == false
        end

        Builtins.y2milestone("User decided to retry...") if try_again
      end

      Builtins.y2milestone("PackageLock::Check result: %1", @have_lock)
      @have_lock
    end

    # Tries to acquire the packager (zypp) lock.
    # Reports an error if another process has the lock already.
    # Will only report once even if called multiple times.
    # @param [Boolean] show_continue_button show option to continue without access
    # @return [Hash] with lock status and user reaction
    def Connect(show_continue_button)
      # we already have a lock
      return { "connected" => @have_lock, "aborted" => @aborted } if !@have_lock.nil?

      try_again = true

      # while not having a lock and user wants to try again
      while try_again
        # Invoke a cheap call that accesses the zypp lock
        @have_lock = Pkg.Connect == true # nil guard
        break if @have_lock == true

        if @have_lock != true
          if AskPackageKit()
            # let the PackageKit quit before retrying
            Builtins.sleep(2000)
            next
          end

          if show_continue_button
            ret2 = Popup.AnyQuestion3(
              # TRANSLATORS: a popup headline
              _("Accessing the Software Management Failed"),
              Ops.add(
                Ops.add(Pkg.LastError, "\n\n"),
                # TRANSLATORS: an error message with question
                _(
                  "Would you like to retry accessing the software manager,\n" \
                  "continue without having access to the software management,\n" \
                  "or abort?\n"
                )
              ),
              Label.RetryButton,
              Label.ContinueButton,
              Label.AbortButton,
              # default is 'Retry'
              :focus_yes
            )

            try_again = ret2 == :yes

            # NOTE: due to the changed labels this actually means that [Abort] was pressed!!
            @aborted = true if ret2 == :retry
          else
            ret2 = Popup.AnyQuestion(
              # TRANSLATORS: a popup headline
              _("Accessing the Software Management Failed"),
              Ops.add(
                Ops.add(Pkg.LastError, "\n\n"),
                # TRANSLATORS: an error message with question
                _("Would you like to abort or try again?\n")
              ),
              Label.RetryButton,
              Label.AbortButton,
              # default is 'Retry'
              :focus_yes
            )

            try_again = ret2
            @aborted = !ret2
          end

          Builtins.y2milestone(
            "try_again: %1, aborted: %2",
            try_again,
            @aborted
          )
        end

        Builtins.y2milestone("User decided to retry...") if try_again
      end

      ret = { "connected" => @have_lock, "aborted" => @aborted }
      Builtins.y2milestone("PackageLock::Connect result: %1", ret)

      deep_copy(ret)
    end

    publish function: :Check, type: "boolean ()"
    publish function: :Connect, type: "map <string, any> (boolean)"
  end

  PackageLock = PackageLockClass.new
  PackageLock.main
end