add defensive logic to package installer

This commit is contained in:
Shaun Walker 2023-03-29 08:47:54 -04:00
parent 3a79fa074a
commit 82221f54c5
2 changed files with 86 additions and 81 deletions

View File

@ -190,7 +190,7 @@ else
try try
{ {
await PackageService.InstallPackagesAsync(); await PackageService.InstallPackagesAsync();
AddModuleMessage(string.Format(Localizer["Success.Translation.Install"], NavigateUrl("admin/system")), MessageType.Success); AddModuleMessage(string.Format(Localizer["Success.Language.Install"], NavigateUrl("admin/system")), MessageType.Success);
_install = false; _install = false;
StateHasChanged(); StateHasChanged();
} }

View File

@ -30,15 +30,12 @@ namespace Oqtane.Infrastructure
public void InstallPackages() public void InstallPackages()
{ {
if (!InstallPackages(_environment.WebRootPath, _environment.ContentRootPath)) InstallPackages(_environment.WebRootPath, _environment.ContentRootPath);
{
// error installing packages
}
} }
public static bool InstallPackages(string webRootPath, string contentRootPath) public static bool InstallPackages(string webRootPath, string contentRootPath)
{ {
bool install = false; bool install = true;
string binPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); string binPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
string sourceFolder = Path.Combine(contentRootPath, "Packages"); string sourceFolder = Path.Combine(contentRootPath, "Packages");
@ -82,98 +79,106 @@ namespace Oqtane.Infrastructure
// iterate through Nuget packages in source folder // iterate through Nuget packages in source folder
foreach (string packagename in Directory.GetFiles(sourceFolder, "*.nupkg")) foreach (string packagename in Directory.GetFiles(sourceFolder, "*.nupkg"))
{ {
// iterate through files try
using (ZipArchive archive = ZipFile.OpenRead(packagename))
{ {
string frameworkversion = ""; // iterate through files
// locate nuspec using (ZipArchive archive = ZipFile.OpenRead(packagename))
foreach (ZipArchiveEntry entry in archive.Entries)
{ {
if (entry.FullName.ToLower().EndsWith(".nuspec")) string frameworkversion = "";
{ // locate nuspec
// open nuspec
XmlTextReader reader = new XmlTextReader(entry.Open());
reader.Namespaces = false; // remove namespace
XmlDocument doc = new XmlDocument();
doc.Load(reader);
// get framework dependency
XmlNode node = doc.SelectSingleNode("/package/metadata/dependencies/dependency[@id='Oqtane.Framework']");
if (node != null)
{
frameworkversion = node.Attributes["version"].Value;
}
reader.Close();
break;
}
}
// if compatible with framework version
if (frameworkversion == "" || Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) >= 0)
{
List<string> assets = new List<string>();
bool manifest = false;
string name = Path.GetFileNameWithoutExtension(packagename);
// deploy to appropriate locations
foreach (ZipArchiveEntry entry in archive.Entries) foreach (ZipArchiveEntry entry in archive.Entries)
{ {
string filename = ""; if (entry.FullName.ToLower().EndsWith(".nuspec"))
// evaluate entry root folder
switch (entry.FullName.Split('/')[0])
{ {
case "lib": // lib/net*/... // open nuspec
filename = ExtractFile(entry, binPath, 2); XmlTextReader reader = new XmlTextReader(entry.Open());
break; reader.Namespaces = false; // remove namespace
case "wwwroot": // wwwroot/... XmlDocument doc = new XmlDocument();
filename = ExtractFile(entry, webRootPath, 1); doc.Load(reader);
break; // get framework dependency
case "runtimes": // runtimes/name/... XmlNode node = doc.SelectSingleNode("/package/metadata/dependencies/dependency[@id='Oqtane.Framework']");
filename = ExtractFile(entry, binPath, 0); if (node != null)
break;
case "ref": // ref/net*/...
filename = ExtractFile(entry, Path.Combine(binPath, "ref"), 2);
break;
case "refs": // refs/net*/...
filename = ExtractFile(entry, Path.Combine(binPath, "refs"), 2);
break;
case "content": // content/...
filename = ExtractFile(entry, contentRootPath, 0);
break;
}
if (filename != "")
{
// ContentRootPath sometimes produces inconsistent path casing - so can't use string.Replace()
filename = Regex.Replace(filename, Regex.Escape(contentRootPath), "", RegexOptions.IgnoreCase);
assets.Add(filename);
if (!manifest && Path.GetExtension(filename) == ".log")
{ {
manifest = true; frameworkversion = node.Attributes["version"].Value;
}
reader.Close();
break;
}
}
// if compatible with framework version
if (frameworkversion == "" || Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) >= 0)
{
List<string> assets = new List<string>();
bool manifest = false;
string name = Path.GetFileNameWithoutExtension(packagename);
// deploy to appropriate locations
foreach (ZipArchiveEntry entry in archive.Entries)
{
string filename = "";
// evaluate entry root folder
switch (entry.FullName.Split('/')[0])
{
case "lib": // lib/net*/...
filename = ExtractFile(entry, binPath, 2);
break;
case "wwwroot": // wwwroot/...
filename = ExtractFile(entry, webRootPath, 1);
break;
case "runtimes": // runtimes/name/...
filename = ExtractFile(entry, binPath, 0);
break;
case "ref": // ref/net*/...
filename = ExtractFile(entry, Path.Combine(binPath, "ref"), 2);
break;
case "refs": // refs/net*/...
filename = ExtractFile(entry, Path.Combine(binPath, "refs"), 2);
break;
case "content": // content/...
filename = ExtractFile(entry, contentRootPath, 0);
break;
}
if (filename != "")
{
// ContentRootPath sometimes produces inconsistent path casing - so can't use string.Replace()
filename = Regex.Replace(filename, Regex.Escape(contentRootPath), "", RegexOptions.IgnoreCase);
assets.Add(filename);
if (!manifest && Path.GetExtension(filename) == ".log")
{
manifest = true;
}
} }
} }
}
// save dynamic list of assets // save dynamic list of assets
if (!manifest && assets.Count != 0) if (!manifest && assets.Count != 0)
{
string manifestpath = Path.Combine(sourceFolder, name + ".log");
if (File.Exists(manifestpath))
{ {
File.Delete(manifestpath); string manifestpath = Path.Combine(sourceFolder, name + ".log");
if (File.Exists(manifestpath))
{
File.Delete(manifestpath);
}
if (!Directory.Exists(Path.GetDirectoryName(manifestpath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(manifestpath));
}
File.WriteAllText(manifestpath, JsonSerializer.Serialize(assets, new JsonSerializerOptions { WriteIndented = true }));
} }
if (!Directory.Exists(Path.GetDirectoryName(manifestpath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(manifestpath));
}
File.WriteAllText(manifestpath, JsonSerializer.Serialize(assets, new JsonSerializerOptions { WriteIndented = true }));
} }
} }
} }
catch (Exception ex)
{
// problem installing package - logging is not possible as this is a static method
Debug.WriteLine($"Oqtane Error: Installing Package {packagename} - {ex}");
install = false;
}
// remove package // remove package
File.Delete(packagename); File.Delete(packagename);
install = true;
} }
return install; return install;