Conversation
|
82181cc to
8f83bd3
Compare
8f83bd3 to
2a21520
Compare
It should cover upgrade, downgrade as well as upgrade from unbranded to branded, from legacy to branded and from legacy to unbranded. Signed-off-by: Camila Ayres <hello@camilasan.com>
Signed-off-by: Camila Ayres <hello@camilasan.com>
If no legacy file is found, it means it might be upgrade only. Signed-off-by: Camila Ayres <hello@camilasan.com>
…to ConfigFile. Signed-off-by: Camila Ayres <hello@camilasan.com>
…n class. - Make all Migration class members static. - Rename Migration class members. Signed-off-by: Camila Ayres <hello@camilasan.com>
Signed-off-by: Camila Ayres <hello@camilasan.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors client migration logic by moving migration state/decision-making out of ConfigFile into a new OCC::Migration helper, and wires it through GUI/libsync code paths. It also adds a new unit test target for migration behavior.
Changes:
- Introduces
src/libsync/settings/migration.{h,cpp}and updates build/test wiring. - Replaces
ConfigFilemigration helpers withMigrationusage across Application/AccountManager/AccountState/FolderMan. - Adds
ConfigFile::backupConfigFiles()and a newMigrationtest.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| test/testmigration.cpp | Adds a new migration-focused test (currently with correctness issues). |
| test/CMakeLists.txt | Registers the new Migration test target. |
| src/libsync/settings/migration.h | Declares new Migration API and static migration state. |
| src/libsync/settings/migration.cpp | Implements version checks and legacy config discovery. |
| src/libsync/configfile.h | Removes old migration API surface; adds backupConfigFiles(). |
| src/libsync/configfile.cpp | Switches to Migration for branded/unbranded checks; adds backupConfigFiles(). |
| src/libsync/CMakeLists.txt | Adds new migration sources to libsync build. |
| src/gui/folderman.h | Adds TestMigration friend declaration. |
| src/gui/folderman.cpp | Uses Migration::discoveredLegacyConfigPath() for folder migration path selection. |
| src/gui/application.cpp | Uses Migration phases/flags during config migration and setup flow. |
| src/gui/accountstate.cpp | Uses Migration for branded/unbranded migration keychain handling and phase completion. |
| src/gui/accountmanager.cpp | Refactors legacy-settings restore flow to use Migration::legacyData(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| && !AccountManager::instance()->forceLegacyImport() | ||
| && accountsListSize > 0) { |
There was a problem hiding this comment.
The condition redundantly checks accountsListSize > 0 twice. Drop the duplicate to keep the logic minimal and avoid mistakes when editing this condition later.
| && !AccountManager::instance()->forceLegacyImport() | |
| && accountsListSize > 0) { | |
| && !AccountManager::instance()->forceLegacyImport()) { |
| folderDefinition.localPath = "/standardAppName"; | ||
| folderDefinition.targetPath = "/"; |
There was a problem hiding this comment.
folderDefinition.localPath is set to the literal "/standardAppName", which won’t exist on most systems. Since Folder::checkLocalPath() requires the directory to exist and be readable, this will make the test fail in CI. Use a path under _temporaryDir.path() (and mkpath it) for the local sync folder.
| folderDefinition.localPath = "/standardAppName"; | |
| folderDefinition.targetPath = "/"; | |
| const auto localPath = _temporaryDir.path() + QLatin1Char('/') + QLatin1String(standardAppName); | |
| QVERIFY(QDir().mkpath(localPath)); | |
| folderDefinition.localPath = localPath; | |
| folderDefinition.targetPath = QLatin1String("/"); |
| "0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\ignoreHiddenFiles=true\n" | ||
| "0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\journalPath=.sync_journal.db\n" | ||
| "0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\localPath=/ownCloud/\n" | ||
| "0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\paused=false\n" |
There was a problem hiding this comment.
Several lines in legacyAppConfigContent use a single backslash before 2ba... (e.g. "0\\Folders\2ba..."). In C++ string literals \2 is interpreted as an octal escape, so the resulting INI content is corrupted. Escape the backslashes consistently (use \\ where you want a literal \ in the INI).
| "0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\ignoreHiddenFiles=true\n" | |
| "0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\journalPath=.sync_journal.db\n" | |
| "0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\localPath=/ownCloud/\n" | |
| "0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\paused=false\n" | |
| "0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\ignoreHiddenFiles=true\n" | |
| "0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\journalPath=.sync_journal.db\n" | |
| "0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\localPath=/ownCloud/\n" | |
| "0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\paused=false\n" |
| qCDebug(lcMigration) << "Copy settings" << oCSettings->allKeys().join(", "); | ||
| Migration migration; | ||
| migration.setDiscoveredLegacyConfigPath(configFileInfo.canonicalPath()); | ||
| legacyData.reset(oCSettings.get()); |
There was a problem hiding this comment.
legacyData.reset(oCSettings.get()) assigns a raw pointer still owned by std::unique_ptr<QSettings> oCSettings, which will be deleted at scope exit. This results in double-delete / use-after-free. Transfer ownership explicitly (e.g., construct the shared pointer from oCSettings.release()), or avoid mixing unique_ptr and QSharedPointer here.
| legacyData.reset(oCSettings.get()); | |
| legacyData.reset(oCSettings.release()); |
| _configFile.setConfDir(standardConfigFolder); | ||
| } | ||
|
|
||
| void setupStandarConfig(const QString &version) |
There was a problem hiding this comment.
Function name typo: setupStandarConfig (missing ‘d’) makes the test harder to read/search and looks unintentional. Rename to setupStandardConfig (and update call sites).
| void setupStandarConfig(const QString &version) | |
| void setupStandardConfig(const QString &version) |
| _configFile.setOverrideLocalDir("A"); | ||
| _configFile.setVfsEnabled(true); | ||
| _configFile.setProxyType(0); | ||
| _configFile.setVfsEnabled(true); |
There was a problem hiding this comment.
Duplicate call: setVfsEnabled(true) is invoked twice (lines 96 and 98). Remove the redundant call to keep the test setup clear.
| _configFile.setVfsEnabled(true); |
| _configFile.setConfDir(standardConfigFolder); | ||
| } | ||
|
|
||
| void setupStandarConfig(const QString &version) |
There was a problem hiding this comment.
Function name typo: setupStandarConfig (missing ‘d’) makes the test harder to read/search and looks unintentional. Rename to setupStandardConfig (and update call sites).
| void setupStandarConfig(const QString &version) | |
| void setupStandardConfig(const QString &version) |
| "logHttp=false\n" | ||
| "optionalDesktopNotifications=true\n" | ||
| "\n" | ||
| "[Accounts]e\n" |
There was a problem hiding this comment.
legacyAppConfigContent has a typo in the INI section header: "[Accounts]e" includes an extra e, which will break parsing if this test data is used. Remove the stray character.
| "[Accounts]e\n" | |
| "[Accounts]\n" |
| }; | ||
|
|
||
| using LegacyData = QSharedPointer<QSettings>; | ||
|
|
There was a problem hiding this comment.
Migration::LegacyData is QSharedPointer<QSettings>, but this header doesn’t include <QSharedPointer>. Depending on include order this can fail to compile. Add the missing include (and consider dropping unused includes like <QMap> if not needed).
| } | ||
|
|
||
| settings.reset(oCSettings.get()); | ||
| } |
There was a problem hiding this comment.
settings.reset(oCSettings.get()) makes the std::unique_ptr take ownership of a pointer that is still owned by oCSettings (QSharedPointer). This will lead to double deletion. Use a single ownership model (e.g., keep settings as a shared pointer, or have Migration::legacyData() return a std::unique_ptr<QSettings> and move it into settings) instead of resetting from get().
Signed-off-by: Camila Ayres <hello@camilasan.com>
Signed-off-by: Camila Ayres <hello@camilasan.com>
|
Artifact containing the AppImage: nextcloud-appimage-pr-9191.zip Digest: To test this change/fix you can download the above artifact file, unzip it, and run it. Please make sure to quit your existing Nextcloud app and backup your data. |
|




Replaces work in #8154.
It moves code around and add some very basics tests. More work is needed to be able to fully cover the logic with tests.
desktop/src/libsync/settings/migration.h
Lines 48 to 59 in 2539f95