1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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
|
from PyQt6.QtCore import QProcess, Qt
from PyQt6.QtWidgets import QHBoxLayout, QInputDialog, QLineEdit, QMessageBox, QVBoxLayout, QWidget
from raveos_center import muveletek, snapshotok
from raveos_center.elemek import Kartya, cimke, gomb
from raveos_center.folyamat import FolyamatAblak
from raveos_center.hatter import ervenytelenit, gyorsitott, tarolt
AZON = "snapshotok"
CIM = "Snapshotok"
class SnapshotSor(QWidget):
def __init__(self, elem, utolso, visszaallit, torol):
super().__init__()
self.setObjectName("appsor")
self.setProperty("utolso", utolso)
self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
sor = QHBoxLayout(self)
sor.setContentsMargins(16, 12, 16, 12)
sor.setSpacing(16)
datum = cimke(elem["datum"], "mono")
datum.setFixedWidth(150)
sor.addWidget(datum)
szovegek = QVBoxLayout()
szovegek.setSpacing(2)
szovegek.addWidget(cimke(elem["leiras"] or "-", None, True))
szovegek.addWidget(cimke(f"#{elem['szam']} {elem['tipus_nev']}", "monohalvany"))
sor.addLayout(szovegek, 1)
helper = muveletek.helper_elerheto()
vissza = gomb("Visszaállítás", kicsi=True)
vissza.setEnabled(helper)
vissza.clicked.connect(lambda: visszaallit(elem))
sor.addWidget(vissza, 0, Qt.AlignmentFlag.AlignVCenter)
torles = gomb("Törlés", kicsi=True)
torles.setEnabled(helper)
torles.clicked.connect(lambda: torol(elem))
sor.addWidget(torles, 0, Qt.AlignmentFlag.AlignVCenter)
class Snapshotok(QWidget):
def __init__(self, kozpont):
super().__init__()
self.kozpont = kozpont
self.adat = None
doboz = QVBoxLayout(self)
doboz.setContentsMargins(0, 20, 0, 0)
doboz.setSpacing(16)
fej = QHBoxLayout()
fej.setSpacing(16)
self.leiras = cimke(
"A btrfs snapshot a rendszer egy pillanatnyi állapota. Ha egy frissítés után gond van, egy korábbi "
"állapotra vissza tudsz állni. A saját fájljaidat (/home) a visszaállítás nem érinti.",
"masodlagos",
True,
)
fej.addWidget(self.leiras, 1)
self.uj_gomb = gomb("Új snapshot", fo=True)
self.uj_gomb.clicked.connect(self.uj)
fej.addWidget(self.uj_gomb, 0, Qt.AlignmentFlag.AlignTop)
doboz.addLayout(fej)
self.info = cimke("", "monozold", True)
self.info.hide()
doboz.addWidget(self.info)
self.figyelem = cimke("", "figyelem", True)
self.figyelem.hide()
doboz.addWidget(self.figyelem)
self.beallitas_gomb = gomb("Snapper beállítása", fo=True)
self.beallitas_gomb.clicked.connect(self._beallitas)
self.beallitas_gomb.hide()
gs = QHBoxLayout()
gs.addWidget(self.beallitas_gomb)
gs.addStretch(1)
doboz.addLayout(gs)
self.kartya = Kartya(terkoz=0, margo=0)
doboz.addWidget(self.kartya)
doboz.addStretch(1)
def megjelenik(self, *args):
if tarolt("snapshotok") is None:
self.uj_gomb.setEnabled(False)
self._info("Betöltés...")
gyorsitott("snapshotok", snapshotok.allapot, kesz=self._kesz, hiba=self._hiba, kor=30)
if args and args[0] == "uj":
self.uj()
def frissit(self):
ervenytelenit("snapshotok", "snapshot")
gyorsitott("snapshotok", snapshotok.allapot, kesz=self._kesz, hiba=self._hiba)
def _hiba(self, uzenet):
self._figyelmeztet(f"A snapshotok nem olvashatók: {uzenet}")
def _info(self, szoveg):
self.info.setText(szoveg)
self.info.setVisible(bool(szoveg))
def _figyelmeztet(self, szoveg):
self.figyelem.setText(szoveg)
self.figyelem.setVisible(bool(szoveg))
def _kesz(self, adat):
self.adat = adat
helper = muveletek.helper_elerheto()
kesz = adat["fajlrendszer"] == "btrfs" and adat["snapper"]
self.uj_gomb.setVisible(kesz)
self.uj_gomb.setEnabled(kesz and helper)
self.beallitas_gomb.setVisible(snapshotok.snapper_telepitheto(adat))
self.beallitas_gomb.setEnabled(helper)
self.kartya.setVisible(kesz)
if adat["fajlrendszer"] != "btrfs":
self._info("")
self._figyelmeztet(
f"Snapshothoz btrfs fájlrendszer kell. Ez a gép {adat['fajlrendszer'] or 'ismeretlen'} fájlrendszert "
"használ, ezért itt nem érhető el. A RaveOS telepítésekor a lemez partícionálásánál ext4 és btrfs "
"közül lehet választani: ha snapshotot szeretnél, a btrfs-t válaszd."
)
return
if not adat["snapper"]:
self._info("")
if snapshotok.snapper_telepitheto(adat):
self._figyelmeztet(
"A gép btrfs-t használ, de a snapper még nincs beállítva. Egy kattintással beállítható: "
"utána minden csomagművelet előtt automatikusan snapshot készül."
)
else:
self._figyelmeztet(
"A gép btrfs-t használ, de az alvolumen-elrendezése eltér a RaveOS-étól (@ és @snapshots), "
"ezért a snapper itt nem állítható be automatikusan."
)
return
if adat["alvolumen"] != "/@":
self._figyelmeztet("A rendszer most nem a fő alvolumenről (@) fut, ezért visszaállítás nem indítható.")
elif adat["hiba"]:
self._figyelmeztet(adat["hiba"])
elif not helper:
self._figyelmeztet("A RaveOS Center rendszerhelpere nincs telepítve, ezért snapshot nem kezelhető.")
else:
self._figyelmeztet("")
self._info(
("Automatikus snapshot minden csomagművelet előtt és után (snap-pac). " if adat["snap_pac"] else "")
+ f"{len(adat['lista'])} snapshot, a régiek automatikusan törlődnek."
)
self._lista(adat)
def _lista(self, adat):
elrendezes = self.kartya.elrendezes
while elrendezes.count():
w = elrendezes.takeAt(0).widget()
if w:
w.deleteLater()
if not adat["lista"]:
ures = cimke("Még nincs snapshot.", "halvany")
ures.setContentsMargins(16, 16, 16, 16)
elrendezes.addWidget(ures)
return
for i, elem in enumerate(adat["lista"]):
elrendezes.addWidget(SnapshotSor(elem, i == len(adat["lista"]) - 1, self.visszaallit, self.torol))
def _futtat(self, cim, lepes, siker):
ablak = FolyamatAblak(self, cim, [lepes], siker)
ablak.exec()
self.frissit()
return ablak.rendben
def uj(self):
if not self.adat or not self.uj_gomb.isEnabled():
return
leiras, ok = QInputDialog.getText(
self, "Új snapshot", "Leírás (például: Driver csere előtt):", QLineEdit.EchoMode.Normal, "Kézi snapshot"
)
leiras = leiras.strip()
if not ok:
return
if not snapshotok.ervenyes_leiras(leiras):
QMessageBox.warning(self, "Új snapshot", "A leírás 1-80 karakter lehet: betűk, számok, szóköz és . _ : , ( ) -")
return
self._futtat("Új snapshot", muveletek.Lepes("Snapshot készítése", muveletek.root("snapshot", leiras)), "A snapshot elkészült.")
def torol(self, elem):
if QMessageBox.question(
self, "Snapshot törlése", f"Törlöd a(z) #{elem['szam']} snapshotot?\n{elem['datum']} {elem['leiras']}"
) != QMessageBox.StandardButton.Yes:
return
self._futtat(
"Snapshot törlése",
muveletek.Lepes("Snapshot törlése", muveletek.root("snapshot-torles", str(elem["szam"]))),
"A snapshot törölve.",
)
def visszaallit(self, elem):
kernelek = snapshotok.kernel_valtozas(elem["szam"])
ellenorizheto = kernelek is not None
kernelek = kernelek or []
hianyzo = [k for k in kernelek if not k["cache"]]
if hianyzo:
QMessageBox.warning(
self,
"Visszaállítás",
"Ennek a snapshotnak a kernelcsomagja már nincs meg a csomag-cache-ben "
f"({', '.join(k['nev'] + ' ' + k['regi'] for k in hianyzo)}), ezért a visszaállított rendszer nem "
"indulna el. Válassz újabb snapshotot.",
)
return
kernel_szoveg = "".join(f"\n- {k['nev']}: {k['most'] or 'nincs'} -> {k['regi']}" for k in kernelek)
szoveg = (
f"A rendszer visszaáll erre az állapotra:\n#{elem['szam']} {elem['datum']} {elem['leiras']}\n\n"
"A saját fájljaid (/home) nem változnak. A mostani rendszer a következő visszaállításig megmarad "
"tartalékként. A változás újraindítás után lép életbe."
+ (f"\n\nA kernel is visszaáll:{kernel_szoveg}" if kernelek else "")
+ ("" if ellenorizheto else "\n\nA snapshot kernelverziója innen nem olvasható, a visszaállítás előtt a rendszer "
"ellenőrzi, és ha a kernelcsomag hiányzik, nem végzi el.")
+ "\n\nFolytatod?"
)
if QMessageBox.question(self, "Visszaállítás", szoveg) != QMessageBox.StandardButton.Yes:
return
rendben = self._futtat(
"Visszaállítás",
muveletek.Lepes("Snapshot visszaállítása", muveletek.root("snapshot-visszaallit", str(elem["szam"]))),
"A visszaállítás elkészült. Indítsd újra a gépet.",
)
if not rendben:
return
doboz = QMessageBox(self)
doboz.setWindowTitle("Visszaállítás")
doboz.setIcon(QMessageBox.Icon.Warning)
doboz.setText(
"A visszaállítás újraindítás után lép életbe. Amit addig a gépen változtatsz (telepítés, beállítás, "
"rendszerfájlok), az a tartalék rendszerbe kerül, és elvész. A /home-ban lévő fájljaid megmaradnak.\n\n"
"Javasolt most újraindítani."
)
most = doboz.addButton("Újraindítás most", QMessageBox.ButtonRole.AcceptRole)
doboz.addButton("Később", QMessageBox.ButtonRole.RejectRole)
doboz.setDefaultButton(most)
doboz.exec()
if doboz.clickedButton() is most:
QProcess.startDetached("systemctl", ["reboot"])
def _beallitas(self):
self._futtat(
"Snapper beállítása",
muveletek.Lepes("Snapper beállítása", muveletek.root("snapper-beallitas")),
"A snapper beállítva, az első snapshot elkészült.",
)
FUL = Snapshotok
|