• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-yast2 / 13440235285

20 Feb 2025 04:40PM UTC coverage: 41.869% (-0.02%) from 41.889%
13440235285

push

github

web-flow
Merge pull request #1316 from yast/agama_kernel_conf

Respect Agama kernel parameters

2 of 4 new or added lines in 1 file covered. (50.0%)

265 existing lines in 40 files now uncovered.

12605 of 30106 relevant lines covered (41.87%)

10.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.17
/library/packages/src/modules/PackageSystem.rb
1
# ***************************************************************************
2
#
3
# Copyright (c) 2002 - 2012 Novell, Inc.
4
# All Rights Reserved.
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of version 2 of the GNU General Public License as
8
# published by the Free Software Foundation.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, contact Novell, Inc.
17
#
18
# To contact Novell about this file by physical or electronic mail,
19
# you may find current contact information at www.novell.com
20
#
21
# ***************************************************************************
22
# File:  modules/PackageSystem.ycp
23
# Package:  yast2
24
# Summary:  Packages manipulation (system)
25
# Authors:  Martin Vidner <mvidner@suse.cz>
26
#    Michal Svec <msvec@suse.cz>
27
# Flags:  Stable
28
#
29
# $Id$
30
#
31
# The documentation is maintained at
32
# <a href="../index.html">.../docs/index.html</a>.
33
require "yast"
1✔
34
require "yast2/execute"
1✔
35
require "shellwords"
1✔
36

37
module Yast
1✔
38
  class PackageSystemClass < Module
1✔
39
    include Yast::Logger
1✔
40

41
    def main
1✔
42
      Yast.import "Pkg"
1✔
43
      textdomain "base"
1✔
44

45
      Yast.import "Kernel"
1✔
46
      Yast.import "Mode"
1✔
47
      Yast.import "PackageCallbacks"
1✔
48
      Yast.import "PackageLock"
1✔
49
      Yast.import "Report"
1✔
50
      Yast.import "Stage"
1✔
51
      Yast.import "CommandLine"
1✔
52
      Yast.import "Installation"
1✔
53

54
      # Was last operation canceled?
55
      #
56
      # Used to enhance the exit status to distinguish between package
57
      # installation fail and installation canceled by user, as in the second
58
      # case doesn't make much sense to display any error
59
      # Is set to true when user canceled package installation, from
60
      # PackageSystem::* functions
61
      @last_op_canceled = false
1✔
62

63
      # Has Pkg::TargetInit run?
64
      @target_initialized = false
1✔
65

66
      Yast.include self, "packages/common.rb"
1✔
67

68
      @_rpm_query_binary_initialized = false
1✔
69
      @_rpm_query_binary = "/usr/bin/rpm"
1✔
70
    end
71

72
    # Ensure that Pkg:: calls work.
73
    # This may become superfluous.
74
    def EnsureTargetInit
1✔
75
      # do not initialize the target system in the first installation stage when
76
      # running in instsys, there is no RPM DB in the RAM disk image (bnc#742420)
77
      if Stage.initial && !Mode.live_installation
×
78
        Builtins.y2milestone(
×
79
          "Skipping target initialization in first stage installation"
80
        )
81
        return
×
82
      end
83

84
      PackageLock.Check
×
85
      # always initizalize target, it should be cheap according to #45356
86
      @target_initialized = Pkg.TargetInit(Installation.destdir, false)
×
87

UNCOV
88
      nil
×
89
    end
90

91
    # Ensure that Pkg:: calls working with the installation sources work
92
    def EnsureSourceInit
1✔
93
      PackageLock.Check
×
94

95
      # no repository present (not even a disabled one)
96
      if Pkg.SourceGetCurrent(false).empty?
×
97
        # this way, if somebody closed the cache outside of Package
98
        # (typically in installation), we will reinitialize
99
        # it's cheap if cache is already initialized
100
        Pkg.SourceStartCache(true)
×
101
        return
×
102
      end
103

104
      if !@target_initialized
×
105
        # make sure we have the RPM keys imported
106
        EnsureTargetInit()
×
107
      end
108

109
      # at least one enabled repository?
110
      if Pkg.SourceGetCurrent(true).empty?
×
111
        # all repositories are disabled or no repository defined
112
        Builtins.y2warning("No package repository available")
×
113
      end
114

UNCOV
115
      nil
×
116
    end
117

118
    def DoInstall(packages)
1✔
119
      packages = deep_copy(packages)
×
120
      DoInstallAndRemove(packages, [])
×
121
    end
122

123
    def DoRemove(packages)
1✔
124
      packages = deep_copy(packages)
×
125
      DoInstallAndRemove([], packages)
×
126
    end
127

128
    def SelectPackages(toinstall, toremove)
1✔
129
      toinstall = deep_copy(toinstall)
×
130
      toremove = deep_copy(toremove)
×
131
      ok = true
×
132

133
      Builtins.foreach(toinstall) do |p|
×
134
        if ok == true && (Pkg.PkgInstall(p) != true)
×
135
          Builtins.y2error("Package %1 install failed: %2", p, Pkg.LastError)
×
136
          ok = false
×
137
        end
138
      end
139
      return false if ok != true
×
140

141
      Builtins.foreach(toremove) do |p|
×
142
        if ok == true && (Pkg.PkgDelete(p) != true)
×
143
          Builtins.y2error("Package %1 delete failed: %2", p, Pkg.LastError)
×
144
          ok = false
×
145
        end
146
      end
147

148
      ok
×
149
    end
150

151
    def DoInstallAndRemoveInt(toinstall, toremove)
1✔
152
      toinstall = deep_copy(toinstall)
1✔
153
      toremove = deep_copy(toremove)
1✔
154
      Builtins.y2debug("toinstall: %1, toremove: %2", toinstall, toremove)
1✔
155
      return false if !PackageLock.Check
1✔
156

157
      EnsureTargetInit()
1✔
158
      EnsureSourceInit()
1✔
159
      ok = true
1✔
160

161
      Yast.import "Label"
1✔
162
      Yast.import "Popup"
1✔
163
      Yast.import "PackagesUI"
1✔
164

165
      # licenses: #35250
166
      licenses = Pkg.PkgGetLicensesToConfirm(toinstall)
1✔
167
      if Ops.greater_than(Builtins.size(licenses), 0)
1✔
168
        rt_licenses_l = Builtins.maplist(licenses) do |p, l|
×
169
          if Mode.commandline
×
170
            Builtins.sformat("%1\n%2", p, l)
×
171
          else
172
            Builtins.sformat("<p><b>%1</b></p>\n%2", p, l)
×
173
          end
174
        end
175

176
        accepted = false
×
177

178
        if Mode.commandline
×
179
          # print the licenses
180
          CommandLine.Print(Builtins.mergestring(rt_licenses_l, "\n"))
×
181
          # print the question
182
          CommandLine.Print(_("Do you accept this license agreement?"))
×
183

184
          accepted = !CommandLine.YesNo
×
185
        else
186
          accepted = !Popup.AnyQuestionRichText(
×
187
            # popup heading, with rich text widget and Yes/No buttons
188
            _("Do you accept this license agreement?"),
189
            Builtins.mergestring(rt_licenses_l, "\n"),
190
            70,
191
            20,
192
            Label.YesButton,
193
            Label.NoButton,
194
            :focus_none
195
          )
196
        end
197

198
        Builtins.y2milestone("Licenses accepted: %1", accepted)
×
199

200
        if !accepted
×
201
          Builtins.y2milestone("License not accepted: %1", toinstall)
×
202
          @last_op_canceled = true
×
203
          return false
×
204
        end
205

206
        # mark licenses as confirmed
207
        Builtins.foreach(licenses) { |p, _l| Pkg.PkgMarkLicenseConfirmed(p) }
×
208
        @last_op_canceled = false
×
209
      end
210

211
      return false if !SelectPackages(toinstall, toremove)
1✔
212

213
      if !Pkg.PkgSolve(false)
1✔
214
        Builtins.y2error("Package solve failed: %1", Pkg.LastError)
×
215

216
        # error message, after pressing [OK] the package manager is displayed
217
        Report.Error(
×
218
          _(
219
            "There are unresolved dependencies which need\nto be solved manually in the software manager."
220
          )
221
        )
222

223
        # disable repomanagement during installation
224
        repomgmt = !Mode.installation
×
225
        # start the package selector
226
        ret = PackagesUI.RunPackageSelector(
×
227
          "enable_repo_mgr" => repomgmt, "mode" => :summaryMode
228
        )
229

230
        Builtins.y2internal("Package selector returned: %1", ret)
×
231

232
        # do not fix the system
233
        return false if [:cancel, :close].include?(ret)
×
234
      end
235

236
      # is a package or a patch selected for installation?
237
      any_to_install = Pkg.IsAnyResolvable(:package, :to_install) ||
1✔
238
        Pkg.IsAnyResolvable(:patch, :to_install)
239

240
      # [int successful, list failed, list remaining, list srcremaining, list update_messages]
241
      result = Pkg.PkgCommit(0)
1✔
242
      Builtins.y2debug("PkgCommit: %1", result)
1✔
243
      if result.nil? || Ops.get_list(result, 1, []) != []
1✔
244
        Builtins.y2error(
×
245
          "Package commit failed: %1",
246
          Ops.get_list(result, 1, [])
247
        )
248
        return false
×
249
      end
250

251
      PackagesUI.show_update_messages(result)
1✔
252

253
      Builtins.foreach(Ops.get_list(result, 2, [])) do |remaining|
1✔
254
        if ok == true && Builtins.contains(toinstall, remaining)
×
255
          Builtins.y2error("Package remain: %1", remaining)
×
256
          ok = false
×
257
        end
258
      end
259
      return false if ok != true
1✔
260

261
      # Show popup when new kernel was installed
262
      # But omit it during installation, one is run at its end.
263
      # #25071
264
      Kernel.InformAboutKernelChange if !Stage.initial && !Stage.cont
1✔
265

266
      # a package or a patch was installed, may be that there is a new yast agent
267
      if any_to_install
1✔
268
        # register the new agents
269
        SCR.RegisterNewAgents
1✔
270
      end
271

272
      true
1✔
273
    end
274

275
    # Install and remove requested packages
276
    # @note The packages are by default installed also with soft dependencies
277
    #   (like Recommends or Supplements)
278
    # @param toinstall [Array<String>] the list of package to install (package names)
279
    # @param toremove [Array<String>] the list of package to remove (package names)
280
    # @return [Boolean] `true`` on success, `false` on error
281
    def DoInstallAndRemove(toinstall, toremove)
1✔
282
      return false if !PackageLock.Check
2✔
283

284
      # the DoInstallAndRemoveInt() call initializes the libzypp internally
285
      # but we need initialized libzypp earlier to change the solver settings
286
      EnsureTargetInit()
1✔
287
      EnsureSourceInit()
1✔
288

289
      # remember the current solver flags
290
      solver_flags = Pkg.GetSolverFlags
1✔
291

292
      # do not install recommended packages for already installed packages (bnc#445476)
293
      Pkg.SetSolverFlags("ignoreAlreadyRecommended" => true)
1✔
294

295
      ret = DoInstallAndRemoveInt(toinstall, toremove)
1✔
296

297
      # restore the original flags
298
      Pkg.SetSolverFlags(solver_flags)
1✔
299

300
      ret
1✔
301
    end
302

303
    # Is a package available?
304
    # @return true if yes (nil = no package source available)
305
    def Available(package)
1✔
306
      EnsureTargetInit()
×
307
      EnsureSourceInit()
×
308

309
      # at least one enabled repository present?
310
      if Pkg.SourceGetCurrent(true).empty?
×
311
        # error no source initialized
312
        return nil
×
313
      end
314

315
      Pkg.IsAvailable(package)
×
316
    end
317

318
    def InitRPMQueryBinary
1✔
319
      return if @_rpm_query_binary_initialized
×
320

321
      # rpmqpack is a way faster
322
      if SCR.Read(path(".target.size"), "/usr/bin/rpmqpack") > -1
×
323
        @_rpm_query_binary = "/usr/bin/rpmqpack "
×
324
      # than rpm itself
325
      elsif SCR.Read(path(".target.size"), "/usr/bin/rpm") > -1
×
326
        @_rpm_query_binary = "/usr/bin/rpm -q "
×
327
      end
328
      # FIXME: else branch if none is installed? critical failure without rpm?
329

330
      @_rpm_query_binary_initialized = true
×
331

UNCOV
332
      nil
×
333
    end
334

335
    # Is a package provided in the system? Is there any installed package providing 'package'?
336
    #
337
    # @param package [String] name of the package to check if provided
338
    # @return [Boolean] whether the package is provided in the system or not
339
    def Installed(package)
1✔
340
      # This is a most commonly called function and so it's
341
      # important that it's fast, especially in the common
342
      # case, where all dependencies are satisfied.
343
      # Unfortunately, initializing Pkg reads the RPM database...
344
      # so we must avoid it.
345
      # added --whatprovides due to bug #76181
346
      # Use Yast::Execute to prevent false positives (boo#1137992)
347
      rpm_command = ["/usr/bin/rpm", "-q", "--whatprovides", package]
2✔
348
      # We are not raising exceptions in case of return codes different than
349
      # 0 or 1. So do not plan to modify the current behavior.
350
      output, return_code = Yast::Execute.stdout.on_target!(rpm_command, allowed_exitstatus: 0..1)
2✔
351
      log.info "Query installed package with '#{rpm_command.join(" ")}' and result #{output}"
2✔
352

353
      # return Pkg::IsProvided (package);
354
      return_code == 0
2✔
355
    end
356

357
    # Is a package installed? Checks only the package name in contrast to Installed() function.
358
    # @return true if yes
359
    def PackageInstalled(package)
1✔
360
      InitRPMQueryBinary()
×
361

362
      # This is commonly called function and so it's
363
      # important that it's fast, especially in the common
364
      # case, where all dependencies are satisfied.
365
      0 ==
×
366
        Convert.to_integer(
367
          SCR.Execute(
368
            path(".target.bash"),
369
            "#{@_rpm_query_binary} #{package.shellescape}"
370
          )
371
        )
372
    end
373

374
    # Is a package available? Checks only package name, not list of provides.
375
    # @return true if yes (nil = no package source available)
376
    def PackageAvailable(package)
1✔
377
      EnsureTargetInit()
×
378
      EnsureSourceInit()
×
379

380
      # at least one enabled repository present?
381
      if Pkg.SourceGetCurrent(true).empty?
×
382
        # error no source initialized
383
        return nil
×
384
      end
385

386
      Pkg.PkgAvailable(package)
×
387
    end
388

389
    # Check if packages are installed
390
    #
391
    # Install them if they are not and user approves installation
392
    #
393
    # @param a list of packages to check (and install)
394
    # @return [Boolean] true if installation succeeded or packages were installed,
395
    # false otherwise
396
    def CheckAndInstallPackages(packages)
1✔
397
      log.warn "DEPRECATED: call Package.CheckAndInstallPackages instead"
1✔
398
      Yast.import "Package"
1✔
399
      Package.CheckAndInstallPackages(packages)
1✔
400
    end
401

402
    # Check if packages are installed
403
    #
404
    #
405
    # Install them if they are not and user approves installation
406
    # If installation fails (or wasn't allowed), ask user if he wants to continue
407
    #
408
    # @param [Array<String>] packages a list of packages to check (and install)
409
    # @return [Boolean] true if installation succeeded, packages were installed
410
    # before or user decided to continue, false otherwise
411
    def CheckAndInstallPackagesInteractive(packages)
1✔
412
      log.warn "DEPRECATED: call Package.CheckAndInstallPackagesInteractive instead"
1✔
413
      Yast.import "Package"
1✔
414
      Package.CheckAndInstallPackagesInteractive(packages)
1✔
415
    end
416

417
    def InstallKernel(kernel_modules)
1✔
418
      kernel_modules = deep_copy(kernel_modules)
×
419
      # this function may be responsible for the horrible startup time
420
      Builtins.y2milestone("want: %1", kernel_modules)
×
421
      if kernel_modules == []
×
422
        return true # nothing to do
×
423
      end
424

425
      # check whether tag "kernel" is provided
426
      # do not initialize the package manager if it's not necessary
427
      rpm_command = "/usr/bin/rpm -q --whatprovides kernel"
×
428
      Builtins.y2milestone("Starting RPM query: %1", rpm_command)
×
429
      output = Convert.to_map(
×
430
        SCR.Execute(path(".target.bash_output"), rpm_command)
431
      )
432
      Builtins.y2debug("result of the query: %1", output)
×
433

434
      if Ops.get_integer(output, "exit", -1) == 0
×
435
        packages = Builtins.splitstring(
×
436
          Ops.get_string(output, "stdout", ""),
437
          "\n"
438
        )
439
        packages = Builtins.filter(packages) { |pkg| pkg != "" }
×
440
        Builtins.y2milestone("Packages providing tag 'kernel': %1", packages)
×
441

442
        return true if Ops.greater_than(Builtins.size(packages), 0)
×
443

444
        Builtins.y2milestone("Huh? Kernel is not installed??")
×
445
      else
446
        Builtins.y2warning("RPM query failed, quering the package manager...")
×
447
      end
448

449
      EnsureTargetInit()
×
450

451
      provides = Pkg.PkgQueryProvides("kernel")
×
452
      Builtins.y2milestone("provides: %1", provides)
×
453

454
      kernels = Builtins.filter(provides) do |l|
×
455
        Ops.get_symbol(l, 1, :NONE) == :BOTH ||
×
456
          Ops.get_symbol(l, 1, :NONE) == Ops.get_symbol(l, 2, :NONE)
457
      end
458

459
      Builtins.y2error("not exactly one package provides tag kernel") if Builtins.size(kernels) != 1
×
460

461
      kernel = Ops.get_string(kernels, [0, 0], "none")
×
462
      packs = [kernel]
×
463

464
      EnsureSourceInit() if !Pkg.IsProvided(kernel)
×
465

466
      # TODO: for 9.2, we always install all packages, but
467
      # we could only install those really needed (#44394)
468
      InstallAll(packs)
×
469
    end
470

471
    publish function: :Available, type: "boolean (string)"
1✔
472
    publish function: :Installed, type: "boolean (string)"
1✔
473
    publish function: :DoInstall, type: "boolean (list <string>)"
1✔
474
    publish function: :DoRemove, type: "boolean (list <string>)"
1✔
475
    publish function: :DoInstallAndRemove, type: "boolean (list <string>, list <string>)"
1✔
476
    publish function: :AvailableAll, type: "boolean (list <string>)"
1✔
477
    publish function: :AvailableAny, type: "boolean (list <string>)"
1✔
478
    publish function: :InstalledAll, type: "boolean (list <string>)"
1✔
479
    publish function: :InstalledAny, type: "boolean (list <string>)"
1✔
480
    publish function: :InstallMsg, type: "boolean (string, string)"
1✔
481
    publish function: :InstallAllMsg, type: "boolean (list <string>, string)"
1✔
482
    publish function: :InstallAnyMsg, type: "boolean (list <string>, string)"
1✔
483
    publish function: :RemoveMsg, type: "boolean (string, string)"
1✔
484
    publish function: :RemoveAllMsg, type: "boolean (list <string>, string)"
1✔
485
    publish function: :Install, type: "boolean (string)"
1✔
486
    publish function: :InstallAll, type: "boolean (list <string>)"
1✔
487
    publish function: :InstallAny, type: "boolean (list <string>)"
1✔
488
    publish function: :Remove, type: "boolean (string)"
1✔
489
    publish function: :RemoveAll, type: "boolean (list <string>)"
1✔
490
    publish function: :LastOperationCanceled, type: "boolean ()"
1✔
491
    publish function: :EnsureTargetInit, type: "void ()"
1✔
492
    publish function: :EnsureSourceInit, type: "void ()"
1✔
493
    publish function: :PackageInstalled, type: "boolean (string)"
1✔
494
    publish function: :PackageAvailable, type: "boolean (string)"
1✔
495
    publish function: :CheckAndInstallPackages, type: "boolean (list <string>)"
1✔
496
    publish function: :CheckAndInstallPackagesInteractive, type: "boolean (list <string>)"
1✔
497
    publish function: :InstallKernel, type: "boolean (list <string>)"
1✔
498
  end
499

500
  PackageSystem = PackageSystemClass.new
1✔
501
  PackageSystem.main
1✔
502
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc