d-installer 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +29 -0
- data/Gemfile.lock +75 -0
- data/bin/d-installer +74 -0
- data/etc/d-installer.yaml +284 -0
- data/lib/dinstaller/can_ask_question.rb +48 -0
- data/lib/dinstaller/cmdline_args.rb +80 -0
- data/lib/dinstaller/cockpit_manager.rb +176 -0
- data/lib/dinstaller/config.rb +128 -0
- data/lib/dinstaller/config_reader.rb +164 -0
- data/lib/dinstaller/dbus/base_object.rb +58 -0
- data/lib/dinstaller/dbus/clients/base.rb +71 -0
- data/lib/dinstaller/dbus/clients/language.rb +86 -0
- data/lib/dinstaller/dbus/clients/manager.rb +76 -0
- data/lib/dinstaller/dbus/clients/software.rb +185 -0
- data/lib/dinstaller/dbus/clients/users.rb +112 -0
- data/lib/dinstaller/dbus/clients/with_progress.rb +56 -0
- data/lib/dinstaller/dbus/clients/with_service_status.rb +75 -0
- data/lib/dinstaller/dbus/clients.rb +34 -0
- data/lib/dinstaller/dbus/interfaces/progress.rb +113 -0
- data/lib/dinstaller/dbus/interfaces/service_status.rb +89 -0
- data/lib/dinstaller/dbus/language.rb +93 -0
- data/lib/dinstaller/dbus/language_service.rb +92 -0
- data/lib/dinstaller/dbus/manager.rb +147 -0
- data/lib/dinstaller/dbus/manager_service.rb +132 -0
- data/lib/dinstaller/dbus/question.rb +176 -0
- data/lib/dinstaller/dbus/questions.rb +124 -0
- data/lib/dinstaller/dbus/service_runner.rb +97 -0
- data/lib/dinstaller/dbus/service_status.rb +87 -0
- data/lib/dinstaller/dbus/software/manager.rb +131 -0
- data/lib/dinstaller/dbus/software/proposal.rb +82 -0
- data/lib/dinstaller/dbus/software.rb +31 -0
- data/lib/dinstaller/dbus/software_service.rb +86 -0
- data/lib/dinstaller/dbus/storage/proposal.rb +170 -0
- data/lib/dinstaller/dbus/storage.rb +30 -0
- data/lib/dinstaller/dbus/users.rb +132 -0
- data/lib/dinstaller/dbus/users_service.rb +92 -0
- data/lib/dinstaller/dbus/with_service_status.rb +48 -0
- data/lib/dinstaller/dbus/y2dir/manager/modules/Package.rb +51 -0
- data/lib/dinstaller/dbus/y2dir/manager/modules/PackagesProposal.rb +62 -0
- data/lib/dinstaller/dbus/y2dir/modules/Autologin.rb +214 -0
- data/lib/dinstaller/dbus/y2dir/software/modules/SpaceCalculation.rb +44 -0
- data/lib/dinstaller/dbus.rb +11 -0
- data/lib/dinstaller/errors.rb +28 -0
- data/lib/dinstaller/installation_phase.rb +106 -0
- data/lib/dinstaller/language.rb +73 -0
- data/lib/dinstaller/luks_activation_question.rb +92 -0
- data/lib/dinstaller/manager.rb +261 -0
- data/lib/dinstaller/network.rb +53 -0
- data/lib/dinstaller/package_callbacks.rb +69 -0
- data/lib/dinstaller/progress.rb +149 -0
- data/lib/dinstaller/question.rb +103 -0
- data/lib/dinstaller/questions_manager.rb +145 -0
- data/lib/dinstaller/security.rb +96 -0
- data/lib/dinstaller/service_status_recorder.rb +58 -0
- data/lib/dinstaller/software.rb +232 -0
- data/lib/dinstaller/storage/actions.rb +90 -0
- data/lib/dinstaller/storage/callbacks/activate.rb +93 -0
- data/lib/dinstaller/storage/callbacks/activate_luks.rb +93 -0
- data/lib/dinstaller/storage/callbacks/activate_multipath.rb +77 -0
- data/lib/dinstaller/storage/callbacks.rb +30 -0
- data/lib/dinstaller/storage/manager.rb +104 -0
- data/lib/dinstaller/storage/proposal.rb +197 -0
- data/lib/dinstaller/storage.rb +30 -0
- data/lib/dinstaller/users.rb +156 -0
- data/lib/dinstaller/with_progress.rb +63 -0
- data/lib/dinstaller.rb +5 -0
- data/share/dbus.conf +38 -0
- data/share/dbus.service +5 -0
- data/share/systemd.service +14 -0
- metadata +295 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2022] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
module DInstaller
|
23
|
+
# Manager for questions
|
24
|
+
#
|
25
|
+
# Allows to configure callbacks with the actions to perform when adding, deleting or waiting for
|
26
|
+
# questions.
|
27
|
+
class QuestionsManager
|
28
|
+
# @return [Array<Question>]
|
29
|
+
attr_reader :questions
|
30
|
+
|
31
|
+
# Constructor
|
32
|
+
#
|
33
|
+
# @params logger [Logger]
|
34
|
+
def initialize(logger)
|
35
|
+
@logger = logger
|
36
|
+
@questions = []
|
37
|
+
@on_add_callbacks = []
|
38
|
+
@on_delete_callbacks = []
|
39
|
+
@on_wait_callbacks = []
|
40
|
+
end
|
41
|
+
|
42
|
+
# Adds a question
|
43
|
+
#
|
44
|
+
# Callbacks are called after adding the question, see {#on_add}.
|
45
|
+
#
|
46
|
+
# @yieldparam question [Question] added question
|
47
|
+
#
|
48
|
+
# @param question [Question]
|
49
|
+
# @return [Boolean] whether the question was added
|
50
|
+
def add(question)
|
51
|
+
return false if include?(question)
|
52
|
+
|
53
|
+
questions << question
|
54
|
+
on_add_callbacks.each { |c| c.call(question) }
|
55
|
+
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
# Deletes the given question
|
60
|
+
#
|
61
|
+
# Callbacks are called after deleting the question, see {#on_delete}.
|
62
|
+
#
|
63
|
+
# @yieldparam question [Question] deleted question
|
64
|
+
#
|
65
|
+
# @param question [Question]
|
66
|
+
# @return [Boolean] whether the question was deleted
|
67
|
+
def delete(question)
|
68
|
+
return false unless include?(question)
|
69
|
+
|
70
|
+
questions.delete(question)
|
71
|
+
on_delete_callbacks.each { |c| c.call(question) }
|
72
|
+
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
# Waits until all questions are answered
|
77
|
+
#
|
78
|
+
# Callbacks are periodically called while waiting, see {#on_wait}.
|
79
|
+
def wait
|
80
|
+
logger.info "Waiting for questions to be answered"
|
81
|
+
|
82
|
+
loop do
|
83
|
+
on_wait_callbacks.each(&:call)
|
84
|
+
sleep(0.1)
|
85
|
+
break if questions_answered?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Registers a callback to be called when a new question is added
|
90
|
+
#
|
91
|
+
# @param block [Proc]
|
92
|
+
def on_add(&block)
|
93
|
+
on_add_callbacks << block
|
94
|
+
end
|
95
|
+
|
96
|
+
# Registers a callback to be called when a question is deleted
|
97
|
+
#
|
98
|
+
# @param block [Proc]
|
99
|
+
def on_delete(&block)
|
100
|
+
on_delete_callbacks << block
|
101
|
+
end
|
102
|
+
|
103
|
+
# Registers a callback to be called while waiting for questions be answered
|
104
|
+
#
|
105
|
+
# @param block [Proc]
|
106
|
+
def on_wait(&block)
|
107
|
+
on_wait_callbacks << block
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
# @return [Logger]
|
113
|
+
attr_reader :logger
|
114
|
+
|
115
|
+
# Callbacks to be called when the a new question is added
|
116
|
+
#
|
117
|
+
# @return [Array<Proc>]
|
118
|
+
attr_reader :on_add_callbacks
|
119
|
+
|
120
|
+
# Callbacks to be called when the a question is deleted
|
121
|
+
#
|
122
|
+
# @return [Array<Proc>]
|
123
|
+
attr_reader :on_delete_callbacks
|
124
|
+
|
125
|
+
# Callbacks to be called when waiting for answers
|
126
|
+
#
|
127
|
+
# @return [Array<Proc>]
|
128
|
+
attr_reader :on_wait_callbacks
|
129
|
+
|
130
|
+
# Whether a question with the same id as the given question is already in the list of questions
|
131
|
+
#
|
132
|
+
# @param question [Question]
|
133
|
+
# @return [Boolean]
|
134
|
+
def include?(question)
|
135
|
+
questions.any? { |q| q.id == question.id }
|
136
|
+
end
|
137
|
+
|
138
|
+
# Whether all questions are already answered
|
139
|
+
#
|
140
|
+
# @return [Boolean]
|
141
|
+
def questions_answered?
|
142
|
+
questions.all?(&:answered?)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2022] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
require "yast"
|
23
|
+
require "y2security/lsm"
|
24
|
+
require "yast2/execute"
|
25
|
+
|
26
|
+
require "dinstaller/config"
|
27
|
+
|
28
|
+
# FIXME: monkey patching of security config to not read control.xml and
|
29
|
+
# instead use DIinstaller::Config
|
30
|
+
# TODO: add ability to set product features in LSM::Base
|
31
|
+
module Y2Security
|
32
|
+
module LSM
|
33
|
+
# modified LSM Base class to use dinstaller config
|
34
|
+
class Base
|
35
|
+
def product_feature_settings
|
36
|
+
return @product_feature_settings unless @product_feature_settings.nil?
|
37
|
+
|
38
|
+
value = ::DInstaller::Config.current.data["security"]["available_lsms"][id.to_s]
|
39
|
+
res = if value
|
40
|
+
{
|
41
|
+
selectable: true,
|
42
|
+
configurable: true,
|
43
|
+
patterns: (value["patterns"] || []).join(" "),
|
44
|
+
mode: value["policy"]
|
45
|
+
}
|
46
|
+
else
|
47
|
+
{
|
48
|
+
selectable: false,
|
49
|
+
configurable: false,
|
50
|
+
patterns: "",
|
51
|
+
mode: nil
|
52
|
+
}
|
53
|
+
end
|
54
|
+
@product_feature_settings = res
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module DInstaller
|
61
|
+
# Backend class between dbus service and yast code
|
62
|
+
class Security
|
63
|
+
# @return [Logger]
|
64
|
+
attr_reader :logger
|
65
|
+
|
66
|
+
def initialize(logger, config)
|
67
|
+
@config = config
|
68
|
+
@logger = logger
|
69
|
+
end
|
70
|
+
|
71
|
+
def write
|
72
|
+
lsm_config.save
|
73
|
+
end
|
74
|
+
|
75
|
+
def probe
|
76
|
+
selected_lsm = config.data["security"]["lsm"]
|
77
|
+
lsm_config.select(selected_lsm)
|
78
|
+
|
79
|
+
patterns = if selected_lsm.nil?
|
80
|
+
[]
|
81
|
+
else
|
82
|
+
lsm_data = config.data["security"]["available_lsms"][selected_lsm]
|
83
|
+
lsm_data["patterns"]
|
84
|
+
end
|
85
|
+
Yast::PackagesProposal.SetResolvables("LSM", :pattern, patterns)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
attr_reader :config
|
91
|
+
|
92
|
+
def lsm_config
|
93
|
+
Y2Security::LSM::Config.instance
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2022] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
require "dinstaller/dbus/service_status"
|
23
|
+
|
24
|
+
module DInstaller
|
25
|
+
# Allows to record the status of services and to register callbacks to be called when a service
|
26
|
+
# status changes its value
|
27
|
+
class ServiceStatusRecorder
|
28
|
+
def initialize
|
29
|
+
@statuses = {}
|
30
|
+
@on_service_status_change_callbacks = []
|
31
|
+
end
|
32
|
+
|
33
|
+
# Saves the status of the given service and runs the callbacks if the status has changed
|
34
|
+
#
|
35
|
+
# @param service_name [String]
|
36
|
+
# @param status [String] see {ServiceStatus}
|
37
|
+
def save(service_name, status)
|
38
|
+
return if @statuses[service_name] == status
|
39
|
+
|
40
|
+
@statuses[service_name] = status
|
41
|
+
@on_service_status_change_callbacks.each(&:call)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Name of services with busy status
|
45
|
+
#
|
46
|
+
# @return [Array<String>]
|
47
|
+
def busy_services
|
48
|
+
@statuses.select { |_service, status| status == DBus::ServiceStatus::BUSY }.keys
|
49
|
+
end
|
50
|
+
|
51
|
+
# Registers callbacks to be called when saving a new status
|
52
|
+
#
|
53
|
+
# @param block [Proc]
|
54
|
+
def on_service_status_change(&block)
|
55
|
+
@on_service_status_change_callbacks << block
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2021] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
require "yast"
|
23
|
+
require "fileutils"
|
24
|
+
require "dinstaller/package_callbacks"
|
25
|
+
require "dinstaller/config"
|
26
|
+
require "dinstaller/with_progress"
|
27
|
+
require "y2packager/product"
|
28
|
+
|
29
|
+
Yast.import "PackageInstallation"
|
30
|
+
Yast.import "Pkg"
|
31
|
+
Yast.import "Stage"
|
32
|
+
|
33
|
+
# YaST specific code lives under this namespace
|
34
|
+
module DInstaller
|
35
|
+
# This class is responsible for software handling
|
36
|
+
class Software
|
37
|
+
include WithProgress
|
38
|
+
|
39
|
+
GPG_KEYS_GLOB = "/usr/lib/rpm/gnupg/keys/gpg-*"
|
40
|
+
private_constant :GPG_KEYS_GLOB
|
41
|
+
|
42
|
+
attr_reader :product
|
43
|
+
|
44
|
+
DEFAULT_LANGUAGES = ["en_US"].freeze
|
45
|
+
private_constant :DEFAULT_LANGUAGES
|
46
|
+
|
47
|
+
attr_accessor :languages
|
48
|
+
|
49
|
+
# FIXME: what about defining a Product class?
|
50
|
+
# @return [Array<Array<String,Hash>>] An array containing the product ID and
|
51
|
+
# additional information in a hash
|
52
|
+
attr_reader :products
|
53
|
+
|
54
|
+
def initialize(config, logger)
|
55
|
+
@config = config
|
56
|
+
@logger = logger
|
57
|
+
@languages = DEFAULT_LANGUAGES
|
58
|
+
@products = @config.data["products"]
|
59
|
+
if @config.multi_product?
|
60
|
+
@product = nil
|
61
|
+
else
|
62
|
+
@product = @products.keys.first # use the available product as default
|
63
|
+
@config.pick_product(@product)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def select_product(name)
|
68
|
+
return if name == @product
|
69
|
+
raise ArgumentError unless @products[name]
|
70
|
+
|
71
|
+
@config.pick_product(name)
|
72
|
+
@product = name
|
73
|
+
end
|
74
|
+
|
75
|
+
def probe
|
76
|
+
logger.info "Probing software"
|
77
|
+
|
78
|
+
store_original_repos
|
79
|
+
Yast::Pkg.SetSolverFlags("ignoreAlreadyRecommended" => false, "onlyRequires" => true)
|
80
|
+
|
81
|
+
# as we use liveDVD with normal like ENV, lets temporary switch to normal to use its repos
|
82
|
+
Yast::Stage.Set("normal")
|
83
|
+
|
84
|
+
start_progress(3)
|
85
|
+
progress.step("Initialize target repositories") { initialize_target_repos }
|
86
|
+
progress.step("Initialize sources") { add_base_repo }
|
87
|
+
progress.step("Making the initial proposal") do
|
88
|
+
proposal = Yast::Packages.Proposal(force_reset = true, reinit = false, _simple = true)
|
89
|
+
logger.info "proposal #{proposal["raw_proposal"]}"
|
90
|
+
end
|
91
|
+
|
92
|
+
Yast::Stage.Set("initial")
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize_target_repos
|
96
|
+
Yast::Pkg.TargetInitialize("/")
|
97
|
+
import_gpg_keys
|
98
|
+
end
|
99
|
+
|
100
|
+
def propose
|
101
|
+
Yast::Pkg.TargetFinish # ensure that previous target is closed
|
102
|
+
Yast::Pkg.TargetInitialize(Yast::Installation.destdir)
|
103
|
+
Yast::Pkg.TargetLoad
|
104
|
+
Yast::Pkg.SetAdditionalLocales(languages)
|
105
|
+
select_base_product(@config.data["software"]["base_product"])
|
106
|
+
|
107
|
+
add_resolvables
|
108
|
+
proposal = Yast::Packages.Proposal(force_reset = false, reinit = false, _simple = true)
|
109
|
+
logger.info "proposal #{proposal["raw_proposal"]}"
|
110
|
+
|
111
|
+
solve_dependencies
|
112
|
+
|
113
|
+
# do not return proposal hash, so intentional nil here
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def install
|
118
|
+
start_progress(count_packages)
|
119
|
+
PackageCallbacks.setup(count_packages, progress)
|
120
|
+
|
121
|
+
# TODO: error handling
|
122
|
+
commit_result = Yast::PackageInstallation.Commit({})
|
123
|
+
|
124
|
+
if commit_result.nil? || commit_result.empty?
|
125
|
+
logger.error("Commit failed")
|
126
|
+
raise Yast::Pkg.LastError
|
127
|
+
end
|
128
|
+
|
129
|
+
logger.info "Commit result #{commit_result}"
|
130
|
+
end
|
131
|
+
|
132
|
+
# Writes the repositories information to the installed system
|
133
|
+
def finish
|
134
|
+
start_progress(2)
|
135
|
+
progress.step("Writing repositories to the target system") do
|
136
|
+
Yast::Pkg.SourceSaveAll
|
137
|
+
Yast::Pkg.TargetFinish
|
138
|
+
Yast::Pkg.SourceCacheCopyTo(Yast::Installation.destdir)
|
139
|
+
end
|
140
|
+
progress.step("Restoring original repositories") { restore_original_repos }
|
141
|
+
end
|
142
|
+
|
143
|
+
# Determine whether the given tag is provided by the selected packages
|
144
|
+
#
|
145
|
+
# @param tag [String] Tag to search for (package names, requires/provides, or file
|
146
|
+
# names)
|
147
|
+
# @return [Boolean] true if it is provided; false otherwise
|
148
|
+
def provision_selected?(tag)
|
149
|
+
Yast::Pkg.IsSelected(tag) || Yast::Pkg.IsProvided(tag)
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
# adds resolvables from yaml config for given product
|
155
|
+
def add_resolvables
|
156
|
+
mandatory_patterns = @config.data["software"]["mandatory_patterns"] || []
|
157
|
+
Yast::PackagesProposal.SetResolvables("d-installer", :pattern, mandatory_patterns)
|
158
|
+
|
159
|
+
optional_patterns = @config.data["software"]["optional_patterns"] || []
|
160
|
+
Yast::PackagesProposal.SetResolvables("d-installer", :pattern, optional_patterns,
|
161
|
+
optional: true)
|
162
|
+
end
|
163
|
+
|
164
|
+
# call solver to satisfy dependency or log error
|
165
|
+
def solve_dependencies
|
166
|
+
res = Yast::Pkg.PkgSolve(unused = true)
|
167
|
+
logger.info "solver run #{res.inspect}"
|
168
|
+
|
169
|
+
return if res
|
170
|
+
|
171
|
+
logger.error "Solver failed: #{Yast::Pkg.LastError}"
|
172
|
+
logger.error "Details: #{Yast::Pkg.LastErrorDetails}"
|
173
|
+
logger.error "Solving issues: #{Yast::Pkg.PkgSolveErrors}"
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [Logger]
|
177
|
+
attr_reader :logger
|
178
|
+
|
179
|
+
def count_packages
|
180
|
+
Yast::Pkg.PkgMediaCount.reduce(0) { |sum, res| sum + res.reduce(0, :+) }
|
181
|
+
end
|
182
|
+
|
183
|
+
def import_gpg_keys
|
184
|
+
gpg_keys = Dir.glob(GPG_KEYS_GLOB).map(&:to_s)
|
185
|
+
logger.info "Importing GPG keys: #{gpg_keys}"
|
186
|
+
gpg_keys.each do |path|
|
187
|
+
Yast::Pkg.ImportGPGKey(path, true)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def add_base_repo
|
192
|
+
@config.data["software"]["installation_repositories"].each do |repo|
|
193
|
+
Yast::Pkg.SourceCreate(repo, "/") # TODO: having that dir also in config?
|
194
|
+
end
|
195
|
+
|
196
|
+
Yast::Pkg.SourceSaveAll
|
197
|
+
end
|
198
|
+
|
199
|
+
def select_base_product(name)
|
200
|
+
base_product = Y2Packager::Product.available_base_products.find do |product|
|
201
|
+
product.name == name
|
202
|
+
end
|
203
|
+
logger.info "Base product to select: #{base_product&.name}"
|
204
|
+
base_product&.select
|
205
|
+
end
|
206
|
+
|
207
|
+
REPOS_BACKUP = "/etc/zypp/repos.d.dinstaller.backup"
|
208
|
+
private_constant :REPOS_BACKUP
|
209
|
+
|
210
|
+
REPOS_DIR = "/etc/zypp/repos.d"
|
211
|
+
private_constant :REPOS_DIR
|
212
|
+
|
213
|
+
# ensure that repos backup is there and repos.d is empty
|
214
|
+
def store_original_repos
|
215
|
+
# Backup was already created, so just remove all repos
|
216
|
+
if File.directory?(REPOS_BACKUP)
|
217
|
+
logger.info "removing #{REPOS_DIR}"
|
218
|
+
FileUtils.rm_rf(REPOS_DIR)
|
219
|
+
else # move repos to backup
|
220
|
+
logger.info "moving #{REPOS_DIR} to #{REPOS_BACKUP}"
|
221
|
+
FileUtils.mv(REPOS_DIR, REPOS_BACKUP)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def restore_original_repos
|
226
|
+
logger.info "removing #{REPOS_DIR}"
|
227
|
+
FileUtils.rm_rf(REPOS_DIR)
|
228
|
+
logger.info "moving #{REPOS_BACKUP} to #{REPOS_DIR}"
|
229
|
+
FileUtils.mv(REPOS_BACKUP, REPOS_DIR)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2022] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
require "y2storage/storage_manager"
|
23
|
+
|
24
|
+
module DInstaller
|
25
|
+
module Storage
|
26
|
+
# Backend class to get the list of actions over the storage devices
|
27
|
+
class Actions
|
28
|
+
# @param logger [Logger]
|
29
|
+
def initialize(logger)
|
30
|
+
@logger = logger
|
31
|
+
end
|
32
|
+
|
33
|
+
# All actions properly sorted
|
34
|
+
#
|
35
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
36
|
+
def all
|
37
|
+
main_actions + subvolume_actions
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @param [Logger]
|
43
|
+
attr_reader :logger
|
44
|
+
|
45
|
+
# Sorted main actions (everything except subvolume actions)
|
46
|
+
#
|
47
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
48
|
+
def main_actions
|
49
|
+
actions = self.actions.reject { |a| subvol_action?(a) }
|
50
|
+
sort_actions(actions)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sorted subvolume actions
|
54
|
+
#
|
55
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
56
|
+
def subvolume_actions
|
57
|
+
actions = self.actions.select { |a| subvol_action?(a) }
|
58
|
+
sort_actions(actions)
|
59
|
+
end
|
60
|
+
|
61
|
+
# All actions, without sorting
|
62
|
+
#
|
63
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
64
|
+
def actions
|
65
|
+
actiongraph = Y2Storage::StorageManager.instance.staging.actiongraph
|
66
|
+
|
67
|
+
return [] unless actiongraph
|
68
|
+
|
69
|
+
actiongraph.compound_actions
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sorts actions, placing destructive actions at the end
|
73
|
+
#
|
74
|
+
# @param actions [Array<Y2Storage::CompoundAction>]
|
75
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
76
|
+
def sort_actions(actions)
|
77
|
+
delete, other = actions.partition(&:delete?)
|
78
|
+
delete.concat(other)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Whether the action acts over a Btrfs subvolume
|
82
|
+
#
|
83
|
+
# @param action [Y2Storage::CompoundAction]
|
84
|
+
# @return [Boolean]
|
85
|
+
def subvol_action?(action)
|
86
|
+
action.device_is?(:btrfs_subvolume)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|