diff --git a/webapp/README.md b/webapp/README.md index c01b0e66..5cb5853b 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -15,7 +15,11 @@ projects: github_token: << github token >> ``` -also the project repository (client repository) needs to be cloned locally. and has in the root folder config +Multiple projects are supported, and multiple projects in the same local git repository +are supported, but configuring multiple porjects with different `repo_path`, resolving to +same local git repository, is _not_ supported. + +The project repository (client repository) needs to be cloned locally. and has in the root folder config file `lyra.yml` with the example content: diff --git a/webapp/src/Cache.ts b/webapp/src/Cache.ts index ae9d4082..9ca9a511 100644 --- a/webapp/src/Cache.ts +++ b/webapp/src/Cache.ts @@ -1,26 +1,19 @@ /* global globalThis */ -import { debug } from '@/utils/log'; -import { IGit } from '@/utils/git/IGit'; import { LanguageNotSupported } from '@/errors'; +import { LyraProjectConfig } from '@/utils/lyraConfig'; import { ProjectStore } from '@/store/ProjectStore'; import { RepoGit } from '@/RepoGit'; -import { SimpleGitWrapper } from '@/utils/git/SimpleGitWrapper'; +import { ServerConfig } from '@/utils/serverConfig'; import { Store } from '@/store/Store'; import YamlTranslationAdapter from '@/utils/adapters/YamlTranslationAdapter'; -import { LyraConfig, LyraProjectConfig } from '@/utils/lyraConfig'; -import { ServerConfig, ServerProjectConfig } from '@/utils/serverConfig'; export class Cache { - private static hasPulled = new Set(); - public static async getLanguage(projectName: string, lang: string) { const serverProjectConfig = await ServerConfig.getProjectConfig(projectName); - await Cache.gitPullIfNeeded(serverProjectConfig); - const lyraConfig = await LyraConfig.readFromDir( - serverProjectConfig.repoPath, - ); + const repoGit = await RepoGit.getRepoGit(serverProjectConfig); + const lyraConfig = await repoGit.getLyraConfig(); const lyraProjectConfig = lyraConfig.getProjectConfigByPath( serverProjectConfig.projectPath, ); @@ -47,21 +40,4 @@ export class Cache { return globalThis.store.getProjectStore(lyraProjectConfig.absPath); } - - private static async gitPullIfNeeded(spConfig: ServerProjectConfig) { - const { repoPath, baseBranch } = spConfig; - if (Cache.hasPulled.has(repoPath)) { - debug(`repoPath: ${repoPath} is already pulled`); - return; - } - await RepoGit.cloneIfNotExist(spConfig); - debug(`prepare git options for path: ${repoPath}`); - const git: IGit = new SimpleGitWrapper(repoPath); - debug(`git checkout ${baseBranch} branch...`); - await git.checkout(baseBranch); - debug('git pull...'); - await git.pull(); - debug(`git done checkout ${baseBranch} branch and pull`); - Cache.hasPulled.add(repoPath); - } } diff --git a/webapp/src/RepoGit.ts b/webapp/src/RepoGit.ts index 89d6523a..66601ade 100644 --- a/webapp/src/RepoGit.ts +++ b/webapp/src/RepoGit.ts @@ -14,13 +14,31 @@ import { debug, info, warn } from '@/utils/log'; import { WriteLanguageFileError, WriteLanguageFileErrors } from '@/errors'; export class RepoGit { + private static repositories: { + [name: string]: Promise; + } = {}; + private readonly git: IGit; private lyraConfig?: LyraConfig; - constructor(private readonly spConfig: ServerProjectConfig) { + private constructor(private readonly spConfig: ServerProjectConfig) { this.git = new SimpleGitWrapper(spConfig.repoPath); } + static async getRepoGit(spConfig: ServerProjectConfig): Promise { + const key = spConfig.repoPath; + if (key in RepoGit.repositories) { + return RepoGit.repositories[key]; + } + const { promise, resolve, reject } = Promise.withResolvers(); + RepoGit.repositories[key] = promise; + + const repository = new RepoGit(spConfig); + repository.checkoutBaseAndPull().then(() => resolve(repository), reject); + + return promise; + } + public static async cloneIfNotExist( spConfig: ServerProjectConfig, ): Promise { @@ -116,7 +134,7 @@ export class RepoGit { return response.data.html_url; } - private async getLyraConfig(): Promise { + async getLyraConfig(): Promise { if (this.lyraConfig === undefined) { await RepoGit.cloneIfNotExist(this.spConfig); this.lyraConfig = await LyraConfig.readFromDir(this.spConfig.repoPath); diff --git a/webapp/src/app/api/messages/[projectName]/route.ts b/webapp/src/app/api/messages/[projectName]/route.ts index 97cc63fb..abc4e68b 100644 --- a/webapp/src/app/api/messages/[projectName]/route.ts +++ b/webapp/src/app/api/messages/[projectName]/route.ts @@ -1,4 +1,3 @@ -import { LyraConfig } from '@/utils/lyraConfig'; import MessageAdapterFactory from '@/utils/adapters/MessageAdapterFactory'; import { RepoGit } from '@/RepoGit'; import { ServerConfig } from '@/utils/serverConfig'; @@ -18,9 +17,8 @@ export async function GET( const serverProjectConfig = await ServerConfig.getProjectConfig(projectName); await RepoGit.cloneIfNotExist(serverProjectConfig); - const lyraConfig = await LyraConfig.readFromDir( - serverProjectConfig.repoPath, - ); + const repoGit = await RepoGit.getRepoGit(serverProjectConfig); + const lyraConfig = await repoGit.getLyraConfig(); const projectConfig = lyraConfig.getProjectConfigByPath( serverProjectConfig.projectPath, ); diff --git a/webapp/src/app/api/pull-request/[projectName]/route.ts b/webapp/src/app/api/pull-request/[projectName]/route.ts index b6265166..172c220e 100644 --- a/webapp/src/app/api/pull-request/[projectName]/route.ts +++ b/webapp/src/app/api/pull-request/[projectName]/route.ts @@ -37,7 +37,7 @@ export async function POST( try { syncLock.set(repoPath, true); - const repoGit = new RepoGit(serverProjectConfig); + const repoGit = await RepoGit.getRepoGit(serverProjectConfig); const baseBranch = await repoGit.checkoutBaseAndPull(); const langFilePaths = await repoGit.saveLanguageFiles( serverProjectConfig.projectPath, diff --git a/webapp/src/app/api/translations/[projectName]/[lang]/[msgId]/route.ts b/webapp/src/app/api/translations/[projectName]/[lang]/[msgId]/route.ts index b73f7c10..8f20522d 100644 --- a/webapp/src/app/api/translations/[projectName]/[lang]/[msgId]/route.ts +++ b/webapp/src/app/api/translations/[projectName]/[lang]/[msgId]/route.ts @@ -1,5 +1,4 @@ import { Cache } from '@/Cache'; -import { LyraConfig } from '@/utils/lyraConfig'; import { RepoGit } from '@/RepoGit'; import { ServerConfig } from '@/utils/serverConfig'; import { @@ -24,10 +23,11 @@ export async function PUT( const { lang, msgId, projectName } = context.params; const payload = await req.json(); const { text } = payload; - // TODO: include getProjectConfig & readFromDir in a try/catch block and check for error to return a certain 500 error + // TODO: include getProjectConfig() and getLyraConfig() in a try/catch block and check for error to return a certain 500 error const serverProjectConfig = await ServerConfig.getProjectConfig(projectName); await RepoGit.cloneIfNotExist(serverProjectConfig); - const lyraConfig = await LyraConfig.readFromDir(serverProjectConfig.repoPath); + const repoGit = await RepoGit.getRepoGit(serverProjectConfig); + const lyraConfig = await repoGit.getLyraConfig(); try { const projectConfig = lyraConfig.getProjectConfigByPath( diff --git a/webapp/src/utils/adapters/MessageAdapterFactory.ts b/webapp/src/utils/adapters/MessageAdapterFactory.ts index 61e1eed4..047654e4 100644 --- a/webapp/src/utils/adapters/MessageAdapterFactory.ts +++ b/webapp/src/utils/adapters/MessageAdapterFactory.ts @@ -3,11 +3,11 @@ import YamlMessageAdapter from './YamlMessageAdapter'; import { LyraProjectConfig, MessageKind } from '../lyraConfig'; export default class MessageAdapterFactory { - static createAdapter(config: LyraProjectConfig) { - if (config.messageKind == MessageKind.TS) { - return new TsMessageAdapter(config.absMessagesPath); + static createAdapter(lpConfig: LyraProjectConfig) { + if (lpConfig.messageKind == MessageKind.TS) { + return new TsMessageAdapter(lpConfig.absMessagesPath); } else { - return new YamlMessageAdapter(config.absMessagesPath); + return new YamlMessageAdapter(lpConfig.absMessagesPath); } } }