diff --git a/README.md b/README.md index 94c4f18526..d288a6b0d9 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ TODO: use a url shortener To build and run this software you need a few tools. To install them on openSUSE Tumbleweed just type: - $ sudo zypper in gcc gcc-c++ make openssl-devel ruby-devel npm + $ sudo zypper in gcc gcc-c++ make openssl-devel ruby-devel augeas-devel npm ## yastd diff --git a/deploy.sh b/deploy.sh index 9336d64b2e..e252fe2ae4 100644 --- a/deploy.sh +++ b/deploy.sh @@ -1,5 +1,5 @@ #! /bin/sh -sudo zypper --non-interactive install gcc gcc-c++ make openssl-devel ruby-devel npm git || exit 1 +sudo zypper --non-interactive install gcc gcc-c++ make openssl-devel ruby-devel npm git augeas-devel || exit 1 git clone https://github.com/yast/the-installer || exit 1 cd the-installer diff --git a/yastd-proxy/Gemfile b/yastd-proxy/Gemfile index f2b2fb6552..af34c30685 100644 --- a/yastd-proxy/Gemfile +++ b/yastd-proxy/Gemfile @@ -10,3 +10,4 @@ gem "sinatra" gem "sinatra-cors" gem "ruby-dbus", require: "dbus" gem "thin" +gem "rexml" # ruby3 has it as separate gem diff --git a/yastd/Gemfile b/yastd/Gemfile index 8d89064797..a5c4be7529 100644 --- a/yastd/Gemfile +++ b/yastd/Gemfile @@ -4,8 +4,8 @@ source "https://rubygems.org" gem "rake" gem "ruby-dbus" +gem "rexml" # dependency of dbus gem "eventmachine" -gem "nokogiri" # Required by YaST gem "cheetah" diff --git a/yastd/lib/yast2/dbus/installer.rb b/yastd/lib/yast2/dbus/installer.rb index 4b72c369fc..209ea66a5d 100644 --- a/yastd/lib/yast2/dbus/installer.rb +++ b/yastd/lib/yast2/dbus/installer.rb @@ -42,6 +42,8 @@ def initialize(installer, logger, *args) self.StatusChanged(status.id) end + installer.dbus_obj = self + super(*args) end @@ -170,7 +172,7 @@ def initialize(installer, logger, *args) # - total_substeps: total count of smaller steps done as part of big step. Can be 0, which means no substeps defined # - current_substep: current substep. Always in range of 0..total_substeps dbus_signal :Progress, - "message:s, total_steps:t, current_step: t, total_substeps: t, current_substep: t" + "message:s, total_steps:t, current_step:t, total_substeps:t, current_substep:t" end end end diff --git a/yastd/lib/yast2/progress.rb b/yastd/lib/yast2/installation_progress.rb similarity index 50% rename from yastd/lib/yast2/progress.rb rename to yastd/lib/yast2/installation_progress.rb index 9a236a07c0..d92559665c 100644 --- a/yastd/lib/yast2/progress.rb +++ b/yastd/lib/yast2/installation_progress.rb @@ -22,23 +22,70 @@ # YaST specific code lives under this namespace module Yast2 # This class represents the installer status - class Progress - def initialize(dbus_obj) + class InstallationProgress + KNOWN_STEPS = 3 # keep it in sync with installer.rb + def initialize(dbus_obj, logger: nil) @dbus_obj = dbus_obj + @logger = logger @total_pkgs = 0 @remaining_pkgs = 0 end + def partitioning(&block) + report( + # TODO: localization + "Partitioning target disk", 0 + ) + block.call(self) + report( + # TODO: localization + "Partitioning finished", 1 + ) + end + + def package_installation(&block) + report( + # TODO: localization + "Starting to install packages", 1 + ) + block.call(self) + report( + # TODO: localization + "Package installation finished", 2 + ) + end + + def bootloader_installation(&block) + report( + # TODO: localization + "Starting to deploy bootloader", 2 + ) + block.call(self) + report( + # TODO: localization + "Installation finished", 3 + ) + end + def packages_to_install=(value) @total_pkgs = @remaining_pkgs = value end def package_installed @remaining_pkgs -= 1 - @dbus_obj&.report_progress( + report( # TODO: localization "Installing packages (#{@remaining_pkgs} remains)", - 1, 0, @total_pkgs, @total_pkgs - @remaining_pkgs + 1, substeps: @total_pkgs, current_substep: @total_pkgs - @remaining_pkgs + ) + end + + private + + def report(title, step, substeps: 0, current_substep: 0) + @logger&.info title + @dbus_obj&.Progress( + title, KNOWN_STEPS, step, substeps, current_substep ) end end diff --git a/yastd/lib/yast2/installer.rb b/yastd/lib/yast2/installer.rb index e84d591071..3e1e8a8e5c 100644 --- a/yastd/lib/yast2/installer.rb +++ b/yastd/lib/yast2/installer.rb @@ -4,7 +4,7 @@ require "y2storage" require "yast2/installer_status" require "yast2/software" -require "yast2/progress" +require "yast2/installation_progress" require "bootloader/proposal_client" require "bootloader/finish_client" require "dbus" @@ -63,7 +63,6 @@ def initialize(logger: nil) @status = InstallerStatus::IDLE @logger = logger || Logger.new(STDOUT) @software = Software.new(@logger) - @progress = Progress.new(nil) # TODO: fix passing progress # Set stage to initial, so it will act as installer for some cases like # proposing installer instead of reading current one Yast::Stage.Set("initial") @@ -86,9 +85,8 @@ def options def probe change_status(InstallerStatus::PROBING) probe_languages - @software.probe - @software.propose probe_storage + @software.probe true rescue StandardError => e logger.error "Probing error: #{e.inspect}" @@ -120,20 +118,29 @@ def storage_proposal end def install - Yast::Installation.destdir = "/mnt" - logger.info "Installing(partitioning)" - change_status(InstallerStatus::PARTITIONING) - Yast::WFM.CallFunction("inst_prepdisk", []) - # Install software - logger.info "Installing(installing software)" change_status(InstallerStatus::INSTALLING) - @software.install(@progress) - # Install bootloader - logger.info "Installing(bootloader)" + Yast::Installation.destdir = "/mnt" + # lets propose it here to be sure that software proposal reflects product selection + # FIXME: maybe repropose after product selection change? + # first make bootloader proposal to be sure that required packages is installed proposal = ::Bootloader::ProposalClient.new.make_proposal({}) logger.info "Bootloader proposal #{proposal.inspect}" - ::Bootloader::FinishClient.new.write - logger.info "Installing(finished)" + @software.propose + + progress = InstallationProgress.new(@dbus_obj, logger: logger) + progress.partitioning do |_| + Yast::WFM.CallFunction("inst_prepdisk", []) + end + progress.package_installation do |progr| + # call inst bootloader to get properly initialized bootloader + # sysconfig before package installation + Yast::WFM.CallFunction("inst_bootloader", []) + @software.install(progr) + end + progress.bootloader_installation do |_| + Yast::WFM.SCROpen("chroot=#{Yast::Installation.destdir}:scr", false) + ::Bootloader::FinishClient.new.write + end change_status(InstallerStatus::IDLE) end @@ -146,6 +153,10 @@ def on_status_change(&block) @on_status_change = block end + def dbus_obj=(obj) + @dbus_obj = obj + end + private def change_status(new_status) diff --git a/yastd/lib/yast2/software.rb b/yastd/lib/yast2/software.rb index caa4efbead..a7dcee9866 100644 --- a/yastd/lib/yast2/software.rb +++ b/yastd/lib/yast2/software.rb @@ -25,6 +25,7 @@ Yast.import "Pkg" Yast.import "PackageInstallation" +Yast.import "Stage" # YaST specific code lives under this namespace module Yast2 @@ -46,19 +47,38 @@ def select_product(name) def probe logger.info "Probing software" + # as we use liveDVD with normal like ENV, lets temporary switch to normal to use its repos + Yast::Stage.Set("normal") Yast::Pkg.TargetInitialize("/") Yast::Pkg.TargetLoad Yast::Pkg.SourceRestore Yast::Pkg.SourceLoad @products = Y2Packager::Product.all - end - - def propose @product = @products.first&.name + proposal = Yast::Packages.Proposal(force_reset = true, reinit = false, _simple = true) + @logger.info "proposal #{proposal["raw_proposal"]}" + Yast::Stage.Set("initial") raise "No Product Available" unless @product + end - Yast::Packages.Proposal(force_reset = true, reinit = true, _simple = true) + def propose + Yast::Pkg.TargetInitialize(Yast::Installation.destdir) + Yast::Pkg.TargetLoad + selected_product = @products.find { |p| p.name == @product } + selected_product.select + @logger.info "selected product #{selected_product.inspect}" + + # as we use liveDVD with normal like ENV, lets temporary switch to normal to use its repos + Yast::Stage.Set("normal") + # FIXME: workaround to have at least reasonable proposal + Yast::PackagesProposal.AddResolvables("the-installer", :pattern, ["base", "enhanced_base"]) + proposal = Yast::Packages.Proposal(force_reset = false, reinit = false, _simple = true) + @logger.info "proposal #{proposal["raw_proposal"]}" + res = Yast::Pkg.PkgSolve(unused = true) + @logger.info "solver run #{res.inspect}" + + Yast::Stage.Set("initial") # do not return proposal hash, so intentional nil here nil end @@ -69,13 +89,14 @@ def install(progress) PackageCallbacks.setup(progress) # TODO: error handling - Yast::Pkg.TargetInitialize(Yast::Installation.destdir) commit_result = Yast::PackageInstallation.Commit({}) if commit_result.nil? || commit_result.empty? - log.error("Commit failed") + @logger.error("Commit failed") raise Yast::Pkg.LastError end + + @logger.info "Commit result #{commit_result}" end private