mirror of
https://github.com/stablyai/orca.git
synced 2026-09-24 16:02:41 +00:00
perf: bound working tree diff reads (#4171)
Unstaged source-control diffs now check the working-tree file size before readFile and use the existing 10 MB diff budget to avoid pulling huge generated files into the main process.
This commit is contained in:
@@ -8,6 +8,7 @@ const {
|
||||
lstatMock,
|
||||
realpathMock,
|
||||
readFileMock,
|
||||
statMock,
|
||||
rmMock,
|
||||
existsSyncMock
|
||||
} = vi.hoisted(() => ({
|
||||
@@ -16,6 +17,7 @@ const {
|
||||
lstatMock: vi.fn(),
|
||||
realpathMock: vi.fn(),
|
||||
readFileMock: vi.fn(),
|
||||
statMock: vi.fn(),
|
||||
rmMock: vi.fn(),
|
||||
existsSyncMock: vi.fn()
|
||||
}))
|
||||
@@ -33,6 +35,7 @@ vi.mock('fs/promises', () => ({
|
||||
lstat: lstatMock,
|
||||
realpath: realpathMock,
|
||||
readFile: readFileMock,
|
||||
stat: statMock,
|
||||
rm: rmMock
|
||||
}))
|
||||
|
||||
@@ -252,7 +255,12 @@ describe('getDiff', () => {
|
||||
gitExecFileAsyncBufferMock.mockReset()
|
||||
lstatMock.mockReset()
|
||||
readFileMock.mockReset()
|
||||
statMock.mockReset()
|
||||
existsSyncMock.mockReset()
|
||||
statMock.mockResolvedValue({
|
||||
isFile: () => true,
|
||||
size: 12
|
||||
})
|
||||
})
|
||||
|
||||
it('uses the index as the left side for unstaged diffs when present', async () => {
|
||||
@@ -318,6 +326,21 @@ describe('getDiff', () => {
|
||||
expect(result.modifiedIsBinary).toBe(false)
|
||||
})
|
||||
|
||||
it('does not read oversized working-tree files into memory', async () => {
|
||||
gitExecFileAsyncBufferMock.mockResolvedValueOnce({ stdout: Buffer.from('index-content\n') })
|
||||
statMock.mockResolvedValueOnce({
|
||||
isFile: () => true,
|
||||
size: 10 * 1024 * 1024 + 1
|
||||
})
|
||||
|
||||
const result = await getDiff('/repo', 'dist/large.log', false)
|
||||
|
||||
expect(readFileMock).not.toHaveBeenCalled()
|
||||
expect(result.kind).toBe('binary')
|
||||
expect(result.modifiedIsBinary).toBe(true)
|
||||
expect(result.modifiedContent).toBe('')
|
||||
})
|
||||
|
||||
it('includes preview metadata for pdf diffs', async () => {
|
||||
const pdfBuffer = Buffer.from([0x25, 0x50, 0x44, 0x46, 0x00])
|
||||
gitExecFileAsyncBufferMock.mockResolvedValueOnce({ stdout: pdfBuffer })
|
||||
|
||||
+10
-1
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable max-lines */
|
||||
import { existsSync } from 'fs'
|
||||
import { readFile } from 'fs/promises'
|
||||
import { readFile, stat } from 'fs/promises'
|
||||
import * as path from 'path'
|
||||
import type {
|
||||
GitBranchChangeEntry,
|
||||
@@ -950,6 +950,15 @@ async function readGitBlobAtOidPath(
|
||||
|
||||
async function readWorkingTreeFile(filePath: string): Promise<GitBlobReadResult> {
|
||||
try {
|
||||
const fileStat = await stat(filePath)
|
||||
if (!fileStat.isFile()) {
|
||||
return { content: '', isBinary: false, exists: false }
|
||||
}
|
||||
if (fileStat.size > MAX_GIT_SHOW_BYTES) {
|
||||
// Why: git blob reads are capped through maxBuffer; mirror that bound for
|
||||
// unstaged working-tree content before readFile can pull in huge assets.
|
||||
return { content: '', isBinary: true, exists: true }
|
||||
}
|
||||
const buffer = await readFile(filePath)
|
||||
return bufferToBlob(buffer, filePath)
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user