From 1b4d32eed3d918c32231900a6d1dc6ea113176de Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Sun, 11 May 2025 00:07:41 +0200 Subject: [PATCH] Prepared tailwind system for plugin builds and exports via nuget. Removed obsolete old css bundling. Added helper scripts for building. Rewritten build scripts --- .gitignore | 6 +- Moonlight.ApiServer/Models/PluginManifest.cs | 1 - .../Moonlight.ApiServer.csproj | 1 + .../Services/BundleGenerationService.cs | 183 ------------------ Moonlight.ApiServer/Services/BundleService.cs | 14 -- Moonlight.ApiServer/Startup.cs | 24 --- Moonlight.Client/Moonlight.Client.csproj | 12 +- Moonlight.Client/Styles/build.bat | 1 - Moonlight.Client/Styles/build.sh | 2 - Moonlight.Client/Styles/exports.css | 26 +++ Moonlight.Client/Styles/package-lock.json | 28 ++- Moonlight.Client/Styles/package.json | 7 +- Moonlight.Client/Styles/preTailwind.css | 1 + Moonlight.Client/Styles/resolveNuget.js | 80 ++++++++ Moonlight.Client/Styles/style.css | 30 +-- Moonlight.Client/wwwroot/index.html | 6 +- .../Scripts/Functions/ContentFunctions.cs | 60 ++++++ Resources/Scripts/Functions/SrcFunctions.cs | 47 +++++ .../Functions/StaticWebAssetsFunctions.cs | 93 +++++++++ Resources/Scripts/Program.cs | 26 +++ Resources/Scripts/Scripts.csproj | 10 + Resources/Scripts/buildNuget.ps1 | 97 ---------- Resources/Scripts/buildNuget.sh | 58 ------ Resources/Scripts/generateNuget.sh | 25 +++ Resources/Scripts/patchClient.csx | 66 ------- Resources/Scripts/prepareNugetCache.ps1 | 15 -- Resources/Scripts/prepareNugetCache.sh | 17 -- Resources/Scripts/prepareNugetOverride.sh | 7 + 28 files changed, 424 insertions(+), 519 deletions(-) delete mode 100644 Moonlight.ApiServer/Services/BundleGenerationService.cs delete mode 100644 Moonlight.ApiServer/Services/BundleService.cs delete mode 100644 Moonlight.Client/Styles/build.bat delete mode 100755 Moonlight.Client/Styles/build.sh create mode 100644 Moonlight.Client/Styles/exports.css create mode 100644 Moonlight.Client/Styles/preTailwind.css create mode 100644 Moonlight.Client/Styles/resolveNuget.js create mode 100644 Resources/Scripts/Functions/ContentFunctions.cs create mode 100644 Resources/Scripts/Functions/SrcFunctions.cs create mode 100644 Resources/Scripts/Functions/StaticWebAssetsFunctions.cs create mode 100644 Resources/Scripts/Program.cs create mode 100644 Resources/Scripts/Scripts.csproj delete mode 100644 Resources/Scripts/buildNuget.ps1 delete mode 100644 Resources/Scripts/buildNuget.sh create mode 100644 Resources/Scripts/generateNuget.sh delete mode 100644 Resources/Scripts/patchClient.csx delete mode 100644 Resources/Scripts/prepareNugetCache.ps1 delete mode 100644 Resources/Scripts/prepareNugetCache.sh create mode 100644 Resources/Scripts/prepareNugetOverride.sh diff --git a/.gitignore b/.gitignore index f1b5721e..62642574 100644 --- a/.gitignore +++ b/.gitignore @@ -428,4 +428,8 @@ core.min.css # Build script for nuget packages finalPackages/ -nupkgs/ \ No newline at end of file +nupkgs/ + +# Scripts +**/bin/** +**/obj/** \ No newline at end of file diff --git a/Moonlight.ApiServer/Models/PluginManifest.cs b/Moonlight.ApiServer/Models/PluginManifest.cs index bcd7bf18..cda0d868 100644 --- a/Moonlight.ApiServer/Models/PluginManifest.cs +++ b/Moonlight.ApiServer/Models/PluginManifest.cs @@ -10,6 +10,5 @@ public class PluginManifest public string[] Scripts { get; set; } = []; public string[] Styles { get; set; } = []; - public string[] BundledStyles { get; set; } = []; public Dictionary Assemblies { get; set; } = new(); } \ No newline at end of file diff --git a/Moonlight.ApiServer/Moonlight.ApiServer.csproj b/Moonlight.ApiServer/Moonlight.ApiServer.csproj index 9a90b529..0b648e2f 100644 --- a/Moonlight.ApiServer/Moonlight.ApiServer.csproj +++ b/Moonlight.ApiServer/Moonlight.ApiServer.csproj @@ -19,6 +19,7 @@ .dockerignore + false diff --git a/Moonlight.ApiServer/Services/BundleGenerationService.cs b/Moonlight.ApiServer/Services/BundleGenerationService.cs deleted file mode 100644 index 9356a299..00000000 --- a/Moonlight.ApiServer/Services/BundleGenerationService.cs +++ /dev/null @@ -1,183 +0,0 @@ -using ExCSS; -using Microsoft.Extensions.FileProviders; -using MoonCore.Helpers; - -namespace Moonlight.ApiServer.Services; - -public class BundleGenerationService : IHostedService -{ - private readonly ILogger Logger; - private readonly IWebHostEnvironment HostEnvironment; - private readonly PluginService PluginService; - private readonly BundleService BundleService; - - public BundleGenerationService( - ILogger logger, - IWebHostEnvironment hostEnvironment, - BundleService bundleService, - PluginService pluginService - ) - { - Logger = logger; - HostEnvironment = hostEnvironment; - BundleService = bundleService; - PluginService = pluginService; - } - - private async Task Bundle(CancellationToken cancellationToken) - { - Logger.LogInformation("Bundling css files..."); - - // Search the physical path for the defined files - var physicalCssFiles = new List(); - - foreach (var cssFile in BundleService.GetCssFiles()) - { - var fileInfo = HostEnvironment.WebRootFileProvider.GetFileInfo(cssFile); - - if (fileInfo is NotFoundFileInfo || fileInfo.PhysicalPath == null) - { - fileInfo = PluginService.WwwRootFileProvider.GetFileInfo(cssFile); - - if (fileInfo is NotFoundFileInfo || fileInfo.PhysicalPath == null) - { - Logger.LogWarning( - "Unable to find physical path for the requested css file '{file}'. Make sure its inside a wwwroot folder", - cssFile - ); - - continue; - } - } - - Logger.LogTrace("Discovered css file '{path}' at '{physicalPath}'", cssFile, fileInfo.PhysicalPath); - - physicalCssFiles.Add(fileInfo.PhysicalPath); - } - - if (physicalCssFiles.Count == 0) - Logger.LogWarning( - "No physical paths to css files loaded. The generated bundle will be empty. Unless this is intended by you this is a bug"); - - // TODO: Implement cache - - // TODO: File system watcher for development - - var bundleContent = await CreateCssBundle(physicalCssFiles); - - Directory.CreateDirectory(PathBuilder.Dir("storage", "tmp")); - - await File.WriteAllTextAsync(PathBuilder.File("storage", "tmp", "bundle.css"), bundleContent, - cancellationToken); - - Logger.LogInformation("Successfully built css bundle"); - } - - private async Task CreateCssBundle(List physicalPaths) - { - if (physicalPaths.Count == 0) // No stylesheets defined => nothing to process - return ""; - - if (physicalPaths.Count == 1) // Only one stylesheet => nothing to process - return await File.ReadAllTextAsync(physicalPaths[0]); - - // Simple bundler just to test - var result = ""; - - foreach (var path in physicalPaths) - { - result += await File.ReadAllTextAsync(path); - } - - return result; - - // Create bundle by stripping out double declared classes and combining all css files into one bundle - var parser = new StylesheetParser(); - string? content = null; - Stylesheet? mainStylesheet = null; - var additionalStyleSheets = new List(); - - foreach (var physicalPath in physicalPaths) - { - try - { - var fileContent = await File.ReadAllTextAsync(physicalPath); - var stylesheet = await parser.ParseAsync(fileContent); - - // Check if it's the first stylesheet we are loading - if (mainStylesheet == null || content == null) - { - // Delegate the first stylesheet to be the main one - content = fileContent + "\n"; - mainStylesheet = stylesheet; - } - else - additionalStyleSheets.Add(stylesheet); // All other stylesheets are to be processed - } - catch (Exception e) - { - Logger.LogError("An error occured while parsing css file: {e}", e); - } - } - - // Handle an empty main stylesheet delegation - if (mainStylesheet == null || content == null) - { - Logger.LogError("An unable to delegate main stylesheet. Did every load attempt of an stylesheet fail?"); - return ""; - } - - // Process stylesheets against the main one - foreach (var stylesheet in additionalStyleSheets) - { - // Style - foreach (var styleRule in stylesheet.StyleRules) - { - if (mainStylesheet.StyleRules.Any(x => x.Selector.Text == styleRule.Selector.Text)) - continue; - - content += styleRule.StylesheetText.Text + "\n"; - } - - // Container - foreach (var containerRule in stylesheet.ContainerRules) - { - if (mainStylesheet.ContainerRules.Any(x => x.ConditionText == containerRule.ConditionText)) - continue; - - content += containerRule.StylesheetText.Text + "\n"; - } - - // Import Rule - foreach (var importRule in stylesheet.ImportRules) - { - if (mainStylesheet.ImportRules.Any(x => x.Text == importRule.Text)) - continue; - - content = importRule.StylesheetText.Text + "\n" + content; - } - - // Media Rules - foreach (var mediaRule in stylesheet.MediaRules) - content += mediaRule.StylesheetText.Text + "\n"; - - // Page Rules - foreach (var pageRule in stylesheet.PageRules) - { - if (mainStylesheet.PageRules.Any(x => x.SelectorText == pageRule.SelectorText)) - continue; - - content += pageRule.StylesheetText.Text + "\n"; - } - } - - return content; - } - - // - public Task StartAsync(CancellationToken cancellationToken) - => Bundle(cancellationToken); - - public Task StopAsync(CancellationToken cancellationToken) - => Task.CompletedTask; -} \ No newline at end of file diff --git a/Moonlight.ApiServer/Services/BundleService.cs b/Moonlight.ApiServer/Services/BundleService.cs deleted file mode 100644 index 65dff75a..00000000 --- a/Moonlight.ApiServer/Services/BundleService.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Moonlight.ApiServer.Services; - -public class BundleService -{ - private readonly List CssFiles = new(); - - public void BundleCss(string path) - => CssFiles.Add(path); - - public void BundleCssRange(string[] paths) - => CssFiles.AddRange(paths); - - public IEnumerable GetCssFiles() => CssFiles; -} \ No newline at end of file diff --git a/Moonlight.ApiServer/Startup.cs b/Moonlight.ApiServer/Startup.cs index b14e1491..baf2ee51 100644 --- a/Moonlight.ApiServer/Startup.cs +++ b/Moonlight.ApiServer/Startup.cs @@ -54,9 +54,6 @@ public class Startup private PluginService PluginService; private AssemblyLoadContext PluginLoadContext; - // Asset bundling - private BundleService BundleService = new(); - private IPluginStartup[] PluginStartups; public async Task Run(string[] args, Assembly[]? additionalAssemblies = null, @@ -71,7 +68,6 @@ public class Startup await CreateStorage(); await SetupAppConfiguration(); await SetupLogging(); - await SetupBundling(); await LoadPlugins(); await InitializePlugins(); @@ -132,15 +128,6 @@ public class Startup return Task.CompletedTask; } - private Task SetupBundling() - { - BundleService = new(); - - BundleService.BundleCss("css/core.min.css"); - - return Task.CompletedTask; - } - #region Base private Task RegisterBase() @@ -257,13 +244,6 @@ public class Startup // Configure base services for initialisation startupSc.AddSingleton(Configuration); - // Add bundle service so plugins can do additional bundling if required - startupSc.AddSingleton(BundleService); - - // Auto add all files specified in the bundledStyles section to the bundle job - foreach (var plugin in PluginService.LoadedPlugins.Keys) - BundleService.BundleCssRange(plugin.BundledStyles); - startupSc.AddLogging(builder => { builder.ClearProviders(); @@ -308,10 +288,6 @@ public class Startup private Task RegisterPluginAssets() { - WebApplicationBuilder.Services.AddHostedService(sp => sp.GetRequiredService()); - WebApplicationBuilder.Services.AddSingleton(); - WebApplicationBuilder.Services.AddSingleton(BundleService); - return Task.CompletedTask; } diff --git a/Moonlight.Client/Moonlight.Client.csproj b/Moonlight.Client/Moonlight.Client.csproj index ebb3871f..fdcf16e2 100644 --- a/Moonlight.Client/Moonlight.Client.csproj +++ b/Moonlight.Client/Moonlight.Client.csproj @@ -9,6 +9,7 @@ **\bin\**;**\obj\**;**\node_modules\**;**\Styles\*.json + True @@ -40,11 +41,6 @@ src Never - - true - src - Never - true styles @@ -72,10 +68,4 @@ - - - - - - diff --git a/Moonlight.Client/Styles/build.bat b/Moonlight.Client/Styles/build.bat deleted file mode 100644 index d2e8ac20..00000000 --- a/Moonlight.Client/Styles/build.bat +++ /dev/null @@ -1 +0,0 @@ -npx tailwindcss -i style.css -o ../wwwroot/css/core.min.css --watch \ No newline at end of file diff --git a/Moonlight.Client/Styles/build.sh b/Moonlight.Client/Styles/build.sh deleted file mode 100755 index e0b4d567..00000000 --- a/Moonlight.Client/Styles/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/bash -npx tailwindcss -i style.css -o ../wwwroot/css/core.min.css --watch \ No newline at end of file diff --git a/Moonlight.Client/Styles/exports.css b/Moonlight.Client/Styles/exports.css new file mode 100644 index 00000000..ef65190c --- /dev/null +++ b/Moonlight.Client/Styles/exports.css @@ -0,0 +1,26 @@ +@import "./additions/fonts.css"; +@import "./additions/theme.css" layer(theme); + +/* @import "./additions/theme.white.css"; */ + +@import "./additions/buttons.css" layer(components); +@import "./additions/cards.css" layer(components); +@import "./additions/forms.css" layer(utilities); +@import "./additions/progress.css" layer(components); +@import "./additions/scrollbar.css" layer(components); +@import "./additions/loaders.css" layer(components); +@import "./additions/tabs.css" layer(components); + +@source "./mappings/*.map"; + +#blazor-error-ui { + display: none; +} + +#blazor-loader-label:after { + content: var(--blazor-load-percentage-text, "Loading"); +} + +#blazor-loader-progress { + width: var(--blazor-load-percentage, 0%); +} \ No newline at end of file diff --git a/Moonlight.Client/Styles/package-lock.json b/Moonlight.Client/Styles/package-lock.json index 2457a48a..5f77706a 100644 --- a/Moonlight.Client/Styles/package-lock.json +++ b/Moonlight.Client/Styles/package-lock.json @@ -7,7 +7,8 @@ "dependencies": { "@tailwindcss/cli": "^4.1.4", "@tailwindcss/forms": "^0.5.10", - "tailwindcss": "^4.1.4" + "tailwindcss": "^4.1.4", + "xml2js": "^0.6.2" } }, "node_modules/@parcel/watcher": { @@ -904,6 +905,11 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, "node_modules/tailwindcss": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.5.tgz", @@ -927,6 +933,26 @@ "engines": { "node": ">=8.0" } + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } } } } diff --git a/Moonlight.Client/Styles/package.json b/Moonlight.Client/Styles/package.json index 160f929b..07658d07 100644 --- a/Moonlight.Client/Styles/package.json +++ b/Moonlight.Client/Styles/package.json @@ -2,6 +2,11 @@ "dependencies": { "@tailwindcss/cli": "^4.1.4", "@tailwindcss/forms": "^0.5.10", - "tailwindcss": "^4.1.4" + "tailwindcss": "^4.1.4", + "xml2js": "^0.6.2" + }, + "scripts": { + "tailwind": "npx tailwindcss -i style.css -o ../wwwroot/css/style.min.css --watch", + "pretailwind": "node resolveNuget.js ../Moonlight.Client.csproj" } } diff --git a/Moonlight.Client/Styles/preTailwind.css b/Moonlight.Client/Styles/preTailwind.css new file mode 100644 index 00000000..84c676a4 --- /dev/null +++ b/Moonlight.Client/Styles/preTailwind.css @@ -0,0 +1 @@ +@import "./additions/fonts.css"; \ No newline at end of file diff --git a/Moonlight.Client/Styles/resolveNuget.js b/Moonlight.Client/Styles/resolveNuget.js new file mode 100644 index 00000000..15fcb577 --- /dev/null +++ b/Moonlight.Client/Styles/resolveNuget.js @@ -0,0 +1,80 @@ +const fs = require('fs'); +const path = require('path'); +const os = require('os'); +const xml2js = require('xml2js'); + +// Helpers +function getPackageRefs(csprojPath) { + const xml = fs.readFileSync(csprojPath, 'utf8'); + const parser = new xml2js.Parser(); + + return new Promise((resolve, reject) => { + parser.parseString(xml, (err, result) => { + if (err) return reject(err); + + const itemGroups = result.Project.ItemGroup || []; + const refs = []; + + for (const group of itemGroups) { + const packages = group.PackageReference || []; + for (const pkg of packages) { + const name = pkg.$.Include; + const version = pkg.$.Version || (pkg.Version && pkg.Version[0]); + if (name && version) { + refs.push({ name: name.toLowerCase(), version }); + } + } + } + resolve(refs); + }); + }); +} + +async function main() { + const csprojPath = process.argv[2]; + if (!csprojPath || !fs.existsSync(csprojPath)) { + console.error('Usage: Missing csproj path'); + process.exit(1); + } + + const nugetPath = path.join(os.homedir(), '.nuget', 'packages'); + const moonlightDir = path.join(__dirname, 'node_modules', 'moonlight'); + fs.mkdirSync(moonlightDir, { recursive: true }); + + const refs = await getPackageRefs(csprojPath); + + var outputCss = ""; + var preOutputCss = ""; + + for (const { name, version } of refs) { + const packagePath = path.join(nugetPath, name, version); + const exportsFile = path.join(packagePath, 'styles', 'exports.css'); + const preTailwindFile = path.join(packagePath, 'styles', 'preTailwind.css'); + const sourceFolder = path.join(packagePath, 'src'); + + const rel = (p) => p.replace(/\\/g, '/'); + + if (fs.existsSync(exportsFile)) { + outputCss += `@import "${rel(exportsFile)}";\n`; + } + + if (fs.existsSync(preTailwindFile)) { + preOutputCss += `@import "${rel(preTailwindFile)}";\n`; + } + + if (fs.existsSync(sourceFolder)) { + outputCss += `@source "${rel(path.join(sourceFolder, "**", "*.razor"))}";\n`; + outputCss += `@source "${rel(path.join(sourceFolder, "**", "*.cs"))}";\n`; + outputCss += `@source "${rel(path.join(sourceFolder, "**", "*.html"))}";\n`; + } + } + + fs.writeFileSync(path.join(moonlightDir, 'nuget.css'), outputCss); + fs.writeFileSync(path.join(moonlightDir, 'preTailwind.nuget.css'), preOutputCss); + console.log(`Generated nuget.css in ${moonlightDir}`); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); \ No newline at end of file diff --git a/Moonlight.Client/Styles/style.css b/Moonlight.Client/Styles/style.css index 63c9d537..0e4ef916 100644 --- a/Moonlight.Client/Styles/style.css +++ b/Moonlight.Client/Styles/style.css @@ -1,32 +1,14 @@ -@import "./additions/fonts.css"; +@import "./preTailwind.css"; +@import "moonlight/preTailwind.nuget.css"; + @import "tailwindcss"; -@import "./additions/theme.css" layer(theme); -/* @import "./additions/theme.white.css"; */ - -@import "./additions/buttons.css" layer(components); -@import "./additions/cards.css" layer(components); -@import "./additions/forms.css" layer(utilities); -@import "./additions/progress.css" layer(components); -@import "./additions/scrollbar.css" layer(components); -@import "./additions/loaders.css" layer(components); -@import "./additions/tabs.css" layer(components); +@import "./exports.css"; +@import "moonlight/nuget.css"; @plugin "@tailwindcss/forms"; @source "../**/*.razor"; @source "../**/*.cs"; @source "../**/*.html"; -@source "./mappings/*.map"; - -#blazor-error-ui { - display: none; -} - -#blazor-loader-label:after { - content: var(--blazor-load-percentage-text, "Loading"); -} - -#blazor-loader-progress { - width: var(--blazor-load-percentage, 0%); -} \ No newline at end of file +@source "./mappings/*.map"; \ No newline at end of file diff --git a/Moonlight.Client/wwwroot/index.html b/Moonlight.Client/wwwroot/index.html index c66c776f..98f69182 100644 --- a/Moonlight.Client/wwwroot/index.html +++ b/Moonlight.Client/wwwroot/index.html @@ -6,10 +6,10 @@ Moonlight.Client - + - - + + diff --git a/Resources/Scripts/Functions/ContentFunctions.cs b/Resources/Scripts/Functions/ContentFunctions.cs new file mode 100644 index 00000000..2319445d --- /dev/null +++ b/Resources/Scripts/Functions/ContentFunctions.cs @@ -0,0 +1,60 @@ +using System.IO.Compression; +using System.Text.RegularExpressions; + +namespace Scripts.Functions; + +public static class ContentFunctions +{ + public static async Task Run(string[] args) + { + if (args.Length < 2) + { + Console.WriteLine("Please provide the path to a nuget file and at least one regex expression"); + return; + } + + var nugetPath = args[0]; + + var regexs = args + .Skip(1) + .Select(x => new Regex(x)) + .ToArray(); + + Console.WriteLine(string.Join(", ", args + .Skip(1) + .Select(x => new Regex(x)))); + + if (!File.Exists(nugetPath)) + { + Console.WriteLine("The provided file does not exist"); + return; + } + + Console.WriteLine("Modding nuget package..."); + using var zipFile = ZipFile.Open(nugetPath, ZipArchiveMode.Update); + + foreach (var zipArchiveEntry in zipFile.Entries) + { + Console.WriteLine(zipArchiveEntry.FullName); + } + + Console.WriteLine("Searching for files to remove"); + var files = zipFile.Entries + .Where(x => x.FullName.Trim('/').StartsWith("content")) + .Where(x => + { + var name = x.FullName + .Replace("contentFiles/", "") + .Replace("content/", ""); + + Console.WriteLine(name); + + return regexs.Any(y => y.IsMatch(name)); + }) + .ToArray(); + + Console.WriteLine($"Found {files.Length} file(s) to remove"); + foreach (var file in files) + file.Delete(); + } +} \ No newline at end of file diff --git a/Resources/Scripts/Functions/SrcFunctions.cs b/Resources/Scripts/Functions/SrcFunctions.cs new file mode 100644 index 00000000..3af2ccd7 --- /dev/null +++ b/Resources/Scripts/Functions/SrcFunctions.cs @@ -0,0 +1,47 @@ +using System.IO.Compression; + +namespace Scripts.Functions; + +public static class SrcFunctions +{ + public static async Task Run(string[] args) + { + if (args.Length != 3) + { + Console.WriteLine("Please provide the path to a nuget file, a search pattern and a path"); + return; + } + + var nugetPath = args[0]; + var path = args[1]; + var pattern = args[2]; + + if (!File.Exists(nugetPath)) + { + Console.WriteLine("The provided file does not exist"); + return; + } + + Console.WriteLine("Modding nuget package..."); + using var zipFile = ZipFile.Open(nugetPath, ZipArchiveMode.Update); + + var filesToAdd = Directory.GetFiles(path, pattern, SearchOption.AllDirectories); + + foreach (var file in filesToAdd) + { + var name = file.Replace(path, "").Replace("\\", "/"); + + Console.WriteLine($"{file} => /src/{name}"); + + var entry = zipFile.CreateEntry($"src/{name}"); + await using var entryStream = entry.Open(); + + await using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + await fs.CopyToAsync(entryStream); + fs.Close(); + + await entryStream.FlushAsync(); + entryStream.Close(); + } + } +} \ No newline at end of file diff --git a/Resources/Scripts/Functions/StaticWebAssetsFunctions.cs b/Resources/Scripts/Functions/StaticWebAssetsFunctions.cs new file mode 100644 index 00000000..de6318c1 --- /dev/null +++ b/Resources/Scripts/Functions/StaticWebAssetsFunctions.cs @@ -0,0 +1,93 @@ +using System.IO.Compression; +using System.Text.RegularExpressions; +using System.Xml.Linq; + +namespace Scripts.Functions; + +public static class StaticWebAssetsFunctions +{ + public static async Task Run(string[] args) + { + if (args.Length < 2) + { + Console.WriteLine("Please provide the path to a nuget file and at least one regex expression"); + return; + } + + var nugetPath = args[0]; + + var regexs = args + .Skip(1) + .Select(x => new Regex(x)) + .ToArray(); + + if (!File.Exists(nugetPath)) + { + Console.WriteLine("The provided file does not exist"); + return; + } + + Console.WriteLine("Modding nuget package..."); + using var zipFile = ZipFile.Open(nugetPath, ZipArchiveMode.Update); + + Console.WriteLine("Searching for files to remove"); + var files = zipFile.Entries + .Where(x => x.FullName.Trim('/').StartsWith("staticwebassets")) + .Where(x => + { + var name = x.FullName.Replace("staticwebassets/", ""); + + return regexs.Any(y => y.IsMatch(name)); + }) + .ToArray(); + + Console.WriteLine($"Found {files.Length} file(s) to remove"); + foreach (var file in files) + file.Delete(); + + Console.WriteLine("Modifying static web assets build target"); + var oldBuildTargetEntry = zipFile + .Entries + .FirstOrDefault(x => x.FullName == "build/Microsoft.AspNetCore.StaticWebAssets.props"); + + if (oldBuildTargetEntry == null) + { + Console.WriteLine("Build target file not found in nuget packages"); + return; + } + + await using var oldBuildTargetStream = oldBuildTargetEntry.Open(); + + var contentXml = await XDocument.LoadAsync( + oldBuildTargetStream, + LoadOptions.None, + CancellationToken.None + ); + + oldBuildTargetStream.Close(); + oldBuildTargetEntry.Delete(); + + var assetRefsToRemove = contentXml + .Descendants("StaticWebAsset") + .Where(asset => + { + var element = asset.Element("RelativePath"); + + if (element == null) + return false; + + return regexs.Any(y => y.IsMatch(element.Value)); + }) + .ToArray(); + + foreach (var asset in assetRefsToRemove) + asset.Remove(); + + var newBuildTargetEntry = zipFile.CreateEntry("build/Microsoft.AspNetCore.StaticWebAssets.props"); + await using var newBuildTargetStream = newBuildTargetEntry.Open(); + + await contentXml.SaveAsync(newBuildTargetStream, SaveOptions.None, CancellationToken.None); + + newBuildTargetStream.Close(); + } +} \ No newline at end of file diff --git a/Resources/Scripts/Program.cs b/Resources/Scripts/Program.cs new file mode 100644 index 00000000..a0dbec12 --- /dev/null +++ b/Resources/Scripts/Program.cs @@ -0,0 +1,26 @@ +using Scripts.Functions; + +if (args.Length == 0) +{ + Console.WriteLine("You need to specify a module to run"); + return; +} + +var module = args[0]; +var moduleArgs = args.Skip(1).ToArray(); + +switch (module) +{ + case "staticWebAssets": + await StaticWebAssetsFunctions.Run(moduleArgs); + break; + case "content": + await ContentFunctions.Run(moduleArgs); + break; + case "src": + await SrcFunctions.Run(moduleArgs); + break; + default: + Console.WriteLine($"No module named {module} found"); + break; +} \ No newline at end of file diff --git a/Resources/Scripts/Scripts.csproj b/Resources/Scripts/Scripts.csproj new file mode 100644 index 00000000..2150e379 --- /dev/null +++ b/Resources/Scripts/Scripts.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/Resources/Scripts/buildNuget.ps1 b/Resources/Scripts/buildNuget.ps1 deleted file mode 100644 index 31ed224f..00000000 --- a/Resources/Scripts/buildNuget.ps1 +++ /dev/null @@ -1,97 +0,0 @@ -# Set strict mode to stop on errors -$ErrorActionPreference = "Stop" - -# Ensure the script is running in the main directory -Write-Host "Building nuget packages" - -Write-Host "Searching & building project files" -# Find all .csproj files recursively -$projectFiles = Get-ChildItem -Recurse -Filter "*.csproj" - -foreach ($project in $projectFiles) { - # Extract project name (without extension) - $projectName = $project.BaseName - - # Extract version from the .csproj file - $projectVersion = Select-String -Path $project.FullName -Pattern "(.*?)" | ForEach-Object { - $_.Matches.Groups[1].Value - } - - if (-not $projectVersion) { - Write-Host "No tag found in $($project.FullName), skipping." - continue - } - - # Build and pack the project - $projectPath = $project.DirectoryName - $pwd = (Get-Location).Path - Push-Location $projectPath - dotnet build --configuration Release - dotnet pack --configuration Release --output "$pwd\nupkgs" - Pop-Location - - # Modifying the NuGet package - Write-Host "Modding nuget package" - $nugetPackage = Get-ChildItem "$pwd\nupkgs" -Filter "*.nupkg" | Select-Object -First 1 - - # Rename .nupkg to .zip - $zipPackage = "$($nugetPackage.FullName).zip" - Rename-Item -Path $nugetPackage.FullName -NewName $zipPackage - - Expand-Archive -Path $zipPackage -DestinationPath "$pwd\nupkgs\mod" -Force - - if ($projectName -eq "Moonlight.ApiServer") { - Remove-Item "$pwd\nupkgs\mod\content" -Recurse -Force -ErrorAction SilentlyContinue - Remove-Item "$pwd\nupkgs\mod\contentFiles" -Recurse -Force -ErrorAction SilentlyContinue - - $xmlFilePath = "$pwd\nupkgs\mod\$projectName.nuspec" - $xmlContent = Get-Content -Path $xmlFilePath -Raw - $regexPattern = ']*>[\s\S]*?<\/contentFiles>' - - $updatedContent = [System.Text.RegularExpressions.Regex]::Replace( - $xmlContent, - $regexPattern, - "", - [System.Text.RegularExpressions.RegexOptions]::IgnoreCase - ) - - Set-Content -Path $xmlFilePath -Value $updatedContent -Encoding UTF8 - } - - if ($projectName -eq "Moonlight.Client") { - Remove-Item "$pwd\nupkgs\mod\staticwebassets\_framework" -Recurse -Force - - $xmlFilePath = "$pwd\nupkgs\mod\build\Microsoft.AspNetCore.StaticWebAssets.props" - $xmlContent = Get-Content -Path $xmlFilePath -Raw - - $regexPattern = ']*>(?:(?!<\/StaticWebAsset>).)*?_framework/blazor\.webassembly\.js(?:\.gz)?<\/RelativePath>.*?<\/StaticWebAsset>' - - $updatedContent = [System.Text.RegularExpressions.Regex]::Replace( - $xmlContent, - $regexPattern, - "", - [System.Text.RegularExpressions.RegexOptions]::Singleline - ) - - Set-Content -Path $xmlFilePath -Value $updatedContent -Encoding UTF8 - } - - # Repack the modified NuGet package - Write-Host "Repacking nuget package" - Remove-Item $zipPackage - Push-Location "$pwd\nupkgs\mod" - Compress-Archive -Path * -DestinationPath $zipPackage -Force - Pop-Location - - # Rename .zip back to .nupkg - Rename-Item -Path $zipPackage -NewName $nugetPackage.FullName - - # Move the final package to the output directory - $finalDir = "$pwd\finalPackages" - New-Item -ItemType Directory -Path $finalDir -Force | Out-Null - Move-Item -Path $nugetPackage.FullName -Destination $finalDir - - # Cleanup - Write-Host "Cleaning up" - Remove-Item "$pwd\nupkgs\mod" -Recurse -Force -} diff --git a/Resources/Scripts/buildNuget.sh b/Resources/Scripts/buildNuget.sh deleted file mode 100644 index 615ead34..00000000 --- a/Resources/Scripts/buildNuget.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -set -e - -# Note: Run in main directory, i.e. where the Moonlight.sln is - -echo "Building nuget packages" - -echo "Searching & building project files" -project_files=$(find . -name "*.csproj") - -for project in $project_files; do - # Extract project name - project_name=$(basename "$project" .csproj) - - # Extract version - project_version=$(grep -oPm1 "(?<=)[^<]+" "$project") - if [ -z "$project_version" ]; then - echo "No tag found in $project, skipping." - continue - fi - - # Building nuget package - pwd=$(pwd) - project_path=$(dirname $project) - (cd $project_path; dotnet build --configuration Release; dotnet pack --configuration Release --output $pwd/nupkgs) - - # Mod nuget package - echo "Modding nuget package" - nugetPackage=$(find $pwd/nupkgs -name "*.nupkg") - - unzip -o $nugetPackage -d $pwd/nupkgs/mod - - if [ "$project_name" = "Moonlight.ApiServer" ]; then - rm -r $pwd/nupkgs/mod/content - rm -r $pwd/nupkgs/mod/contentFiles - - sed -i "//,/<\/contentFiles>/d" $pwd/nupkgs/mod/Moonlight.ApiServer.nuspec - fi - - if [ "$project_name" = "Moonlight.Client" ]; then - rm -r $pwd/nupkgs/mod/staticwebassets/_framework - - sed -i '//,/<\/StaticWebAsset>/d' $pwd/nupkgs/mod/build/Microsoft.AspNetCore.StaticWebAssets.props - sed -i '//,/<\/StaticWebAsset>/d' $pwd/nupkgs/mod/build/Microsoft.AspNetCore.StaticWebAssets.props - - fi - - echo "Repacking nuget package" - rm $nugetPackage - (cd nupkgs/mod/; zip -r -o $nugetPackage *) - - mkdir -p $pwd/finalPackages/ - - mv $nugetPackage $pwd/finalPackages/ - - echo "Cleaning up" - rm -r $pwd/nupkgs/mod -done \ No newline at end of file diff --git a/Resources/Scripts/generateNuget.sh b/Resources/Scripts/generateNuget.sh new file mode 100644 index 00000000..acfa0068 --- /dev/null +++ b/Resources/Scripts/generateNuget.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# We are building the packages in the debug mode because they are meant for development +# purposes only. When build for production, release builds will be used ofc + +set -e + +echo "Creating nuget packages" +mkdir -p finalPackages + +echo "+ ApiServer Server" +dotnet build -c Debug Moonlight.ApiServer +dotnet pack -c Debug Moonlight.ApiServer --output finalPackages/ +dotnet run --project Resources/Scripts/Scripts.csproj content finalPackages/Moonlight.ApiServer.2.1.0.nupkg ".*" + +echo "+ Client" +dotnet build -c Debug Moonlight.Client +dotnet pack -c Debug Moonlight.Client --output finalPackages/ +dotnet run --project Resources/Scripts/Scripts.csproj staticWebAssets finalPackages/Moonlight.Client.2.1.0.nupkg "_framework\/.*" style.min.css +dotnet run --project Resources/Scripts/Scripts.csproj src finalPackages/Moonlight.Client.2.1.0.nupkg Moonlight.Client/ *.razor +dotnet run --project Resources/Scripts/Scripts.csproj src finalPackages/Moonlight.Client.2.1.0.nupkg Moonlight.Client/ wwwroot/*.html + +echo "+ Shared library" +dotnet build -c Debug Moonlight.Shared +dotnet pack -c Debug Moonlight.Shared --output finalPackages/ \ No newline at end of file diff --git a/Resources/Scripts/patchClient.csx b/Resources/Scripts/patchClient.csx deleted file mode 100644 index 0215356f..00000000 --- a/Resources/Scripts/patchClient.csx +++ /dev/null @@ -1,66 +0,0 @@ -using System.IO.Compression; -using System.Text; -using System.Xml.Linq; - -// Handle arguments -if (Args.Count != 1) -{ - Console.WriteLine("You need to provide the path to a nuget file as a parameter"); - return; -} - -var nugetPath = Args[0]; - -// Check if file exists -if (!File.Exists(nugetPath)) -{ - Console.WriteLine("The provided file does not exist"); - return; -} - -// Open file to modify -Console.WriteLine($"Modding nuget package: {nugetPath}"); -var zipFile = ZipFile.Open(nugetPath, ZipArchiveMode.Update, Encoding.UTF8); - -// First we want to remove the framework files -Console.WriteLine("Removing framework files"); - -var frameworkEntries = zipFile.Entries - .Where(x => x.FullName.Contains("staticwebassets/_framework")) - .ToArray(); - -foreach (var frameworkEntry in frameworkEntries) - frameworkEntry.Delete(); - -// Then we want to modify the build targets for static web assets -var oldBuildTarget = zipFile.Entries - .First(x => x.FullName == "build/Microsoft.AspNetCore.StaticWebAssets.props"); - -// Load old content -var oldContentStream = oldBuildTarget.Open(); - -// Parse xml and remove framework references -Console.WriteLine("Removing framework web asset references"); - -var contentXml = XDocument.Load(oldContentStream); -oldContentStream.Close(); -oldContentStream.Dispose(); -oldBuildTarget.Delete(); - -var assetsToRemove = contentXml - .Descendants("StaticWebAsset") - .Where(asset => - asset.Element("RelativePath")?.Value.Contains("_framework") == true) - .ToArray(); - -foreach (var asset in assetsToRemove) - asset.Remove(); - -var newBuildTarget = zipFile.CreateEntry("build/Microsoft.AspNetCore.StaticWebAssets.props"); -var newContentStream = newBuildTarget.Open(); -contentXml.Save(newContentStream); - -await newContentStream.FlushAsync(); -newContentStream.Close(); - -zipFile.Dispose(); \ No newline at end of file diff --git a/Resources/Scripts/prepareNugetCache.ps1 b/Resources/Scripts/prepareNugetCache.ps1 deleted file mode 100644 index f996e219..00000000 --- a/Resources/Scripts/prepareNugetCache.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -# This script requires a NuGet override folder at %userprofile%\NugetOverride - -# Clear old build cache -Remove-Item -Recurse -Force nupkgs, finalPackages - -# Build and replace NuGet packages -& "Resources\Scripts\buildNuget.ps1" -Copy-Item -Path finalPackages\* -Destination $env:userprofile\NugetOverride -Force - -# Clean package cache -Remove-Item -Recurse -Force $env:userprofile\.nuget\packages\moonlight.apiserver -Remove-Item -Recurse -Force $env:userprofile\.nuget\packages\moonlight.shared -Remove-Item -Recurse -Force $env:userprofile\.nuget\packages\moonlight.client - -Write-Output "Done :>" diff --git a/Resources/Scripts/prepareNugetCache.sh b/Resources/Scripts/prepareNugetCache.sh deleted file mode 100644 index 1b24ce22..00000000 --- a/Resources/Scripts/prepareNugetCache.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# This script required a nuget override folder at ~/NugetOverride - -# Clear old build cache -rm -rf nupkgs/ finalPackages/ - -# Build and replace nuget packages -bash Resources/Scripts/buildNuget.sh -cp finalPackages/* ~/NugetOverride/ - -# Clean package cache -rm -rf ~/.nuget/packages/moonlight.apiserver/ -rm -rf ~/.nuget/packages/moonlight.shared/ -rm -rf ~/.nuget/packages/moonlight.client/ - -echo "Done :>" \ No newline at end of file diff --git a/Resources/Scripts/prepareNugetOverride.sh b/Resources/Scripts/prepareNugetOverride.sh new file mode 100644 index 00000000..ae7c1c30 --- /dev/null +++ b/Resources/Scripts/prepareNugetOverride.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +bash Resources/Scripts/generateNuget.sh + +echo "+ Copying to nuget override" +cp finalPackages/*.nupkg ~/NugetOverride/ +rm -r ~/.nuget/packages/moonlight.* \ No newline at end of file