mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-23 00:02:38 -05:00
229 lines
8.6 KiB
Python
229 lines
8.6 KiB
Python
"""
|
|
/***************************************************************************
|
|
qgsplugininstallerinstallingdialog.py
|
|
Plugin Installer module
|
|
-------------------
|
|
Date : June 2013
|
|
Copyright : (C) 2013 by Borys Jurgiel
|
|
Email : info at borysjurgiel dot pl
|
|
|
|
This module is based on former plugin_installer plugin:
|
|
Copyright (C) 2007-2008 Matthew Perry
|
|
Copyright (C) 2008-2013 Borys Jurgiel
|
|
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
from qgis.PyQt import uic
|
|
from qgis.PyQt.QtCore import QDir, QUrl, QFile, QCoreApplication
|
|
from qgis.PyQt.QtWidgets import QDialog
|
|
from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply
|
|
|
|
from qgis.core import (
|
|
QgsNetworkAccessManager,
|
|
QgsApplication,
|
|
QgsNetworkRequestParameters,
|
|
)
|
|
from qgis.utils import HOME_PLUGIN_PATH
|
|
|
|
from .installer_data import removeDir, repositories
|
|
from .unzip import unzip
|
|
|
|
Ui_QgsPluginInstallerInstallingDialogBase, _ = uic.loadUiType(
|
|
Path(__file__).parent / "qgsplugininstallerinstallingbase.ui"
|
|
)
|
|
|
|
|
|
class QgsPluginInstallerInstallingDialog(
|
|
QDialog, Ui_QgsPluginInstallerInstallingDialogBase
|
|
):
|
|
# ----------------------------------------- #
|
|
|
|
def __init__(self, parent, plugin, stable=True):
|
|
QDialog.__init__(self, parent)
|
|
self.setupUi(self)
|
|
self.plugin = plugin
|
|
self.mResult = ""
|
|
self.progressBar.setRange(0, 0)
|
|
self.progressBar.setFormat("%p%")
|
|
self.labelName.setText(plugin["name"])
|
|
self.buttonBox.clicked.connect(self.abort)
|
|
|
|
self.url = QUrl(
|
|
plugin["download_url_stable"]
|
|
if stable
|
|
else plugin["download_url_experimental"]
|
|
)
|
|
self.redirectionCounter = 0
|
|
|
|
fileName = plugin["filename"]
|
|
tmpDir = QDir.tempPath()
|
|
tmpPath = QDir.cleanPath(tmpDir + "/" + fileName)
|
|
self.file = QFile(tmpPath)
|
|
|
|
self.requestDownloading()
|
|
|
|
def requestDownloading(self):
|
|
self.request = QNetworkRequest(self.url)
|
|
self.request.setAttribute(
|
|
QNetworkRequest.Attribute(
|
|
QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass
|
|
),
|
|
"QgsPluginInstallerInstallingDialog",
|
|
)
|
|
authcfg = repositories.all()[self.plugin["zip_repository"]]["authcfg"]
|
|
if authcfg and isinstance(authcfg, str):
|
|
if not QgsApplication.authManager().updateNetworkRequest(
|
|
self.request, authcfg.strip()
|
|
):
|
|
self.mResult = self.tr(
|
|
"Update of network request with authentication "
|
|
"credentials FAILED for configuration '{0}'"
|
|
).format(authcfg)
|
|
self.request = None
|
|
|
|
if self.request is not None:
|
|
self.reply = QgsNetworkAccessManager.instance().get(self.request)
|
|
self.reply.downloadProgress.connect(self.readProgress)
|
|
self.reply.finished.connect(self.requestFinished)
|
|
|
|
self.stateChanged(4)
|
|
|
|
def exec(self):
|
|
if self.request is None:
|
|
return QDialog.DialogCode.Rejected
|
|
|
|
QDialog.exec(self)
|
|
|
|
# ----------------------------------------- #
|
|
def result(self):
|
|
return self.mResult
|
|
|
|
# ----------------------------------------- #
|
|
def stateChanged(self, state):
|
|
messages = [
|
|
QCoreApplication.translate(
|
|
"QgsPluginInstallerInstallingDialog", "Installing…"
|
|
),
|
|
QCoreApplication.translate(
|
|
"QgsPluginInstallerInstallingDialog", "Resolving host name…"
|
|
),
|
|
QCoreApplication.translate(
|
|
"QgsPluginInstallerInstallingDialog", "Connecting…"
|
|
),
|
|
QCoreApplication.translate(
|
|
"QgsPluginInstallerInstallingDialog", "Host connected. Sending request…"
|
|
),
|
|
QCoreApplication.translate(
|
|
"QgsPluginInstallerInstallingDialog", "Downloading data…"
|
|
),
|
|
self.tr("Idle"),
|
|
QCoreApplication.translate(
|
|
"QgsPluginInstallerInstallingDialog", "Closing connection…"
|
|
),
|
|
self.tr("Error"),
|
|
]
|
|
self.labelState.setText(messages[state])
|
|
|
|
# ----------------------------------------- #
|
|
def readProgress(self, done, total):
|
|
if total > 0:
|
|
self.progressBar.setMaximum(total)
|
|
self.progressBar.setValue(done)
|
|
|
|
# ----------------------------------------- #
|
|
def requestFinished(self):
|
|
reply = self.sender()
|
|
self.buttonBox.setEnabled(False)
|
|
if reply.error() != QNetworkReply.NetworkError.NoError:
|
|
self.mResult = reply.errorString()
|
|
if reply.error() == QNetworkReply.NetworkError.OperationCanceledError:
|
|
self.mResult += "<br/><br/>" + QCoreApplication.translate(
|
|
"QgsPluginInstaller",
|
|
"If you haven't canceled the download manually, it might be caused by a timeout. In this case consider increasing the connection timeout value in QGIS options.",
|
|
)
|
|
self.reject()
|
|
reply.deleteLater()
|
|
return
|
|
elif reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) in (
|
|
301,
|
|
302,
|
|
):
|
|
redirectionUrl = reply.attribute(
|
|
QNetworkRequest.Attribute.RedirectionTargetAttribute
|
|
)
|
|
self.redirectionCounter += 1
|
|
if self.redirectionCounter > 4:
|
|
self.mResult = QCoreApplication.translate(
|
|
"QgsPluginInstaller", "Too many redirections"
|
|
)
|
|
self.reject()
|
|
reply.deleteLater()
|
|
return
|
|
else:
|
|
if redirectionUrl.isRelative():
|
|
redirectionUrl = reply.url().resolved(redirectionUrl)
|
|
# Fire a new request and exit immediately in order to quietly destroy the old one
|
|
self.url = redirectionUrl
|
|
self.requestDownloading()
|
|
reply.deleteLater()
|
|
return
|
|
|
|
self.file.open(QFile.OpenModeFlag.WriteOnly)
|
|
self.file.write(reply.readAll())
|
|
self.file.close()
|
|
self.stateChanged(0)
|
|
reply.deleteLater()
|
|
pluginDir = HOME_PLUGIN_PATH
|
|
tmpPath = self.file.fileName()
|
|
# make sure that the parent directory exists
|
|
if not QDir(pluginDir).exists():
|
|
QDir().mkpath(pluginDir)
|
|
# if the target directory already exists as a link, remove the link without resolving:
|
|
QFile(pluginDir + str(QDir.separator()) + self.plugin["id"]).remove()
|
|
try:
|
|
unzip(
|
|
str(tmpPath), str(pluginDir)
|
|
) # test extract. If fails, then exception will be raised and no removing occurs
|
|
# removing old plugin files if exist
|
|
removeDir(
|
|
QDir.cleanPath(pluginDir + "/" + self.plugin["id"])
|
|
) # remove old plugin if exists
|
|
unzip(str(tmpPath), str(pluginDir)) # final extract.
|
|
except:
|
|
self.mResult = (
|
|
self.tr(
|
|
"Failed to unzip the plugin package. Probably it's broken or missing from the repository. You may also want to make sure that you have write permission to the plugin directory:"
|
|
)
|
|
+ "\n"
|
|
+ pluginDir
|
|
)
|
|
self.reject()
|
|
return
|
|
try:
|
|
# cleaning: removing the temporary zip file
|
|
QFile(tmpPath).remove()
|
|
except:
|
|
pass
|
|
self.close()
|
|
|
|
# ----------------------------------------- #
|
|
def abort(self):
|
|
if self.reply.isRunning():
|
|
self.reply.finished.disconnect()
|
|
self.reply.abort()
|
|
del self.reply
|
|
self.mResult = self.tr("Aborted by user")
|
|
self.reject()
|