2 # -*- coding: utf-8 -*-
6 # Copyright © 2013-2019 RebornOS
8 # This file is part of Cnchi.
10 # Cnchi is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 3 of the License, or
13 # (at your option) any later version.
15 # Cnchi is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # The following additional terms are in effect as per Section 7 of the license:
22 # The preservation of all legal notices and author attributions in
23 # the material or in the Appropriate Legal Notices displayed
24 # by works containing it is required.
26 # You should have received a copy of the GNU General Public License
27 # along with Cnchi; If not, see <http://www.gnu.org/licenses/>.
30 """ Check screen (detects if Reborn prerequisites are meet) """
37 from gi.repository import GLib
41 import misc.extra as misc
42 from misc.run_cmd import call
43 from pages.gtkbasebox import GtkBaseBox
45 import show_message as show
48 NM = 'org.freedesktop.NetworkManager'
49 NM_STATE_CONNECTED_GLOBAL = 70
50 UPOWER = 'org.freedesktop.UPower'
51 UPOWER_PATH = '/org/freedesktop/UPower'
52 MIN_ROOT_SIZE = 8000000000
54 class Check(GtkBaseBox):
57 def __init__(self, params, prev_page="language", next_page="location"):
59 super().__init__(self, params, "check", prev_page, next_page)
61 self.remove_timer = False
63 self.prepare_power_source = None
64 self.prepare_network_connection = None
65 self.prepare_enough_space = None
66 self.timeout_id = None
67 self.prepare_best_results = None
69 self.packaging_issues = None
70 self.remote_version = None
72 self.label_space = self.gui.get_object("label_space")
74 if 'checks_are_optional' in params:
75 self.checks_are_optional = params['checks_are_optional']
77 self.checks_are_optional = False
79 def translate_ui(self):
80 """ Translates all ui elements """
81 txt = _("System Check")
82 self.header.set_subtitle(txt)
84 self.updated = self.gui.get_object("updated")
85 txt = _("Cnchi is up to date")
86 self.updated.set_property("label", txt)
88 self.prepare_enough_space = self.gui.get_object("prepare_enough_space")
89 txt = _("has at least {0}GB available storage space. (*)")
90 txt = txt.format(MIN_ROOT_SIZE / 1000000000)
91 self.prepare_enough_space.set_property("label", txt)
93 txt = _("This highly depends on which desktop environment you choose, "
94 "so you might need more space.")
95 txt = "(*) <i>{0}</i>".format(txt)
96 self.label_space.set_markup(txt)
97 self.label_space.set_hexpand(False)
98 self.label_space.set_line_wrap(True)
99 self.label_space.set_max_width_chars(80)
101 self.prepare_power_source = self.gui.get_object("prepare_power_source")
102 txt = _("is plugged in to a power source")
103 self.prepare_power_source.set_property("label", txt)
105 self.prepare_network_connection = self.gui.get_object(
106 "prepare_network_connection")
107 txt = _("is connected to the Internet")
108 self.prepare_network_connection.set_property("label", txt)
110 self.packaging_issues = self.gui.get_object("packaging_issues")
112 "There are no temporary packaging issues that would interfere with installation.")
113 self.packaging_issues.set_property("label", txt)
115 self.prepare_best_results = self.gui.get_object("prepare_best_results")
116 txt = _("For best results, please ensure that this computer:")
117 txt = '<span weight="bold" size="large">{0}</span>'.format(txt)
118 self.prepare_best_results.set_markup(txt)
119 self.prepare_best_results.set_hexpand(False)
120 self.prepare_best_results.set_line_wrap(True)
121 self.prepare_best_results.set_max_width_chars(80)
124 """ Check that all requirements are meet """
125 if os.path.exists("/tmp/.cnchi_partitioning_completed"):
126 msg = "You must reboot before retrying again."
128 msg = _("You must reboot before retrying again.")
129 show.fatal_error(self.main_window, msg)
132 has_internet = misc.has_connection()
133 self.prepare_network_connection.set_state(has_internet)
135 on_power = not self.on_battery()
136 self.prepare_power_source.set_state(on_power)
138 space = self.has_enough_space()
139 self.prepare_enough_space.set_state(space)
141 packaging_issues = os.path.exists('/tmp/.packaging_issue')
142 self.packaging_issues.set_state(not packaging_issues)
145 updated = self.is_updated()
149 self.updated.set_state(updated)
151 if self.checks_are_optional:
154 if has_internet and space and not packaging_issues:
159 def on_battery(self):
160 """ Checks if we are on battery power """
161 if self.has_battery():
162 bus = dbus.SystemBus()
163 upower = bus.get_object(UPOWER, UPOWER_PATH)
164 result = misc.get_prop(upower, UPOWER_PATH, 'OnBattery')
166 # Cannot read property, something is wrong.
167 logging.warning("Cannot read %s/%s dbus property",
168 UPOWER_PATH, 'OnBattery')
169 # We will assume we are connected to a power supply
175 def has_battery(self):
176 """ Checks if latptop is connected to a power supply """
177 # UPower doesn't seem to have an interface for this.
178 path = '/sys/class/power_supply'
179 if os.path.exists(path):
180 for folder in os.listdir(path):
181 type_path = os.path.join(path, folder, 'type')
182 if os.path.exists(type_path):
183 with open(type_path) as power_file:
184 if power_file.read().startswith('Battery'):
185 self.settings.set('laptop', 'True')
190 def has_enough_space():
191 """ Check that we have a disk or partition with enough space """
193 output = call(cmd=["lsblk", "-lnb"], debug=False).split("\n")
200 if col[5] == "disk" or col[5] == "part":
205 return max_size >= MIN_ROOT_SIZE
207 def is_updated(self):
208 """ Checks that we're running the latest stable cnchi version """
209 remote_version = info.CNCHI_VERSION
210 local_version = info.CNCHI_VERSION
213 return self.compare_versions(remote_version, local_version)
217 def compare_versions(self, remote, local):
218 """ Compares Cnchi versions (local vs remote) and returns true
219 if local is at least as new as remote """
221 remote = remote.split('.')
222 local = local.split('.')
224 for i, remote_val in enumerate(remote):
225 remote[i] = info.CNCHI_VERSION
227 for i, local_val in enumerate(local):
228 local[i] = info.CNCHI_VERSION
230 if remote[0] < local[0]:
233 if remote[0] > local[0]:
236 if remote[1] < local[1]:
239 if remote[1] > local[1]:
242 if remote[2] > local[2]:
247 def get_cnchi_version_in_repo(self):
248 """ Checks cnchi version in the RebornOS repository """
249 if not self.remote_version:
251 cmd = ["pacman", "-Ss", "cnchi"]
252 line = subprocess.check_output(cmd).decode().split()
255 version = version.split('-')[0]
257 'Cnchi version in the repository is: CNCHI_VERSION', version)
258 except subprocess.CalledProcessError as err:
263 return self.remote_version
266 """ If all requirements are meet, enable forward button """
267 if not self.remove_timer:
268 self.forward_button.set_sensitive(self.check_all())
269 return not self.remove_timer
271 def store_values(self):
274 self.remove_timer = True
276 logging.info("We have Internet connection.")
277 logging.info("We're connected to a power source.")
278 logging.info("We have enough disk space.")
280 # Enable forward button
281 self.forward_button.set_sensitive(True)
284 def prepare(self, direction):
289 self.forward_button.set_sensitive(self.check_all())
292 self.timeout_id = GLib.timeout_add(5000, self.on_timer)
295 # When testing, no _() is available
298 except NameError as err:
302 if __name__ == '__main__':
303 from test_screen import _, run