Got more of the install checker working and inspecting package assemblies for report.

This commit is contained in:
Shannon
2013-10-25 11:35:09 +11:00
parent 2587b06361
commit c5c1946d1b
6 changed files with 125 additions and 38 deletions

View File

@@ -3,46 +3,48 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace Umbraco.Core.Packaging
{
internal class PackageBinaryInspector
internal class PackageBinaryInspector : MarshalByRefObject
{
public static IEnumerable<string> BinariesContainInstanceOf<T>(string dllPath)
public IEnumerable<string> PerformScan<T>(string dllPath, out string[] errorReport)
{
var result = new List<string>();
if (Directory.Exists(dllPath) == false)
{
throw new DirectoryNotFoundException("Could not find directory " + dllPath);
}
var files = Directory.GetFiles(dllPath, "*.dll");
var dllsWithReference = new List<string>();
var errors = new List<string>();
var assembliesWithErrors = new List<string>();
//we need this handler to resolve assembly dependencies below
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, e) =>
{
var ass = Assembly.ReflectionOnlyLoad(e.Name);
if (ass == null)
{
throw new TypeLoadException("Could not load assembly " + e.Name);
}
return ass;
var a = Assembly.ReflectionOnlyLoad(e.Name);
if (a == null) throw new TypeLoadException("Could not load assembly " + e.Name);
return a;
};
//First load each dll file into the context
foreach (var f in files)
{
if (File.Exists(f) == false)
{
throw new FileNotFoundException("Could not find file " + f);
}
Assembly.ReflectionOnlyLoadFrom(f);
}
//First load each dll file into the context
foreach (var f in files) Assembly.ReflectionOnlyLoadFrom(f);
var toIgnore = new List<string>();
////before we try to load these assemblies into context, ensure we haven't done that already
//var alreadyLoaded = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies();
////First load each dll file into the context
//foreach (var f in files.Where(a => !IsAlreadyLoaded(a, alreadyLoaded)))
//{
// //NOTE: if you're loading an already loaded assembly from a new location
// // you will get a FileLoadException here.
// Assembly.ReflectionOnlyLoadFrom(f);
//}
//Then load each referenced assembly into the context
foreach (var f in files)
@@ -54,27 +56,81 @@ namespace Umbraco.Core.Packaging
{
Assembly.ReflectionOnlyLoad(assemblyName.FullName);
}
catch (Exception)
catch (FileNotFoundException)
{
//if an exception occurs it means that a referenced assembly could not be found - unless something else strange is going on.
//we'll log an error for this to return in our report
result.Add("This package references an assembly that was not found (" + assemblyName.FullName + "), this package may have problems running");
toIgnore.Add(f);
//if an exception occurs it means that a referenced assembly could not be found
errors.Add(
string.Concat("This package references the assembly '",
assemblyName.Name,
"' which was not found, this package may have problems running"));
assembliesWithErrors.Add(f);
}
}
}
//now that we have all referenced types into the context we can look up stuff
foreach (var f in files.Except(toIgnore))
foreach (var f in files.Except(assembliesWithErrors))
{
//now we need to see if they contain any type 'T'
var reflectedAssembly = Assembly.ReflectionOnlyLoadFrom(f);
var found = reflectedAssembly.GetExportedTypes().Where(TypeHelper.IsTypeAssignableFrom<T>).ToArray();
result.AddRange(found.Select(x => x.FullName));
var found = reflectedAssembly.GetExportedTypes().Where(TypeHelper.IsTypeAssignableFrom<T>);
if (found.Any())
{
dllsWithReference.Add(reflectedAssembly.FullName);
}
}
errorReport = errors.ToArray();
return dllsWithReference;
}
public static IEnumerable<string> ScanAssembliesForTypeReference<T>(string dllPath, out string[] errorReport)
{
var appDomain = GetTempAppDomain();
var type = typeof(PackageBinaryInspector);
var value = (PackageBinaryInspector) appDomain.CreateInstanceAndUnwrap(
type.Assembly.FullName,
type.FullName);
var result = value.PerformScan<T>(dllPath, out errorReport);
AppDomain.Unload(appDomain);
return result;
}
private static AppDomain GetTempAppDomain()
{
//copy the current app domain setup but don't shadow copy files
var appName = "TempDomain" + Guid.NewGuid();
var domainSetup = new AppDomainSetup
{
ApplicationName = appName,
ShadowCopyFiles = "false",
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
DynamicBase = AppDomain.CurrentDomain.SetupInformation.DynamicBase,
LicenseFile = AppDomain.CurrentDomain.SetupInformation.LicenseFile,
LoaderOptimization = AppDomain.CurrentDomain.SetupInformation.LoaderOptimization,
PrivateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath,
PrivateBinPathProbe = AppDomain.CurrentDomain.SetupInformation.PrivateBinPathProbe
};
//create new domain with full trust
return AppDomain.CreateDomain(
appName,
AppDomain.CurrentDomain.Evidence,
domainSetup,
new PermissionSet(PermissionState.Unrestricted));
}
//private static bool IsAlreadyLoaded(string assemblyFile, IEnumerable<Assembly> alreadyLoaded)
//{
// return alreadyLoaded.Any(assembly => GetAssemblyLocation(assembly) == assemblyFile);
//}
//private static string GetAssemblyLocation(Assembly assembly)
//{
// var uri = new Uri(assembly.CodeBase);
// return uri.LocalPath;
//}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Runtime.Serialization;
using System.Web;
using System.Web.Security;
using Newtonsoft.Json;
@@ -11,6 +12,7 @@ namespace Umbraco.Core.Security
/// <remarks>
/// All values are lazy loaded for performance reasons as the constructor is called for every single request
/// </remarks>
[Serializable]
public class UmbracoBackOfficeIdentity : FormsIdentity
{
public UmbracoBackOfficeIdentity(FormsAuthenticationTicket ticket)
@@ -104,5 +106,6 @@ namespace Umbraco.Core.Security
HttpContext.Current.Items[typeof (UmbracoBackOfficeIdentity)] = DeserializedData;
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Runtime.Serialization;
using System;
using System.Runtime.Serialization;
namespace Umbraco.Core.Security
{
@@ -6,6 +7,7 @@ namespace Umbraco.Core.Security
/// Data structure used to store information in the authentication cookie
/// </summary>
[DataContract(Name = "userData", Namespace = "")]
[Serializable]
internal class UserData
{
public UserData()

View File

@@ -157,6 +157,11 @@ namespace umbraco.presentation.developer.packages
}
}
if (_installer.ContainsLegacyPropertyEditors)
{
LegacyPropertyEditorPanel.Visible = true;
}
if (_installer.ContainsBinaryFileErrors)
{
BinaryFileErrorsPanel.Visible = true;

View File

@@ -301,6 +301,7 @@ namespace umbraco.presentation.developer.packages {
protected global::umbraco.uicontrols.PropertyPanel pp_templateConflicts;
protected global::umbraco.uicontrols.PropertyPanel BinaryFileErrorsPanel;
protected global::umbraco.uicontrols.PropertyPanel LegacyPropertyEditorPanel;
protected global::System.Web.UI.WebControls.Literal BinaryFileErrorReport;
/// <summary>

View File

@@ -63,15 +63,20 @@ namespace umbraco.cms.businesslogic.packager
public IDictionary<string, string> ConflictingTemplateAliases { get { return _conflictingTemplateAliases; } }
/// <summary>
/// Indicates that the package contains legacy property editors that are not compatible with this version (v7)
/// Indicates that the package contains assembly reference errors
/// </summary>
public bool ContainsBinaryFileErrors { get; private set; }
/// <summary>
/// List each property editor that is not compatible
/// List each assembly reference error
/// </summary>
public List<string> BinaryFileErrors { get { return _binaryFileErrors; } }
/// <summary>
/// Indicates that the package contains legacy property editors
/// </summary>
public bool ContainsLegacyPropertyEditors { get; private set; }
public bool ContainsStyleSheeConflicts { get; private set; }
public IDictionary<string, string> ConflictingStyleSheetNames { get { return _conflictingStyleSheetNames; } }
@@ -597,11 +602,16 @@ namespace umbraco.cms.businesslogic.packager
if (ContainsUnsecureFiles)
{
//Now we want to see if the DLLs contain any legacy data types since we want to warn people about that
var binaryFileErrors = PackageBinaryInspector.BinariesContainInstanceOf<IDataType>(tempDir).ToArray();
if (binaryFileErrors.Any())
string[] assemblyErrors;
var assembliesWithReferences = PackageBinaryInspector.ScanAssembliesForTypeReference<IDataType>(tempDir, out assemblyErrors).ToArray();
if (assemblyErrors.Any())
{
ContainsBinaryFileErrors = true;
BinaryFileErrors.AddRange(binaryFileErrors);
BinaryFileErrors.AddRange(assemblyErrors);
}
if (assembliesWithReferences.Any())
{
ContainsLegacyPropertyEditors = true;
}
}
@@ -741,8 +751,18 @@ namespace umbraco.cms.businesslogic.packager
private static string UnPack(string zipName)
{
// Unzip
string tempDir = IOHelper.MapPath(SystemDirectories.Data) + Path.DirectorySeparatorChar + Guid.NewGuid().ToString();
Directory.CreateDirectory(tempDir);
//the temp directory will be the package GUID - this keeps it consistent!
//the zipName is always the package Guid.umb
var packageFileName = Path.GetFileNameWithoutExtension(zipName);
var packageId = Guid.NewGuid();
Guid.TryParse(packageFileName, out packageId);
string tempDir = IOHelper.MapPath(SystemDirectories.Data) + Path.DirectorySeparatorChar + packageId.ToString();
//clear the directory if it exists
if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true);
Directory.CreateDirectory(tempDir);
var s = new ZipInputStream(File.OpenRead(zipName));