Files
crosslangdevstudio/ViewModels/PublishDialogViewModel.cs
2025-10-22 17:31:32 -05:00

279 lines
8.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading.Tasks;
using System.Web;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CrossLangDevStudio.Messages;
using CrossLangDevStudio.Views;
using Newtonsoft.Json;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.BZip2;
using System.Text;
using Avalonia.Platform.Storage;
namespace CrossLangDevStudio.ViewModels;
public partial class PublishDialogViewModel : ViewModelBase
{
public string Path { get; }
public PublishDialogViewModel(string path)
{
Path = path;
foreach (var item in CrossLangShell.GetServers())
{
Servers.Add(item);
}
Targets.Add(new Target("copy", "Just Copy"));
Targets.Add(new Target("crvm", "Merge"));
Targets.Add(new Target("cmake", "CMake"));
Targets.Add(new Target("header", "C++ Header"));
this.TargetIndex = 0;
}
[ObservableProperty]
private string _prefix = "Tesses.CrossLang.Runtime";
public ObservableCollection<string> Servers { get; } = new ObservableCollection<string>();
[ObservableProperty]
private int _serverIndex = 0;
public ObservableCollection<Target> Targets { get; } = new ObservableCollection<Target>();
[ObservableProperty]
private int _targetIndex = 0;
[ObservableProperty]
private string _output = "";
int _ot=0;
public int OutputType
{
get => _ot;
set {
_ot = value;
switch(value)
{
case 0:
OutputLabel = "Directory To Publish To (Optional)";
break;
case 1:
OutputLabel = "Zip Path";
break;
case 2:
case 3:
case 4:
OutputLabel = "Tar Path";
break;
}
}
}
[ObservableProperty]
private string _outputLabel = "Directory To Publish To (Optional)";
[RelayCommand]
private async Task BrowseAsync()
{
var window = await WeakReferenceMessenger.Default.Send<GetWindowMessage>();
if (OutputType == 0)
{
var res = await window.StorageProvider.OpenFolderPickerAsync(new Avalonia.Platform.Storage.FolderPickerOpenOptions() { Title = "Pick publish folder" });
if (res.Count != 0)
{
string? path = res[0].TryGetLocalPath();
if (!string.IsNullOrWhiteSpace(path))
this.Output = path;
}
}
else
{
string ext = "zip";
switch(OutputType)
{
case 2:
ext = "tar";
break;
case 3:
ext = "tar.gz";
break;
case 4:
ext = "tar.bz2";
break;
}
var res = await window.StorageProvider.SaveFilePickerAsync(new Avalonia.Platform.Storage.FilePickerSaveOptions() { Title = $"Save {ext}", DefaultExtension = $".{ext}" , FileTypeChoices = [new FilePickerFileType(ext.ToUpper()){ Patterns =[$".{ext}"]}]});
if (res is not null)
{
string? path = res.TryGetLocalPath();
if (!string.IsNullOrWhiteSpace(path))
this.Output = path;
}
}
}
[RelayCommand]
private async Task LoadAsync()
{
Targets.Clear();
Targets.Add(new Target("copy", "Just Copy"));
Targets.Add(new Target("crvm", "Merge"));
Targets.Add(new Target("cmake", "CMake"));
Targets.Add(new Target("header", "C++ Header"));
this.TargetIndex = 0;
if (ServerIndex >= 0 && ServerIndex < this.Servers.Count)
{
string url = $"{this.Servers[ServerIndex].TrimEnd('/')}/api/v1/search?type=archive";
if (!string.IsNullOrWhiteSpace(Prefix))
{
url = $"{url}&q={HttpUtility.UrlEncode(Prefix.TrimEnd('.'))}.";
}
var window = await WeakReferenceMessenger.Default.Send(new GetWindowMessage());
if (window is not null && window.DataContext is MainWindowViewModel mwvm)
{
int page = 0;
bool hadany = false;
do
{
var body = await mwvm.Client.GetStringAsync($"{url}&offset={page}");
page++;
var res = JsonConvert.DeserializeObject<PackageManagerViewModel.SearchResult>(body);
if (res is not null)
{
hadany = res.Packages.Count > 0;
foreach (var item in res.Packages)
{
string name = item.Name;
if (!string.IsNullOrWhiteSpace(Prefix))
{
int prefixLen = Prefix.TrimEnd('.').Length + 1;
name = name.Substring(prefixLen);
}
Targets.Add(new Target(name, name));
}
}
} while (hadany);
}
}
}
[RelayCommand]
private async Task PublishAsync()
{
string ident = Targets[TargetIndex].Real;
await CrossLangShell.PublishAsync(Path, ident, Prefix, OutputType == 0 ? Output : "");
void Tar(Stream strm)
{
string dir = System.IO.Path.Combine(Path, "publish", ident);
using (var tarArchive = TarArchive.CreateOutputTarArchive(strm, Encoding.UTF8))
{
tarArchive.RootPath = System.IO.Path.DirectorySeparatorChar == '/' ? dir : dir.Replace('\\', '/');
if (tarArchive.RootPath.EndsWith("/"))
tarArchive.RootPath = tarArchive.RootPath.Remove(tarArchive.RootPath.Length - 1);
DirectoryContents(tarArchive, dir);
}
/*
TarEntry ent = TarEntry.CreateEntryFromFile();
ent.TarHeader.Mode = 0755;
ent.TarHeader.UserId = 1000;
ent.TarHeader.GroupId = 1000;
*/
}
if (OutputType > 0)
{
switch (OutputType)
{
case 1:
{
FastZip z = new FastZip();
z.CreateZip(Output, System.IO.Path.Combine(Path, "publish", ident), true, null);
}
break;
case 2:
{
using (var strm = File.Create(Output))
Tar(strm);
}
break;
case 3:
{
using (var strm = File.Create(Output))
{
using (var gz = new GZipOutputStream(strm))
Tar(gz);
}
}
break;
case 4:
{
using (var strm = File.Create(Output))
{
using (var bzip2 = new BZip2OutputStream(strm))
Tar(bzip2);
}
}
break;
}
}
_ = WeakReferenceMessenger.Default.Send(new PublishCloseMessage());
}
[RelayCommand]
private void Cancel()
{
WeakReferenceMessenger.Default.Send(new PublishCloseMessage());
}
private void DirectoryContents(TarArchive tarArchive, string src)
{
TarEntry tarEntry = TarEntry.CreateEntryFromFile(src);
tarArchive.WriteEntry(tarEntry, false);
// Write each file to the tar.
string[] filenames = Directory.GetFiles(src);
foreach (string filename in filenames)
{
tarEntry = TarEntry.CreateEntryFromFile(filename);
tarEntry.TarHeader.UserId = 1000;
tarEntry.TarHeader.GroupId = 1000;
tarArchive.WriteEntry(tarEntry, true);
}
string[] directories = Directory.GetDirectories(src);
foreach (string directory in directories)
DirectoryContents(tarArchive, directory);
}
}
public class Target(string real, string pretty)
{
public string Real => real;
public string Pretty => pretty;
public override string ToString()
{
return Pretty;
}
}