Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions backend/scripts/askpass.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
#!/bin/sh
VSCODE_GIT_ASKPASS_PIPE=`mktemp`
ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" VSCODE_GIT_ASKPASS_TYPE="https" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $VSCODE_GIT_ASKPASS_EXTRA_ARGS $*
set -e

if [ -z "$VSCODE_GIT_ASKPASS_NODE" ] || [ -z "$VSCODE_GIT_ASKPASS_MAIN" ]; then
echo '' >&2
exit 0
fi

VSCODE_GIT_ASKPASS_PIPE=$(mktemp) || {
echo '' >&2
exit 0
}
ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" VSCODE_GIT_ASKPASS_TYPE="https" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $VSCODE_GIT_ASKPASS_EXTRA_ARGS $* || {
rm -f "$VSCODE_GIT_ASKPASS_PIPE"
echo '' >&2
exit 0
}
cat $VSCODE_GIT_ASKPASS_PIPE
rm $VSCODE_GIT_ASKPASS_PIPE
rm -f $VSCODE_GIT_ASKPASS_PIPE
104 changes: 64 additions & 40 deletions backend/src/routes/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,76 @@ import { getErrorMessage, getStatusCode } from '../utils/error-utils'
export function createFileRoutes() {
const app = new Hono()

app.get('download-zip', async(c) => {
return c.json({ error: 'No path provided' }, 400)
})
app.get('*', async (c) => {
const path = c.req.path

if (path.endsWith('/download-zip')) {
const match = path.match(/\/api\/files\/(.+?)\/download-zip$/)
const userPath = match?.[1]

if (!userPath) {
return c.json({ error: 'No path provided' }, 400)
}

try {
logger.info(`Starting ZIP archive creation for ${userPath}`)

const includeGit = c.req.query('includeGit') === 'true'
const includePathsParam = c.req.query('includePaths')
const includePaths = includePathsParam ? includePathsParam.split(',').map((p: string) => p.trim()) : undefined

app.get(':path{.+}/download-zip', async (c) => {
const userPath = c.req.param('path')
const options: import('../services/archive').ArchiveOptions = {
includeGit,
includePaths
}

const archivePath = await archiveService.createDirectoryArchive(userPath, undefined, options)
const archiveSize = await archiveService.getArchiveSize(archivePath)
const archiveStream = archiveService.getArchiveStream(archivePath)
const dirName = userPath.split('/').pop() || 'download'

logger.info(`ZIP archive created: ${archivePath} (${archiveSize} bytes)`)

if (!userPath) {
return c.json({ error: 'No path provided' }, 400)
archiveStream.on('end', () => {
archiveService.deleteArchive(archivePath)
})

archiveStream.on('error', () => {
archiveService.deleteArchive(archivePath)
})

return new Response(archiveStream as unknown as ReadableStream, {
status: 200,
headers: {
'Content-Type': 'application/zip',
'Content-Disposition': `attachment; filename="${dirName}.zip"`,
'Content-Length': archiveSize.toString(),
},
})
} catch (error: unknown) {
logger.error('Failed to create directory archive:', error)
return c.json({ error: getErrorMessage(error) || 'Failed to create archive' }, getStatusCode(error) as ContentfulStatusCode)
}
}

try {
logger.info(`Starting ZIP archive creation for ${userPath}`)

const archivePath = await archiveService.createDirectoryArchive(userPath)
const archiveSize = await archiveService.getArchiveSize(archivePath)
const archiveStream = archiveService.getArchiveStream(archivePath)
const dirName = userPath.split('/').pop() || 'download'

logger.info(`ZIP archive created: ${archivePath} (${archiveSize} bytes)`)

archiveStream.on('end', () => {
archiveService.deleteArchive(archivePath)
})

archiveStream.on('error', () => {
archiveService.deleteArchive(archivePath)
})

return new Response(archiveStream as unknown as ReadableStream, {
status: 200,
headers: {
'Content-Type': 'application/zip',
'Content-Disposition': `attachment; filename="${dirName}.zip"`,
'Content-Length': archiveSize.toString(),
},
})
} catch (error: unknown) {
logger.error('Failed to create directory archive:', error)
return c.json({ error: getErrorMessage(error) || 'Failed to create archive' }, getStatusCode(error) as ContentfulStatusCode)
if (path.endsWith('/ignored-paths')) {
const userPath = path.replace(/\/api\/files\/(.+?)\/ignored-paths$/, '$1')

if (!userPath || userPath === '/ignored-paths') {
return c.json({ error: 'No path provided' }, 400)
}

try {
const ignoredPaths = await archiveService.getIgnoredPathsList(userPath)
return c.json({ ignoredPaths })
} catch (error: unknown) {
logger.error('Failed to get ignored paths:', error)
return c.json({ error: getErrorMessage(error) || 'Failed to get ignored paths' }, getStatusCode(error) as ContentfulStatusCode)
}
}
})

app.get('/*', async (c) => {
try {
const userPath = c.req.path.replace(/^\/api\/files\//, '') || ''
const userPath = path.replace(/^\/api\/files\//, '') || ''
const download = c.req.query('download') === 'true'
const raw = c.req.query('raw') === 'true'
const startLineParam = c.req.query('startLine')
Expand Down Expand Up @@ -164,4 +188,4 @@ export function createFileRoutes() {
})

return app
}
}
21 changes: 15 additions & 6 deletions backend/src/routes/repos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,23 +261,32 @@ app.get('/', async (c) => {
try {
const id = parseInt(c.req.param('id'))
const repo = db.getRepoById(database, id)

if (!repo) {
return c.json({ error: 'Repo not found' }, 404)
}

const repoPath = path.resolve(getReposPath(), repo.localPath)
const repoName = path.basename(repo.localPath)


const includeGit = c.req.query('includeGit') === 'true'
const includePathsParam = c.req.query('includePaths')
const includePaths = includePathsParam ? includePathsParam.split(',').map(p => p.trim()) : undefined

const options: import('../services/archive').ArchiveOptions = {
includeGit,
includePaths
}

logger.info(`Starting archive creation for repo ${id}: ${repoPath}`)
const archivePath = await archiveService.createRepoArchive(repoPath)
const archivePath = await archiveService.createRepoArchive(repoPath, options)
const archiveSize = await archiveService.getArchiveSize(archivePath)
const archiveStream = archiveService.getArchiveStream(archivePath)

archiveStream.on('end', () => {
archiveService.deleteArchive(archivePath)
})

archiveStream.on('error', () => {
archiveService.deleteArchive(archivePath)
})
Expand Down
Loading