feat: Implement occupied directories handling during data copy (#7485)

* feat: Implement occupied directories handling during data copy

- Added `occupiedDirs` constant to manage directories that should not be copied.
- Enhanced the `copyOccupiedDirsInMainProcess` function to copy occupied directories to a new app data path in the main process.
- Updated IPC and preload APIs to support passing occupied directories during the copy operation.
- Modified the DataSettings component to utilize the new copy functionality with occupied directories.

* fix: Improve occupied directories handling during data copy

- Updated the filter logic in the `registerIpc` function to resolve directory paths correctly.
- Modified the `DataSettings` component to pass the correct occupied directories format during the copy operation.
This commit is contained in:
beyondkmp 2025-06-25 00:39:28 +08:00 committed by GitHub
parent becb6543e0
commit 3640d846b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 48 additions and 4 deletions

View File

@ -409,3 +409,5 @@ export enum FeedUrl {
EARLY_ACCESS = 'https://github.com/CherryHQ/cherry-studio/releases/latest/download'
}
export const defaultTimeout = 5 * 1000 * 60
export const occupiedDirs = ['logs', 'Network', 'Partitions/webview/Network']

View File

@ -1,5 +1,33 @@
import { occupiedDirs } from '@shared/config/constant'
import { app } from 'electron'
import fs from 'fs'
import path from 'path'
import { initAppDataDir } from './utils/file'
app.isPackaged && initAppDataDir()
// 在主进程中复制 appData 中某些一直被占用的文件
// 在renderer进程还没有启动时主进程可以复制这些文件到新的appData中
function copyOccupiedDirsInMainProcess() {
const newAppDataPath = process.argv
.slice(1)
.find((arg) => arg.startsWith('--new-data-path='))
?.split('--new-data-path=')[1]
if (!newAppDataPath) {
return
}
if (process.platform === 'win32') {
const appDataPath = app.getPath('userData')
occupiedDirs.forEach((dir) => {
const dirPath = path.join(appDataPath, dir)
const newDirPath = path.join(newAppDataPath, dir)
if (fs.existsSync(dirPath)) {
fs.cpSync(dirPath, newDirPath, { recursive: true })
}
})
}
}
copyOccupiedDirsInMainProcess()

View File

@ -269,9 +269,17 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
})
// Copy user data to new location
ipcMain.handle(IpcChannel.App_Copy, async (_, oldPath: string, newPath: string) => {
ipcMain.handle(IpcChannel.App_Copy, async (_, oldPath: string, newPath: string, occupiedDirs: string[] = []) => {
try {
await fs.promises.cp(oldPath, newPath, { recursive: true })
await fs.promises.cp(oldPath, newPath, {
recursive: true,
filter: (src) => {
if (occupiedDirs.some((dir) => src.startsWith(path.resolve(dir)))) {
return false
}
return true
}
})
return { success: true }
} catch (error: any) {
log.error('Failed to copy user data:', error)

View File

@ -32,7 +32,8 @@ const api = {
hasWritePermission: (path: string) => ipcRenderer.invoke(IpcChannel.App_HasWritePermission, path),
setAppDataPath: (path: string) => ipcRenderer.invoke(IpcChannel.App_SetAppDataPath, path),
getDataPathFromArgs: () => ipcRenderer.invoke(IpcChannel.App_GetDataPathFromArgs),
copy: (oldPath: string, newPath: string) => ipcRenderer.invoke(IpcChannel.App_Copy, oldPath, newPath),
copy: (oldPath: string, newPath: string, occupiedDirs: string[] = []) =>
ipcRenderer.invoke(IpcChannel.App_Copy, oldPath, newPath, occupiedDirs),
setStopQuitApp: (stop: boolean, reason: string) => ipcRenderer.invoke(IpcChannel.App_SetStopQuitApp, stop, reason),
flushAppData: () => ipcRenderer.invoke(IpcChannel.App_FlushAppData),
isNotEmptyDir: (path: string) => ipcRenderer.invoke(IpcChannel.App_IsNotEmptyDir, path),

View File

@ -19,6 +19,7 @@ import store, { useAppDispatch } from '@renderer/store'
import { setSkipBackupFile as _setSkipBackupFile } from '@renderer/store/settings'
import { AppInfo } from '@renderer/types'
import { formatFileSize } from '@renderer/utils'
import { occupiedDirs } from '@shared/config/constant'
import { Button, Progress, Switch, Typography } from 'antd'
import { FileText, FolderCog, FolderInput, Sparkle } from 'lucide-react'
import { FC, useEffect, useState } from 'react'
@ -500,7 +501,11 @@ const DataSettings: FC = () => {
await new Promise((resolve) => setTimeout(resolve, 2000))
// 开始复制过程
const copyResult = await window.api.copy(originalPath, newPath)
const copyResult = await window.api.copy(
originalPath,
newPath,
occupiedDirs.map((dir) => originalPath + '/' + dir)
)
// 停止进度更新
if (progressInterval) {