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 Servers { get; } = new ObservableCollection(); [ObservableProperty] private int _serverIndex = 0; public ObservableCollection Targets { get; } = new ObservableCollection(); [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(); 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(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; } }