Editor/LibraryDetailProxy.cs
using System;
using System.Text.Json;
using System.Threading.Tasks;
using System.IO;
using static Editor.Label;
using System.Diagnostics;
using Editor;
public class LibraryDetailProxy : Widget
{
Package Package;
LibraryProject SelectedLibrary;
Button InstallButton;
Button UninstallButton;
ComboBox LibraryList;
LibraryProject ComboLibrarySelection;
Label ComboLibraryLabel;
Button InstallLibraryButton;
Button UninstallLibraryButton;
ImportedLibraries importedLibraries = new ImportedLibraries();
public string libraryStagingFolder => $@"{Project.Current.RootDirectory}\staging\libraryimporter";
public string projectAssetsFolder => GetAssetsFolder(Project.Current, Package);
public string projectCodeFolder => GetCodeFolder(Project.Current, Package);
public string projectEditorFolder => GetEditorFolder(Project.Current, Package);
public string selectedLibraryAssetsFolder => GetAssetsFolder(ComboLibrarySelection?.Project, SelectedLibrary?.Project?.Package);
public string selectedLibraryCodeFolder => GetCodeFolder(ComboLibrarySelection?.Project, SelectedLibrary?.Project?.Package);
public string selectedLibraryEditorFolder => GetEditorFolder(ComboLibrarySelection?.Project, SelectedLibrary?.Project?.Package);
public List<string> blacklistedFolders = new List<string> { "bin", "obj", "Properties" };
public List<string> blacklistedFileTypes = new List<string> { ".csproj" };
public string importingLibraryToLibraryID => $"{SelectedLibrary.Project.Package.Ident}-{ComboLibrarySelection.Project.Package.Ident}";
public LibraryDetailProxy( Package package ) : base()
{
Package = package;
Layout = Layout.Column();
Layout.Margin = 8;
Layout.Spacing = 4;
importedLibraries = ImportedLibraries.Load();
_ = FetchAndBuild();
}
async Task FetchAndBuild()
{
if ( !this.IsValid() ) return;
Layout.Clear( true );
if ( !Sandbox.Package.TryParseIdent( Package.FullIdent, out var ident ) )
return;
SelectedLibrary = LibrarySystem.All.FirstOrDefault(x => x.Project.Package.Ident == Package.Ident && x.Project.Package.Org == Package.Org);
bool hasStagedLibrary = importedLibraries.packageIndentToStagedVersion.ContainsKey(Package.Ident);
string stagedVersion = "";
if (hasStagedLibrary)
{
stagedVersion = importedLibraries.packageIndentToStagedVersion[Package.Ident];
}
bool stagedVersionDifferentFromInstalled = stagedVersion != SelectedLibrary.Version.ToString();
bool hasImportedLibraryToProject = importedLibraries.packageIndentToProjectImportedVersion.ContainsKey(Package.Ident);
string importedVersionToProject = "";
if (hasImportedLibraryToProject)
{
importedVersionToProject = importedLibraries.packageIndentToProjectImportedVersion[Package.Ident];
}
bool importedVersionDifferentFromInstalled = importedVersionToProject != SelectedLibrary.Version.ToString();
// do we have this package installed? what is the version?
if ( ident.org != "local" )
{
Package = await Package.FetchAsync( $"{ident.org}.{ident.package}", false ) ?? Package;
if ( !this.IsValid() ) return;
}
// Header, todo, icon and title
Layout.Add( new Label( $"{Package.Title} from {Package.Org.Title}" ) );
Layout.Add( new Label( $"Installed Version: {SelectedLibrary.Version}" ) );
if (!hasStagedLibrary)
{
Layout.Add(new Label($"Library has not been staged."));
InstallButton = new Button("Stage Library (move contents into staging folder)", this) { Pressed = () => MoveLibraryFolderToStaging(SelectedLibrary) };
Layout.Add(InstallButton);
Layout.AddStretchCell();
return;
}
Layout.Add(new Label(""));
Layout.Add(new Label("Staging"));
Layout.Add(new Label($"Staged Version: {stagedVersion}"));
if (stagedVersionDifferentFromInstalled)
{
InstallButton = new Button("Restage Library (move contents into staging folder)", this) { Pressed = () => MoveLibraryFolderToStaging(SelectedLibrary) };
Layout.Add(InstallButton);
}
Layout.Add(new Label(""));
Layout.Add(new Label($"Project"));
if (hasImportedLibraryToProject)
{
Layout.Add(new Label($"Imported Version: {importedVersionToProject}"));
}
if (hasImportedLibraryToProject && importedVersionDifferentFromInstalled)
{
InstallButton = new Button("Reimport to Project", this) { Pressed = () => CopyStagedLibraryToProject(SelectedLibrary) };
Layout.Add(InstallButton);
}
else if (!hasImportedLibraryToProject)
{
InstallButton = new Button("Import to Project", this) { Pressed = () => CopyStagedLibraryToProject(SelectedLibrary) };
Layout.Add(InstallButton);
}
if (hasImportedLibraryToProject)
{
UninstallButton = new Button("Remove from Project", this) { Pressed = () => DeleteImportedLibraryFolderFromProject(SelectedLibrary) };
Layout.Add(UninstallButton);
}
var otherLibraries = LibrarySystem.All.Where(x => x.Project.Package.Ident != "libraryimporter" && x.Project.Package.Ident != SelectedLibrary.Project.Package.Ident);
ComboLibrarySelection = otherLibraries.FirstOrDefault();
if (ComboLibrarySelection == null)
{
Layout.AddStretchCell();
return;
}
Layout.Add(new Label(""));
Layout.Add(new Label($"Library"));
bool hasImportedLibraryToLibrary = importedLibraries.packageIndentToLibraryImportedVersion.ContainsKey(importingLibraryToLibraryID);
string importedVersionToLibrary = "";
if (hasImportedLibraryToLibrary)
{
importedVersionToLibrary = importedLibraries.packageIndentToLibraryImportedVersion[importingLibraryToLibraryID];
}
bool importedVersionDifferentFromInstalledLibrary = importedVersionToLibrary != SelectedLibrary.Version.ToString();
ComboLibraryLabel = new Label($"");
Layout.Add(ComboLibraryLabel);
if (hasImportedLibraryToLibrary)
{
ComboLibraryLabel.Text = $"Imported Version: {importedVersionToLibrary}";
}
else
{
ComboLibraryLabel.Hide();
}
LibraryList = new ComboBox(this);
Layout.Add(LibraryList);
foreach (var otherLibrary in otherLibraries)
{
LibraryList.AddItem($"{otherLibrary.Project.Package.Title}", null, () => OnComboBoxLibrarySelected(otherLibrary), null, ComboLibrarySelection == otherLibrary);
}
InstallLibraryButton = new Button("Reimport to Library", this) { Pressed = () => CopyStagedLibraryToLibrary(SelectedLibrary, ComboLibrarySelection) };
Layout.Add(InstallLibraryButton);
if (!hasImportedLibraryToLibrary)
{
InstallLibraryButton.Text = "Import to Library";
}
if (hasImportedLibraryToLibrary && !importedVersionDifferentFromInstalledLibrary)
{
InstallLibraryButton.Hide();
}
UninstallLibraryButton = new Button("Remove from Library", this) { Pressed = () => DeleteImportedLibraryFolderFromLibrary() };
Layout.Add(UninstallLibraryButton);
if (!hasImportedLibraryToLibrary)
{
UninstallLibraryButton.Hide();
}
// information about this
Layout.AddStretchCell();
}
void OnComboBoxLibrarySelected(LibraryProject libraryProject)
{
ComboLibrarySelection = libraryProject;
// TODO: Check the state of export
// Duplicated logic, but fuck it I'm bored of this
bool hasImportedLibraryToLibrary = importedLibraries.packageIndentToLibraryImportedVersion.ContainsKey(importingLibraryToLibraryID);
string importedVersionToLibrary = "";
if (hasImportedLibraryToLibrary)
{
importedVersionToLibrary = importedLibraries.packageIndentToLibraryImportedVersion[importingLibraryToLibraryID];
}
bool importedVersionDifferentFromInstalledLibrary = importedVersionToLibrary != SelectedLibrary.Version.ToString();
if (hasImportedLibraryToLibrary)
{
if (importedVersionDifferentFromInstalledLibrary)
{
InstallLibraryButton.Text = "Reimport to Library";
InstallLibraryButton.Show();
}
else
{
InstallLibraryButton.Hide();
}
UninstallLibraryButton.Show();
}
else
{
InstallLibraryButton.Text = "Import to Library";
InstallLibraryButton.Show();
UninstallLibraryButton.Hide();
}
}
void CopyStagedLibraryToProject(LibraryProject libraryProject)
{
if (libraryProject?.Project?.Package == null)
{
Log.Error($"CopyStagedLibraryToProject() error null libraryProject!!!");
return;
}
string libraryRootFolder = @$"{libraryStagingFolder}\{libraryProject.Project.Package.Ident}";
string libraryCodeFolder = @$"{libraryRootFolder}\code";
string libraryEditorFolder = @$"{libraryRootFolder}\Editor";
string libraryAssetsFolder = @$"{libraryRootFolder}\Assets";
CopyFiles(libraryCodeFolder, projectCodeFolder);
CopyFiles(libraryEditorFolder, projectEditorFolder);
CopyFiles(libraryCodeFolder, projectAssetsFolder);
importedLibraries.packageIndentToProjectImportedVersion[Package.Ident] = libraryProject.Version.ToString();
importedLibraries.Save();
_ = FetchAndBuild();
}
void CopyStagedLibraryToLibrary(LibraryProject libraryProject, LibraryProject targetLibraryProject)
{
if (libraryProject?.Project?.Package == null || targetLibraryProject?.Project?.Package == null)
{
Log.Error($"CopyStagedLibraryToLibrary() error null libraryProject or targetLibraryProject!!!");
return;
}
string libraryRootFolder = @$"{libraryStagingFolder}\{libraryProject.Project.Package.Ident}";
string libraryCodeFolder = @$"{libraryRootFolder}\code";
string libraryEditorFolder = @$"{libraryRootFolder}\Editor";
string libraryAssetsFolder = @$"{libraryRootFolder}\Assets";
CopyFiles(libraryCodeFolder, selectedLibraryCodeFolder);
CopyFiles(libraryEditorFolder, selectedLibraryCodeFolder);
CopyFiles(libraryCodeFolder, selectedLibraryAssetsFolder);
importedLibraries.packageIndentToLibraryImportedVersion[importingLibraryToLibraryID] = libraryProject.Version.ToString();
importedLibraries.Save();
_ = FetchAndBuild();
}
void MoveLibraryFolderToStaging(LibraryProject libraryProject)
{
if (libraryProject?.Project?.Package == null)
{
Log.Error($"MoveLibraryFolderToStaging() error null libraryProject!!!");
return;
}
string stageFolderRoot = @$"{libraryStagingFolder}\{libraryProject.Project.Package.Ident}\";
string libraryRootFolder = $"{libraryProject.Project.RootDirectory.FullName}";
string libraryCodeFolder = @$"{libraryRootFolder}\code";
string libraryEditorFolder = @$"{libraryRootFolder}\Editor";
string libraryAssetsFolder = @$"{libraryRootFolder}\Assets";
string libraryUnitTestFolder = @$"{libraryRootFolder}\UnitTests";
string targetCodeFolder = @$"{libraryStagingFolder}\{libraryProject.Project.Package.Ident}\code";
string targetEditorFolder = @$"{libraryStagingFolder}\{libraryProject.Project.Package.Ident}\Editor";
string targetAssetsFolder = @$"{libraryStagingFolder}\{libraryProject.Project.Package.Ident}\Assets";
if (Directory.Exists(stageFolderRoot))
{
Directory.Delete(stageFolderRoot, true);
}
CopyFiles(libraryCodeFolder, targetCodeFolder, true);
CopyFiles(libraryEditorFolder, targetEditorFolder, true);
CopyFiles(libraryAssetsFolder, targetAssetsFolder, true);
try
{
// I don't care about unit tests, so fuck em
if (Directory.Exists(libraryUnitTestFolder))
{
Directory.Delete(libraryUnitTestFolder, true);
}
}
catch
{
Log.Error("Could not delete libraryUnitTestFolder, you'll have to do it manually.");
}
importedLibraries.packageIndentToStagedVersion[libraryProject.Project.Package.Ident] = libraryProject.Version.ToString();
importedLibraries.Save();
_ = FetchAndBuild();
}
void CopyFiles(string sourceFolder, string targetFolder, bool moveNotCopy = false)
{
var relativePaths = GetRelativeFilePaths(sourceFolder, blacklistedFolders, blacklistedFileTypes);
//Log.Info($"CopyFiles() relativePaths: {relativePaths.Count()}");
foreach (var path in relativePaths)
{
var sourcePath = @$"{sourceFolder}\{path}";
var targetPath = @$"{targetFolder}\{path}";
var targetDirectory = Path.GetDirectoryName(targetPath);
if (!Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
if (moveNotCopy)
{
File.Move(sourcePath, targetPath, true);
}
else
{
File.Copy(sourcePath, targetPath, true);
}
//Log.Info($"{(moveNotCopy ? "Move" : "Copy")} sourcePath: {sourcePath} to targetPath: {targetPath}");
}
}
void DeleteImportedLibraryFolderFromProject(LibraryProject libraryProject)
{
if (Directory.Exists(projectCodeFolder))
{
Directory.Delete(projectCodeFolder, true);
}
if (Directory.Exists(projectEditorFolder))
{
Directory.Delete(projectEditorFolder, true);
}
if (Directory.Exists(projectAssetsFolder))
{
Directory.Delete(projectAssetsFolder, true);
}
string packageIdent = libraryProject.Project.Package.Ident;
if (importedLibraries.packageIndentToProjectImportedVersion.ContainsKey(packageIdent))
{
importedLibraries.packageIndentToProjectImportedVersion.Remove(packageIdent);
importedLibraries.Save();
}
_ = FetchAndBuild();
}
void DeleteImportedLibraryFolderFromLibrary()
{
if (Directory.Exists(selectedLibraryCodeFolder))
{
Directory.Delete(selectedLibraryCodeFolder, true);
}
if (Directory.Exists(selectedLibraryEditorFolder))
{
Directory.Delete(selectedLibraryEditorFolder, true);
}
if (Directory.Exists(selectedLibraryAssetsFolder))
{
Directory.Delete(selectedLibraryAssetsFolder, true);
}
if (importedLibraries.packageIndentToLibraryImportedVersion.ContainsKey(importingLibraryToLibraryID))
{
importedLibraries.packageIndentToLibraryImportedVersion.Remove(importingLibraryToLibraryID);
importedLibraries.Save();
}
_ = FetchAndBuild();
}
void DeleteImportedLibraryFolderInLibrary(string packageIndent)
{
string folder = @$"{selectedLibraryCodeFolder}";
string folderEditor = @$"{selectedLibraryEditorFolder}";
if (Directory.Exists(folder))
{
Directory.Delete(folder, true);
}
if (Directory.Exists(folderEditor))
{
Directory.Delete(folderEditor, true);
}
string id = $"{ComboLibrarySelection.Project.Package.Ident}-{Package.Ident}";
if (importedLibraries.packageIndentToLibraryImportedVersion.ContainsKey(id))
{
importedLibraries.packageIndentToLibraryImportedVersion.Remove(id);
importedLibraries.Save();
}
}
static IEnumerable<string> GetRelativeFilePaths(string rootDirectory, List<string> blacklistedFolders, List<string> blacklistedFileTypes)
{
var filePaths = new List<string>();
if (!Directory.Exists(rootDirectory))
{
return filePaths;
}
foreach (var filePath in Directory.EnumerateFiles(rootDirectory, "*.*", SearchOption.AllDirectories))
{
// Check if the file is in a blacklisted folder
var directoryName = Path.GetDirectoryName(filePath);
if (blacklistedFolders.Any(folder => directoryName.Contains(folder, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
// Check if the file has a blacklisted extension
var fileExtension = Path.GetExtension(filePath);
if (blacklistedFileTypes.Contains(fileExtension, StringComparer.OrdinalIgnoreCase))
{
continue;
}
// Get the relative path
var relativePath = Path.GetRelativePath(rootDirectory, filePath);
filePaths.Add(relativePath);
}
return filePaths;
}
public string GetAssetsFolder(Project inProject, Package inPackage)
{
if (inProject == null || inPackage == null)
return null;
string folder = @$"{inProject.GetAssetsPath()}\libraries\{inPackage.Ident}";
return folder;
}
public string GetCodeFolder(Project inProject, Package inPackage)
{
if (inProject == null || inPackage == null)
return null;
string folder = @$"{inProject.GetCodePath()}\libraries\{inPackage.Ident}";
return folder;
}
public string GetEditorFolder(Project inProject, Package inPackage)
{
if (inProject == null || inPackage == null)
return null;
string folder = @$"{inProject.GetRootPath()}\Editor\libraries\{inPackage.Ident}";
return folder;
}
protected override Vector2 SizeHint()
{
return new Vector2( 300, 100 );
}
}
public class ImportedLibraries
{
public Dictionary<string, string> packageIndentToProjectImportedVersion { get; set; } = new Dictionary<string, string>();
public Dictionary<string, string> packageIndentToLibraryImportedVersion { get; set; } = new Dictionary<string, string>();
public Dictionary<string, string> packageIndentToStagedVersion { get; set; } = new Dictionary<string, string>();
static string libraryStagingFolder => $@"{Project.Current.RootDirectory}\staging\libraryimporter";
static string saveFilePath => @$"{libraryStagingFolder}\imported_libraries.json";
public void Save()
{
var json = JsonSerializer.Serialize(this, GetSerializerOptions());
System.IO.File.WriteAllText(saveFilePath, json);
}
public static ImportedLibraries Load()
{
if (!System.IO.File.Exists(saveFilePath))
{
return new ImportedLibraries();
}
var fileContents = System.IO.File.ReadAllText(saveFilePath);
var inst = JsonSerializer.Deserialize<ImportedLibraries>(fileContents, GetSerializerOptions());
return inst;
}
public static JsonSerializerOptions GetSerializerOptions()
{
var serializerOptions = new JsonSerializerOptions();
serializerOptions.WriteIndented = true;
return serializerOptions;
}
}