8 """ |
8 """ |
9 |
9 |
10 import os |
10 import os |
11 import glob |
11 import glob |
12 |
12 |
13 from PyQt5.QtCore import pyqtSlot, QObject, QProcess |
13 from PyQt6.QtCore import pyqtSlot, QObject, QProcess |
14 from PyQt5.QtWidgets import QMenu, QDialog, QInputDialog, QLineEdit |
14 from PyQt6.QtWidgets import QMenu, QDialog, QInputDialog, QLineEdit |
15 |
15 |
16 from E5Gui import E5MessageBox |
16 from EricWidgets import EricMessageBox |
17 from E5Gui.E5Application import e5App |
17 from EricWidgets.EricApplication import ericApp |
18 from E5Gui.E5Action import E5Action |
18 from EricGui.EricAction import EricAction |
19 |
19 |
20 import Utilities |
20 import Utilities |
21 |
21 |
22 from ..FlaskCommandDialog import FlaskCommandDialog |
22 from ..FlaskCommandDialog import FlaskCommandDialog |
23 |
23 |
41 super().__init__(parent) |
41 super().__init__(parent) |
42 |
42 |
43 self.__plugin = plugin |
43 self.__plugin = plugin |
44 self.__project = project |
44 self.__project = project |
45 |
45 |
46 self.__e5project = e5App().getObject("Project") |
46 self.__ericProject = ericApp().getObject("Project") |
47 |
47 |
48 self.__migrationSummaryDialog = None |
48 self.__migrationSummaryDialog = None |
49 |
49 |
50 def initActions(self): |
50 def initActions(self): |
51 """ |
51 """ |
52 Public method to define the flask-migrate actions. |
52 Public method to define the flask-migrate actions. |
53 """ |
53 """ |
54 self.actions = [] |
54 self.actions = [] |
55 |
55 |
56 self.migrateConfigAct = E5Action( |
56 self.migrateConfigAct = EricAction( |
57 self.tr('Configure Migrate'), |
57 self.tr('Configure Migrate'), |
58 self.tr('C&onfigure Migrate'), |
58 self.tr('C&onfigure Migrate'), |
59 0, 0, |
59 0, 0, |
60 self, 'flask_config_migrate') |
60 self, 'flask_config_migrate') |
61 self.migrateConfigAct.setStatusTip(self.tr( |
61 self.migrateConfigAct.setStatusTip(self.tr( |
67 )) |
67 )) |
68 self.migrateConfigAct.triggered.connect( |
68 self.migrateConfigAct.triggered.connect( |
69 self.__configureMigrate) |
69 self.__configureMigrate) |
70 self.actions.append(self.migrateConfigAct) |
70 self.actions.append(self.migrateConfigAct) |
71 |
71 |
72 self.migrateInstallAct = E5Action( |
72 self.migrateInstallAct = EricAction( |
73 self.tr('Install flask-migrate'), |
73 self.tr('Install flask-migrate'), |
74 self.tr('Install &flask-migrate'), |
74 self.tr('Install &flask-migrate'), |
75 0, 0, |
75 0, 0, |
76 self, 'flask_install_migrate') |
76 self, 'flask_install_migrate') |
77 self.migrateInstallAct.setStatusTip(self.tr( |
77 self.migrateInstallAct.setStatusTip(self.tr( |
84 )) |
84 )) |
85 self.migrateInstallAct.triggered.connect( |
85 self.migrateInstallAct.triggered.connect( |
86 self.__installFlaskMigrate) |
86 self.__installFlaskMigrate) |
87 self.actions.append(self.migrateInstallAct) |
87 self.actions.append(self.migrateInstallAct) |
88 |
88 |
89 self.migrateAvailabilityAct = E5Action( |
89 self.migrateAvailabilityAct = EricAction( |
90 self.tr('Check flask-migrate Availability'), |
90 self.tr('Check flask-migrate Availability'), |
91 self.tr('Check flask-migrate &Availability'), |
91 self.tr('Check flask-migrate &Availability'), |
92 0, 0, |
92 0, 0, |
93 self, 'flask_check_migrate') |
93 self, 'flask_check_migrate') |
94 self.migrateAvailabilityAct.setStatusTip(self.tr( |
94 self.migrateAvailabilityAct.setStatusTip(self.tr( |
103 |
103 |
104 ######################################################### |
104 ######################################################### |
105 ## action to initialize the database migration system |
105 ## action to initialize the database migration system |
106 ######################################################### |
106 ######################################################### |
107 |
107 |
108 self.migrateInitAct = E5Action( |
108 self.migrateInitAct = EricAction( |
109 self.tr('Initialize Migrations'), |
109 self.tr('Initialize Migrations'), |
110 self.tr('&Initialize Migrations'), |
110 self.tr('&Initialize Migrations'), |
111 0, 0, |
111 0, 0, |
112 self, 'flask_init_migrations') |
112 self, 'flask_init_migrations') |
113 self.migrateInitAct.setStatusTip(self.tr( |
113 self.migrateInitAct.setStatusTip(self.tr( |
123 |
123 |
124 ######################################################### |
124 ######################################################### |
125 ## action to create a new database migration |
125 ## action to create a new database migration |
126 ######################################################### |
126 ######################################################### |
127 |
127 |
128 self.migrateCreateAct = E5Action( |
128 self.migrateCreateAct = EricAction( |
129 self.tr('Create Migration'), |
129 self.tr('Create Migration'), |
130 self.tr('&Create Migration'), |
130 self.tr('&Create Migration'), |
131 0, 0, |
131 0, 0, |
132 self, 'flask_create_migration') |
132 self, 'flask_create_migration') |
133 self.migrateCreateAct.setStatusTip(self.tr( |
133 self.migrateCreateAct.setStatusTip(self.tr( |
143 |
143 |
144 ######################################################### |
144 ######################################################### |
145 ## action to up- and downgrade a databse |
145 ## action to up- and downgrade a databse |
146 ######################################################### |
146 ######################################################### |
147 |
147 |
148 self.upgradeDatabaseAct = E5Action( |
148 self.upgradeDatabaseAct = EricAction( |
149 self.tr('Upgrade Database'), |
149 self.tr('Upgrade Database'), |
150 self.tr('&Upgrade Database'), |
150 self.tr('&Upgrade Database'), |
151 0, 0, |
151 0, 0, |
152 self, 'flask_upgrade_database') |
152 self, 'flask_upgrade_database') |
153 self.upgradeDatabaseAct.setStatusTip(self.tr( |
153 self.upgradeDatabaseAct.setStatusTip(self.tr( |
158 )) |
158 )) |
159 self.upgradeDatabaseAct.triggered.connect( |
159 self.upgradeDatabaseAct.triggered.connect( |
160 self.upgradeDatabase) |
160 self.upgradeDatabase) |
161 self.actions.append(self.upgradeDatabaseAct) |
161 self.actions.append(self.upgradeDatabaseAct) |
162 |
162 |
163 self.downgradeDatabaseAct = E5Action( |
163 self.downgradeDatabaseAct = EricAction( |
164 self.tr('Downgrade Database'), |
164 self.tr('Downgrade Database'), |
165 self.tr('&Downgrade Database'), |
165 self.tr('&Downgrade Database'), |
166 0, 0, |
166 0, 0, |
167 self, 'flask_downgrade_database') |
167 self, 'flask_downgrade_database') |
168 self.downgradeDatabaseAct.setStatusTip(self.tr( |
168 self.downgradeDatabaseAct.setStatusTip(self.tr( |
177 |
177 |
178 ######################################################### |
178 ######################################################### |
179 ## actions to show migrations history information |
179 ## actions to show migrations history information |
180 ######################################################### |
180 ######################################################### |
181 |
181 |
182 self.migrationSummaryAct = E5Action( |
182 self.migrationSummaryAct = EricAction( |
183 self.tr('Show Migrations Summary'), |
183 self.tr('Show Migrations Summary'), |
184 self.tr('Show Migrations &Summary'), |
184 self.tr('Show Migrations &Summary'), |
185 0, 0, |
185 0, 0, |
186 self, 'flask_show_migrations_summary') |
186 self, 'flask_show_migrations_summary') |
187 self.migrationSummaryAct.setStatusTip(self.tr( |
187 self.migrationSummaryAct.setStatusTip(self.tr( |
193 )) |
193 )) |
194 self.migrationSummaryAct.triggered.connect( |
194 self.migrationSummaryAct.triggered.connect( |
195 self.__showMigrationsSummary) |
195 self.__showMigrationsSummary) |
196 self.actions.append(self.migrationSummaryAct) |
196 self.actions.append(self.migrationSummaryAct) |
197 |
197 |
198 self.migrationHistoryAct = E5Action( |
198 self.migrationHistoryAct = EricAction( |
199 self.tr('Show Migrations History'), |
199 self.tr('Show Migrations History'), |
200 self.tr('Show Migrations &History'), |
200 self.tr('Show Migrations &History'), |
201 0, 0, |
201 0, 0, |
202 self, 'flask_show_migrations_history') |
202 self, 'flask_show_migrations_history') |
203 self.migrationHistoryAct.setStatusTip(self.tr( |
203 self.migrationHistoryAct.setStatusTip(self.tr( |
269 interpreter = self.__project.getVirtualenvInterpreter() |
269 interpreter = self.__project.getVirtualenvInterpreter() |
270 if interpreter and Utilities.isinpath(interpreter): |
270 if interpreter and Utilities.isinpath(interpreter): |
271 detector = os.path.join( |
271 detector = os.path.join( |
272 os.path.dirname(__file__), "FlaskMigrateDetector.py") |
272 os.path.dirname(__file__), "FlaskMigrateDetector.py") |
273 proc = QProcess() |
273 proc = QProcess() |
274 proc.setProcessChannelMode(QProcess.MergedChannels) |
274 proc.setProcessChannelMode( |
|
275 QProcess.ProcessChannelMode.MergedChannels) |
275 proc.start(interpreter, [detector]) |
276 proc.start(interpreter, [detector]) |
276 finished = proc.waitForFinished(30000) |
277 finished = proc.waitForFinished(30000) |
277 if finished and proc.exitCode() == 0: |
278 if finished and proc.exitCode() == 0: |
278 return True |
279 return True |
279 |
280 |
295 |
296 |
296 migrations = self.__project.getData("flask-migrate", |
297 migrations = self.__project.getData("flask-migrate", |
297 "migrationsDirectory") |
298 "migrationsDirectory") |
298 if migrations: |
299 if migrations: |
299 if abspath: |
300 if abspath: |
300 migrations = self.__e5project.getAbsoluteUniversalPath( |
301 migrations = self.__ericProject.getAbsoluteUniversalPath( |
301 migrations) |
302 migrations) |
302 else: |
303 else: |
303 workdir = self.__project.getApplication()[0] |
304 workdir = self.__project.getApplication()[0] |
304 migrations = os.path.relpath( |
305 migrations = os.path.relpath( |
305 self.__e5project.getAbsoluteUniversalPath(migrations), |
306 self.__ericProject.getAbsoluteUniversalPath(migrations), |
306 workdir |
307 workdir |
307 ) |
308 ) |
308 else: |
309 else: |
309 if abspath: |
310 if abspath: |
310 migrations = self.__e5project.getAbsoluteUniversalPath( |
311 migrations = self.__ericProject.getAbsoluteUniversalPath( |
311 "migrations") |
312 "migrations") |
312 |
313 |
313 return migrations |
314 return migrations |
314 |
315 |
315 def projectClosed(self): |
316 def projectClosed(self): |
331 """ |
332 """ |
332 from .MigrateConfigDialog import MigrateConfigDialog |
333 from .MigrateConfigDialog import MigrateConfigDialog |
333 |
334 |
334 config = self.__project.getData("flask-migrate", "") |
335 config = self.__project.getData("flask-migrate", "") |
335 dlg = MigrateConfigDialog(config) |
336 dlg = MigrateConfigDialog(config) |
336 if dlg.exec() == QDialog.Accepted: |
337 if dlg.exec() == QDialog.DialogCode.Accepted: |
337 config = dlg.getConfiguration() |
338 config = dlg.getConfiguration() |
338 self.__project.setData("flask-migrate", "", config) |
339 self.__project.setData("flask-migrate", "", config) |
339 |
340 |
340 def __ensureMigrateConfigured(self): |
341 def __ensureMigrateConfigured(self): |
341 """ |
342 """ |
352 environment. |
353 environment. |
353 """ |
354 """ |
354 venvName = self.__project.getVirtualEnvironment() |
355 venvName = self.__project.getVirtualEnvironment() |
355 if venvName: |
356 if venvName: |
356 interpreter = self.__project.getFullCommand("python") |
357 interpreter = self.__project.getFullCommand("python") |
357 pip = e5App().getObject("Pip") |
358 pip = ericApp().getObject("Pip") |
358 pip.installPackages(["flask-migrate"], interpreter=interpreter) |
359 pip.installPackages(["flask-migrate"], interpreter=interpreter) |
359 self.determineCapability() |
360 self.determineCapability() |
360 else: |
361 else: |
361 E5MessageBox.critical( |
362 EricMessageBox.critical( |
362 None, |
363 None, |
363 self.tr("Install flask-migrate"), |
364 self.tr("Install flask-migrate"), |
364 self.tr("The 'flask-migrate' extension could not be installed" |
365 self.tr("The 'flask-migrate' extension could not be installed" |
365 " because no virtual environment has been" |
366 " because no virtual environment has been" |
366 " configured.")) |
367 " configured.")) |
374 msg = ( |
375 msg = ( |
375 self.tr("The 'flask-migrate' extension is installed.") |
376 self.tr("The 'flask-migrate' extension is installed.") |
376 if self.__project.hasCapability("flask-migrate") else |
377 if self.__project.hasCapability("flask-migrate") else |
377 self.tr("The 'flask-migrate' extension is not installed.") |
378 self.tr("The 'flask-migrate' extension is not installed.") |
378 ) |
379 ) |
379 E5MessageBox.information( |
380 EricMessageBox.information( |
380 None, |
381 None, |
381 self.tr("flask-migrate Availability"), |
382 self.tr("flask-migrate Availability"), |
382 msg) |
383 msg) |
383 |
384 |
384 ######################################################### |
385 ######################################################### |
397 |
398 |
398 args = ["init"] |
399 args = ["init"] |
399 if migrations: |
400 if migrations: |
400 args += ["--directory", migrations] |
401 args += ["--directory", migrations] |
401 |
402 |
402 multidb = E5MessageBox.yesNo( |
403 multidb = EricMessageBox.yesNo( |
403 None, |
404 None, |
404 self.tr("Multiple Databases"), |
405 self.tr("Multiple Databases"), |
405 self.tr("""Shall the support for multiple databases be""" |
406 self.tr("""Shall the support for multiple databases be""" |
406 """ activated?""")) |
407 """ activated?""")) |
407 if multidb: |
408 if multidb: |
417 for root, _dirs, files in os.walk( |
418 for root, _dirs, files in os.walk( |
418 self.__migrationsDirectory(abspath=True) |
419 self.__migrationsDirectory(abspath=True) |
419 ): |
420 ): |
420 for fileName in files: |
421 for fileName in files: |
421 fullName = os.path.join(root, fileName) |
422 fullName = os.path.join(root, fileName) |
422 self.__e5project.appendFile(fullName) |
423 self.__ericProject.appendFile(fullName) |
423 |
424 |
424 browser = (e5App().getObject("ProjectBrowser") |
425 browser = (ericApp().getObject("ProjectBrowser") |
425 .getProjectBrowser("others")) |
426 .getProjectBrowser("others")) |
426 alembic = os.path.join( |
427 alembic = os.path.join( |
427 self.__migrationsDirectory(abspath=True), |
428 self.__migrationsDirectory(abspath=True), |
428 "alembic.ini" |
429 "alembic.ini" |
429 ) |
430 ) |
445 |
446 |
446 message, ok = QInputDialog.getText( |
447 message, ok = QInputDialog.getText( |
447 None, |
448 None, |
448 title, |
449 title, |
449 self.tr("Enter a short message for the migration:"), |
450 self.tr("Enter a short message for the migration:"), |
450 QLineEdit.Normal) |
451 QLineEdit.EchoMode.Normal) |
451 if ok: |
452 if ok: |
452 args = ["migrate"] |
453 args = ["migrate"] |
453 if migrations: |
454 if migrations: |
454 args += ["--directory", migrations] |
455 args += ["--directory", migrations] |
455 if message: |
456 if message: |
464 if dlg.normalExit(): |
465 if dlg.normalExit(): |
465 versionsPattern = os.path.join( |
466 versionsPattern = os.path.join( |
466 self.__migrationsDirectory(abspath=True), |
467 self.__migrationsDirectory(abspath=True), |
467 "versions", "*.py") |
468 "versions", "*.py") |
468 for fileName in glob.iglob(versionsPattern): |
469 for fileName in glob.iglob(versionsPattern): |
469 self.__e5project.appendFile(fileName) |
470 self.__ericProject.appendFile(fileName) |
470 |
471 |
471 ######################################################### |
472 ######################################################### |
472 ## slots to up- and downgrade a databse |
473 ## slots to up- and downgrade a databse |
473 ######################################################### |
474 ######################################################### |
474 |
475 |