Improve binary detection

libgit2 optimizes around not loading the content, when there's no
content callbacks configured.

So we aren't able to get a clear answer from radicle-surf if a file in a
diff is a binary or not.

A simple way without doing additional API requests is to check if the
file type is a executable and if there are no hunks (since we don't get
any deltas in binaries), this is a strong
indicator for a binary.

Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
Sebastian Martinez
2023-09-26 09:04:01 +02:00
parent 9b15911f83
commit bd6ba784b3
4 changed files with 42 additions and 5 deletions
+2
View File
@@ -13,6 +13,7 @@ import type {
CommitHeader,
Diff,
DiffContent,
DiffFile,
HunkLine,
} from "./lib/project/commit.js";
import type { Issue, IssueState } from "./lib/project/issue.js";
@@ -46,6 +47,7 @@ export type {
CommitHeader,
Diff,
DiffContent,
DiffFile,
DiffResponse,
HunkLine,
Issue,
+14 -1
View File
@@ -1,5 +1,14 @@
import type { z } from "zod";
export type { Commits, HunkLine, Commit, Diff, CommitHeader, DiffContent };
export type {
Commits,
HunkLine,
Hunks,
Commit,
Diff,
CommitHeader,
DiffFile,
DiffContent,
};
import { array, literal, number, object, optional, string, union } from "zod";
export { commitHeaderSchema, diffSchema, commitSchema, commitsSchema };
@@ -36,6 +45,8 @@ const deletionHunkLineSchema = object({
type: literal("deletion"),
});
type DiffFile = z.infer<typeof diffFileSchema>;
const diffFileSchema = object({
oid: string(),
mode: union([
@@ -64,6 +75,8 @@ const hunkLineSchema = union([
contextHunkLineSchema,
]);
type Hunks = z.infer<typeof changesetHunkSchema>;
const changesetHunkSchema = object({
header: string(),
lines: array(hunkLineSchema),
+19 -4
View File
@@ -1,5 +1,11 @@
<script lang="ts">
import type { BaseUrl, CommitBlob, Diff } from "@httpd-client";
import type {
BaseUrl,
Diff,
CommitBlob,
DiffContent,
DiffFile,
} from "@httpd-client";
import { pluralize } from "@app/lib/pluralize";
@@ -42,6 +48,15 @@
}
return s.join(", ");
};
// Since libgit2 optimizes around not loading the content, when no content callbacks are configured,
// and we don't want to loop over all diffs in radicle-surf to get a correct answer.
// We assume that a `blobExecutable` file with no hunks is a binary file.
function getFileType(diff: DiffContent, file: DiffFile): DiffContent["type"] {
return file.mode === "blobExecutable" && diff.hunks.length === 0
? "binary"
: diff.type;
}
</script>
<style>
@@ -77,7 +92,7 @@
{baseUrl}
revision={revision ?? files[file.new.oid].lastCommit.id}
filePath={file.path}
fileDiff={file.diff}
fileDiff={{ ...file.diff, type: getFileType(file.diff, file.new) }}
headerBadgeCaption="added" />
{/each}
{#each diff.deleted as file}
@@ -86,7 +101,7 @@
{baseUrl}
revision={revision ?? files[file.old.oid].lastCommit.id}
filePath={file.path}
fileDiff={file.diff}
fileDiff={{ ...file.diff, type: getFileType(file.diff, file.old) }}
headerBadgeCaption="deleted" />
{/each}
{#each diff.modified as file}
@@ -95,7 +110,7 @@
{baseUrl}
revision={revision ?? files[file.new.oid].lastCommit.id}
filePath={file.path}
fileDiff={file.diff} />
fileDiff={{ ...file.diff, type: getFileType(file.diff, file.new) }} />
{/each}
{#each diff.moved as file}
{#if file.diff}
+7
View File
@@ -103,6 +103,13 @@ test("copied file", async ({ page }) => {
await expect(page.getByText("copied", { exact: true })).toBeVisible();
});
test("binary file detection in diffs", async ({ page }) => {
await page.goto(
`${sourceBrowsingUrl}/commits/335dd6dc89b535a4a31e9422c803199bb6b0a09a`,
);
await expect(page.getByText("Binary file")).toBeVisible();
});
test("navigation to source tree at specific revision", async ({ page }) => {
await page.goto(
`${sourceBrowsingUrl}/commits/0801aceeab500033f8d608778218657bd626ef73`,