Skip to content

Commit 63cda6f

Browse files
committed
Use pyplugin_installer
1 parent d7a3ba1 commit 63cda6f

File tree

2 files changed

+13
-131
lines changed

2 files changed

+13
-131
lines changed

docs/docs/getting_started.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,12 @@ In the `Project` tab:
8484

8585
## Install the module plugin
8686

87-
In the `Plugin` tab, you can install the module plugin (ie. TWW plugin). There are two ways to install the plugin:
87+
In the `Plugin` tab, you can install the module plugin (ie. TWW plugin). There are two possibilities:
8888

89-
1. Click `Install`
90-
* If running oQtopus from QGIS, the plugin is installed in the current QGIS profile.
91-
* If running oQtopus standalone, you get asked to select the QGIS profile directory.
89+
1. Click `Install` and it will be installed in the current QGIS profile. Note: this is possible only if running oQtopus from QGIS.
9290
2. Click `Copy ZIP to directory`:
9391
* You can copy the plugin zip file to a directory of your choice.
94-
* Then in QGIS > Extension > Install and manage extension > Install from ZIP
92+
* Then in QGIS > Extension > Install and manage extension > Install from ZIP.
9593

9694

9795
## oQtopus as a standalone python executable

oqtopus/gui/plugin_widget.py

Lines changed: 10 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import os
22
import shutil
3-
import tempfile
4-
import zipfile
53

6-
from qgis.PyQt.QtCore import QDir, QStandardPaths, QUrl
4+
from qgis.PyQt.QtCore import QUrl
75
from qgis.PyQt.QtGui import QDesktopServices
86
from qgis.PyQt.QtWidgets import QFileDialog, QMessageBox, QWidget
97

@@ -84,141 +82,27 @@ def __installClicked(self):
8482
QtUtils.setFontItalic(self.info_label, True)
8583
return
8684

87-
# Determine QGIS user plugins directory (profile/python/plugins)
8885
try:
89-
from qgis.core import QgsApplication
86+
from pyplugin_installer import instance as plugin_installer_instance
9087

91-
qgis_settings_dir = QgsApplication.qgisSettingsDirPath()
92-
except Exception:
93-
qgis_settings_dir = None
88+
installer = plugin_installer_instance()
89+
installer.installFromZipFile(asset_plugin.package_zip)
9490

95-
if not qgis_settings_dir:
96-
answer = QMessageBox.question(
97-
self,
98-
self.tr("Error"),
99-
self.tr(
100-
"Can't determine QGIS profile directory automatically. Please open the profile folder or cancel."
101-
),
102-
QMessageBox.StandardButton.Open | QMessageBox.StandardButton.Cancel,
103-
)
104-
if answer == QMessageBox.StandardButton.Cancel:
105-
return
106-
107-
# No qgis classes available: look into usual Qt settings folder
108-
qgis_app_dir = QStandardPaths.locate(
109-
QStandardPaths.StandardLocation.GenericDataLocation,
110-
"QGIS/QGIS3/profiles",
111-
QStandardPaths.LocateOption.LocateDirectory,
112-
)
113-
114-
qgis_settings_dir = QFileDialog.getExistingDirectory(
115-
self,
116-
self.tr("Open QGIS Profile Folder"),
117-
qgis_app_dir,
118-
)
119-
if not qgis_settings_dir:
120-
return
121-
122-
plugins_dir = os.path.join(qgis_settings_dir, "python", "plugins")
123-
124-
# Ensure plugins directory exists (create if necessary)
125-
try:
126-
os.makedirs(plugins_dir, exist_ok=True)
127-
except Exception as e:
128-
QMessageBox.critical(
129-
self,
130-
self.tr("Error"),
131-
self.tr(f"Can't create plugins directory '{plugins_dir}': {e}"),
132-
)
13391
return
13492

135-
# Extract zip to a temporary directory and move to plugins folder
136-
try:
137-
with tempfile.TemporaryDirectory() as tmpdir:
138-
with zipfile.ZipFile(asset_plugin.package_zip, "r") as zf:
139-
zf.extractall(tmpdir)
140-
141-
# Inspect top-level entries
142-
qdir = QDir(tmpdir)
143-
entries_info = qdir.entryInfoList(QDir.Filter.NoDotAndDotDot | QDir.Filter.Dirs)
144-
# Require exactly one top-level directory (well-formed plugin zip)
145-
if len(entries_info) != 1:
146-
QMessageBox.critical(
147-
self,
148-
self.tr("Invalid plugin package"),
149-
self.tr(
150-
"The plugin zip must contain exactly one top-level directory. "
151-
"Please provide a properly packaged plugin."
152-
),
153-
)
154-
return
155-
156-
dest_name = entries_info[0].fileName()
157-
src_path = os.path.join(tmpdir, dest_name)
158-
dest_path = os.path.join(plugins_dir, dest_name)
159-
160-
# If destination exists, ask user whether to overwrite
161-
if os.path.exists(dest_path):
162-
res = QMessageBox.question(
163-
self,
164-
self.tr("Overwrite plugin"),
165-
self.tr(
166-
f"The plugin '{dest_name}' already exists in the QGIS plugins folder. Overwrite?"
167-
),
168-
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
169-
)
170-
if res != QMessageBox.StandardButton.Yes:
171-
return
172-
# Remove existing plugin directory
173-
try:
174-
if os.path.islink(dest_path) or os.path.isfile(dest_path):
175-
os.remove(dest_path)
176-
else:
177-
shutil.rmtree(dest_path)
178-
except Exception as e:
179-
QMessageBox.critical(
180-
self,
181-
self.tr("Error"),
182-
self.tr(f"Failed to remove existing plugin '{dest_path}': {e}"),
183-
)
184-
return
185-
186-
# Move the extracted plugin into plugins directory
187-
try:
188-
shutil.move(src_path, dest_path)
189-
except Exception:
190-
# If move fails (cross-device), fallback to copytree
191-
try:
192-
shutil.copytree(src_path, dest_path)
193-
except Exception as e2:
194-
QMessageBox.critical(
195-
self,
196-
self.tr("Error"),
197-
self.tr(f"Failed to install plugin to '{dest_path}': {e2}"),
198-
)
199-
return
200-
201-
QMessageBox.information(
202-
self,
203-
self.tr("Plugin installed"),
204-
self.tr(
205-
f"Plugin '{dest_name}' installed to QGIS profile plugins folder:\n{dest_path}\n\nYou may need to restart QGIS or enable the plugin from the Plugin Manager."
206-
),
207-
)
208-
209-
except zipfile.BadZipFile:
210-
QMessageBox.critical(
93+
except ImportError:
94+
QMessageBox.warning(
21195
self,
21296
self.tr("Error"),
213-
self.tr("The plugin package is not a valid zip archive."),
97+
self.tr("Plugin installation is not possible when oQtopus is running standalone."),
21498
)
21599
return
100+
216101
except Exception as e:
217-
logger.exception("Unexpected error during plugin installation")
218-
QMessageBox.critical(
102+
QMessageBox.warning(
219103
self,
220104
self.tr("Error"),
221-
self.tr(f"Failed to install plugin: {e}"),
105+
self.tr("Plugin installation failed with an exception: {0}").format(str(e)),
222106
)
223107
return
224108

0 commit comments

Comments
 (0)