Skip to content

Commit

Permalink
refactor: post pull
Browse files Browse the repository at this point in the history
  • Loading branch information
cnblogs-dudu committed Dec 18, 2023
1 parent 094fbc4 commit c59c3bf
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 126 deletions.
6 changes: 1 addition & 5 deletions src/cmd/post-list/open-post-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -18,10 +17,7 @@ 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)
}
if (autoPull && filePath.length > 0) if (!(await fsUtil.exists(filePath))) await postPull(post, true, true)
} else {
filePath = post
}
Expand Down
63 changes: 17 additions & 46 deletions src/cmd/post-list/open-post-in-vscode.ts
Original file line number Diff line number Diff line change
@@ -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()
Expand All @@ -17,54 +16,26 @@ 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<Uri | false> {
const mappedPostFilePath = PostFileMapManager.getFilePath(postId)
export async function openPostInVscode(postId: number): Promise<Uri | undefined> {
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(`创建目录失败: ${<string>e}`)
throw e
}
}
async function getMappedPostFilePath(postId: number) {
const mappedPostFilePath = PostFileMapManager.getFilePath(postId)
if (mappedPostFilePath != null) return mappedPostFilePath

if (await postPull(postId, true, true)) return PostFileMapManager.getFilePath(postId)
}
140 changes: 67 additions & 73 deletions src/cmd/post-list/post-pull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,74 +11,82 @@ 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<number | undefined | null> {
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 !== undefined && !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<boolean> {
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 {
if (!uriPath.startsWith('/')) uriPath = Uri.file(uriPath).path
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)

if (await fsUtil.exists(fsPath)) {
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<number | undefined> {
let postId = PostFileMapManager.getPostId(fileUri.path)
if (postId == null) {
const mapPost = '关联已有博文并拉取'
Expand All @@ -97,32 +105,18 @@ 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
}
}

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
}
4 changes: 2 additions & 2 deletions src/infra/fs/fsUtil.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit c59c3bf

Please sign in to comment.