Class: Yast::PackageSystemClass

Inherits:
Module
  • Object
show all
Includes:
Logger
Defined in:
library/packages/src/modules/PackageSystem.rb

Instance Method Summary collapse

Instance Method Details

#Available(package) ⇒ Object

Is a package available?

Returns:

  • true if yes (nil = no package source available)



305
306
307
308
309
310
311
312
313
314
315
316
# File 'library/packages/src/modules/PackageSystem.rb', line 305

def Available(package)
  EnsureTargetInit()
  EnsureSourceInit()

  # at least one enabled repository present?
  if Pkg.SourceGetCurrent(true).empty?
    # error no source initialized
    return nil
  end

  Pkg.IsAvailable(package)
end

#CheckAndInstallPackages(packages) ⇒ Boolean

Check if packages are installed

Install them if they are not and user approves installation

false otherwise

Parameters:

  • a

    list of packages to check (and install)

Returns:

  • (Boolean)

    true if installation succeeded or packages were installed,



396
397
398
399
400
# File 'library/packages/src/modules/PackageSystem.rb', line 396

def CheckAndInstallPackages(packages)
  log.warn "DEPRECATED: call Package.CheckAndInstallPackages instead"
  Yast.import "Package"
  Package.CheckAndInstallPackages(packages)
end

#CheckAndInstallPackagesInteractive(packages) ⇒ Boolean

Check if packages are installed

Install them if they are not and user approves installation If installation fails (or wasn't allowed), ask user if he wants to continue

before or user decided to continue, false otherwise

Parameters:

  • packages (Array<String>)

    a list of packages to check (and install)

Returns:

  • (Boolean)

    true if installation succeeded, packages were installed



411
412
413
414
415
# File 'library/packages/src/modules/PackageSystem.rb', line 411

def CheckAndInstallPackagesInteractive(packages)
  log.warn "DEPRECATED: call Package.CheckAndInstallPackagesInteractive instead"
  Yast.import "Package"
  Package.CheckAndInstallPackagesInteractive(packages)
end

#DoInstall(packages) ⇒ Object



118
119
120
121
# File 'library/packages/src/modules/PackageSystem.rb', line 118

def DoInstall(packages)
  packages = deep_copy(packages)
  DoInstallAndRemove(packages, [])
end

#DoInstallAndRemove(toinstall, toremove) ⇒ Boolean

Note:

The packages are by default installed also with soft dependencies (like Recommends or Supplements)

Install and remove requested packages

Parameters:

  • toinstall (Array<String>)

    the list of package to install (package names)

  • toremove (Array<String>)

    the list of package to remove (package names)

Returns:

  • (Boolean)

    trueon success,false` on error



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'library/packages/src/modules/PackageSystem.rb', line 281

def DoInstallAndRemove(toinstall, toremove)
  return false if !PackageLock.Check

  # the DoInstallAndRemoveInt() call initializes the libzypp internally
  # but we need initialized libzypp earlier to change the solver settings
  EnsureTargetInit()
  EnsureSourceInit()

  # remember the current solver flags
  solver_flags = Pkg.GetSolverFlags

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

  ret = DoInstallAndRemoveInt(toinstall, toremove)

  # restore the original flags
  Pkg.SetSolverFlags(solver_flags)

  ret
end

#DoInstallAndRemoveInt(toinstall, toremove) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'library/packages/src/modules/PackageSystem.rb', line 151

def DoInstallAndRemoveInt(toinstall, toremove)
  toinstall = deep_copy(toinstall)
  toremove = deep_copy(toremove)
  Builtins.y2debug("toinstall: %1, toremove: %2", toinstall, toremove)
  return false if !PackageLock.Check

  EnsureTargetInit()
  EnsureSourceInit()
  ok = true

  Yast.import "Label"
  Yast.import "Popup"
  Yast.import "PackagesUI"

  # licenses: #35250
  licenses = Pkg.PkgGetLicensesToConfirm(toinstall)
  if Ops.greater_than(Builtins.size(licenses), 0)
    rt_licenses_l = Builtins.maplist(licenses) do |p, l|
      if Mode.commandline
        Builtins.sformat("%1\n%2", p, l)
      else
        Builtins.sformat("<p><b>%1</b></p>\n%2", p, l)
      end
    end

    accepted = false

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

      accepted = !CommandLine.YesNo
    else
      accepted = !Popup.AnyQuestionRichText(
        # popup heading, with rich text widget and Yes/No buttons
        _("Do you accept this license agreement?"),
        Builtins.mergestring(rt_licenses_l, "\n"),
        70,
        20,
        Label.YesButton,
        Label.NoButton,
        :focus_none
      )
    end

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

    if !accepted
      Builtins.y2milestone("License not accepted: %1", toinstall)
      @last_op_canceled = true
      return false
    end

    # mark licenses as confirmed
    Builtins.foreach(licenses) { |p, _l| Pkg.PkgMarkLicenseConfirmed(p) }
    @last_op_canceled = false
  end

  return false if !SelectPackages(toinstall, toremove)

  if !Pkg.PkgSolve(false)
    Builtins.y2error("Package solve failed: %1", Pkg.LastError)

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

    # disable repomanagement during installation
    repomgmt = !Mode.installation
    # start the package selector
    ret = PackagesUI.RunPackageSelector(
      "enable_repo_mgr" => repomgmt, "mode" => :summaryMode
    )

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

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

  # is a package or a patch selected for installation?
  any_to_install = Pkg.IsAnyResolvable(:package, :to_install) ||
    Pkg.IsAnyResolvable(:patch, :to_install)

  # [int successful, list failed, list remaining, list srcremaining, list update_messages]
  result = Pkg.PkgCommit(0)
  Builtins.y2debug("PkgCommit: %1", result)
  if result.nil? || Ops.get_list(result, 1, []) != []
    Builtins.y2error(
      "Package commit failed: %1",
      Ops.get_list(result, 1, [])
    )
    return false
  end

  PackagesUI.show_update_messages(result)

  Builtins.foreach(Ops.get_list(result, 2, [])) do |remaining|
    if ok == true && Builtins.contains(toinstall, remaining)
      Builtins.y2error("Package remain: %1", remaining)
      ok = false
    end
  end
  return false if ok != true

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

  # a package or a patch was installed, may be that there is a new yast agent
  if any_to_install
    # register the new agents
    SCR.RegisterNewAgents
  end

  true
end

#DoRemove(packages) ⇒ Object



123
124
125
126
# File 'library/packages/src/modules/PackageSystem.rb', line 123

def DoRemove(packages)
  packages = deep_copy(packages)
  DoInstallAndRemove([], packages)
end

#EnsureSourceInitObject

Ensure that Pkg:: calls working with the installation sources work



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'library/packages/src/modules/PackageSystem.rb', line 92

def EnsureSourceInit
  PackageLock.Check

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

  if !@target_initialized
    # make sure we have the RPM keys imported
    EnsureTargetInit()
  end

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

  nil
end

#EnsureTargetInitObject

Ensure that Pkg:: calls work. This may become superfluous.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'library/packages/src/modules/PackageSystem.rb', line 74

def EnsureTargetInit
  # do not initialize the target system in the first installation stage when
  # running in instsys, there is no RPM DB in the RAM disk image (bnc#742420)
  if Stage.initial && !Mode.live_installation
    Builtins.y2milestone(
      "Skipping target initialization in first stage installation"
    )
    return
  end

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

  nil
end

#InitRPMQueryBinaryObject



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'library/packages/src/modules/PackageSystem.rb', line 318

def InitRPMQueryBinary
  return if @_rpm_query_binary_initialized

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

  @_rpm_query_binary_initialized = true

  nil
end

#Installed(package) ⇒ Boolean

Is a package provided in the system? Is there any installed package providing 'package'?

Parameters:

  • package (String)

    name of the package to check if provided

Returns:

  • (Boolean)

    whether the package is provided in the system or not



339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'library/packages/src/modules/PackageSystem.rb', line 339

def Installed(package)
  # This is a most commonly called function and so it's
  # important that it's fast, especially in the common
  # case, where all dependencies are satisfied.
  # Unfortunately, initializing Pkg reads the RPM database...
  # so we must avoid it.
  # added --whatprovides due to bug #76181
  # Use Yast::Execute to prevent false positives (boo#1137992)
  rpm_command = ["/usr/bin/rpm", "-q", "--whatprovides", package]
  # We are not raising exceptions in case of return codes different than
  # 0 or 1. So do not plan to modify the current behavior.
  output, return_code = Yast::Execute.stdout.on_target!(rpm_command, allowed_exitstatus: 0..1)
  log.info "Query installed package with '#{rpm_command.join(" ")}' and result #{output}"

  # return Pkg::IsProvided (package);
  return_code == 0
end

#InstallKernel(kernel_modules) ⇒ Object



417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File 'library/packages/src/modules/PackageSystem.rb', line 417

def InstallKernel(kernel_modules)
  kernel_modules = deep_copy(kernel_modules)
  # this function may be responsible for the horrible startup time
  Builtins.y2milestone("want: %1", kernel_modules)
  if kernel_modules == []
    return true # nothing to do
  end

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

  if Ops.get_integer(output, "exit", -1) == 0
    packages = Builtins.splitstring(
      Ops.get_string(output, "stdout", ""),
      "\n"
    )
    packages = Builtins.filter(packages) { |pkg| pkg != "" }
    Builtins.y2milestone("Packages providing tag 'kernel': %1", packages)

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

    Builtins.y2milestone("Huh? Kernel is not installed??")
  else
    Builtins.y2warning("RPM query failed, quering the package manager...")
  end

  EnsureTargetInit()

  provides = Pkg.PkgQueryProvides("kernel")
  Builtins.y2milestone("provides: %1", provides)

  kernels = Builtins.filter(provides) do |l|
    Ops.get_symbol(l, 1, :NONE) == :BOTH ||
      Ops.get_symbol(l, 1, :NONE) == Ops.get_symbol(l, 2, :NONE)
  end

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

  kernel = Ops.get_string(kernels, [0, 0], "none")
  packs = [kernel]

  EnsureSourceInit() if !Pkg.IsProvided(kernel)

  # TODO: for 9.2, we always install all packages, but
  # we could only install those really needed (#44394)
  InstallAll(packs)
end

#mainObject



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'library/packages/src/modules/PackageSystem.rb', line 41

def main
  Yast.import "Pkg"
  textdomain "base"

  Yast.import "Kernel"
  Yast.import "Mode"
  Yast.import "PackageCallbacks"
  Yast.import "PackageLock"
  Yast.import "Report"
  Yast.import "Stage"
  Yast.import "CommandLine"
  Yast.import "Installation"

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

  # Has Pkg::TargetInit run?
  @target_initialized = false

  Yast.include self, "packages/common.rb"

  @_rpm_query_binary_initialized = false
  @_rpm_query_binary = "/usr/bin/rpm"
end

#PackageAvailable(package) ⇒ Object

Is a package available? Checks only package name, not list of provides.

Returns:

  • true if yes (nil = no package source available)



376
377
378
379
380
381
382
383
384
385
386
387
# File 'library/packages/src/modules/PackageSystem.rb', line 376

def PackageAvailable(package)
  EnsureTargetInit()
  EnsureSourceInit()

  # at least one enabled repository present?
  if Pkg.SourceGetCurrent(true).empty?
    # error no source initialized
    return nil
  end

  Pkg.PkgAvailable(package)
end

#PackageInstalled(package) ⇒ Object

Is a package installed? Checks only the package name in contrast to Installed() function.

Returns:

  • true if yes



359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'library/packages/src/modules/PackageSystem.rb', line 359

def PackageInstalled(package)
  InitRPMQueryBinary()

  # This is commonly called function and so it's
  # important that it's fast, especially in the common
  # case, where all dependencies are satisfied.
  0 ==
    Convert.to_integer(
      SCR.Execute(
        path(".target.bash"),
        "#{@_rpm_query_binary} #{package.shellescape}"
      )
    )
end

#SelectPackages(toinstall, toremove) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'library/packages/src/modules/PackageSystem.rb', line 128

def SelectPackages(toinstall, toremove)
  toinstall = deep_copy(toinstall)
  toremove = deep_copy(toremove)
  ok = true

  Builtins.foreach(toinstall) do |p|
    if ok == true && (Pkg.PkgInstall(p) != true)
      Builtins.y2error("Package %1 install failed: %2", p, Pkg.LastError)
      ok = false
    end
  end
  return false if ok != true

  Builtins.foreach(toremove) do |p|
    if ok == true && (Pkg.PkgDelete(p) != true)
      Builtins.y2error("Package %1 delete failed: %2", p, Pkg.LastError)
      ok = false
    end
  end

  ok
end