Skip to content

Commit

Permalink
feat(ruby): implement the DoneProvide callback
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Jan 22, 2025
1 parent b37d635 commit f101e8f
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def InitPackageCallbacks(logger = nil)
Agama::Software::Callbacks::Media.new(
questions_client, logger
).setup

Agama::Software::Callbacks::Provide.new(
questions_client, logger
).setup
end

# Returns the client to ask questions
Expand All @@ -59,4 +63,3 @@ def questions_client
PackageCallbacks = PackageCallbacksClass.new
PackageCallbacks.main
end

1 change: 1 addition & 0 deletions service/lib/agama/software/callbacks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ module Callbacks

require "agama/software/callbacks/media"
require "agama/software/callbacks/progress"
require "agama/software/callbacks/provide"
require "agama/software/callbacks/signature"
101 changes: 101 additions & 0 deletions service/lib/agama/software/callbacks/provide.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# frozen_string_literal: true

# Copyright (c) [2025] SUSE LLC
#
# 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 SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "yast"
require "agama/question"

Yast.import "Pkg"

module Agama
module Software
module Callbacks
# Provide callbacks
class Provide
include Yast::I18n

# From https://github.com/openSUSE/libzypp/blob/d90a93fc2a248e6592bd98114f82a0b88abadb72/zypp/ZYppCallbacks.h#L111
NO_ERROR = 0
NOT_FOUND = 1
IO_ERROR = 2
INVALID = 3

# Constructor
#
# @param questions_client [Agama::DBus::Clients::Questions]
# @param logger [Logger]
def initialize(questions_client, logger)
@questions_client = questions_client
@logger = logger
end

# Register the callbacks
def setup
Pkg.CallbackDoneProvide(
fun_ref(method(:done_provide), "string (integer, string, string)")
)
end

# Media change callback
#
# @return [String] "I" for ignore, "R" for retry and "C" for abort (not implemented)
# @see https://github.com/yast/yast-yast2/blob/19180445ab935a25edd4ae0243aa7a3bcd09c9de/library/packages/src/modules/PackageCallbacks.rb#L620
def done_provide(error, reason, name)
args = [error, reason, name]
logger.debug "DoneProvide callback: #{args.inspect}"

message = case error
when NO_ERROR, NOT_FOUND
# "Not found" (error 1) is handled by the MediaChange callback.
nil
when IO_ERROR
Yast::Builtins.sformat(_("Package %1 could not be downloaded (input/output error)."),
name)
when INVALID
Yast::Builtins.sformat(_("Package %1 is broken, integrity check has failed."), name)
else
logger.warn "DoneProvide: unknown error: '#{error}'"
end

return if message.nil?

question = Agama::Question.new(
qclass: "software.provide_error",
text: message,
options: [:Retry, :Ignore],
default_option: :Retry,
data: { "reason" => reason }
)
questions_client.ask(question) do |question_client|
(question_client.answer == :Retry) ? "R" : "I"
end
end

private

# @return [Agama::DBus::Clients::Questions]
attr_reader :questions_client

# @return [Logger]
attr_reader :logger
end
end
end
end
91 changes: 91 additions & 0 deletions service/test/agama/software/callbacks/provide_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# frozen_string_literal: true

# Copyright (c) [2022-2023] SUSE LLC
#
# 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 SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require_relative "../../../test_helper"
require "agama/software/callbacks/provide"
require "agama/dbus/clients/questions"
require "agama/dbus/clients/question"

describe Agama::Software::Callbacks::Provide do
subject { described_class.new(questions_client, logger) }

let(:questions_client) { instance_double(Agama::DBus::Clients::Questions) }

let(:logger) { Logger.new($stdout, level: :warn) }

let(:answer) { :Retry }

describe "#media_changed" do
before do
allow(questions_client).to receive(:ask).and_yield(question_client)
allow(question_client).to receive(:answer).and_return(answer)
end

let(:question_client) { instance_double(Agama::DBus::Clients::Question) }

context "when the file is not found" do
it "does not register a question" do
expect(questions_client).to_not receive(:ask)
subject.done_provide(1, "Some dummy reason", "dummy-package")
end
end

context "when the there is an I/O error" do
it "registers a question informing of the error" do
expect(questions_client).to receive(:ask) do |q|
expect(q.text).to include("could not be downloaded")
end
subject.done_provide(2, "Some dummy reason", "dummy-package")
end
end

context "when the there is an I/O error" do
it "registers a question informing of the error" do
expect(questions_client).to receive(:ask) do |q|
expect(q.text).to include("integrity check has failed")
end
subject.done_provide(3, "Some dummy reason", "dummy-package")
end
end

context "when the user answers :Retry" do
let(:answer) { :Retry }

it "returns 'R'" do
ret = subject.done_provide(
2, "Some dummy reason", "dummy-package"
)
expect(ret).to eq("R")
end
end

context "when the user answers :Skip" do
let(:answer) { :Ignore }

it "returns 'I'" do
ret = subject.done_provide(
2, "Some dummy reason", "dummy-package"
)
expect(ret).to eq("I")
end
end
end
end

0 comments on commit f101e8f

Please sign in to comment.