From c0d22d3959630c937c3694bc5168e56bedd68b88 Mon Sep 17 00:00:00 2001 From: Ca2didi Date: Mon, 19 May 2025 18:44:50 +0800 Subject: [PATCH] feat: Add overlay commit mode. --- Flawless.Client/Service/RepositoryService.cs | 87 +++++++++++++------- 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/Flawless.Client/Service/RepositoryService.cs b/Flawless.Client/Service/RepositoryService.cs index f7ca449..8c6207b 100644 --- a/Flawless.Client/Service/RepositoryService.cs +++ b/Flawless.Client/Service/RepositoryService.cs @@ -1221,11 +1221,13 @@ public class RepositoryService : BaseService var localDb = GetRepositoryLocalDatabase(repo); - var manifestList = CreateCommitManifestByCurrentBaselineAndChanges(localDb.LocalAccessor, changes); + var (manifestList, miniManifestList) = CreateCommitManifestByCurrentBaselineAndChanges(localDb.LocalAccessor, changes); + var snapshot = manifestList.Select(l => $"{l.ModifyTime.ToBinary()}${l.WorkPath}"); + + Guid commitId; try { - // Renew for once. if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync())) { @@ -1234,38 +1236,63 @@ public class RepositoryService : BaseService } // Decide create new depot, create full depot or create addon depot. - var changesSize = localDb.LocalAccessor.Changes.Values.Sum(x => (long) x.File.Size); var hasAddOrModify = localDb.LocalAccessor.Changes.Any(x => x.Value.Type == ChangeInfoType.Add || x.Value.Type == ChangeInfoType.Modify); + var newDepot = forceBaseline || hasAddOrModify || localDb.RepoAccessor == null; - - // Generate depot - var tempDepotPath = await CreateDepotIntoTempFileAsync(repo, manifestList); - if (tempDepotPath == null) return null; - - // Upload and create commit - await using var str = File.OpenRead(tempDepotPath); - var snapshot = manifestList.Select(l => $"{l.ModifyTime.ToBinary()}${l.WorkPath}"); - if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync())) + if (newDepot) { - api.ClearGateway(); - return null; + var changesSize = localDb.LocalAccessor.Changes.Values.Sum(x => (long) x.File.Size); + var baselineSize = localDb.RepoAccessor?.Sum(x => (long) x.Size) ?? 0; + var changesRatio = changesSize / (double) baselineSize; + var isBaseline = forceBaseline || localDb.CurrentCommit == null || changesRatio > 0.8f; + var depotFiles = isBaseline ? manifestList : miniManifestList; + + // Generate depot + var tempDepotPath = await CreateDepotIntoTempFileAsync(repo, depotFiles); + if (tempDepotPath == null) return null; + Console.WriteLine($"Create new {(isBaseline ? "baseline" : "overlay")} depot at \"{tempDepotPath}\""); + + // Upload and create commit + await using var str = File.OpenRead(tempDepotPath); + if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync())) + { + api.ClearGateway(); + return null; + } + + var requireDepot = isBaseline ? [] : new[] {localDb.CurrentCommit.ToString()!}; + var rsp = await api.Gateway.CreateCommit(repo.OwnerName, repo.Name, + new StreamPart(str, Path.GetFileName(tempDepotPath)), message, snapshot, requireDepot, ""); + + commitId = rsp.CommitId; + + // Move depot file to destination + var depotsPath = PathUtility.GetWorkspaceDepotCachePath(Api.Current.Username.Value!, repo.OwnerName, repo.Name); + var finalPath = Path.Combine(depotsPath, rsp.MainDepotId.ToString()); + Directory.CreateDirectory(depotsPath); + File.Move(tempDepotPath, finalPath, true); + } + else + { + // Upload and create commit + if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync())) + { + api.ClearGateway(); + return null; + } + + var rsp = await api.Gateway.CreateCommit(repo.OwnerName, repo.Name, null!, + message, snapshot, [], localDb.CurrentCommit?.ToString() ?? ""); + + commitId = rsp.CommitId; } - var rsp = await api.Gateway.CreateCommit(repo.OwnerName, repo.Name, - new StreamPart(str, Path.GetFileName(tempDepotPath)), message, snapshot, [], string.Empty); - - // Move depot file to destination - var depotsPath = PathUtility.GetWorkspaceDepotCachePath(Api.Current.Username.Value!, repo.OwnerName, repo.Name); - var finalPath = Path.Combine(depotsPath, rsp.MainDepotId.ToString()); - Directory.CreateDirectory(depotsPath); - File.Move(tempDepotPath, finalPath, true); - // Fetch mapped manifest - var manifest = await DownloadManifestFromServerAsync(repo, rsp.CommitId); + var manifest = await DownloadManifestFromServerAsync(repo, commitId); if (manifest == null) return null; - var accessor = await DownloadDepotsAndUseLocalCachesToGenerateRepositoryFileTreeAccessorFromServerAsync(repo, rsp.CommitId); + var accessor = await DownloadDepotsAndUseLocalCachesToGenerateRepositoryFileTreeAccessorFromServerAsync(repo, commitId); if (accessor == null) return null; //todo this is a really fatal issue... if (localDb.RepoAccessor != null) { @@ -1282,10 +1309,11 @@ public class RepositoryService : BaseService // Point to latest state. localDb.RepoAccessor = accessor; - localDb.CurrentCommit = rsp.CommitId; + localDb.CurrentCommit = commitId; localDb.LocalAccessor.SetBaseline(accessor); SaveRepositoryLocalDatabaseChanges(repo); + Console.WriteLine($"Successful create commit as {commitId}"); return manifest; } catch (Exception e) @@ -1296,11 +1324,12 @@ public class RepositoryService : BaseService } } - public List CreateCommitManifestByCurrentBaselineAndChanges + private (List, List) CreateCommitManifestByCurrentBaselineAndChanges (LocalFileTreeAccessor accessor, IEnumerable changes, bool hard = false) { // Create a new depot file manifest. var files = accessor.BaselineFiles.Values.ToList(); + var overlayFsStatus = new List(); foreach (var c in changes) { switch (c.Type) @@ -1325,6 +1354,7 @@ public class RepositoryService : BaseService } files.Add(c.File); + overlayFsStatus.Add(c.File); break; } case ChangeInfoType.Remove: @@ -1355,12 +1385,13 @@ public class RepositoryService : BaseService } files[idx] = c.File; + overlayFsStatus.Add(c.File); break; } } } - return files; + return (files, overlayFsStatus); } public async ValueTask CreateDepotIntoTempFileAsync(RepositoryModel repo, IEnumerable depotFiles)