From 60a65b078e3444ca66a1ccb7f6283f59093b36e0 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Sun, 22 May 2022 11:02:12 +0800 Subject: [PATCH] Turn methods to thin wrappers Make methods as thin wrappers to Git executable. Also pass the child process for easy stream operations to consumers. --- package.json | 4 +- prisma/schema.prisma | 70 --------------- src/index.ts | 1 - src/modules/common/index.ts | 1 - src/modules/common/models.ts | 12 --- src/modules/git/Git.service.ts | 151 +++++++++------------------------ src/modules/git/index.ts | 1 - src/modules/git/models.ts | 38 --------- src/modules/log/Log.service.ts | 33 ------- src/modules/log/index.ts | 2 - src/modules/log/models.ts | 18 ---- src/utils/error.ts | 1 - src/utils/process.ts | 29 +------ yarn.lock | 24 ------ 14 files changed, 40 insertions(+), 345 deletions(-) delete mode 100644 prisma/schema.prisma delete mode 100644 src/modules/common/index.ts delete mode 100644 src/modules/common/models.ts delete mode 100644 src/modules/git/models.ts delete mode 100644 src/modules/log/Log.service.ts delete mode 100644 src/modules/log/index.ts delete mode 100644 src/modules/log/models.ts delete mode 100644 src/utils/error.ts diff --git a/package.json b/package.json index efc0893..7d2095c 100644 --- a/package.json +++ b/package.json @@ -82,8 +82,6 @@ "access": "public" }, "dependencies": { - "@prisma/client": "^3.14.0", - "@theoryofnekomata/uuid-buffer": "^0.1.0", - "prisma": "^3.14.0" + "@theoryofnekomata/uuid-buffer": "^0.1.0" } } diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index 0d101be..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,70 +0,0 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "sqlite" - url = env("DATABASE_URL") -} - -model User { - id Bytes @id - username String @unique - password String - createdAt DateTime @default(now()) - properties Property[] - userOrgs UserOrg[] -} - -model Property { - id Bytes @id - userId Bytes - user User @relation(fields: [userId], references: [id]) - name String - value String -} - -model Org { - id Bytes @id - name String @unique - description String - createdAt DateTime @default(now()) - orgUsers UserOrg[] -} - -model UserOrg { - id Int @id @default(autoincrement()) - userId Bytes - user User @relation(fields: [userId], references: [id]) - orgId Bytes - org Org @relation(fields: [orgId], references: [id]) -} - -model Repo { - id Bytes @id - name String - visibility Int - ownerId Bytes - ownerType Int - createdAt DateTime @default(now()) -} - -model Log { - id Int @id @default(autoincrement()) - subjectUserId Bytes - subjectUsername String - action String - createdAt DateTime @default(now()) - parameters LogParameter[] -} - -model LogParameter { - id Int @id @default(autoincrement()) - logId Int - log Log @relation(fields: [logId], references: [id]) - key String - value String -} diff --git a/src/index.ts b/src/index.ts index 9cbbfe2..fa912d4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1 @@ -export * as common from './modules/common'; export * as git from './modules/git'; diff --git a/src/modules/common/index.ts b/src/modules/common/index.ts deleted file mode 100644 index e9644da..0000000 --- a/src/modules/common/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './models'; diff --git a/src/modules/common/models.ts b/src/modules/common/models.ts deleted file mode 100644 index 9356cac..0000000 --- a/src/modules/common/models.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Uuid} from '@theoryofnekomata/uuid-buffer'; - -export type User = { - id: Uuid, - username: string, -} - -export type Org = { - id: Uuid, - name: string, - description: string, -} diff --git a/src/modules/git/Git.service.ts b/src/modules/git/Git.service.ts index 9b9d3bf..65b032b 100644 --- a/src/modules/git/Git.service.ts +++ b/src/modules/git/Git.service.ts @@ -1,133 +1,58 @@ -import * as path from 'path'; -import {Uuid} from '@theoryofnekomata/uuid-buffer'; -import {PrismaClient} from '@prisma/client'; +import {ChildProcess} from 'child_process'; import {spawn} from '../../utils/process'; import {mkdirp, unlink} from '../../utils/fs'; -import {User} from '../common'; -import {LogService, LogServiceImpl} from '../log'; -import * as models from './models'; -import {notFoundFactory} from '../../utils/error'; export interface GitService { - create(data: models.CreateRepoData, subject: User): Promise - delete(repoId: models.Repo['id'], subject: User): Promise + create(repoBasePath: string): Promise + delete(repoBasePath: string): Promise + advertiseReceivePackRefs(repoBasePath: string): Promise + advertiseUploadPackRefs(repoBasePath: string): Promise + receivePack(repoBasePath: string): Promise + uploadPack(repoBasePath: string): Promise } export class GitServiceImpl implements GitService { - private readonly prismaClient: PrismaClient - private readonly logService: LogService - - constructor() { - this.prismaClient = new PrismaClient(); - this.logService = new LogServiceImpl() + private static isWindows() { + return /^win/.test(process.platform); } - private static getRepoBasePath(repoIdString: string) { - return path.join('repos', repoIdString) + async create(repoBasePath: string): Promise { + await mkdirp(repoBasePath); + return spawn( + repoBasePath, + 'git', ['init', '--bare'], + ); } - private async getOwnerName(ownerId: Uuid, ownerType: models.OwnerType) { - let owner: models.Owner - if (ownerType === models.OwnerType.USER) { - owner = await this.prismaClient.user.findUnique({ - where: { - id: ownerId, - }, - rejectOnNotFound: notFoundFactory(models.UserNotFoundError), - }) - return owner.username; - } - - if (ownerType === models.OwnerType.ORG) { - owner = await this.prismaClient.org.findUnique({ - where: { - id: ownerId, - }, - rejectOnNotFound: notFoundFactory(models.OrgNotFoundError), - }) - return owner.name; - } - - throw new models.UnknownOwnerTypeError('Unknown owner type.') + async delete(repoBasePath: string): Promise { + await unlink(repoBasePath); } - private static async createRepoFiles(repoIdString: string) { - const repoBasePath = GitServiceImpl.getRepoBasePath(repoIdString); - await mkdirp(repoBasePath); - await spawn(repoBasePath, 'git', ['init', '--bare']); + async advertiseReceivePackRefs(repoBasePath: string): Promise { + const command = GitServiceImpl.isWindows() ? 'git' : 'git-receive-pack'; + const commonArgs = ['--stateless-rpc', '--advertise-refs', '.']; + const args = GitServiceImpl.isWindows() ? ['receive-pack', ...commonArgs] : commonArgs; + return spawn(repoBasePath, command, args); } - async create(data: models.CreateRepoData, subject: User): Promise { - const repoId = Uuid.v4(); - const repoIdString = repoId.toString() - - await GitServiceImpl.createRepoFiles(repoIdString); - const repoMetadata = await this.prismaClient.repo.create({ - data: { - id: repoId, - name: data.name, - visibility: data.visibility, - ownerId: data.ownerId, - ownerType: data.ownerType, - }, - }); - - const ownerName = await this.getOwnerName(data.ownerId, data.ownerType); - await this.logService.create( - subject, - models.GitAction.REPO_CREATED, - { - key: 'repoId', - value: repoIdString, - }, - { - key: 'repoName', - value: data.name, - }, - { - key: 'ownerId', - value: data.ownerId.toString(), - }, - { - key: 'ownerName', - value: ownerName, - }, - ); - - return { - ...repoMetadata, - id: Uuid.from(repoMetadata.id), - }; + async advertiseUploadPackRefs(repoBasePath: string): Promise { + const command = GitServiceImpl.isWindows() ? 'git' : 'git-upload-pack'; + const commonArgs = ['--stateless-rpc', '--advertise-refs', '.']; + const args = GitServiceImpl.isWindows() ? ['upload-pack', ...commonArgs] : commonArgs; + return spawn(repoBasePath, command, args); } - async delete(repoId: models.Repo['id'], subject: User): Promise { - const repoIdString = repoId.toString(); - const repo = await this.prismaClient.repo.findUnique({ - where: { - id: repoId, - }, - rejectOnNotFound: notFoundFactory(models.RepoNotFoundError), - }); - await this.prismaClient.repo.delete({ - where: { - id: repoId, - }, - }); - - const repoBasePath = GitServiceImpl.getRepoBasePath(repoIdString); - await unlink(repoBasePath); + async receivePack(repoBasePath: string): Promise { + const command = GitServiceImpl.isWindows() ? 'git' : 'git-receive-pack'; + const commonArgs = ['--stateless-rpc', '.']; + const args = GitServiceImpl.isWindows() ? ['receive-pack', ...commonArgs] : commonArgs; + return spawn(repoBasePath, command, args); + } - await this.logService.create( - subject, - models.GitAction.REPO_REMOVED, - { - key: 'repoId', - value: repoIdString, - }, - { - key: 'repoName', - value: repo.name, - }, - ); + async uploadPack(repoBasePath: string): Promise { + const command = GitServiceImpl.isWindows() ? 'git' : 'git-upload-pack'; + const commonArgs = ['--stateless-rpc', '.']; + const args = GitServiceImpl.isWindows() ? ['upload-pack', ...commonArgs] : commonArgs; + return spawn(repoBasePath, command, args); } } diff --git a/src/modules/git/index.ts b/src/modules/git/index.ts index 875e234..6f990af 100644 --- a/src/modules/git/index.ts +++ b/src/modules/git/index.ts @@ -1,2 +1 @@ export * from './Git.service' -export * from './models' diff --git a/src/modules/git/models.ts b/src/modules/git/models.ts deleted file mode 100644 index e6edd32..0000000 --- a/src/modules/git/models.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {Uuid} from '@theoryofnekomata/uuid-buffer'; -import {Org, User} from '../common'; - -export enum RepoVisibility { - PRIVATE, - INTERNAL, - PUBLIC, -} - -export enum OwnerType { - USER, - ORG, -} - -export type Owner = User | Org; - -export enum GitAction { - REPO_CREATED = 'REPO_CREATED', - REPO_REMOVED = 'REPO_REMOVED', -} - -export type Repo = { - id: Uuid, - name: string, - ownerId: Uuid, - ownerType: OwnerType, - visibility: RepoVisibility, -} - -export type CreateRepoData = Omit; - -export class UnknownOwnerTypeError extends Error {} - -export class UserNotFoundError extends Error {} - -export class OrgNotFoundError extends Error {} - -export class RepoNotFoundError extends Error {} diff --git a/src/modules/log/Log.service.ts b/src/modules/log/Log.service.ts deleted file mode 100644 index d09ee33..0000000 --- a/src/modules/log/Log.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Prisma, PrismaClient } from '@prisma/client'; -import {User} from '../common'; -import {Log, LogParameterData} from './models'; - -export interface LogService { - create(subject: User, action: string, ...parameters: LogParameterData[]): Promise -} - -export class LogServiceImpl implements LogService { - private readonly prismaClient: PrismaClient - - constructor() { - this.prismaClient = new PrismaClient() - } - - async create(subject: User, action: string, ...parameters: LogParameterData[]): Promise { - const createData: Prisma.LogCreateInput = { - subjectUsername: subject.username, - subjectUserId: subject.id, - action, - } - - if (parameters.length > 0) { - createData['parameters'] = { - create: parameters, - } - } - - return this.prismaClient.log.create({ - data: createData, - }) - } -} diff --git a/src/modules/log/index.ts b/src/modules/log/index.ts deleted file mode 100644 index 297cf31..0000000 --- a/src/modules/log/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './Log.service' -export * from './models' diff --git a/src/modules/log/models.ts b/src/modules/log/models.ts deleted file mode 100644 index 3da0805..0000000 --- a/src/modules/log/models.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {Uuid} from '@theoryofnekomata/uuid-buffer'; - -export type LogParameter = { - id: number, - logId: number, - key: string, - value: string, -} - -export type Log = { - id: number, - subjectUserId: Uuid, - subjectUsername: string, - action: string, - createdAt: Date, -} - -export type LogParameterData = Pick; diff --git a/src/utils/error.ts b/src/utils/error.ts deleted file mode 100644 index 35364ad..0000000 --- a/src/utils/error.ts +++ /dev/null @@ -1 +0,0 @@ -export const notFoundFactory = (ErrorClass: { new(): T }) => () => new ErrorClass() diff --git a/src/utils/process.ts b/src/utils/process.ts index e8ab304..f30def9 100644 --- a/src/utils/process.ts +++ b/src/utils/process.ts @@ -4,31 +4,4 @@ export const spawn = ( cwd: string, command: string, args: string[], - parentProcess = process, -) => new Promise((resolve, reject) => { - let stdout = ''; - let stderr = ''; - - const theChildProcess = childProcess.spawn(command, args, { - cwd, - }); - - theChildProcess.stdout.on('data', (data) => { - parentProcess.stdout.write(data); - stdout += data; - }); - - theChildProcess.stderr.on('data', (data) => { - parentProcess.stderr.write(data); - stderr += data; - }); - - theChildProcess.on('close', (code) => { - if (code !== 0) { - reject(new Error(stderr)); - return; - } - - resolve(stdout); - }) -}) \ No newline at end of file +) => childProcess.spawn(command, args, { cwd }); diff --git a/yarn.lock b/yarn.lock index 99439fb..bbb4d20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -347,23 +347,6 @@ resolved "https://registry.yarnpkg.com/@ovyerus/licenses/-/licenses-6.4.4.tgz#596e3ace46ab7c70bcf0e2b17f259796a4bedf9f" integrity sha512-IHjc31WXciQT3hfvdY+M59jBkQp70Fpr04tNDVO5rez2PNv4u8tE6w//CkU+GeBoO9k2ahneSqzjzvlgjyjkGw== -"@prisma/client@^3.14.0": - version "3.14.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.14.0.tgz#bb90405c012fcca11f4647d91153ed4c58f3bd48" - integrity sha512-atb41UpgTR1MCst0VIbiHTMw8lmXnwUvE1KyUCAkq08+wJyjRE78Due+nSf+7uwqQn+fBFYVmoojtinhlLOSaA== - dependencies: - "@prisma/engines-version" "3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a" - -"@prisma/engines-version@3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a": - version "3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a.tgz#4edae57cf6527f35e22cebe75e49214fc0e99ac9" - integrity sha512-D+yHzq4a2r2Rrd0ZOW/mTZbgDIkUkD8ofKgusEI1xPiZz60Daks+UM7Me2ty5FzH3p/TgyhBpRrfIHx+ha20RQ== - -"@prisma/engines@3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a": - version "3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a.tgz#7fa11bc26a51d450185c816cc0ab8cac673fb4bf" - integrity sha512-LwZvI3FY6f43xFjQNRuE10JM5R8vJzFTSmbV9X0Wuhv9kscLkjRlZt0BEoiHmO+2HA3B3xxbMfB5du7ZoSFXGg== - "@theoryofnekomata/uuid-buffer@^0.1.0": version "0.1.0" resolved "https://js.pack.modal.sh/@theoryofnekomata%2fuuid-buffer/-/uuid-buffer-0.1.0.tgz#0917314e8230ce1a2047172b3277512bc0fd73a3" @@ -2435,13 +2418,6 @@ pridepack@1.1.1: resolve.exports "^1.1.0" yargs "^17.2.1" -prisma@^3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.14.0.tgz#dd67ece37d7b5373e9fd9588971de0024b49be81" - integrity sha512-l9MOgNCn/paDE+i1K2fp9NZ+Du4trzPTJsGkaQHVBufTGqzoYHuNk8JfzXuIn0Gte6/ZjyKj652Jq/Lc1tp2yw== - dependencies: - "@prisma/engines" "3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a" - prompts@^2.3.2, prompts@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"