From 7b9fca8d0061cf5e5af08cba98e9d5b6dbbed8ec Mon Sep 17 00:00:00 2001 From: HampusM Date: Wed, 21 Jul 2021 22:00:04 +0200 Subject: Began with better backend error handling & cleaned up the backend --- packages/server/src/git/blob.ts | 4 +++ packages/server/src/git/branch.ts | 21 ++++++++++---- packages/server/src/git/commit.ts | 6 +++- packages/server/src/git/error.ts | 49 +++++++++++++++++++++++++++++++ packages/server/src/git/misc.ts | 5 ---- packages/server/src/git/reference.ts | 15 ++++++++++ packages/server/src/git/repository.ts | 54 ++++++++++++++++++++++++++--------- packages/server/src/git/tag.ts | 12 ++++---- packages/server/src/git/tree.ts | 16 ++++++----- 9 files changed, 145 insertions(+), 37 deletions(-) create mode 100644 packages/server/src/git/error.ts (limited to 'packages/server/src/git') diff --git a/packages/server/src/git/blob.ts b/packages/server/src/git/blob.ts index aeb1381..e44a979 100644 --- a/packages/server/src/git/blob.ts +++ b/packages/server/src/git/blob.ts @@ -1,4 +1,5 @@ import { TreeEntry as NodeGitTreeEntry } from "nodegit"; +import { BlobError, createError } from "./error"; export class Blob { private _ng_tree_entry: NodeGitTreeEntry; @@ -8,6 +9,9 @@ export class Blob { } public async content(): Promise { + if(!this._ng_tree_entry.isBlob()) { + throw(createError(BlobError, 500, "Not a blob")); + } return this._ng_tree_entry.isBlob() ? (await this._ng_tree_entry.getBlob()).toString() : ""; } } \ No newline at end of file diff --git a/packages/server/src/git/branch.ts b/packages/server/src/git/branch.ts index 90241a0..163eca7 100644 --- a/packages/server/src/git/branch.ts +++ b/packages/server/src/git/branch.ts @@ -1,10 +1,15 @@ import { CommitSummary } from "./commit"; import { Reference } from "./reference"; import { Repository } from "./repository"; +import { Repository as NodeGitRepository } from "nodegit"; +import { BranchError, createError } from "./error"; export class Branch extends Reference { public async latestCommit(): Promise { - const latest_commit = this._owner.nodegitRepository.getBranchCommit(this._ng_reference); + const latest_commit = this._owner.nodegitRepository.getBranchCommit(this._ng_reference).catch(() => { + throw(createError(BranchError, 500, "Failed to get the latest commit")); + }); + return { id: (await latest_commit).sha(), message: (await latest_commit).message(), @@ -12,13 +17,19 @@ export class Branch extends Reference { }; } - public static async lookup(owner: Repository, branch: string): Promise { + public static async lookup(owner: Repository, branch: string): Promise { const reference = await owner.nodegitRepository.getBranch(branch).catch(err => { if(err.errno === -3) { - return null; + throw(createError(BranchError, 404, "Branch not found!")); } - throw(err); + throw(createError(BranchError, 500, "Something went wrong.")); }); - return reference ? new Branch(owner, reference) : null; + return new Branch(owner, reference); + } + + public static async lookupExists(ng_repository: NodeGitRepository, branch: string): Promise { + return ng_repository.getBranch(branch) + .then(() => true) + .catch(() => false); } } \ No newline at end of file diff --git a/packages/server/src/git/commit.ts b/packages/server/src/git/commit.ts index 4b3e44b..94afda0 100644 --- a/packages/server/src/git/commit.ts +++ b/packages/server/src/git/commit.ts @@ -1,5 +1,5 @@ import { Commit as NodeGitCommit, Oid as NodeGitOid } from "nodegit"; -import { Author } from "./misc"; +import { Author } from "../../../shared_types/src"; import { Diff } from "./diff"; import { Repository } from "./repository"; import { Tree } from "./tree"; @@ -66,4 +66,8 @@ export class Commit { .then(() => true) .catch(() => false); } + + public static async masterCommit(owner: Repository): Promise { + return new Commit(owner, await owner.nodegitRepository.getMasterCommit()); + } } \ No newline at end of file diff --git a/packages/server/src/git/error.ts b/packages/server/src/git/error.ts new file mode 100644 index 0000000..0429a6c --- /dev/null +++ b/packages/server/src/git/error.ts @@ -0,0 +1,49 @@ +export abstract class BaseError implements Error { + code: number; + name: string; + message: string; + stack?: string | undefined; + + constructor(code: number, message: string) { + this.name = "Githermit Error"; + + this.code = code; + this.message = message; + } +} + +export class RepositoryError extends BaseError { + constructor(code: number, message: string) { + super(code, "A repository error has occured: " + message); + } +} + +export class BranchError extends BaseError { + constructor(code: number, message: string) { + super(code, "A branch error has occured: " + message); + } +} + +export class TagError extends BaseError { + constructor(code: number, message: string) { + super(code, "A tag error has occured: " + message); + } +} + +export class TreeError extends BaseError { + constructor(code: number, message: string) { + super(code, "A tree error has occured: " + message); + } +} + +export class BlobError extends BaseError { + constructor(code: number, message: string) { + super(code, "A blob error has occured: " + message); + } +} + +type ErrorConstructorType = new (code: number, message: string) => T; + +export function createError(ErrorConstructor: ErrorConstructorType, code: number, message: string): E { + return new ErrorConstructor(code, message); +} \ No newline at end of file diff --git a/packages/server/src/git/misc.ts b/packages/server/src/git/misc.ts index fcfaf29..637cb8c 100644 --- a/packages/server/src/git/misc.ts +++ b/packages/server/src/git/misc.ts @@ -6,11 +6,6 @@ export async function findAsync(arr: T[], callback: (t: T) => Promise { return new Promise(resolve => { readFile(`${base_dir}/${repository}/${file}`, (err, content) => { diff --git a/packages/server/src/git/reference.ts b/packages/server/src/git/reference.ts index 36f1312..b24f72d 100644 --- a/packages/server/src/git/reference.ts +++ b/packages/server/src/git/reference.ts @@ -1,6 +1,16 @@ import { Reference as NodeGitReference } from "nodegit"; import { Repository } from "./repository"; +type ReferenceClass = new(owner: Repository, reference: NodeGitReference) => T; + +export function isNodeGitReferenceBranch(ref: NodeGitReference): boolean { + return Boolean(ref.isBranch()); +} + +export function isNodeGitReferenceTag(ref: NodeGitReference): boolean { + return Boolean(ref.isTag()); +} + export abstract class Reference { protected _ng_reference: NodeGitReference; protected _owner: Repository; @@ -15,4 +25,9 @@ export abstract class Reference { this.id = reference.target().tostrS(); this.name = reference.shorthand(); } + + public static async all(owner: Repository, Target: ReferenceClass, ref_fn: (ref: NodeGitReference) => boolean): Promise { + const references = await owner.nodegitRepository.getReferences(); + return references.filter(ref_fn).map(ref => new Target(owner, ref)); + } } \ No newline at end of file diff --git a/packages/server/src/git/repository.ts b/packages/server/src/git/repository.ts index ff23761..c95edaa 100644 --- a/packages/server/src/git/repository.ts +++ b/packages/server/src/git/repository.ts @@ -7,6 +7,8 @@ import { Commit } from "./commit"; import { FastifyReply } from "fastify"; import { Tag } from "./tag"; import { Tree } from "./tree"; +import { BranchError, createError, RepositoryError } from "./error"; +import { isNodeGitReferenceBranch, isNodeGitReferenceTag, Reference } from "./reference"; function getFullRepositoryName(repo_name: string) { return repo_name.endsWith(".git") ? repo_name : `${repo_name}.git`; @@ -19,12 +21,21 @@ type RepositoryName = { type RepositoryConstructorData = { description: string | null, - owner: string | null + owner: string | null, + branch: string +} + +// This fucking shit isn't in the Nodegit documentation. +interface WeirdNodeGitError extends Error { + errno: number; + errorFunction: string; } export class Repository { private _ng_repository: NodeGitRepository; + private _branch: string; + public name: RepositoryName; public base_dir: string; public description: string | null; @@ -39,6 +50,12 @@ export class Repository { this.base_dir = dirname(repository.path()); this.description = data.description; this.owner = data.owner; + + this._branch = data.branch; + } + + public branch(): Promise { + return Branch.lookup(this, this._branch); } public async commits(): Promise { @@ -49,9 +66,7 @@ export class Repository { } public async tree(): Promise { - const master_commit = await this._ng_repository.getMasterCommit(); - const tree = await master_commit.getTree(); - return new Tree(this, tree); + return Tree.ofRepository(this); } public lookupExists(id: string): Promise { @@ -60,18 +75,16 @@ export class Repository { .catch(() => false); } - public async branches(): Promise { - const references = await this._ng_repository.getReferences(); - return references.filter(ref => ref.isBranch()).map(branch => new Branch(this, branch)); + public branches(): Promise { + return Reference.all(this, Branch, isNodeGitReferenceBranch); } public async tags(): Promise { - const references = await this._ng_repository.getReferences(); - return references.filter(ref => ref.isTag()).map(tag => new Tag(this, tag)); + return Reference.all(this, Tag, isNodeGitReferenceTag); } - public async latestCommit(): Promise { - return new Commit(this, await this._ng_repository.getMasterCommit()); + public async masterCommit(): Promise { + return Commit.masterCommit(this); } public HTTPconnect(req: Request, reply: FastifyReply): void { @@ -82,12 +95,25 @@ export class Repository { return this._ng_repository; } - public static async open(base_dir: string, repository: string): Promise { - const ng_repository = await NodeGitRepository.openBare(`${base_dir}/${getFullRepositoryName(repository)}`); + public static async open(base_dir: string, repository: string, branch?: string): Promise { + let ng_repository = await NodeGitRepository.openBare(`${base_dir}/${getFullRepositoryName(repository)}`).catch((err: WeirdNodeGitError) => { + if(err.errno === -3) { + throw(createError(RepositoryError, 404, "Repository not found")); + } + + throw(createError(RepositoryError, 500, "Unknown error")); + }); + + if(branch) { + if(!await Branch.lookupExists(ng_repository, branch)) { + throw(createError(BranchError, 404, "Branch not found!")); + } + } return new Repository(ng_repository, { description: await getFile(base_dir, getFullRepositoryName(repository), "description"), - owner: await getFile(base_dir, getFullRepositoryName(repository), "owner") + owner: await getFile(base_dir, getFullRepositoryName(repository), "owner"), + branch: branch || "master" }); } diff --git a/packages/server/src/git/tag.ts b/packages/server/src/git/tag.ts index 64828e7..3063a25 100644 --- a/packages/server/src/git/tag.ts +++ b/packages/server/src/git/tag.ts @@ -1,6 +1,5 @@ import { Object as NodeGitObject, Tag as NodeGitTag } from "nodegit"; import { Pack, pack } from "tar-stream"; -import { Author } from "./misc"; import { Blob } from "./blob"; import { Commit } from "./commit"; import { FastifyReply } from "fastify"; @@ -10,6 +9,8 @@ import { Tree } from "./tree"; import { 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) { for(const tree_entry of entries) { @@ -69,14 +70,15 @@ export class Tag extends Reference { }); } - public static async lookup(owner: Repository, tag: string): Promise { + public static async lookup(owner: Repository, tag: string): Promise { const reference = await owner.nodegitRepository.getReference(tag).catch(err => { if(err.errno === -3) { - return null; + throw(createError(TagError, 404, "Tag not found")); } - throw(err); + throw(createError(TagError, 404, "Failed to get tag")); }); - return reference ? new Tag(owner, reference) : null; + + return new Tag(owner, reference); } } \ No newline at end of file diff --git a/packages/server/src/git/tree.ts b/packages/server/src/git/tree.ts index 8697010..2cec528 100644 --- a/packages/server/src/git/tree.ts +++ b/packages/server/src/git/tree.ts @@ -2,6 +2,7 @@ import { Blob } from "./blob"; import { Tree as NodeGitTree } from "nodegit"; import { Repository } from "./repository"; import { TreeEntry } from "./tree_entry"; +import { createError, TreeError } from "./error"; export class Tree { private _ng_tree: NodeGitTree; @@ -16,18 +17,14 @@ export class Tree { return this._ng_tree.entries().map(entry => new TreeEntry(this._owner, entry)); } - public async find(path: string): Promise { + public async find(path: string): Promise { const entry = await this._ng_tree.getEntry(path).catch(err => { if(err.errno === -3) { - return null; + throw(createError(TreeError, 404, "Path not found")); } - throw(err); + throw(createError(TreeError, 500, "Failed to get tree path")); }); - if(!entry) { - return null; - } - return entry.isBlob() ? new Blob(entry) : new Tree(this._owner, await entry.getTree()); } @@ -36,4 +33,9 @@ export class Tree { .then(() => true) .catch(() => false); } + + public static async ofRepository(owner: Repository): Promise { + const master_commit = await owner.masterCommit(); + return master_commit.tree(); + } } \ No newline at end of file -- cgit v1.2.3-18-g5258