Merge branch 'configdir' into 'dev'
Change config dir, offer to migrate See merge request mx-moment/moment!2
This commit is contained in:
commit
9752a2accb
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -16,6 +16,8 @@ dist
|
|||
Makefile
|
||||
mirage
|
||||
mirage.pro.user
|
||||
moment
|
||||
moment.pro.user
|
||||
*.AppImage
|
||||
|
||||
tags
|
||||
|
|
|
@ -27,7 +27,7 @@ QRC_FILE = $$BUILD_DIR/resources.qrc
|
|||
RESOURCES += $$QRC_FILE
|
||||
HEADERS += $$glob_filenames(*.h) submodules/hsluv-c/src/hsluv.h
|
||||
SOURCES += $$glob_filenames(*.cpp) submodules/hsluv-c/src/hsluv.c
|
||||
TARGET = mirage
|
||||
TARGET = moment
|
||||
|
||||
unix:!macx {
|
||||
LIBS += -lX11 -lXss
|
||||
|
@ -61,12 +61,12 @@ no-x11 {
|
|||
executables.files = $$TARGET
|
||||
|
||||
shortcuts.path = $$PREFIX/share/applications
|
||||
shortcuts.files = packaging/mirage.desktop
|
||||
shortcuts.files = packaging/moment.desktop
|
||||
|
||||
icons256.path = $$PREFIX/share/icons/hicolor/256x256/apps
|
||||
icons256.files = packaging/mirage.png
|
||||
icons256.files = packaging/moment.png
|
||||
|
||||
examples.path = $$PREFIX/share/examples/mirage
|
||||
examples.path = $$PREFIX/share/examples/moment
|
||||
examples.files = src/config/settings.py
|
||||
|
||||
INSTALLS += executables shortcuts icons256 examples
|
||||
|
@ -101,7 +101,7 @@ for(file, $$list($$glob_filenames(*.py))) {
|
|||
}
|
||||
|
||||
QMAKE_CLEAN *= $$MOC_DIR $$OBJECTS_DIR $$RCC_DIR $$PYCACHE_DIRS $$QRC_FILE
|
||||
QMAKE_CLEAN *= $$BUILD_DIR $$TARGET Makefile mirage.pro.user .qmake.stash
|
||||
QMAKE_CLEAN *= $$BUILD_DIR $$TARGET Makefile moment.pro.user .qmake.stash
|
||||
QMAKE_CLEAN *= $$glob_filenames(*.pyc, *.qmlc, *.jsc, *.egg-info)
|
||||
QMAKE_CLEAN *= packaging/flatpak/flatpak-env
|
||||
QMAKE_CLEAN *= packaging/flatpak/flatpak-pip-generator
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
"""This package provides Mirage's backend side that can interact with the UI.
|
||||
"""This package provides Moment's backend side that can interact with the UI.
|
||||
|
||||
To learn more about how this package works, you might want to check the
|
||||
documentation in the following modules first:
|
||||
|
@ -12,7 +12,7 @@ documentation in the following modules first:
|
|||
- `nio_callbacks`
|
||||
"""
|
||||
|
||||
__app_name__ = "mirage"
|
||||
__display_name__ = "Mirage"
|
||||
__reverse_dns__ = "io.github.mirukana.mirage"
|
||||
__app_name__ = "moment"
|
||||
__display_name__ = "Moment"
|
||||
__reverse_dns__ = "xyz.mx-moment"
|
||||
__version__ = "0.7.2"
|
||||
|
|
|
@ -104,7 +104,7 @@ class Backend:
|
|||
media_cache: A matrix media cache for downloaded files.
|
||||
|
||||
presences: A `{user_id: Presence}` dict for storing presence info about
|
||||
matrix users registered on Mirage.
|
||||
matrix users registered on Moment.
|
||||
|
||||
mxc_events: A dict storing media `Event` model items for any account
|
||||
that have the same mxc URI
|
||||
|
@ -137,7 +137,7 @@ class Backend:
|
|||
DefaultDict(asyncio.Lock) # {room_id: lock}
|
||||
|
||||
cache_dir = Path(
|
||||
os.environ.get("MIRAGE_CACHE_DIR") or self.appdirs.user_cache_dir,
|
||||
os.environ.get("MOMENT_CACHE_DIR") or self.appdirs.user_cache_dir,
|
||||
)
|
||||
|
||||
self.media_cache: MediaCache = MediaCache(self, cache_dir)
|
||||
|
|
|
@ -95,7 +95,7 @@ class Media:
|
|||
<base download folder>/<homeserver domain>/
|
||||
<file title>_<mxc id>.<file extension>`
|
||||
```
|
||||
e.g. `~/.cache/mirage/downloads/matrix.org/foo_Hm24ar11i768b0el.png`.
|
||||
e.g. `~/.cache/moment/downloads/matrix.org/foo_Hm24ar11i768b0el.png`.
|
||||
"""
|
||||
|
||||
parsed = urlparse(self.mxc)
|
||||
|
@ -304,7 +304,7 @@ class Thumbnail(Media):
|
|||
<file title>_<mxc id>.<file extension>`
|
||||
```
|
||||
e.g.
|
||||
`~/.cache/mirage/thumbnails/matrix.org/32x32/foo_Hm24ar11i768b0el.png`.
|
||||
`~/.cache/moment/thumbnails/matrix.org/32x32/foo_Hm24ar11i768b0el.png`.
|
||||
"""
|
||||
|
||||
size = self.normalize_size(self.server_size or self.wanted_size)
|
||||
|
|
|
@ -197,7 +197,7 @@ class ConfigFile(UserFile):
|
|||
@property
|
||||
def path(self) -> Path:
|
||||
return Path(
|
||||
os.environ.get("MIRAGE_CONFIG_DIR") or
|
||||
os.environ.get("MOMENT_CONFIG_DIR") or
|
||||
self.backend.appdirs.user_config_dir,
|
||||
) / self.filename
|
||||
|
||||
|
@ -209,7 +209,7 @@ class UserDataFile(UserFile):
|
|||
@property
|
||||
def path(self) -> Path:
|
||||
return Path(
|
||||
os.environ.get("MIRAGE_DATA_DIR") or
|
||||
os.environ.get("MOMENT_DATA_DIR") or
|
||||
self.backend.appdirs.user_data_dir,
|
||||
) / self.filename
|
||||
|
||||
|
@ -460,7 +460,7 @@ class NewTheme(UserDataFile, PCNFile):
|
|||
@property
|
||||
def path(self) -> Path:
|
||||
data_dir = Path(
|
||||
os.environ.get("MIRAGE_DATA_DIR") or
|
||||
os.environ.get("MOMENT_DATA_DIR") or
|
||||
self.backend.appdirs.user_data_dir,
|
||||
)
|
||||
return data_dir / "themes" / self.filename
|
||||
|
@ -515,7 +515,7 @@ class Theme(UserDataFile):
|
|||
@property
|
||||
def path(self) -> Path:
|
||||
data_dir = Path(
|
||||
os.environ.get("MIRAGE_DATA_DIR") or
|
||||
os.environ.get("MOMENT_DATA_DIR") or
|
||||
self.backend.appdirs.user_data_dir,
|
||||
)
|
||||
return data_dir / "themes" / self.filename
|
||||
|
|
|
@ -29,7 +29,7 @@ class General:
|
|||
# Can be the name of a built-in theme (Mirage.qpl or Glass.qpl), or
|
||||
# the name (including extension) of a file in the user theme folder, which
|
||||
# is "$XDG_DATA_HOME/mirage/themes" if that environment variable is set,
|
||||
# else "~/.local/share/mirage/themes".
|
||||
# else "~/.local/share/moment/themes".
|
||||
# For Flatpak, it is
|
||||
# "~/.var/app/io.github.mirukana.mirage/data/mirage/themes".
|
||||
theme: str = "Midnight.qpl"
|
||||
|
@ -204,7 +204,7 @@ class Chat:
|
|||
auto_play_gif: bool = True
|
||||
|
||||
# When clicking on a file in the timeline, open it in an external
|
||||
# program instead of displaying it using Mirage's interface.
|
||||
# program instead of displaying it using Moment's interface.
|
||||
# On Linux, the xdg-open command is called.
|
||||
click_opens_externally: bool = False
|
||||
|
||||
|
@ -234,7 +234,7 @@ class Keys:
|
|||
# would need to be pressed.
|
||||
#
|
||||
# A list of default bindings can be found at:
|
||||
# https://github.com/mirukana/mirage/blob/master/docs/KEYBINDINGS.md
|
||||
# https://gitlab.com/mx-moment/moment/-/blob/main/docs/KEYBINDINGS.md
|
||||
|
||||
# Helper functions
|
||||
|
||||
|
@ -280,7 +280,7 @@ class Keys:
|
|||
qml_console = ["F1"]
|
||||
|
||||
# Start the Python backend debugger.
|
||||
# Mirage must be connected to a terminal for this to work.
|
||||
# Moment must be connected to a terminal for this to work.
|
||||
python_debugger = ["Shift+F1"]
|
||||
|
||||
# Start the Python backend debugger in remote access mode.
|
||||
|
|
|
@ -18,9 +18,9 @@ QtObject {
|
|||
-h, --help Show this help and exit
|
||||
|
||||
Environment variables:
|
||||
MIRAGE_CONFIG_DIR Override the default configuration folder
|
||||
MIRAGE_DATA_DIR Override the default application data folder
|
||||
MIRAGE_CACHE_DIR Override the default cache and downloads folder
|
||||
MOMENT_CONFIG_DIR Override the default configuration folder
|
||||
MOMENT_DATA_DIR Override the default application data folder
|
||||
MOMENT_CACHE_DIR Override the default cache and downloads folder
|
||||
http_proxy Override the General.proxy setting, see settings.py
|
||||
`
|
||||
|
||||
|
|
247
src/main.cpp
247
src/main.cpp
|
@ -17,6 +17,7 @@
|
|||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QLockFile>
|
||||
#include <QMessageBox>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
|
@ -97,6 +98,236 @@ void onExitSignal(int signum) {
|
|||
}
|
||||
|
||||
|
||||
void migrateFile(QDir source, QDir destination, QString fname) {
|
||||
if (! QFile::copy(source.filePath(fname), destination.filePath(fname)))
|
||||
qWarning() << "Could not migrate" << fname;
|
||||
}
|
||||
|
||||
|
||||
void migrateShallowDirectory(
|
||||
QDir sourceParent, QDir destinationParent, QString dname
|
||||
) {
|
||||
if (sourceParent.exists(dname)) {
|
||||
if (! destinationParent.mkpath(dname)) {
|
||||
qWarning() << "Could not create directory"
|
||||
<< destinationParent.filePath(dname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
QDir source(sourceParent.filePath(dname));
|
||||
QDir destination(destinationParent.filePath(dname));
|
||||
QFileInfoList files = source.entryInfoList();
|
||||
for (QFileInfo file : files) {
|
||||
if(file.fileName() == "." || file.fileName() == "..")
|
||||
continue;
|
||||
migrateFile(source, destination, file.fileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void offerMigrateFromMirage(
|
||||
QDir configDirMoment, QDir configDirMirage,
|
||||
QDir dataDirMoment, QDir dataDirMirage
|
||||
) {
|
||||
QMessageBox dialog;
|
||||
dialog.setText("Would you like Moment to re-use your logins, "
|
||||
"encryption keys, configuration and themes from Mirage?");
|
||||
dialog.setInformativeText(
|
||||
"Will copy "+configDirMirage.path()+" → "+configDirMoment.path()
|
||||
+"\nWill copy "+dataDirMirage.path()+" → "+dataDirMoment.path());
|
||||
dialog.addButton(QMessageBox::Yes);
|
||||
dialog.addButton(QMessageBox::No);
|
||||
dialog.addButton(QMessageBox::Cancel);
|
||||
int result = dialog.exec();
|
||||
if (result == QMessageBox::Yes) {
|
||||
qWarning("Migrating config and data from Mirage");
|
||||
if (! configDirMoment.mkpath(".")) {
|
||||
qFatal("Could not create config directory");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (! dataDirMoment.mkpath(".")) {
|
||||
qFatal("Could not create data directory");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
migrateFile(configDirMirage, configDirMoment, "settings.py");
|
||||
migrateFile(configDirMirage, configDirMoment, "settings.gui.json");
|
||||
migrateFile(configDirMirage, configDirMoment, "accounts.json");
|
||||
migrateFile(dataDirMirage, dataDirMoment, "history.json");
|
||||
migrateFile(dataDirMirage, dataDirMoment, "state.json");
|
||||
migrateShallowDirectory(dataDirMirage, dataDirMoment, "themes");
|
||||
migrateShallowDirectory(dataDirMirage, dataDirMoment, "encryption");
|
||||
} else if (result == QMessageBox::No) {
|
||||
// Nothing to do. Proceed with starting the app
|
||||
qWarning("Not migrating");
|
||||
return;
|
||||
} else {
|
||||
// Neither "Yes" nor "No" was chosen.
|
||||
// We can't know what the user wants. Just quit.
|
||||
qWarning("Quitting. You can decide about migration next time.");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool shouldMigrateFromMirage() {
|
||||
QString genericConfig = QStandardPaths::writableLocation(
|
||||
QStandardPaths::GenericConfigLocation);
|
||||
QString genericData = QStandardPaths::writableLocation(
|
||||
QStandardPaths::GenericDataLocation);
|
||||
|
||||
// Check whether Moment config already exists
|
||||
{
|
||||
QString customConfigDirMoment(
|
||||
qEnvironmentVariable("MOMENT_CONFIG_DIR")
|
||||
);
|
||||
if (! customConfigDirMoment.isEmpty()) {
|
||||
// MOMENT_CONFIG_DIR is set.
|
||||
// Moment would definitely use this as the config directory.
|
||||
if (QDir(customConfigDirMoment).exists())
|
||||
// But it already exists.
|
||||
// So this is not the first time Moment was started.
|
||||
return false;
|
||||
} else {
|
||||
// No MOMENT_CONFIG_DIR, so check the default config directory.
|
||||
if (QDir(genericConfig + "/moment").exists())
|
||||
// The default config folder exists.
|
||||
// So this is not the first time Moment was started.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether Moment data already exists
|
||||
{
|
||||
QString customDataDirMoment(qEnvironmentVariable("MOMENT_DATA_DIR"));
|
||||
if (! customDataDirMoment.isEmpty()) {
|
||||
// MOMENT_DATA_DIR is set.
|
||||
// Moment would definitely use this as the data directory.
|
||||
if (QDir(customDataDirMoment).exists())
|
||||
// But it already exists.
|
||||
// So this is not the first time Moment was started.
|
||||
return false;
|
||||
} else {
|
||||
// No MOMENT_DATA_DIR, so check the default data directory.
|
||||
if (QDir(genericData + "/moment").exists())
|
||||
// The default data folder exists.
|
||||
// So this is not the first time Moment was started.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether Mirage config exists
|
||||
{
|
||||
QString customConfigDirMirage(
|
||||
qEnvironmentVariable("MIRAGE_CONFIG_DIR")
|
||||
);
|
||||
if (! customConfigDirMirage.isEmpty()) {
|
||||
// MIRAGE_CONFIG_DIR is set.
|
||||
// Mirage would definitely use this as the config directory.
|
||||
if (! QDir(customConfigDirMirage).exists())
|
||||
// But this directory does not exist.
|
||||
// So there is nowhere to migrate from.
|
||||
return false;
|
||||
} else {
|
||||
// No MIRAGE_CONFIG_DIR, so check the default config directory.
|
||||
// Check /matrix-mirage (Debian) first, since it is more specific
|
||||
if (! QDir(genericConfig + "/matrix-mirage").exists())
|
||||
// Default Debian config folder does not exist,
|
||||
// so check whether the normal /mirage exists
|
||||
if (! QDir(genericConfig + "/mirage").exists())
|
||||
// No, neither /matrix-mirage nor /mirage exist.
|
||||
// So there is nowhere to migrate from.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We found out that there is no Moment config dir nor Moment data dir,
|
||||
// but there is a Mirage config dir which can be migrated from.
|
||||
// We could also check for Mirage data dir but it doesn't really matter.
|
||||
// User should definitely be prompted for migration.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void tryMigrateFromMirage() {
|
||||
QString genericConfig = QStandardPaths::writableLocation(
|
||||
QStandardPaths::GenericConfigLocation);
|
||||
QString genericData = QStandardPaths::writableLocation(
|
||||
QStandardPaths::GenericDataLocation);
|
||||
|
||||
QDir configDirMoment, configDirMirage, dataDirMoment, dataDirMirage;
|
||||
|
||||
QString customConfigDirMoment(qEnvironmentVariable("MOMENT_CONFIG_DIR"));
|
||||
configDirMoment = QDir(customConfigDirMoment.isEmpty()
|
||||
? genericConfig + "/moment" : customConfigDirMoment);
|
||||
|
||||
QString customDataDirMoment(qEnvironmentVariable("MOMENT_DATA_DIR"));
|
||||
dataDirMoment = QDir(customDataDirMoment.isEmpty()
|
||||
? genericData + "/moment" : customDataDirMoment);
|
||||
|
||||
QString customConfigDirMirage(qEnvironmentVariable("MIRAGE_CONFIG_DIR"));
|
||||
if (! customConfigDirMirage.isEmpty()) {
|
||||
// MIRAGE_CONFIG_DIR is set.
|
||||
// Mirage would definitely use this as the config directory.
|
||||
// So this is where we should migrate from.
|
||||
configDirMirage = QDir(customConfigDirMirage);
|
||||
} else {
|
||||
// No MIRAGE_CONFIG_DIR.
|
||||
// Check if Mirage default config directory exists
|
||||
// Check /matrix-mirage (Debian) first
|
||||
QDir dirDeb(genericConfig + "/matrix-mirage");
|
||||
if (dirDeb.exists()) {
|
||||
// Default Debian config dir exists.
|
||||
// So this is where we should migrate from.
|
||||
configDirMirage = dirDeb;
|
||||
} else {
|
||||
// No /matrix-mirage found, so check /mirage
|
||||
QDir dir(genericConfig + "/mirage");
|
||||
if (dir.exists())
|
||||
// Default config dir exists.
|
||||
// So this is where we should migrate from.
|
||||
configDirMirage = dir;
|
||||
else
|
||||
// No Mirage config dir found.
|
||||
// Do not migrate.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QString customDataDirMirage(qEnvironmentVariable("MIRAGE_DATA_DIR"));
|
||||
if (! customDataDirMirage.isEmpty()) {
|
||||
// MIRAGE_DATA_DIR is set.
|
||||
// Mirage would definitely use this as the data directory.
|
||||
// So this is where we should migrate from.
|
||||
dataDirMirage = QDir(customDataDirMirage);
|
||||
} else {
|
||||
// No MIRAGE_DATA_DIR.
|
||||
// Check if Mirage default data directory exists
|
||||
// Check /matrix-mirage (Debian) first
|
||||
QDir dirDeb(genericData + "/matrix-mirage");
|
||||
if (dirDeb.exists()) {
|
||||
// Default Debian data dir exists.
|
||||
// So this is where we should migrate from.
|
||||
dataDirMirage = dirDeb;
|
||||
} else {
|
||||
// No /matrix-mirage found, so check /mirage
|
||||
QDir dir(genericData + "/mirage");
|
||||
if (dir.exists())
|
||||
// Default data dir exists.
|
||||
// So this is where we should migrate from.
|
||||
dataDirMirage = dir;
|
||||
else
|
||||
// No Mirage data dir found.
|
||||
// Do not migrate.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
offerMigrateFromMirage(
|
||||
configDirMoment, configDirMirage, dataDirMoment, dataDirMirage
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
bool setLockFile(QString configPath) {
|
||||
|
||||
QDir settingsFolder(configPath);
|
||||
|
@ -130,13 +361,19 @@ int main(int argc, char *argv[]) {
|
|||
qInstallMessageHandler(loggingHandler);
|
||||
|
||||
// Define some basic info about the app before creating the QApplication
|
||||
QApplication::setOrganizationName("mirage");
|
||||
QApplication::setApplicationName("mirage");
|
||||
QApplication::setApplicationDisplayName("Mirage");
|
||||
QApplication::setOrganizationName("moment");
|
||||
QApplication::setApplicationName("moment");
|
||||
QApplication::setApplicationDisplayName("Moment");
|
||||
QApplication::setApplicationVersion("0.7.2");
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
|
||||
QString customConfigDir(qEnvironmentVariable("MIRAGE_CONFIG_DIR"));
|
||||
// app needs to be constructed before attempting to migrate
|
||||
// because migrate displays a popup dialog
|
||||
QApplication app(argc, argv);
|
||||
|
||||
if (shouldMigrateFromMirage()) tryMigrateFromMirage();
|
||||
|
||||
QString customConfigDir(qEnvironmentVariable("MOMENT_CONFIG_DIR"));
|
||||
QString settingsFolder(
|
||||
customConfigDir.isEmpty() ?
|
||||
QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)
|
||||
|
@ -144,8 +381,8 @@ int main(int argc, char *argv[]) {
|
|||
customConfigDir
|
||||
);
|
||||
|
||||
// Attempt to create a lockfile in the settings folder
|
||||
if (! setLockFile(settingsFolder)) return EXIT_SUCCESS;
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// Register handlers for quit signals, e.g. SIGINT/Ctrl-C in unix terminals
|
||||
signal(SIGINT, onExitSignal);
|
||||
|
|
Loading…
Reference in New Issue
Block a user