From a737bc4695f99b05a3c4807c88fc30b1a1eb89b5 Mon Sep 17 00:00:00 2001
From: HampusM <hampus@hampusmat.com>
Date: Mon, 26 Jul 2021 17:33:54 +0200
Subject: Refactored the git tree, tree entry & blob classes

---
 packages/server/src/git/blob.ts                 | 24 ++++++++++++++-----
 packages/server/src/git/tag.ts                  | 18 +++++---------
 packages/server/src/git/tree.ts                 | 16 +++++++------
 packages/server/src/git/tree_entry.ts           | 31 +++++++++++++++++--------
 packages/server/src/routes/api/v1/repo/index.ts |  6 ++---
 5 files changed, 57 insertions(+), 38 deletions(-)

(limited to 'packages/server')

diff --git a/packages/server/src/git/blob.ts b/packages/server/src/git/blob.ts
index e44a979..ef9f9ab 100644
--- a/packages/server/src/git/blob.ts
+++ b/packages/server/src/git/blob.ts
@@ -1,17 +1,29 @@
-import { TreeEntry as NodeGitTreeEntry } from "nodegit";
 import { BlobError, createError } from "./error";
+import { Tree } from "./tree";
+import { BlobTreeEntry } from "./tree_entry";
 
 export class Blob {
-	private _ng_tree_entry: NodeGitTreeEntry;
+	private _tree_entry: BlobTreeEntry;
 
-	constructor(entry: NodeGitTreeEntry) {
-		this._ng_tree_entry = entry;
+	public path;
+
+	constructor(entry: BlobTreeEntry, path: string) {
+		this._tree_entry = entry;
+
+		this.path = path;
 	}
 
 	public async content(): Promise<string> {
-		if(!this._ng_tree_entry.isBlob()) {
+		return this._tree_entry.content();
+	}
+
+	public static async fromPath(tree: Tree, path: string): Promise<Blob> {
+		const entry = await tree.find(path);
+
+		if(!(entry instanceof BlobTreeEntry)) {
 			throw(createError(BlobError, 500, "Not a blob"));
 		}
-		return this._ng_tree_entry.isBlob() ? (await this._ng_tree_entry.getBlob()).toString() : "";
+
+		return new Blob(entry, path);
 	}
 }
\ No newline at end of file
diff --git a/packages/server/src/git/tag.ts b/packages/server/src/git/tag.ts
index 3063a25..473c62d 100644
--- a/packages/server/src/git/tag.ts
+++ b/packages/server/src/git/tag.ts
@@ -1,28 +1,22 @@
 import { Object as NodeGitObject, Tag as NodeGitTag } from "nodegit";
 import { Pack, pack } from "tar-stream";
-import { Blob } from "./blob";
 import { Commit } from "./commit";
 import { FastifyReply } from "fastify";
 import { Reference } from "./reference";
 import { Repository } from "./repository";
-import { Tree } from "./tree";
-import { TreeEntry } from "./tree_entry";
+import { BaseTreeEntry, BlobTreeEntry, TreeEntry } from "./tree_entry";
 import { createGzip } from "zlib";
 import { pipeline } from "stream";
 import { createError, TagError } from "./error";
 import { Author } from "../../../shared_types/src";
 
-async function addArchiveEntries(entries: TreeEntry[], repository: string, archive: Pack) {
+async function addArchiveEntries(entries: BaseTreeEntry[], repository: string, archive: Pack) {
 	for(const tree_entry of entries) {
-		const peeled = (await tree_entry.peel());
-
-		if(tree_entry.type === "blob") {
-			if(peeled instanceof Blob) {
-				archive.entry({ name: `${repository}/${tree_entry.path}` }, await peeled.content());
-			}
+		if(tree_entry instanceof BlobTreeEntry) {
+			archive.entry({ name: `${repository}/${tree_entry.path}` }, await tree_entry.content());
 		}
-		else if(peeled instanceof Tree) {
-			await addArchiveEntries(peeled.entries(), repository, archive);
+		else if(tree_entry instanceof TreeEntry) {
+			await addArchiveEntries((await tree_entry.tree()).entries(), repository, archive);
 		}
 	}
 }
diff --git a/packages/server/src/git/tree.ts b/packages/server/src/git/tree.ts
index 2cec528..ca645ef 100644
--- a/packages/server/src/git/tree.ts
+++ b/packages/server/src/git/tree.ts
@@ -1,23 +1,25 @@
-import { Blob } from "./blob";
 import { Tree as NodeGitTree } from "nodegit";
 import { Repository } from "./repository";
-import { TreeEntry } from "./tree_entry";
+import { BaseTreeEntry, createTreeEntry, TreeEntry } from "./tree_entry";
 import { createError, TreeError } from "./error";
 
 export class Tree {
-	private _ng_tree: NodeGitTree;
-	private _owner: Repository;
+	protected _owner: Repository;
+	protected _ng_tree: NodeGitTree;
+
+	public path: string;
 
 	constructor(owner: Repository, tree: NodeGitTree) {
-		this._ng_tree = tree;
 		this._owner = owner;
+		this._ng_tree = tree;
+		this.path = tree.path();
 	}
 
 	public entries(): TreeEntry[] {
 		return this._ng_tree.entries().map(entry => new TreeEntry(this._owner, entry));
 	}
 
-	public async find(path: string): Promise<Blob | Tree> {
+	public async find(path: string): Promise<BaseTreeEntry> {
 		const entry = await this._ng_tree.getEntry(path).catch(err => {
 			if(err.errno === -3) {
 				throw(createError(TreeError, 404, "Path not found"));
@@ -25,7 +27,7 @@ export class Tree {
 			throw(createError(TreeError, 500, "Failed to get tree path"));
 		});
 
-		return entry.isBlob() ? new Blob(entry) : new Tree(this._owner, await entry.getTree());
+		return createTreeEntry(this._owner, entry);
 	}
 
 	public findExists(path: string): Promise<boolean> {
diff --git a/packages/server/src/git/tree_entry.ts b/packages/server/src/git/tree_entry.ts
index d4eac40..e4780c8 100644
--- a/packages/server/src/git/tree_entry.ts
+++ b/packages/server/src/git/tree_entry.ts
@@ -1,24 +1,21 @@
-import { Blob } from "./blob";
 import { Commit } from "./commit";
 import { TreeEntry as NodeGitTreeEntry } from "nodegit";
 import { Repository } from "./repository";
-import { Tree } from "./tree";
 import { dirname } from "path";
 import { findAsync } from "./misc";
+import { Tree } from "./tree";
 
-export class TreeEntry {
-	private _ng_tree_entry: NodeGitTreeEntry;
-	private _owner: Repository;
+export abstract class BaseTreeEntry {
+	protected _ng_tree_entry: NodeGitTreeEntry;
+	protected _owner: Repository;
 
 	public path: string;
-	public type: "blob" | "tree";
 
 	constructor(owner: Repository, entry: NodeGitTreeEntry) {
 		this._ng_tree_entry = entry;
 		this._owner = owner;
 
 		this.path = entry.path();
-		this.type = entry.isBlob() ? "blob" : "tree";
 	}
 
 	public async latestCommit(): Promise<Commit> {
@@ -28,13 +25,27 @@ export class TreeEntry {
 			const diff = await commit.diff();
 			const patches = await diff.patches();
 
-			return Boolean(this.type === "blob"
+			return Boolean(this instanceof TreeEntry
 				? patches.find(patch => patch.to === this.path)
 				: patches.find(patch => dirname(patch.to).startsWith(this.path)));
 		});
 	}
+}
 
-	public async peel(): Promise<Blob | Tree> {
-		return this.type === "blob" ? new Blob(this._ng_tree_entry) : new Tree(this._owner, await this._ng_tree_entry.getTree());
+export class TreeEntry extends BaseTreeEntry {
+	public async tree(): Promise<Tree> {
+		return new Tree(this._owner, await this._ng_tree_entry.getTree());
 	}
+}
+
+export class BlobTreeEntry extends BaseTreeEntry {
+	public async content(): Promise<string> {
+		return (await this._ng_tree_entry.getBlob()).toString();
+	}
+}
+
+export function createTreeEntry(owner: Repository, entry: NodeGitTreeEntry): BaseTreeEntry {
+	return entry.isBlob()
+		? new BlobTreeEntry(owner, entry)
+		: new TreeEntry(owner, entry);
 }
\ No newline at end of file
diff --git a/packages/server/src/routes/api/v1/repo/index.ts b/packages/server/src/routes/api/v1/repo/index.ts
index 0042b60..395c108 100644
--- a/packages/server/src/routes/api/v1/repo/index.ts
+++ b/packages/server/src/routes/api/v1/repo/index.ts
@@ -3,7 +3,7 @@ import { FastifyInstance, FastifyPluginOptions } from "fastify";
 import { Blob } from "../../../../git/blob";
 import { Repository } from "../../../../git/repository";
 import { Tag } from "../../../../git/tag";
-import { TreeEntry } from "../../../../git/tree_entry";
+import { BaseTreeEntry, TreeEntry } from "../../../../git/tree_entry";
 import { basename } from "path";
 import branches from "./branches";
 import log from "./log";
@@ -36,11 +36,11 @@ function addHooks(fastify: FastifyInstance, opts: FastifyPluginOptions): void {
 		}
 	});
 }
-async function treeEntryMap(entry: TreeEntry) {
+async function treeEntryMap(entry: BaseTreeEntry) {
 	const latest_commit = await entry.latestCommit();
 	return <APITreeEntry>{
 		name: basename(entry.path),
-		type: entry.type,
+		type: entry instanceof TreeEntry ? "tree" : "blob",
 		latest_commit: {
 			id: latest_commit.id,
 			message: latest_commit.message,
-- 
cgit v1.2.3-18-g5258