diff --git a/qtgui/mainwindow.py b/qtgui/mainwindow.py index 3e1ce33..3f72063 100644 --- a/qtgui/mainwindow.py +++ b/qtgui/mainwindow.py @@ -22,7 +22,6 @@ along with this program. If not, see . import logging; logger = logging.getLogger(__name__); logger.info("import") #Standard Library -from sys import argv as sysargv from sys import exit as sysexit #Third Party @@ -50,7 +49,7 @@ from .waitdialog import WaitDialog from .resources import * from .settings import SettingsDialog from .jacktransport import JackTransportControls - +from .movesessionroot import xdgVersionChange api.eventLoop = EventLoop() @@ -164,6 +163,8 @@ class MainWindow(QtWidgets.QMainWindow): self.ui.stack_loaded_session.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.ui.stack_loaded_session.customContextMenuRequested.connect(self.customContextMenu) + #nsmd 1.6.0 + xdgVersionChange(self.qtApp) #Api Callbacks api.callbacks.sessionClosed.append(self.reactCallback_sessionClosed) diff --git a/qtgui/movesessionroot.py b/qtgui/movesessionroot.py new file mode 100644 index 0000000..775d106 --- /dev/null +++ b/qtgui/movesessionroot.py @@ -0,0 +1,160 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright 2022, Nils Hilbricht, Germany ( https://www.hilbricht.net ) + +This file is part of the Laborejo Software Suite ( https://www.laborejo.org ). + +This application 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 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + + +import logging; logger = logging.getLogger(__name__); logger.info("import") + +#Standard Library +import pathlib +from os import getenv, listdir, access, W_OK, R_OK, rmdir +from subprocess import check_output +from shutil import move as shutil_move +from sys import exit as sysexit +from sys import argv as sysargv +from uuid import uuid4 + + +#Third Party +from PyQt5 import QtCore, QtGui, QtWidgets +logger.info(f"PyQt Version: {QtCore.PYQT_VERSION_STR}") + + +def nsmVersionGreater160()->bool: + maj, min, patch = check_output(["nsmd", "--version"]).decode().split(" ")[1].rstrip("\n").split(".") + maj = int(maj) + min = int(min) + + if maj <= 1 and min < 6: + return False + else: + return True + +def xdgVersionChange(qtApp): + """Before we start the engine: + nsmd >= 1.6.0 changed the default session root from ~/NSM Sessions to XDG. + It will still prioritize the old path, if found. + We ask the user to move his files to the correct location now so that the engine can use it this run. + + This check can be made independently from any --session-root parameter and without nsmd started. + """ + + + if any("--session-root" in param for param in sysargv): + #This is not our problem anymore. + return + + if not nsmVersionGreater160(): + return #see docstring + + parent = qtApp.desktop() + + try: + oldexists = pathlib.Path("~/NSM Sessions").expanduser().exists() + except RuntimeError: #no home dir! + oldexists = False + + xdgdatahome = getenv("$XDG_DATA_HOME") + if not xdgdatahome: + try: + xdgdatahome = pathlib.Path("~/.local/share").expanduser() + except RuntimeError: #If there is no xdg env and no home dir let us crash and exit. + logger.error("There is neither $XDG_DATA_HOME nor a home directory! Cannot start in this environment") + #self._callSysExit(). Do not use this because it stores window settings, in a settings dir which might not be available under the circumstances above. + sysexit(0) #directly afterwards @atexit is handled, but this function does not return. + + if not oldexists: + return + + olddir = pathlib.Path("~/NSM Sessions").expanduser() + if not olddir.is_dir(): + logger.error(f"{olddir} exists but it not a directory. Cannot continue with moving session directories. Please handle it yourself.") + errorString = QtCore.QCoreApplication.translate("movesessionroot", "{} exists but it not a directory. Cannot continue with moving session directories. Please handle it yourself.".format(olddir)) + QtWidgets.QMessageBox.critical(parent, errorString) + return + newdir = pathlib.Path(xdgdatahome, "nsm") + newexists = newdir.exists() + + + title = QtCore.QCoreApplication.translate("movesessionroot", "Default session directory changed") + if newexists: #Must merge. + text = QtCore.QCoreApplication.translate("movesessionroot", "Detected both the new NSM 1.6.0 official session directory:\n{}\nAND the old one:\n{}\n\nDo you want Agordejo to move your old files and try to merge them with the new sessions? (Recommended)\n\nYou now have the chance to manually make a backup of your files before pressing 'Yes'".format(newdir, olddir)) + else: #Simply move. + text = QtCore.QCoreApplication.translate("movesessionroot", "With NSM version 1.6.0 the official session directory moved to:\n{}\nYou are still using the old one:\n\n{}\nDo you want Agordejo to move your files? (Recommended)\n\nYou now have the chance to manually make a backup of your files before pressing 'Yes'".format(newdir, olddir)) + + userAllowedMove = QtWidgets.QMessageBox.warning(parent, title, text, QtWidgets.QMessageBox.Yes|QtWidgets.QMessageBox.No) + if not userAllowedMove == QtWidgets.QMessageBox.Yes: + return + + #Test for read and write permissions + if not access(olddir, R_OK): + logger.error(f"{olddir} doesn't have READ permissions. Cannot continue with moving session directories. Please handle it yourself.") + t = QtCore.QCoreApplication.translate("movesessionroot", "{} doesn't have READ permissions.\nCannot continue moving session directories. Please handle it yourself.".format(olddir)) + QtWidgets.QMessageBox.critical(parent, title, t, QtWidgets.QMessageBox.Ok) + return + if not access(olddir, W_OK): + logger.error(f"{olddir} doesn't have WRITE permissions. Cannot continue with moving session directories. Please handle it yourself.") + t = QtCore.QCoreApplication.translate("movesessionroot", "{} doesn't have WRITE permissions.\nCannot continue moving session directories. Please handle it yourself.".format(olddir)) + QtWidgets.QMessageBox.critical(parent, title, t, QtWidgets.QMessageBox.Ok) + return + if newexists and not access(newdir, R_OK): + logger.error(f"{newdir} doesn't have READ permissions. Cannot continue with moving session directories. Please handle it yourself.") + t = QtCore.QCoreApplication.translate("movesessionroot", "{} doesn't have READ permissions.\nCannot continue moving session directories. Please handle it yourself.".format(newdir)) + QtWidgets.QMessageBox.critical(parent, title, t, QtWidgets.QMessageBox.Ok) + return + if newexists and not access(newdir, W_OK): + logger.error(f"{newdir} doesn't have WRITE permissions. Cannot continue with moving session directories. Please handle it yourself.") + t = QtCore.QCoreApplication.translate("movesessionroot", "{} doesn't have WRITE permissions.\nCannot continue moving session directories. Please handle it yourself.".format(newdir)) + QtWidgets.QMessageBox.critical(parent, title, t, QtWidgets.QMessageBox.Ok) + return + + #Tests done. Attempting to actually move the dir. + + if newexists: #We need to merge two directories + if not newdir.is_dir(): + logger.error(f"{newdir} exists but it not a directory. Cannot continue with moving session directories. Please handle it yourself.") + t = QtCore.QCoreApplication.translate("movesessionroot", "{} exists but it not a directory.\nCannot continue moving session directories. Please handle it yourself.".format(newdir)) + QtWidgets.QMessageBox.critical(parent, title, t, QtWidgets.QMessageBox.Ok) + return + + #Are the file conflicts? + oldlist = listdir(olddir) + newlist = listdir(newdir) + if set(oldlist).intersection( set(newlist) ): #Same sessions in both directory. We take the easy way out. + unique_newdir = pathlib.Path(newdir, "backup-" + str(uuid4())) + logger.info(f"Moving and renaming {olddir} to {unique_newdir} as new session root") + shutil_move(olddir, unique_newdir) #this moves and renames the old ~/NSM Sessions. It will disappear from the home dir. + else: #no. we can just move. But we need to move the contents, not the olddir itself into the newdir + for oldsession in oldlist: + shutil_move(pathlib.Path(olddir, oldsession), newdir) #this moves and renames the old ~/NSM Sessions. It will disappear from the home dir. + + else: #the new directory does not exist yet. We can move it. + logger.info(f"Moving and renaming {olddir} to {newdir} as new session root") + shutil_move(olddir, newdir) #this moves and renames the old ~/NSM Sessions. It will disappear from the home dir. + + #If for some reason the old dir is empty and still exists, do this: + if olddir.exists(): + try: + rmdir(olddir) #will raise OSError if not empty. + except OSError: + logger.error(f"We tried to move and merge {olddir} to {newdir} but afterwards the source directory was not empty. There is nothing we can do here. Please handle it yourself. Please look out for incomplete data.") + t = QtCore.QCoreApplication.translate("movesessionroot", "We tried to move and merge {} to {} but afterwards the source directory was not empty. There is nothing we can do here. Please handle it yourself. Please look out for incomplete data.".format(olddir, newdir)) + QtWidgets.QMessageBox.critical(parent, title, t, QtWidgets.QMessageBox.Ok) + return