Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improved module/theme installation by saving the list of files which are in the Nuget package and using that list to remove them during uninstall #715

Merged
merged 1 commit into from
Aug 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions Oqtane.Server/Controllers/ModuleDefinitionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using System.Xml.Linq;
using System.Text.Json;

namespace Oqtane.Controllers
{
Expand Down Expand Up @@ -110,6 +111,7 @@ public void Delete(int id, int siteid)
{
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);

// execute uninstall logic
foreach (Tenant tenant in _tenants.GetTenants())
{
try
Expand All @@ -130,25 +132,28 @@ public void Delete(int id, int siteid)
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "Error Uninstalling {ModuleDefinitionName} For Tenant {Tenant} {Error}", moduledefinition.ModuleDefinitionName, tenant.Name, ex.Message);
}
}


// use assets.json to clean up file resources
string assetfilepath = Path.Combine(_environment.WebRootPath, "Modules", Utilities.GetTypeName(moduledefinition.ModuleDefinitionName), "assets.json");
if (System.IO.File.Exists(assetfilepath))
{
List<string> assets = JsonSerializer.Deserialize<List<string>>(System.IO.File.ReadAllText(assetfilepath));
foreach(string asset in assets)
{
if (System.IO.File.Exists(asset))
{
System.IO.File.Delete(asset);
}
}
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assets Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
}

// clean up module static resource folder
string folder = Path.Combine(_environment.WebRootPath, Path.Combine("Modules", Utilities.GetTypeName(moduledefinition.ModuleDefinitionName)));
if (Directory.Exists(folder))
{
Directory.Delete(folder, true);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
}

// get root assembly name ( note that this only works if modules follow a specific naming convention for their assemblies )
string assemblyname = Utilities.GetAssemblyName(moduledefinition.ModuleDefinitionName).ToLower();
assemblyname = assemblyname.Replace(".client", "").Replace(".oqtane", "");

// remove module assemblies from /bin
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
foreach (string file in Directory.EnumerateFiles(binfolder, assemblyname + "*.*"))
{
System.IO.File.Delete(file);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assembly {Filename} Removed For {ModuleDefinitionName}", file, moduledefinition.ModuleDefinitionName);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Resources Folder Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
}

// remove module definition
Expand Down
23 changes: 17 additions & 6 deletions Oqtane.Server/Controllers/ThemeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Oqtane.Enums;
using Oqtane.Infrastructure;
using Oqtane.Repository;
using System.Text.Json;

// ReSharper disable StringIndexOfIsCultureSpecific.1

Expand Down Expand Up @@ -56,19 +57,29 @@ public void Delete(string themename)
Theme theme = themes.Where(item => item.ThemeName == themename).FirstOrDefault();
if (theme != null && Utilities.GetAssemblyName(theme.ThemeName) != "Oqtane.Client")
{
// use assets.json to clean up file resources
string assetfilepath = Path.Combine(_environment.WebRootPath, "Modules", Utilities.GetTypeName(theme.ThemeName), "assets.json");
if (System.IO.File.Exists(assetfilepath))
{
List<string> assets = JsonSerializer.Deserialize<List<string>>(System.IO.File.ReadAllText(assetfilepath));
foreach (string asset in assets)
{
if (System.IO.File.Exists(asset))
{
System.IO.File.Delete(asset);
}
}
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Assets Removed For {ThemeName}", theme.ThemeName);
}

// clean up theme static resource folder
string folder = Path.Combine(_environment.WebRootPath, "Themes" , Utilities.GetTypeName(theme.ThemeName));
if (Directory.Exists(folder))
{
Directory.Delete(folder, true);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Static Resources Removed For {ThemeName}", theme.ThemeName);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Resource Folder Removed For {ThemeName}", theme.ThemeName);
}

// remove theme assembly from /bin
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
System.IO.File.Delete(Path.Combine(binfolder, Utilities.GetAssemblyName(theme.ThemeName) + ".dll"));
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Assembly {Filename} Removed For {ThemeName}", Utilities.GetAssemblyName(theme.ThemeName) + ".dll", themename);

_installationManager.RestartApplication();
}
}
Expand Down
18 changes: 18 additions & 0 deletions Oqtane.Server/Infrastructure/InstallationManager.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Text.Json;
using System.Xml;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Caching.Memory;
Expand Down Expand Up @@ -80,6 +82,8 @@ public static bool InstallPackages(string folders, string webRootPath)
// if compatible with framework version
if (frameworkversion == "" || Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) >= 0)
{
List<string> assets = new List<string>();

// module and theme packages must be in form of name.1.0.0.nupkg
string name = Path.GetFileNameWithoutExtension(packagename);
string[] segments = name?.Split('.');
Expand All @@ -96,18 +100,32 @@ public static bool InstallPackages(string folders, string webRootPath)
case "lib":
filename = Path.Combine(binFolder, filename);
ExtractFile(entry, filename);
assets.Add(filename);
break;
case "wwwroot":
filename = Path.Combine(webRootPath.Replace(Path.DirectorySeparatorChar + "wwwroot", ""), Utilities.PathCombine(entry.FullName.Split('/')));
ExtractFile(entry, filename);
assets.Add(filename);
break;
case "runtimes":
var destSubFolder = Path.GetDirectoryName(entry.FullName);
filename = Path.Combine(binFolder, destSubFolder, filename);
ExtractFile(entry, filename);
assets.Add(filename);
break;
}
}

// save list of assets
if (assets.Count != 0)
{
string assetfilepath = Path.Combine(webRootPath, "Modules", name, "assets.json");
if (File.Exists(assetfilepath))
{
File.Delete(assetfilepath);
}
File.WriteAllText(assetfilepath, JsonSerializer.Serialize(assets));
}
}
}

Expand Down