#!/usr/bin/python3 from PySide2.QtWidgets import (QApplication, QLabel, QPushButton, QSlider, QLineEdit, QWidget, QVBoxLayout, QHBoxLayout, QDialog, QGroupBox, QTabWidget, QErrorMessage, QListWidgetItem, QGridLayout, QTextEdit, QComboBox, QToolBar, QInputDialog, QAction, QStackedWidget, QTextBrowser) from PySide2.QtCore import (Qt, QThread, Signal, QDir, QProcess, QCoreApplication) from PySide2.QtGui import (QIcon, QMovie) import sys, subprocess, trio, io class UpdatePrompt(QDialog): def __init__(self): super().__init__() self.makeView() return def makeView(self): layout = QVBoxLayout() btnLayout = QHBoxLayout() self.centStack = QStackedWidget() updateButton = QPushButton('Update') cancelButton = QPushButton('Cancel') notifyLabel = QLabel('There are updates scheduled') self.inputBox = QLineEdit() self.outputBox = QTextBrowser() #refreshIcon = QIcon.fromTheme('process-working') self.refreshIcon = QMovie('assets/spin3.gif') refreshAnimation = QLabel() layout.addWidget(notifyLabel) layout.addWidget(self.centStack) layout.addWidget(self.inputBox) layout.addLayout(btnLayout) btnLayout.addWidget(cancelButton) btnLayout.addWidget(updateButton) self.centStack.addWidget(refreshAnimation) self.centStack.addWidget(self.outputBox) refreshAnimation.setMovie(self.refreshIcon) refreshAnimation.setAlignment(Qt.AlignCenter) self.refreshIcon.start() self.inputBox.setEchoMode(QLineEdit.Password) self.inputBox.setFocus() self.inputBox.returnPressed.connect(self.pkgUpdates) updateButton.clicked.connect(self.pkgUpdates) cancelButton.clicked.connect(self.cancelUpdates) self.centStack.setCurrentIndex(1) notifyLabel.setAlignment(Qt.AlignTop) self.outputBox.setReadOnly(True) #self.outputBox.setAlignment(Qt.AlignTop) self.setWindowTitle('Package Updates') self.setLayout(layout) self.resize(450, 250) return async def asetup(self, password): async with trio.open_nursery() as nursery: finishedState = trio.Event() nursery.start_soon(self.upProc, password, 'update', finishedState) #nursery.start_soon(self.KEAlive, finishedState) return async def upProc(self, password, cmd, finishedState): # proc = subprocess.Popen(['sudo', '-S', 'apt-get', cmd, '-y'], # stdout=subprocess.PIPE, # stderr=subprocess.STDOUT, # stdin=subprocess.PIPE) proc = await trio.open_process(['sudo', '-S', 'apt-get', cmd, '-y'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) await proc.stdin.send_all((password + '\n').encode()) result = '' while (proc.poll() == None): QCoreApplication.processEvents() await trio.sleep(0.1) #a = await proc.stdout.receive_some() #a = a.decode() #print(a) #result = result + a #stdout = result.stdout.decode() result = await self.pullOutput(proc) self.appendToOutput(result) proc.terminate() if (cmd == 'update'): await self.upProc(password, 'upgrade', finishedState) finishedState.set() return async def pseudoSleep(self, intervals): i = 0 return async def pullOutput(self, proc): x = await proc.stdout.receive_some() x = x.decode() result = '' while (x != ''): QCoreApplication.processEvents() result = result + x x = await proc.stdout.receive_some() x = x.decode() return result async def KEAlive(self, finishedState): while finishedState.is_set(): QCoreApplication.processEvents() trio.sleep(0.1) return return def appendToOutput(self, add): currentText = self.outputBox.toPlainText() self.outputBox.setText(currentText + 'Running updates\n' + add + '\n') print (add) return def pkgUpdates(self): self.centStack.setCurrentIndex(0) self.refreshIcon.start() QCoreApplication.processEvents() password = self.inputBox.text() if (password == ''): self.passError('The password field cannot be empty') return # password = password.encode() # result = subprocess.run(['sudo', '-S', 'apt-get', 'update'], # stdout=subprocess.PIPE, # stderr=subprocess.STDOUT, input=password) # result = subprocess.run(['sudo', '-S', 'apt-get', 'upgrade', '-y'], # stdout=subprocess.PIPE, # stderr=subprocess.STDOUT, input=password) # stdout = result.stdout.decode() # currentText = self.outputBox.toPlainText() # self.outputBox.setText(currentText + '\nRunning upgrades\n' + stdout) # result = subprocess.run(['sudo', 'apt', 'upgrade', '-y'], # stdout=subprocess.PIPE, # stderr=subprocess.STDOUT, input=password) # currentText = self.outputBox.toPlainText() # self.outputBox.setText(currentText + '\n' + stdout) #self.refreshIcon.stop() trio.run(self.asetup, password) self.centStack.setCurrentIndex(1) self.refreshIcon.stop() return def passError(self, s): passError = QDialog(self) msg = QLabel(s) layout = QVBoxLayout() layout.addWidget(msg) passError.setLayout(layout) okBtn = QPushButton('OK') okBtn.clicked.connect(passError.reject) layout.addWidget(okBtn) passError.exec_() return def cancelUpdates(self): self.reject() return if __name__ == '__main__': app = QApplication([]) view = UpdatePrompt() view.show() sys.exit(app.exec_())