feat: Add merge handling logic.
This commit is contained in:
parent
852d935e80
commit
d3071b4999
@ -112,7 +112,7 @@ public class RepositoryFileTreeAccessor : IDisposable, IAsyncDisposable, IEnumer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryWriteDataIntoStream(string workPath, Stream stream, out DateTime modifyTime)
|
public bool TryWriteDataIntoDisk(string workPath, Stream stream, out DateTime modifyTime)
|
||||||
{
|
{
|
||||||
DisposeCheck();
|
DisposeCheck();
|
||||||
if (stream == null || !stream.CanWrite) throw new ArgumentException("Stream is not writable!");
|
if (stream == null || !stream.CanWrite) throw new ArgumentException("Stream is not writable!");
|
||||||
@ -129,7 +129,7 @@ public class RepositoryFileTreeAccessor : IDisposable, IAsyncDisposable, IEnumer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryWriteDataIntoStream(string workPath, string destinationPath)
|
public bool TryWriteDataIntoDisk(string workPath, string destinationPath)
|
||||||
{
|
{
|
||||||
DisposeCheck();
|
DisposeCheck();
|
||||||
|
|
||||||
|
|||||||
@ -5,15 +5,19 @@ using System.Collections.ObjectModel;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AvaloniaEdit.Utils;
|
using AvaloniaEdit.Utils;
|
||||||
using Flawless.Abstraction;
|
using Flawless.Abstraction;
|
||||||
using Flawless.Client.Models;
|
using Flawless.Client.Models;
|
||||||
using Flawless.Client.Remote;
|
using Flawless.Client.Remote;
|
||||||
|
using Flawless.Client.ViewModels.ModalBox;
|
||||||
|
using Flawless.Client.Views.ModalBox;
|
||||||
using Flawless.Core.BinaryDataFormat;
|
using Flawless.Core.BinaryDataFormat;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Refit;
|
using Refit;
|
||||||
|
using Ursa.Controls;
|
||||||
using CommitManifest = Flawless.Core.Modal.CommitManifest;
|
using CommitManifest = Flawless.Core.Modal.CommitManifest;
|
||||||
using DepotLabel = Flawless.Core.Modal.DepotLabel;
|
using DepotLabel = Flawless.Core.Modal.DepotLabel;
|
||||||
using WorkspaceFile = Flawless.Core.Modal.WorkspaceFile;
|
using WorkspaceFile = Flawless.Core.Modal.WorkspaceFile;
|
||||||
@ -742,7 +746,7 @@ public class RepositoryService : BaseService<RepositoryService>
|
|||||||
|
|
||||||
// Write into fs
|
// Write into fs
|
||||||
if (directory != null) Directory.CreateDirectory(directory);
|
if (directory != null) Directory.CreateDirectory(directory);
|
||||||
if (!accessor.TryWriteDataIntoStream(f.WorkPath, pfs))
|
if (!accessor.TryWriteDataIntoDisk(f.WorkPath, pfs))
|
||||||
throw new InvalidDataException($"Can not write {f.WorkPath} into repository.");
|
throw new InvalidDataException($"Can not write {f.WorkPath} into repository.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -789,7 +793,7 @@ public class RepositoryService : BaseService<RepositoryService>
|
|||||||
case ChangeInfoType.Remove:
|
case ChangeInfoType.Remove:
|
||||||
case ChangeInfoType.Modify:
|
case ChangeInfoType.Modify:
|
||||||
wfs = WorkPath.ToPlatformPath(ci.File.WorkPath, ls.LocalAccessor.WorkingDirectory);
|
wfs = WorkPath.ToPlatformPath(ci.File.WorkPath, ls.LocalAccessor.WorkingDirectory);
|
||||||
ls.RepoAccessor!.TryWriteDataIntoStream(ci.File.WorkPath, wfs);
|
ls.RepoAccessor!.TryWriteDataIntoDisk(ci.File.WorkPath, wfs);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChangeInfoType.Folder:
|
case ChangeInfoType.Folder:
|
||||||
@ -848,13 +852,12 @@ public class RepositoryService : BaseService<RepositoryService>
|
|||||||
{
|
{
|
||||||
if (mergeChanges)
|
if (mergeChanges)
|
||||||
unmerged.Add(f);
|
unmerged.Add(f);
|
||||||
else if (resetChanges && !accessor.TryWriteDataIntoStream(f.WorkPath, pfs))
|
else if (resetChanges && !accessor.TryWriteDataIntoDisk(f.WorkPath, pfs))
|
||||||
throw new InvalidDataException($"Can not write {f.WorkPath} into repository. (Reset changes)");
|
throw new InvalidDataException($"Can not write {f.WorkPath} into repository. (Reset changes)");
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!accessor.TryWriteDataIntoStream(f.WorkPath, pfs))
|
if (!accessor.TryWriteDataIntoDisk(f.WorkPath, pfs))
|
||||||
throw new InvalidDataException($"Can not write {f.WorkPath} into repository.");
|
throw new InvalidDataException($"Can not write {f.WorkPath} into repository.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -864,16 +867,16 @@ public class RepositoryService : BaseService<RepositoryService>
|
|||||||
{
|
{
|
||||||
var tester = accessor.Manifest.FilePaths.Select(static x => x.WorkPath).ToHashSet();
|
var tester = accessor.Manifest.FilePaths.Select(static x => x.WorkPath).ToHashSet();
|
||||||
foreach (var f in Directory.GetFiles(ls.LocalAccessor.WorkingDirectory, "*", SearchOption.AllDirectories))
|
foreach (var f in Directory.GetFiles(ls.LocalAccessor.WorkingDirectory, "*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
var wfs = WorkPath.FromPlatformPath(f, ls.LocalAccessor.WorkingDirectory);
|
var wfs = WorkPath.FromPlatformPath(f, ls.LocalAccessor.WorkingDirectory);
|
||||||
if (!tester.Contains(wfs)) File.Delete(f);
|
if (!tester.Contains(wfs)) File.Delete(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle merge one by one.
|
// Handle merge one by one.
|
||||||
foreach (var f in unmerged)
|
if (unmerged.Count > 0)
|
||||||
{
|
{
|
||||||
throw new Exception("No merge tools has been detected! Merge failed.");
|
await MergeFilesAsync(repo, accessor, unmerged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -933,6 +936,49 @@ public class RepositoryService : BaseService<RepositoryService>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async ValueTask MergeFilesAsync(RepositoryModel repo, RepositoryFileTreeAccessor repoAccessor, IEnumerable<WorkspaceFile> unmerged)
|
||||||
|
{
|
||||||
|
var root = PathUtility.GetWorkspaceManagerPath(Api.C.Username.Value, repo.OwnerName, repo.Name);
|
||||||
|
var srcTem = Path.Combine(root, "MergeInTemp");
|
||||||
|
|
||||||
|
using (Disposable.Create(srcTem, r => Directory.Delete(r, true)))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(root);
|
||||||
|
|
||||||
|
// Prepare server files
|
||||||
|
var wsRoot = PathUtility.GetWorkspacePath(Api.C.Username.Value, repo.OwnerName, repo.Name);
|
||||||
|
var vm = new MergeDialogViewModel(repo, unmerged, srcTem, wsRoot);
|
||||||
|
|
||||||
|
foreach (var f in vm.MergeFiles)
|
||||||
|
{
|
||||||
|
var pf = WorkPath.ToPlatformPath(f.WorkPath, vm.SrcFolder);
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(pf)!);
|
||||||
|
await using var fs = File.Create(pf);
|
||||||
|
repoAccessor.TryWriteDataIntoDisk(f.WorkPath, fs, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raise merge window
|
||||||
|
var opt = UIHelper.DefaultOverlayDialogOptionsYesNo();
|
||||||
|
opt.Buttons = DialogButton.OK;
|
||||||
|
opt.Title = "Merge files";
|
||||||
|
opt.FullScreen = true;
|
||||||
|
opt.IsCloseButtonVisible = false;
|
||||||
|
|
||||||
|
await OverlayDialog.ShowModal<MergeDialogView, MergeDialogViewModel>(vm, AppDefaultValues.HostId, opt);
|
||||||
|
|
||||||
|
// Rollback files
|
||||||
|
foreach (var f in vm.MergeFiles)
|
||||||
|
{
|
||||||
|
var copyFrom = WorkPath.ToPlatformPath(f.WorkPath, vm.TmpFolder);
|
||||||
|
if (!File.Exists(copyFrom)) continue; // If file existed, override it.
|
||||||
|
|
||||||
|
var copyTo = WorkPath.ToPlatformPath(f.WorkPath, vm.DstFolder);
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(copyTo)!);
|
||||||
|
File.Copy(copyFrom, copyTo, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async ValueTask<bool> UpdateCommitsHistoryFromServerAsync(RepositoryModel repo)
|
public async ValueTask<bool> UpdateCommitsHistoryFromServerAsync(RepositoryModel repo)
|
||||||
{
|
{
|
||||||
var api = Api.C;
|
var api = Api.C;
|
||||||
|
|||||||
44
Flawless.Client/ViewModels/ModalBox/MergeDialogViewModel.cs
Normal file
44
Flawless.Client/ViewModels/ModalBox/MergeDialogViewModel.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Flawless.Abstraction;
|
||||||
|
using Flawless.Client.Models;
|
||||||
|
using Flawless.Core.Modal;
|
||||||
|
using ReactiveUI.SourceGenerators;
|
||||||
|
|
||||||
|
namespace Flawless.Client.ViewModels.ModalBox;
|
||||||
|
|
||||||
|
public partial class MergeDialogViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
public ObservableCollection<WorkspaceFile> MergeFiles { get; }
|
||||||
|
|
||||||
|
public RepositoryModel Repository { get; }
|
||||||
|
|
||||||
|
public string SrcFolder { get; }
|
||||||
|
|
||||||
|
public string DstFolder { get; }
|
||||||
|
|
||||||
|
public string TmpFolder { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public MergeDialogViewModel(RepositoryModel repository, IEnumerable<WorkspaceFile> files,
|
||||||
|
string srcFolder, string dstFolder)
|
||||||
|
{
|
||||||
|
Repository = repository;
|
||||||
|
MergeFiles = new ObservableCollection<WorkspaceFile>(files);
|
||||||
|
SrcFolder = srcFolder;
|
||||||
|
DstFolder = dstFolder;
|
||||||
|
TmpFolder = Directory.CreateTempSubdirectory("Flawless_Merge").Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ReactiveCommand]
|
||||||
|
private async Task RaiseMergeToolsAsync(string fileWorkPath)
|
||||||
|
{
|
||||||
|
var srcFile = WorkPath.ToPlatformPath(fileWorkPath, SrcFolder);
|
||||||
|
var dstFile = Path.Combine(fileWorkPath, DstFolder);
|
||||||
|
var tmpFile = Path.Combine(fileWorkPath, TmpFolder);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -479,7 +479,7 @@ public partial class RepositoryViewModel : RoutableViewModelBase
|
|||||||
var kid = Repository.Commits.MaxBy(k => k.CommittedOn)!.CommitId;
|
var kid = Repository.Commits.MaxBy(k => k.CommittedOn)!.CommitId;
|
||||||
var changeDict = changes.ToImmutableDictionary(x => x.File.WorkPath, x => x.File);
|
var changeDict = changes.ToImmutableDictionary(x => x.File.WorkPath, x => x.File);
|
||||||
await RepositoryService.C.SetPointerAndMergeDepotsWithLocalFromRemoteAsync(
|
await RepositoryService.C.SetPointerAndMergeDepotsWithLocalFromRemoteAsync(
|
||||||
Repository, kid, changeDict, RepositoryResetMethod.Merge);
|
Repository, kid, changeDict, RepositoryResetMethod.Keep);
|
||||||
|
|
||||||
await DetectLocalChangesAsyncCommand.Execute();
|
await DetectLocalChangesAsyncCommand.Execute();
|
||||||
await RendererFileTreeAsync();
|
await RendererFileTreeAsync();
|
||||||
|
|||||||
23
Flawless.Client/Views/ModalBox/MergeDialogView.axaml
Normal file
23
Flawless.Client/Views/ModalBox/MergeDialogView.axaml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:vm="clr-namespace:Flawless.Client.ViewModels.ModalBox"
|
||||||
|
xmlns:u="https://irihi.tech/ursa"
|
||||||
|
x:DataType="vm:MergeDialogViewModel"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Flawless.Client.Views.ModalBox.MergeDialogView">
|
||||||
|
<ListBox ItemsSource="{Binding MergeFiles}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ListBoxItem>
|
||||||
|
<Grid Column="Auto, *, Auto">
|
||||||
|
<Label Grid.Column="0" Content="{Binding WorkPath}"/>
|
||||||
|
<u:IconButton Command="{Binding $parent[ItemsControl].((vm:MergeDialogViewModel)DataContext).RaiseMergeToolsCommand}"
|
||||||
|
CommandParameter="{Binding WorkPath}"/>
|
||||||
|
</Grid>
|
||||||
|
</ListBoxItem>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</UserControl>
|
||||||
13
Flawless.Client/Views/ModalBox/MergeDialogView.axaml.cs
Normal file
13
Flawless.Client/Views/ModalBox/MergeDialogView.axaml.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Flawless.Client.Views.ModalBox;
|
||||||
|
|
||||||
|
public partial class MergeDialogView : UserControl
|
||||||
|
{
|
||||||
|
public MergeDialogView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user