plugin support and scaffolding for Yaml plugin

This commit is contained in:
Michael Becker 2024-08-09 22:18:20 -04:00
parent 5dcc91198b
commit 4882e49524
10 changed files with 352 additions and 1 deletions

12
build
View File

@ -16,4 +16,16 @@ THEME_NAME=avondale
for each in mocha-dotnet/src/assets/ui-html/css/common/*.less mocha-dotnet/src/assets/ui-html/css/$THEME_NAME/*.less; do cat $each; echo ""; done | lessc --plugin=less-plugin-clean-css=advanced - output/assets/ui-html/$ASSET_UIHTML_VERSION/css/mochaApp.css for each in mocha-dotnet/src/assets/ui-html/css/common/*.less mocha-dotnet/src/assets/ui-html/css/$THEME_NAME/*.less; do cat $each; echo ""; done | lessc --plugin=less-plugin-clean-css=advanced - output/assets/ui-html/$ASSET_UIHTML_VERSION/css/mochaApp.css
cp mocha-dotnet/src/app/Mocha.ServerApplication/bin/Debug/net8.0/* output/ cp mocha-dotnet/src/app/Mocha.ServerApplication/bin/Debug/net8.0/* output/
if [ ! -d output/plugins ]; then
mkdir output/plugins
fi
for each in mocha-dotnet/src/plugins/*; do
pushd $each
dotnet build
popd
cp $each/bin/Debug/net8.0/*.dll output/plugins
done
exit 0 exit 0

View File

@ -37,6 +37,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{27C300F5
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Core.Tests", "mocha-dotnet\tests\Mocha.Core.Tests\Mocha.Core.Tests.csproj", "{20B7D199-322C-4942-85FE-46B90C75E92A}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Core.Tests", "mocha-dotnet\tests\Mocha.Core.Tests\Mocha.Core.Tests.csproj", "{20B7D199-322C-4942-85FE-46B90C75E92A}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{B024FD23-7084-4DDF-A185-D58BEE7A006F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Plugins.Libraries.Yaml", "mocha-dotnet\src\plugins\Mocha.Plugins.Libraries.Yaml\Mocha.Plugins.Libraries.Yaml.csproj", "{96400F5A-98ED-48FF-8000-6135BDF10360}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -63,6 +67,10 @@ Global
{20B7D199-322C-4942-85FE-46B90C75E92A}.Debug|Any CPU.Build.0 = Debug|Any CPU {20B7D199-322C-4942-85FE-46B90C75E92A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20B7D199-322C-4942-85FE-46B90C75E92A}.Release|Any CPU.ActiveCfg = Release|Any CPU {20B7D199-322C-4942-85FE-46B90C75E92A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20B7D199-322C-4942-85FE-46B90C75E92A}.Release|Any CPU.Build.0 = Release|Any CPU {20B7D199-322C-4942-85FE-46B90C75E92A}.Release|Any CPU.Build.0 = Release|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -82,6 +90,8 @@ Global
{1345068A-1AF8-4FAA-A336-457E73ED23A7} = {D67F792A-95F6-44EC-80A8-C17A0D0B0644} {1345068A-1AF8-4FAA-A336-457E73ED23A7} = {D67F792A-95F6-44EC-80A8-C17A0D0B0644}
{27C300F5-5172-4225-A6F7-3503B9007DD8} = {2A2B84F1-FA6B-4D67-ACB8-E277D50C98F2} {27C300F5-5172-4225-A6F7-3503B9007DD8} = {2A2B84F1-FA6B-4D67-ACB8-E277D50C98F2}
{20B7D199-322C-4942-85FE-46B90C75E92A} = {27C300F5-5172-4225-A6F7-3503B9007DD8} {20B7D199-322C-4942-85FE-46B90C75E92A} = {27C300F5-5172-4225-A6F7-3503B9007DD8}
{B024FD23-7084-4DDF-A185-D58BEE7A006F} = {66EB3261-A473-41C7-8D40-E1B4DC8ED4B3}
{96400F5A-98ED-48FF-8000-6135BDF10360} = {B024FD23-7084-4DDF-A185-D58BEE7A006F}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D28A9CF8-0235-4F8F-865F-C460BDCAE16D} SolutionGuid = {D28A9CF8-0235-4F8F-865F-C460BDCAE16D}

View File

@ -0,0 +1,13 @@

namespace Mocha.Core;
public class Library
{
/// <summary>
/// Applies all attribute and relationship assignments once all instances have been
/// accounted for.
/// </summary>
public void Link()
{
}
}

View File

@ -0,0 +1,107 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
//
// InstanceReference.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2022 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;
using MBS.Core;
namespace Mocha.Core
{
/// <summary>
/// Represents an opaque handle to an instance in a Mocha object management system (OMS).
/// </summary>
public struct LibraryHandle : IEquatable<LibraryHandle>
{
private NanoId _ID;
private bool isNotEmpty;
public static LibraryHandle Create()
{
LibraryHandle handle = new LibraryHandle();
handle._ID = NanoId.Generate();
handle.isNotEmpty = true;
return handle;
}
public byte[] ToByteArray()
{
return System.Text.Encoding.ASCII.GetBytes(_ID.ToString());
}
public static readonly LibraryHandle Empty = new LibraryHandle();
public bool IsEmpty { get { return !isNotEmpty; } }
public bool Equals(LibraryHandle other)
{
if (IsEmpty && other.IsEmpty)
return true;
return _ID == other._ID && !IsEmpty;
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj is LibraryHandle)
{
return this.Equals(((LibraryHandle)obj));
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return _ID.GetHashCode();
}
public static bool operator ==(LibraryHandle left, LibraryHandle right)
{
return left.Equals(right);
}
public static bool operator !=(LibraryHandle left, LibraryHandle right)
{
return !left.Equals(right);
}
public override string ToString()
{
if (IsEmpty)
return "(empty) ";
return _ID.ToString();
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Reflection;
using MBS.Core.Extensibility;
namespace Mocha.Core;
public abstract class LibraryPlugin : Plugin
{
protected abstract void LoadInternal(string filename, Library library);
public void Load(string filename, Library library)
{
LoadInternal(filename, library);
}
protected virtual bool SupportsFileNameInternal(string filename)
{
return false;
}
public bool SupportsFileName(string filename)
{
return SupportsFileNameInternal(filename);
}
}

View File

@ -27,6 +27,8 @@ using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using MBS.Core; using MBS.Core;
using MBS.Core.Extensibility;
using MBS.Core.IO;
using Mocha.Core.MethodImplementations; using Mocha.Core.MethodImplementations;
using Mocha.Core.Oop; using Mocha.Core.Oop;
@ -83,10 +85,17 @@ public abstract class Oms
SelectTenant(tenant); SelectTenant(tenant);
InitializeTenant(); InitializeTenant();
OnTenantCreated(new OmsTenantCreatedEventArgs(tenant, tenantName));
return tenant; return tenant;
} }
public EventHandler<OmsTenantCreatedEventArgs>? TenantCreated;
protected virtual void OnTenantCreated(OmsTenantCreatedEventArgs e)
{
TenantCreated?.Invoke(this, e);
}
public TenantHandle GetTenantByName(string tenantName) public TenantHandle GetTenantByName(string tenantName)
{ {
if (_tenantsByName.ContainsKey(tenantName)) if (_tenantsByName.ContainsKey(tenantName))
@ -1018,4 +1027,83 @@ public abstract class Oms
protected virtual void InitializeTenantInternal() protected virtual void InitializeTenantInternal()
{ {
} }
protected abstract void AddLibraryReferenceInternal(LibraryHandle library);
/// <summary>
/// Adds the specified library reference to the current tenant.
/// </summary>
/// <param name="library"></param>
public void AddLibraryReference(LibraryHandle library)
{
AddLibraryReferenceInternal(library);
}
private Dictionary<string, LibraryHandle> _libraries = new Dictionary<string, LibraryHandle>();
/// <summary>
/// Gets the <see cref="LibraryHandle" /> for the library with the given name.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public LibraryHandle GetLibrary(string name)
{
if (_libraries.ContainsKey(name))
{
return _libraries[name];
}
return LibraryHandle.Empty;
}
/// <summary>
/// Loads the specified library file into memory. To add it to the tenant,
/// first <see cref="SelectTenant" /> the desired tenant, and then call
/// <see cref="AddLibraryReference" />.
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public LibraryHandle LoadLibrary(string filename)
{
// some examples:
// .mcl compiled binary library file (fastest?)
// /path/to/directory containing a bunch of XML / JSON / YAML files
// .mcz ZIP archive of XML / JSON / YAML files (slowest?)
LibraryHandle lh = LibraryHandle.Create();
return lh;
Library lib = new Library();
// _libraries[name] = lh;
if (!File.Exists(filename) && !Directory.Exists(filename))
{
throw new FileNotFoundException(null, filename);
}
// get a list of all library loaders we have implemented
LibraryPlugin[] plugins = Plugin.Get<LibraryPlugin>();
foreach (LibraryPlugin plugin in plugins)
{
Console.WriteLine("found plugin: {0}", plugin.GetType().FullName);
if (plugin.SupportsFileName(filename))
{
// if passed a directory, will enumerate all the
// .xml / .json / .yaml files in the directory and
// subdirectories
plugin.Load(filename, lib);
}
}
// if the files have not already been compiled, we need to do two passes.
// - the first pass loads all instances into our tenant
// - the second pass applies the attributes and relationships, which depend on the
// presence of the instances
// compiling to .mcl binary library format does this all ahead of time and should
// be faster.
// let's be lazy and just look at the file extension to determine how to parse
// once all the instances have been loaded, tell the in-memory library manager
// to do its second pass "linking" the objects
lib.Link();
return lh;
}
} }

View File

@ -0,0 +1,31 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
namespace Mocha.Core;
public class OmsTenantCreatedEventArgs : EventArgs
{
public TenantHandle Tenant { get; }
public string Name { get; }
public OmsTenantCreatedEventArgs(TenantHandle tenant, string name)
{
Tenant = tenant;
Name = name;
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
<ProjectReference Include="..\..\lib\Mocha.Core\Mocha.Core.csproj" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,28 @@
using Mocha.Core;
namespace Mocha.Plugins.Libraries.Yaml;
public class YamlLibraryPlugin : LibraryPlugin
{
protected override bool SupportsFileNameInternal(string filename)
{
return Directory.Exists(filename) || Path.GetExtension(filename).Equals("yaml");
}
protected override void LoadInternal(string filename, Library library)
{
if (Directory.Exists(filename))
{
string[] files = Directory.GetFiles(filename, "*.yaml", SearchOption.AllDirectories);
foreach (string file in files)
{
FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
StreamReader sr = new StreamReader(fs);
var yaml = new YamlStream();
yaml.Load(sr);
}
}
}
}

View File

@ -0,0 +1,9 @@
namespace Mocha.Plugins.Libraries.Yaml;
public class YamlParser
{
public Dictionary<string, object> Parse(Stream stream)
{
StreamReader sr = new StreamReader(stream);
}
}