Skip to content

Commit

Permalink
Merge pull request #1407 from glopesdev/mono-compatibility
Browse files Browse the repository at this point in the history
Mono compatibility improvements
  • Loading branch information
glopesdev authored Jun 12, 2023
2 parents 83f8581 + 2035f80 commit 10fba3d
Show file tree
Hide file tree
Showing 40 changed files with 1,069 additions and 252 deletions.
9 changes: 8 additions & 1 deletion Bonsai.Configuration/OverlayHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

namespace Bonsai.Configuration
{
Expand All @@ -17,7 +18,13 @@ static class OverlayHelper
const string NuGetOverlayCommandFileName = "NuGet-Overlay.cmd";
const string NuGetOverlayCommand = "nuget overlay";
const string NuGetOverlayVersionArgument = "-Version";
static readonly string[] SupportedRuntimes = new[] { "win-x86", "win-x64" };
static readonly string RuntimePlatform = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux" : "win";
public static readonly string[] SupportedRuntimes = RuntimeInformation.OSArchitecture switch
{
Architecture.Arm => new[] { $"{RuntimePlatform}-arm" },
Architecture.Arm64 => new[] { $"{RuntimePlatform}-arm64" },
_ => new[] { $"{RuntimePlatform}-x86", $"{RuntimePlatform}-x64" }
};

static RuntimeGraph GetRuntimeGraph(PackageReaderBase packageReader)
{
Expand Down
45 changes: 45 additions & 0 deletions Bonsai.Configuration/PackageConfigurationUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class PackageConfigurationUpdater : IDisposable
static readonly char[] DirectorySeparators = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
static readonly NuGetFramework NativeFramework = NuGetFramework.ParseFrameworkName("native,Version=v0.0", DefaultFrameworkNameProvider.Instance);
static readonly NuGetFramework WindowsFramework = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Windows, FrameworkConstants.EmptyVersion);
static readonly bool IsRunningOnMono = Type.GetType("Mono.Runtime") != null;

public PackageConfigurationUpdater(NuGetFramework projectFramework, PackageConfiguration configuration, IPackageManager manager, string bootstrapperPath = null, PackageIdentity bootstrapperName = null)
{
Expand Down Expand Up @@ -309,6 +310,48 @@ void RemoveContentFolders(PackageReaderBase package, string installPath, string
}
}

static IEnumerable<string> GetAssemblyConfigFiles(NuGetFramework projectFramework, PackageReaderBase package, string installPath)
{
const string AssemblyConfigExtension = ".dll.config";
var contentFolder = package.GetItems(PackagingConstants.Folders.ContentFiles).GetNearest(projectFramework) ??
package.GetItems(PackagingConstants.Folders.Content).GetNearest(projectFramework);
if (contentFolder == null) return Enumerable.Empty<string>();
return from file in contentFolder.Items
where file.EndsWith(AssemblyConfigExtension)
select Path.Combine(installPath, file);
}

void UpdateAssemblyConfigFiles(PackageReaderBase package, string installPath, Action<string, string> update)
{
var assemblyConfigFiles = GetAssemblyConfigFiles(bootstrapperFramework, package, installPath)
.ToDictionary(configFile => Path.GetFileNameWithoutExtension(configFile));
if (assemblyConfigFiles.Count > 0)
{
var assemblyLocations = GetCompatibleAssemblyReferences(bootstrapperFramework, package);
foreach (var path in assemblyLocations)
{
var assemblyName = Path.GetFileName(path);
if (assemblyConfigFiles.TryGetValue(assemblyName, out string configFilePath))
{
var configFileName = Path.GetFileName(configFilePath);
var assemblyConfigFilePath = Path.GetDirectoryName(path);
assemblyConfigFilePath = Path.Combine(installPath, assemblyConfigFilePath, configFileName);
update(configFilePath, assemblyConfigFilePath);
}
}
}
}

void AddAssemblyConfigFiles(PackageReaderBase package, string installPath)
{
UpdateAssemblyConfigFiles(package, installPath, File.Copy);
}

void RemoveAssemblyConfigFiles(PackageReaderBase package, string installPath)
{
UpdateAssemblyConfigFiles(package, installPath, (_, configFilePath) => File.Delete(configFilePath));
}

class PackageConfigurationPlugin : PackageManagerPlugin
{
public PackageConfigurationPlugin(PackageConfigurationUpdater owner)
Expand Down Expand Up @@ -382,6 +425,7 @@ public override Task OnPackageInstalledAsync(PackageIdentity package, NuGetFrame
Owner.AddContentFolders(installPath, ExtensionsDirectory);
Owner.RegisterLibraryFolders(packageReader, relativePath);
Owner.RegisterAssemblyLocations(packageReader, installPath, relativePath, false);
if (IsRunningOnMono) Owner.AddAssemblyConfigFiles(packageReader, installPath);
var pivots = OverlayHelper.FindPivots(package, packageReader).ToArray();
if (pivots.Length > 0)
{
Expand Down Expand Up @@ -425,6 +469,7 @@ public override async Task OnPackageUninstalledAsync(PackageIdentity package, Nu
Owner.RemoveContentFolders(packageReader, installPath, ExtensionsDirectory);
Owner.RemoveLibraryFolders(packageReader, relativePath);
Owner.RemoveAssemblyLocations(packageReader, relativePath, false);
if (IsRunningOnMono) Owner.RemoveAssemblyConfigFiles(packageReader, installPath);
var pivots = OverlayHelper.FindPivots(package, packageReader).ToArray();
if (pivots.Length > 0)
{
Expand Down
7 changes: 3 additions & 4 deletions Bonsai.Configuration/ScriptExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ public class ScriptExtensions : IDisposable
</PropertyGroup>
</Project>";

IDictionary<string, Configuration.PackageReference> packageMap;
PackageConfiguration packageConfiguration;
TempDirectory assemblyFolder;
readonly IDictionary<string, PackageReference> packageMap;
readonly PackageConfiguration packageConfiguration;
readonly TempDirectory assemblyFolder;

public ScriptExtensions(PackageConfiguration configuration, string outputPath)
{
Expand Down
35 changes: 28 additions & 7 deletions Bonsai.Configuration/ScriptExtensionsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Xml;

Expand Down Expand Up @@ -113,14 +114,34 @@ from assemblyReference in FindAssemblyReferences(
assemblyNames.AddRange(projectReferences);
}

var runtimeDirectory = RuntimeEnvironment.GetRuntimeDirectory();
var runtimeAssemblyMap = Directory
.EnumerateFiles(runtimeDirectory, "*" + DllExtension)
.ToDictionary(Path.GetFileNameWithoutExtension);
var facadesDirectory = Path.Combine(runtimeDirectory, "Facades");
if (Directory.Exists(facadesDirectory) &&
Directory.GetFiles(facadesDirectory, "netstandard.dll").FirstOrDefault() is string netstandardLocation)
{
var netstandardName = Path.GetFileNameWithoutExtension(netstandardLocation);
runtimeAssemblyMap[netstandardName] = netstandardLocation;
}

var assemblyFile = Path.Combine(assemblyDirectory, OutputAssemblyName + DllExtension);
var assemblyReferences = (from fileName in assemblyNames
let assemblyName = Path.GetFileNameWithoutExtension(fileName)
let assemblyLocation = ConfigurationHelper.GetAssemblyLocation(configuration, assemblyName)
select assemblyLocation == null ? fileName :
Path.IsPathRooted(assemblyLocation) ? assemblyLocation :
Path.Combine(configurationRoot, assemblyLocation))
.ToArray();
var assemblyReferences = assemblyNames.Select(GetAssemblyLocation).ToArray();
string GetAssemblyLocation(string fileName)
{
var assemblyName = Path.GetFileNameWithoutExtension(fileName);
var assemblyLocation = ConfigurationHelper.GetAssemblyLocation(configuration, assemblyName);
if (assemblyLocation != null || runtimeAssemblyMap.TryGetValue(assemblyName, out assemblyLocation))
{
return Path.IsPathRooted(assemblyLocation)
? assemblyLocation
: Path.Combine(configurationRoot, assemblyLocation);
}

return fileName;
}

var compilerParameters = new CompilerParameters(assemblyReferences, assemblyFile);
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = false;
Expand Down
21 changes: 17 additions & 4 deletions Bonsai.Design/AnnotationBuilderEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,24 @@ public override bool EditComponent(ITypeDescriptorContext context, object compon
var editorState = (IWorkflowEditorState)provider.GetService(typeof(IWorkflowEditorState));
if (editorState != null && !editorState.WorkflowRunning && component is AnnotationBuilder annotationBuilder)
{
using var editorDialog = new AnnotationBuilderEditorDialog();
editorDialog.Annotation = annotationBuilder.Text;
if (editorDialog.ShowDialog(owner) == DialogResult.OK)
if (AnnotationTextEditor.IsRunningOnMono)
{
annotationBuilder.Text = editorDialog.Annotation;
using var editorDialog = new RichTextEditorDialog();
editorDialog.Text = RichTextEditor.CamelCaseToSpaces(typeof(AnnotationTextEditor).Name);
editorDialog.Value = annotationBuilder.Text;
if (editorDialog.ShowDialog(owner) == DialogResult.OK)
{
annotationBuilder.Text = editorDialog.Value;
}
}
else
{
using var editorDialog = new AnnotationBuilderEditorDialog();
editorDialog.Annotation = annotationBuilder.Text;
if (editorDialog.ShowDialog(owner) == DialogResult.OK)
{
annotationBuilder.Text = editorDialog.Annotation;
}
}
return true;
}
Expand Down
8 changes: 5 additions & 3 deletions Bonsai.Design/AnnotationTextEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ namespace Bonsai.Design
/// Provides a user interface editor that displays a dialog box for editing
/// the annotation text.
/// </summary>
public class AnnotationTextEditor : UITypeEditor
public class AnnotationTextEditor : RichTextEditor
{
internal static readonly bool IsRunningOnMono = Type.GetType("Mono.Runtime") != null;

/// <inheritdoc/>
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
Expand All @@ -21,13 +23,13 @@ public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext contex
/// <inheritdoc/>
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
if (provider != null)
if (provider != null && !IsRunningOnMono)
{
var editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if (editorService != null)
{
using var editorDialog = new AnnotationBuilderEditorDialog();
editorDialog.Annotation = value as string;
editorDialog.Annotation = (string)value;
if (editorService.ShowDialog(editorDialog) == DialogResult.OK)
{
return editorDialog.Annotation;
Expand Down
63 changes: 63 additions & 0 deletions Bonsai.Design/RichTextEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.ComponentModel;
using System.Drawing.Design;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace Bonsai.Design
{
/// <summary>
/// Provides a user interface editor that displays a rich text box for editing
/// the property value.
/// </summary>
public class RichTextEditor : UITypeEditor
{
internal static string CamelCaseToSpaces(string text)
{
var textBuilder = new StringBuilder(text.Length * 2);
for (int i = 0; i < text.Length; i++)
{
if (i > 0 && char.IsUpper(text[i]) && !char.IsUpper(text[i - 1]))
{
textBuilder.Append(' ');
}

textBuilder.Append(text[i]);
}

return textBuilder.ToString();
}

/// <inheritdoc/>
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}

/// <inheritdoc/>
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
if (provider != null)
{
var editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if (editorService != null)
{
using var editorDialog = new RichTextEditorDialog();
editorDialog.Value = (string)value;
if (GetType() is Type editorType && editorType != typeof(RichTextEditor))
{
editorDialog.Text = CamelCaseToSpaces(editorType.Name);
}

if (editorService.ShowDialog(editorDialog) == DialogResult.OK)
{
return editorDialog.Value;
}
}
}

return base.EditValue(context, provider, value);
}
}
}
97 changes: 97 additions & 0 deletions Bonsai.Design/RichTextEditorDialog.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 10fba3d

Please sign in to comment.