Skip to content

Commit c247352

Browse files
committed
Backup only at replacement, warn user on replacement
1 parent 7727b6b commit c247352

7 files changed

Lines changed: 310 additions & 126 deletions

File tree

mslib/msui/_tests/test_updater.py

Lines changed: 36 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,29 @@
3030

3131
from mslib.msui.updater import Updater
3232
from mslib.utils import Worker
33-
from mslib import __version__
3433

3534

36-
class SubprocessVersionMock:
37-
def __init__(self):
38-
self.stdout = "*mss 999.999.999\n"
35+
class SubprocessDifferentVersionMock:
36+
def __init__(self, args=None, **named_args):
3937
self.returncode = 0
38+
self.args = args
39+
if args and "list" in args and "mss" in args:
40+
self.stdout = "*mss 0.0.0\n"
41+
else:
42+
self.stdout = "*mss 999.999.999\n"
4043

4144

4245
class SubprocessSameMock:
43-
def __init__(self):
44-
self.stdout = f"*mss {__version__}\n"
46+
def __init__(self, args=None, **named_args):
47+
self.stdout = "*mss 999.999.999\n"
4548
self.returncode = 0
49+
self.args = args
4650

4751

4852
class SubprocessGitMock:
49-
def __init__(self):
53+
def __init__(self, args=None, **named_args):
5054
self.stdout = "true"
55+
self.args = args
5156

5257

5358
def create_mock(function, on_success=None, on_failure=None, start=True):
@@ -70,110 +75,54 @@ def teardown(self):
7075
self.application.quit()
7176
QtWidgets.QApplication.processEvents()
7277

73-
@mock.patch("subprocess.run", return_value=SubprocessVersionMock())
78+
@mock.patch("subprocess.Popen", new=SubprocessDifferentVersionMock)
79+
@mock.patch("subprocess.run", new=SubprocessDifferentVersionMock)
7480
@mock.patch("mslib.utils.Worker.create", create_mock)
75-
def test_update_recognised(self, mock):
81+
def test_update_recognised(self):
7682
update_available = False
77-
status = ""
78-
progress = 0
79-
finished = False
80-
81-
def status_changed(s):
82-
nonlocal status
83-
status = s
84-
85-
def progress_changed(value):
86-
nonlocal progress
87-
progress = value
8883

8984
def update_signal():
9085
nonlocal update_available
9186
update_available = True
9287

93-
def finished_signal():
94-
nonlocal finished
95-
finished = True
96-
97-
self.updater.on_status_update.connect(status_changed)
98-
self.updater.on_update_finished.connect(finished_signal)
99-
self.updater.on_progress_update.connect(progress_changed)
10088
self.updater.on_update_available.connect(update_signal)
10189
self.updater.run()
10290

10391
assert self.updater.new_version == "999.999.999"
10492
assert update_available
93+
self.updater.new_version = "0.0.0"
10594

10695
self.updater.update_mss()
10796
assert self.updater.base_path == "999.999.999"
10897
assert self.updater.current_path == "999.999.999"
109-
assert progress == 100
110-
assert finished
111-
assert status == "Update finished. Please restart MSS."
98+
assert self.updater.progressBar.value() == 100
99+
assert self.updater.statusLabel.text() == "Update successful. Please restart MSS."
112100

113-
@mock.patch("subprocess.run", return_value=SubprocessSameMock())
101+
@mock.patch("subprocess.Popen", new=SubprocessSameMock)
102+
@mock.patch("subprocess.run", new=SubprocessSameMock)
114103
@mock.patch("mslib.utils.Worker.create", create_mock)
115-
def test_no_update(self, mock):
116-
update_available = False
117-
status = ""
118-
119-
def update_signal():
120-
nonlocal update_available
121-
update_available = True
122-
123-
def status_changed(s):
124-
nonlocal status
125-
status = s
126-
127-
self.updater.on_update_available.connect(update_signal)
128-
self.updater.on_status_update.connect(status_changed)
104+
def test_no_update(self):
129105
self.updater.run()
106+
assert self.updater.statusLabel.text() == "Your MSS is up to date."
130107

131-
assert self.updater.new_version == __version__
132-
assert not update_available
133-
assert status == "Your MSS is up to date."
134-
135-
@mock.patch("subprocess.run", return_value=SubprocessGitMock())
108+
@mock.patch("subprocess.Popen", new=SubprocessGitMock)
109+
@mock.patch("subprocess.run", new=SubprocessGitMock)
136110
@mock.patch("mslib.utils.Worker.create", create_mock)
137-
def test_no_update_on_git(self, mock):
138-
update_available = False
139-
140-
def update_signal():
141-
nonlocal update_available
142-
update_available = True
143-
144-
self.updater.on_update_available.connect(update_signal)
111+
def test_no_update_on_git(self):
145112
self.updater.run()
146-
147113
assert self.updater.new_version is None
148-
assert not update_available
114+
assert self.updater.statusLabel.text() == "Nothing to do"
149115

150-
@mock.patch("subprocess.run", return_value=SubprocessVersionMock())
116+
@mock.patch("subprocess.Popen", new=SubprocessDifferentVersionMock)
117+
@mock.patch("subprocess.run", new=SubprocessDifferentVersionMock)
151118
@mock.patch("mslib.utils.Worker.create", create_mock)
152-
def test_update_failed(self, mock):
119+
def test_update_failed(self):
153120
update_available = False
154-
status = ""
155-
progress = 0
156-
finished = False
157-
158-
def status_changed(s):
159-
nonlocal status
160-
status = s
161-
162-
def progress_changed(value):
163-
nonlocal progress
164-
progress = value
165121

166122
def update_signal():
167123
nonlocal update_available
168124
update_available = True
169125

170-
def finished_signal():
171-
nonlocal finished
172-
finished = True
173-
174-
self.updater.on_status_update.connect(status_changed)
175-
self.updater.on_update_finished.connect(finished_signal)
176-
self.updater.on_progress_update.connect(progress_changed)
177126
self.updater.on_update_available.connect(update_signal)
178127
self.updater.run()
179128

@@ -182,14 +131,12 @@ def finished_signal():
182131
self.updater.new_version = "1000.1000.1000"
183132

184133
self.updater.update_mss()
185-
assert progress == 45
186-
assert not finished
187-
assert status == "Update failed, please do it manually."
188-
189-
@mock.patch("subprocess.run", return_value=SubprocessVersionMock())
190-
@mock.patch("shutil.copytree", return_value=None)
191-
@mock.patch("shutil.rmtree", return_value=None)
192-
def test_environment_replace(self, subprocess_mock, shutil1, shutil2):
193-
self.updater.new_version = "999.999.999"
134+
assert self.updater.statusLabel.text() == "Update failed. Please try it manually or " \
135+
"try replacing the environment!"
136+
137+
@mock.patch("subprocess.Popen", new=SubprocessDifferentVersionMock)
138+
@mock.patch("subprocess.run", new=SubprocessDifferentVersionMock)
139+
def test_environment_replace(self):
140+
self.updater.new_version = "0.0.0"
194141
self.updater._set_base_env_path()
195142
assert self.updater._try_environment_replace()

mslib/msui/mss_pyui.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ def __init__(self, *args):
282282
self.updater = Updater(self)
283283
self.updater.on_update_available.connect(self.notify_on_update)
284284
self.updater.run()
285+
self.actionUpdater.triggered.connect(self.updater.show)
285286

286287
@staticmethod
287288
def preload_wms(urls):
@@ -769,7 +770,7 @@ def notify_on_update(self, old, new):
769770
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
770771
QtWidgets.QMessageBox.No)
771772
if ret == QtWidgets.QMessageBox.Yes:
772-
self.updater.update_mss()
773+
self.updater.show()
773774

774775

775776
def main():

mslib/msui/qt5/ui_mainwindow.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ def setupUi(self, MSSMainWindow):
9595
self.actionLoadConfigurationFile.setObjectName("actionLoadConfigurationFile")
9696
self.actionShortcuts = QtWidgets.QAction(MSSMainWindow)
9797
self.actionShortcuts.setObjectName("actionShortcuts")
98+
self.actionUpdater = QtWidgets.QAction(MSSMainWindow)
99+
self.actionUpdater.setObjectName("actionUpdater")
98100
self.menu_File.addAction(self.actionNewFlightTrack)
99101
self.menu_File.addAction(self.actionOpenFlightTrack)
100102
self.menu_File.addSeparator()
@@ -118,6 +120,7 @@ def setupUi(self, MSSMainWindow):
118120
self.menu_Help.addAction(self.actionOnlineHelp)
119121
self.menu_Help.addAction(self.actionAboutMSUI)
120122
self.menu_Help.addAction(self.actionShortcuts)
123+
self.menu_Help.addAction(self.actionUpdater)
121124
self.menu_Mscolab.addAction(self.actionMscolabProjects)
122125
self.menubar.addAction(self.menu_File.menuAction())
123126
self.menubar.addAction(self.menu_View.menuAction())
@@ -171,3 +174,5 @@ def retranslateUi(self, MSSMainWindow):
171174
self.actionShortcuts.setText(_translate("MSSMainWindow", "Shortcuts"))
172175
self.actionShortcuts.setToolTip(_translate("MSSMainWindow", "Show Current Shortcuts"))
173176
self.actionShortcuts.setShortcut(_translate("MSSMainWindow", "Alt+S"))
177+
self.actionUpdater.setText(_translate("MSSMainWindow", "Updater"))
178+
self.actionUpdater.setToolTip(_translate("MSSMainWindow", "Open the Updater Dialog"))

mslib/msui/qt5/ui_updater_dialog.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,70 @@
1313
class Ui_Updater(object):
1414
def setupUi(self, Updater):
1515
Updater.setObjectName("Updater")
16-
Updater.setWindowModality(QtCore.Qt.ApplicationModal)
16+
Updater.setWindowModality(QtCore.Qt.NonModal)
1717
Updater.resize(854, 353)
1818
self.verticalLayout = QtWidgets.QVBoxLayout(Updater)
1919
self.verticalLayout.setObjectName("verticalLayout")
20+
self.horizontalLayout = QtWidgets.QHBoxLayout()
21+
self.horizontalLayout.setObjectName("horizontalLayout")
22+
self.labelVersion = QtWidgets.QLabel(Updater)
23+
self.labelVersion.setObjectName("labelVersion")
24+
self.horizontalLayout.addWidget(self.labelVersion)
25+
self.btUpdate = QtWidgets.QPushButton(Updater)
26+
self.btUpdate.setEnabled(False)
27+
self.btUpdate.setObjectName("btUpdate")
28+
self.horizontalLayout.addWidget(self.btUpdate)
29+
self.btReplace = QtWidgets.QPushButton(Updater)
30+
self.btReplace.setEnabled(False)
31+
palette = QtGui.QPalette()
32+
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
33+
brush.setStyle(QtCore.Qt.SolidPattern)
34+
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush)
35+
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
36+
brush.setStyle(QtCore.Qt.SolidPattern)
37+
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush)
38+
brush = QtGui.QBrush(QtGui.QColor(190, 190, 190))
39+
brush.setStyle(QtCore.Qt.SolidPattern)
40+
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush)
41+
self.btReplace.setPalette(palette)
42+
self.btReplace.setObjectName("btReplace")
43+
self.horizontalLayout.addWidget(self.btReplace)
44+
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
45+
self.horizontalLayout.addItem(spacerItem)
46+
self.label = QtWidgets.QLabel(Updater)
47+
self.label.setOpenExternalLinks(True)
48+
self.label.setObjectName("label")
49+
self.horizontalLayout.addWidget(self.label)
50+
self.verticalLayout.addLayout(self.horizontalLayout)
2051
self.statusLabel = QtWidgets.QLabel(Updater)
2152
self.statusLabel.setObjectName("statusLabel")
2253
self.verticalLayout.addWidget(self.statusLabel)
2354
self.output = QtWidgets.QPlainTextEdit(Updater)
55+
font = QtGui.QFont()
56+
font.setFamily("Sans Serif")
57+
font.setStyleStrategy(QtGui.QFont.PreferDefault)
58+
self.output.setFont(font)
2459
self.output.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap)
2560
self.output.setReadOnly(True)
61+
self.output.setPlainText("")
2662
self.output.setCenterOnScroll(False)
2763
self.output.setObjectName("output")
2864
self.verticalLayout.addWidget(self.output)
65+
self.progressBar = QtWidgets.QProgressBar(Updater)
66+
self.progressBar.setProperty("value", 0)
67+
self.progressBar.setObjectName("progressBar")
68+
self.verticalLayout.addWidget(self.progressBar)
2969

3070
self.retranslateUi(Updater)
3171
QtCore.QMetaObject.connectSlotsByName(Updater)
3272

3373
def retranslateUi(self, Updater):
3474
_translate = QtCore.QCoreApplication.translate
3575
Updater.setWindowTitle(_translate("Updater", "Updater"))
36-
self.statusLabel.setText(_translate("Updater", "Status"))
76+
self.labelVersion.setText(_translate("Updater", "Newest Version: x.x.x"))
77+
self.btUpdate.setText(_translate("Updater", "Update Current Environment"))
78+
self.btReplace.setToolTip(_translate("Updater", "Closing MSS during this operation may break your environment!"))
79+
self.btReplace.setText(_translate("Updater", "Replace Current Environment"))
80+
self.label.setText(_translate("Updater", "<html><head/><body><p><a href=\"https://mss.readthedocs.io/en/stable/installation.html#install\"><span style=\" text-decoration: underline; color:#0000ff;\">Manual update instructions</span></a></p></body></html>"))
81+
self.statusLabel.setText(_translate("Updater", "Nothing to do"))
82+
self.progressBar.setFormat(_translate("Updater", "Installation Progress: %p%"))

mslib/msui/ui/ui_mainwindow.ui

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ Save a flight track to name it.</string>
135135
<addaction name="actionOnlineHelp"/>
136136
<addaction name="actionAboutMSUI"/>
137137
<addaction name="actionShortcuts"/>
138+
<addaction name="actionUpdater"/>
138139
</widget>
139140
<widget class="QMenu" name="menu_Mscolab">
140141
<property name="title">
@@ -266,6 +267,14 @@ Save a flight track to name it.</string>
266267
<string>Alt+S</string>
267268
</property>
268269
</action>
270+
<action name="actionUpdater">
271+
<property name="text">
272+
<string>Updater</string>
273+
</property>
274+
<property name="toolTip">
275+
<string>Open the Updater Dialog</string>
276+
</property>
277+
</action>
269278
</widget>
270279
<resources/>
271280
<connections>

0 commit comments

Comments
 (0)