From 96456623180ecfaf4cb5ecb0aed8b54aad3ad0c9 Mon Sep 17 00:00:00 2001 From: dudu Date: Sun, 17 Dec 2023 23:01:17 +0800 Subject: [PATCH] refactor: post pull --- src/cmd/post-list/open-post-file.ts | 13 +- src/cmd/post-list/open-post-in-vscode.ts | 62 +++------- src/cmd/post-list/post-pull.ts | 144 +++++++++++------------ src/infra/fs/fsUtil.ts | 4 +- src/service/post/post-file-map.ts | 4 + 5 files changed, 100 insertions(+), 127 deletions(-) diff --git a/src/cmd/post-list/open-post-file.ts b/src/cmd/post-list/open-post-file.ts index 5cc3b972..2bd53870 100644 --- a/src/cmd/post-list/open-post-file.ts +++ b/src/cmd/post-list/open-post-file.ts @@ -6,7 +6,6 @@ import { LocalPost } from '@/service/local-post' import { fsUtil } from '@/infra/fs/fsUtil' import { postPull } from './post-pull' import { Alert } from '@/infra/alert' -import { WorkspaceCfg } from '@/ctx/cfg/workspace' export async function openPostFile( post: LocalPost | Post | string, @@ -18,15 +17,17 @@ export async function openPostFile( filePath = post.filePath } else if (post instanceof Post) { filePath = PostFileMapManager.getFilePath(post.id) ?? '' - if (autoPull) { - if (!(await fsUtil.exists(filePath)) || filePath.indexOf(WorkspaceCfg.getWorkspaceUri().path) < 0) - await postPull(post, false, true) - } + console.log('filePath: ' + filePath) + console.log('file exists: ' + (await fsUtil.exists(filePath))) + if (autoPull && filePath.length > 0) if (!(await fsUtil.exists(filePath))) await postPull(post, true, true) } else { filePath = post } - if (filePath === '') return + if (filePath === '') { + void Alert.warn('filePath is empty') + return + } if (!(await fsUtil.exists(filePath))) await new Promise(f => setTimeout(f, 200)) diff --git a/src/cmd/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts index 11241538..7e00a732 100644 --- a/src/cmd/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -1,13 +1,12 @@ -import path from 'path' -import { FileSystemError, Uri, workspace } from 'vscode' +import { Uri } from 'vscode' import { Post } from '@/model/post' import { Alert } from '@/infra/alert' -import { PostService } from '@/service/post/post' import { PostFileMapManager } from '@/service/post/post-file-map' import { openPostFile } from './open-post-file' import sanitizeFileName from 'sanitize-filename' import { WorkspaceCfg } from '@/ctx/cfg/workspace' import { fsUtil } from '@/infra/fs/fsUtil' +import { postPull } from './post-pull' export function buildLocalPostFileUri(post: Post, appendToFileName = ''): Uri { const workspaceUri = WorkspaceCfg.getWorkspaceUri() @@ -17,54 +16,25 @@ export function buildLocalPostFileUri(post: Post, appendToFileName = ''): Uri { return Uri.joinPath(workspaceUri, `${postTitle}${appendToFileName}.${post.id}.${ext}`) } -export async function openPostInVscode(postId: number, forceUpdateLocalPostFile = false): Promise { - const mappedPostFilePath = PostFileMapManager.getFilePath(postId) +export async function openPostInVscode(postId: number): Promise { + const mappedPostFilePath = await getMappedPostFilePath(postId) - const isFileExist = mappedPostFilePath !== undefined && (await fsUtil.exists(mappedPostFilePath)) - if (mappedPostFilePath !== undefined && isFileExist && !forceUpdateLocalPostFile) { - await openPostFile(mappedPostFilePath) - return Uri.file(mappedPostFilePath) + if (mappedPostFilePath == null) { + void Alert.err(`博文缺少本地关联文件,postId: ${postId}`) + return } - // 本地文件已经被删除了, 确保重新生成博文与本地文件的关联 - if (mappedPostFilePath !== undefined && !isFileExist) - await PostFileMapManager.updateOrCreate(postId, mappedPostFilePath) - - const { post } = await PostService.getPostEditDto(postId) - - const workspaceUri = WorkspaceCfg.getWorkspaceUri() - await mkDirIfNotExist(workspaceUri) - let fileUri = mappedPostFilePath !== undefined ? Uri.file(mappedPostFilePath) : buildLocalPostFileUri(post) - - // 博文尚未关联到本地文件的情况 - // 本地存在和博文同名的文件, 询问用户是要覆盖还是同时保留两者 - if (mappedPostFilePath === undefined && (await fsUtil.exists(fileUri.fsPath))) { - const opt = ['保留本地文件并新建另一个文件', '覆盖本地文件'] - const selected = await Alert.info( - `无法建立博文与本地文件的关联, 文件名冲突`, - { detail: `本地已存在名为 ${path.basename(fileUri.fsPath)} 的文件`, modal: true }, - ...opt - ) - - if (selected === opt[0]) fileUri = buildLocalPostFileUri(post, '-new') + if (!(await fsUtil.exists(mappedPostFilePath))) { + void Alert.err(`博文关联的本地文件不存在,postId: ${postId},path: ${mappedPostFilePath}`) + return } - // 博文内容写入本地文件, 若文件不存在, 会自动创建对应的文件 - await workspace.fs.writeFile(fileUri, Buffer.from(post.postBody)) - await PostFileMapManager.updateOrCreate(postId, fileUri.path) - await openPostFile(post) - return fileUri + await openPostFile(mappedPostFilePath) + return Uri.file(mappedPostFilePath) } -async function mkDirIfNotExist(uri: Uri) { - try { - await workspace.fs.stat(uri) - } catch (err) { - try { - if (err instanceof FileSystemError) await workspace.fs.createDirectory(uri) - } catch (e) { - void Alert.err(`创建目录失败: ${e}`) - throw e - } - } +async function getMappedPostFilePath(postId: number) { + const mappedPostFilePath = PostFileMapManager.getFilePath(postId) + if (mappedPostFilePath != null && (await fsUtil.exists(mappedPostFilePath))) return mappedPostFilePath + if (await postPull(postId, true, true)) return PostFileMapManager.getFilePath(postId) } diff --git a/src/cmd/post-list/post-pull.ts b/src/cmd/post-list/post-pull.ts index 40113f81..e4cfe5b8 100644 --- a/src/cmd/post-list/post-pull.ts +++ b/src/cmd/post-list/post-pull.ts @@ -11,74 +11,86 @@ import { MarkdownCfg } from '@/ctx/cfg/markdown' import { fsUtil } from '@/infra/fs/fsUtil' import { searchPostByTitle } from '@/service/post/search-post-by-title' -export async function postPull(input: Post | PostTreeItem | Uri | undefined | null, showConfirm = true, mute = false) { - const ctxList: CmdCtx[] = [] - let isFreshPull = false - input = input instanceof PostTreeItem ? input.post : input - if (parsePostInput(input) && input.id > 0) { - const post = input - const path = PostFileMapManager.getFilePath(post.id) - if (path === undefined || !(await fsUtil.exists(path))) { - isFreshPull = true - const uri = buildLocalPostFileUri(post) - await workspace.fs.writeFile(uri, Buffer.from(post.postBody)) - await PostFileMapManager.updateOrCreate(post.id, uri.path) - await handlePostInput(input, ctxList, uri.path) - } else { - isFreshPull = !(await fsUtil.exists(path)) - if (!path.startsWith('/')) await PostFileMapManager.updateOrCreate(post.id, Uri.file(path).path) - await handlePostInput(input, ctxList, path) - } - } else { - const uri = parseUriInput(input) - if (uri != null) await handleUriInput(uri, ctxList) +type InputType = Post | PostTreeItem | Uri | number | undefined | null + +async function getPostId(input: InputType): Promise { + if (typeof input === 'number') return input + if (input instanceof Post && input.id > 0) return input.id + if (input instanceof PostTreeItem && input.post.id > 0) return input.post.id + if (input instanceof Uri) { + const postId = await getPostIdFromUri(input) + return postId } - const fileName = resolveFileNames(ctxList) - - if (showConfirm && !isFreshPull && MarkdownCfg.isShowConfirmMsgWhenPullPost()) { - const answer = await Alert.warn( - '确认要拉取远程博文吗?', - { - modal: true, - detail: `本地文件「${fileName}」将被覆盖(可通过设置关闭对话框)`, - }, - '确认' - ) - if (answer !== '确认') return + const doc = window.activeTextEditor?.document + if (doc != null && !doc.isUntitled) { + const postId = await getPostIdFromUri(doc.uri) + return postId } +} - if (ctxList.length <= 0) return +export async function postPull(input: InputType, showConfirm = true, mute = false): Promise { + let isFreshPull = false + let post: Post | null = null - await update(ctxList) + const postId = await getPostId(input) + if (postId == null) { + void Alert.err(`无效的额 postId,值为 ${postId}`) + return false + } - if (!mute) { - if (isFreshPull) await Alert.info(`博文已下载至本地:${resolveFileNames(ctxList)}`) - else await Alert.info(`本地文件已更新: ${resolveFileNames(ctxList)}`) + post = (await PostService.getPostEditDto(postId))?.post + if (post == null) { + void Alert.err(`对应的博文不存在,postId: ${postId}`) + return false } -} -type InputType = Post | Uri | undefined | null -type CmdCtx = { - postId: number - fileUri: Uri -} + let uriPath = PostFileMapManager.getFilePath(post.id) + let fileUri: Uri + if (uriPath == null) { + fileUri = buildLocalPostFileUri(post) + } else { + // replace fsPath with uriPath + if (!uriPath.startsWith('/')) uriPath = Uri.file(uriPath).path + if (!PostFileMapManager.isInWorkspace(uriPath)) fileUri = buildLocalPostFileUri(post) + else fileUri = Uri.parse(uriPath) + } -const parsePostInput = (input: InputType): input is Post => input instanceof Post + uriPath = fileUri.path + const fsPath = fileUri.fsPath + const fileName = path.basename(fsPath) + // eslint-disable-next-line @typescript-eslint/naming-convention + const fileExists = await fsUtil.exists(fsPath) + + if (fileExists) { + if (showConfirm && !isFreshPull && MarkdownCfg.isShowConfirmMsgWhenPullPost()) { + const answer = await Alert.warn( + '确认要拉取远程博文吗?', + { + modal: true, + detail: `本地文件「${fileName}」将被覆盖(可通过设置关闭对话框)`, + }, + '确认' + ) + if (answer !== '确认') return false + } + } else { + isFreshPull = true + } -async function handlePostInput(post: Post, contexts: CmdCtx[], path: string) { + await workspace.fs.writeFile(fileUri, Buffer.from(post.postBody)) + await PostFileMapManager.updateOrCreate(post.id, uriPath) await revealPostListItem(post) - contexts.push({ postId: post.id, fileUri: Uri.file(path) }) -} -function parseUriInput(input: InputType): Uri | undefined { - if (input instanceof Uri) return input + if (!mute) { + if (isFreshPull) await Alert.info(`博文已下载至本地:${fileName}`) + else await Alert.info(`本地文件已更新: ${fileName}`) + } - const doc = window.activeTextEditor?.document - if (doc !== undefined && !doc.isUntitled) return doc.uri + return true } -async function handleUriInput(fileUri: Uri, contexts: CmdCtx[]) { +async function getPostIdFromUri(fileUri: Uri): Promise { let postId = PostFileMapManager.getPostId(fileUri.path) if (postId == null) { const mapPost = '关联已有博文并拉取' @@ -97,7 +109,10 @@ async function handleUriInput(fileUri: Uri, contexts: CmdCtx[]) { postId = PostFileMapManager.extractPostId(filenName) if (postId == null) { const selectedPost = await searchPostByTitle(filenName, '搜索要关联的博文') - if (selectedPost == null) return Alert.info('未选择要关联的博文') + if (selectedPost == null) { + void Alert.info('未选择要关联的博文') + return + } postId = selectedPost.id } } @@ -105,24 +120,7 @@ async function handleUriInput(fileUri: Uri, contexts: CmdCtx[]) { if (postId != null) await PostFileMapManager.updateOrCreate(postId, fileUri.path) } - if (postId == null) return Alert.fileNotLinkedToPost(fileUri) - - contexts.push({ postId, fileUri }) -} - -async function update(contexts: CmdCtx[]) { - for (const ctx of contexts) { - const { fileUri, postId } = ctx - - const { post } = await PostService.getPostEditDto(postId) - - const textEditors = window.visibleTextEditors.filter(x => x.document.uri.fsPath === fileUri.fsPath) - await Promise.all(textEditors.map(editor => editor.document.save())) - await workspace.fs.writeFile(fileUri, Buffer.from(post.postBody)) - } -} + if (postId == null) Alert.fileNotLinkedToPost(fileUri) -function resolveFileNames(ctxList: CmdCtx[]) { - const arr = ctxList.map(x => path.basename(x.fileUri.fsPath)) - return `${arr.join(', ')}` + return postId } diff --git a/src/infra/fs/fsUtil.ts b/src/infra/fs/fsUtil.ts index ae2df1fd..d8afb196 100644 --- a/src/infra/fs/fsUtil.ts +++ b/src/infra/fs/fsUtil.ts @@ -1,9 +1,9 @@ import { Uri, workspace } from 'vscode' export namespace fsUtil { - export async function exists(path: string) { + export async function exists(fsPath: string) { try { - await workspace.fs.stat(Uri.file(path)) + await workspace.fs.stat(Uri.file(fsPath)) return true } catch (e) { return false diff --git a/src/service/post/post-file-map.ts b/src/service/post/post-file-map.ts index 4f4dfb63..dbf7db21 100644 --- a/src/service/post/post-file-map.ts +++ b/src/service/post/post-file-map.ts @@ -99,4 +99,8 @@ export namespace PostFileMapManager { x[1] = filePath.replace(r`${oldWorkspaceUri.fsPath}`, r`${newWorkspaceUri.fsPath}`) }) } + + export function isInWorkspace(fileUriPath: string) { + return fileUriPath.indexOf(WorkspaceCfg.getWorkspaceUri().path) >= 0 + } }