Files
Moonlight/Resources/Scripts/Commands/PackCommand.cs
2025-05-17 18:04:59 +02:00

227 lines
7.4 KiB
C#

using System.IO.Compression;
using System.Xml.Linq;
using Cocona;
using Microsoft.Extensions.Logging;
using Scripts.Helpers;
namespace Scripts.Commands;
public class PackCommand
{
private readonly string TmpDir = "/tmp/mlbuild";
private readonly ILogger<PackCommand> Logger;
private readonly CsprojHelper CsprojHelper;
private readonly NupkgHelper NupkgHelper;
private readonly string[] ValidTags = ["apiserver", "frontend", "shared"];
public PackCommand(
ILogger<PackCommand> logger,
CsprojHelper csprojHelper,
NupkgHelper nupkgHelper
)
{
CsprojHelper = csprojHelper;
NupkgHelper = nupkgHelper;
Logger = logger;
}
[Command("pack", Description = "Packs the specified folder/solution into nuget packages")]
public async Task Pack(
[Argument] string solutionDirectory,
[Argument] string outputLocation,
[Option] string buildConfiguration = "Debug"
)
{
if (!Directory.Exists(solutionDirectory))
{
Logger.LogError("The specified solution directory does not exist");
return;
}
if (!Directory.Exists(outputLocation))
Directory.CreateDirectory(outputLocation);
if (Directory.Exists(TmpDir))
Directory.Delete(TmpDir, true);
Directory.CreateDirectory(TmpDir);
// Find the project files
Logger.LogInformation("Searching for projects inside the specified folder");
var projects = await CsprojHelper.FindProjectsInPath(solutionDirectory, ValidTags);
// Show the user
Logger.LogInformation("Found {count} project(s) to check:", projects.Count);
foreach (var path in projects.Keys)
Logger.LogInformation("- {path}", Path.GetFullPath(path));
// Filter out project files which have specific tags specified
Logger.LogInformation("Filtering projects by tags");
var apiServerProjects = projects
.Where(x => x.Value.PackageTags.Contains("apiserver", StringComparer.InvariantCultureIgnoreCase))
.ToArray();
var frontendProjects = projects
.Where(x => x.Value.PackageTags.Contains("frontend", StringComparer.InvariantCultureIgnoreCase))
.ToArray();
var sharedProjects = projects
.Where(x => x.Value.PackageTags.Contains("shared", StringComparer.InvariantCultureIgnoreCase))
.ToArray();
Logger.LogInformation(
"Found {apiServerCount} api server project(s), {frontendCount} frontend project(s) and {sharedCount} shared project(s)",
apiServerProjects.Length,
frontendProjects.Length,
sharedProjects.Length
);
// Now build all these projects so we can pack them
Logger.LogInformation("Building and packing api server project(s)");
foreach (var apiServerProject in apiServerProjects)
{
var csProjectFile = apiServerProject.Key;
var manifest = apiServerProject.Value;
await CsprojHelper.Build(
csProjectFile,
buildConfiguration
);
var nugetFilePath = await CsprojHelper.Pack(
csProjectFile,
TmpDir,
buildConfiguration
);
var nugetPackage = ZipFile.Open(
nugetFilePath,
ZipArchiveMode.Update
);
await NupkgHelper.RemoveContentFiles(nugetPackage);
// We don't want to clean moonlight references when we are packing moonlight,
// as it would remove references to its own shared project
if (!manifest.PackageId.StartsWith("Moonlight."))
await NupkgHelper.CleanDependencies(nugetPackage, "Moonlight.");
Logger.LogInformation("Finishing package and copying to output directory");
nugetPackage.Dispose();
File.Move(
nugetFilePath,
Path.Combine(outputLocation, Path.GetFileName(nugetFilePath)),
true
);
}
Logger.LogInformation("Building and packing frontend projects");
foreach (var frontendProject in frontendProjects)
{
var csProjectFile = frontendProject.Key;
var manifest = frontendProject.Value;
await CsprojHelper.Build(
csProjectFile,
buildConfiguration
);
var nugetFilePath = await CsprojHelper.Pack(
csProjectFile,
TmpDir,
buildConfiguration
);
var nugetPackage = ZipFile.Open(
nugetFilePath,
ZipArchiveMode.Update
);
await NupkgHelper.RemoveStaticWebAssets(nugetPackage, "_framework");
await NupkgHelper.RemoveStaticWebAssets(nugetPackage, "css/style.min.css");
await NupkgHelper.RemoveContentFiles(nugetPackage);
// We don't want to clean moonlight references when we are packing moonlight,
// as it would remove references to its own shared project
if (!manifest.PackageId.StartsWith("Moonlight."))
await NupkgHelper.CleanDependencies(nugetPackage, "Moonlight.");
// Pack razor and html files into src folder
var additionalSrcFiles = new List<string>();
var basePath = Path.GetDirectoryName(csProjectFile)!;
additionalSrcFiles.AddRange(
Directory.GetFiles(basePath, "*.razor", SearchOption.AllDirectories)
);
additionalSrcFiles.AddRange(
Directory.GetFiles(basePath, "index.html", SearchOption.AllDirectories)
);
await NupkgHelper.AddSourceFiles(
nugetPackage,
additionalSrcFiles.ToArray(),
file => "src/" + file.Replace(basePath, "").Trim('/')
);
Logger.LogInformation("Finishing package and copying to output directory");
nugetPackage.Dispose();
File.Move(
nugetFilePath,
Path.Combine(outputLocation, Path.GetFileName(nugetFilePath)),
true
);
}
Logger.LogInformation("Building and packing shared projects");
foreach (var sharedProject in sharedProjects)
{
var csProjectFile = sharedProject.Key;
var manifest = sharedProject.Value;
await CsprojHelper.Build(
csProjectFile,
buildConfiguration
);
var nugetFilePath = await CsprojHelper.Pack(
csProjectFile,
TmpDir,
buildConfiguration
);
var nugetPackage = ZipFile.Open(
nugetFilePath,
ZipArchiveMode.Update
);
// We don't want to clean moonlight references when we are packing moonlight,
// as it would remove references to its own shared project
if (!manifest.PackageId.StartsWith("Moonlight."))
await NupkgHelper.CleanDependencies(nugetPackage, "Moonlight.");
nugetPackage.Dispose();
File.Move(
nugetFilePath,
Path.Combine(outputLocation, Path.GetFileName(nugetFilePath)),
true
);
}
}
}