Adds logging to the package installer for debugging. Updates DisposableTimer to pass delegates for logging for tracing/info.

Fixes PluginManager cache file handling. Ensures cache file is written with the correct TypeResolutionKind. Have added a check to
ensure the file is replaced if a legacy file is found. Added a check to the PluginManager to load from scanning if the cache item is
not found in the file, this fixes all install issues with the type finding in 4.11.
Added new batch file to reset an umbraco install to vanilla (not 100% complete yet)
This commit is contained in:
Shannon Deminick
2012-11-27 10:42:22 +05:00
parent e9c154f0a2
commit d5e184b133
6 changed files with 523 additions and 245 deletions

View File

@@ -0,0 +1,98 @@
@ECHO OFF
:choice
set /P c=WARNING! Are you sure you want to continue, this will remove all package files, view files, sqlce database, etc... Press 'Y' to auto-remove all files/folders, 'N' to cancel or 'C' to prompt for each folder removal?
if /I "%c%" EQU "C" goto :prompt
if /I "%c%" EQU "Y" goto :auto
if /I "%c%" EQU "N" goto :exit
goto :choice
:prompt
echo Current folder: %CD%
echo Removing sqlce database
del ..\src\Umbraco.Web.UI\App_Data\Umbraco.sdf
echo Resetting installedPackages.config
echo ^<?xml version="1.0" encoding="utf-8"?^>^<packages^>^</packages^> >..\src\Umbraco.Web.UI\App_Data\packages\installed\installedPackages.config
echo Removing plugin cache files
del ..\src\Umbraco.Web.UI\App_Data\TEMP\PluginCache\*.*
echo Removing log files
del ..\src\Umbraco.Web.UI\App_Data\Logs\*.*
echo Removing xslt files
del ..\src\Umbraco.Web.UI\Xslt\*.*
echo Removing user control files
del ..\src\Umbraco.Web.UI\UserControls\*.*
echo Removing view files
del ..\src\Umbraco.Web.UI\Views\*.*
echo Removing razor files
del ..\src\Umbraco.Web.UI\MacroScripts\*.*
echo Removing media files
del ..\src\Umbraco.Web.UI\Media\*.*
echo Removing script files
del ..\src\Umbraco.Web.UI\Scripts\*.*
echo Removing css files
del ..\src\Umbraco.Web.UI\Css\*.*
echo "Umbraco install reverted to clean install"
pause
exit
:auto
echo Current folder: %CD%
echo Removing sqlce database
del ..\src\Umbraco.Web.UI\App_Data\Umbraco.sdf
echo Resetting installedPackages.config
echo ^<?xml version="1.0" encoding="utf-8"?^>^<packages^>^</packages^> >..\src\Umbraco.Web.UI\App_Data\packages\installed\installedPackages.config
echo Removing plugin cache files
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\TEMP\PluginCache\*.*) DO DEL %%A
echo Removing log files
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\Logs\*.*) DO DEL %%A
echo Removing xslt files
FOR %%A IN (..\src\Umbraco.Web.UI\Xslt\*.*) DO DEL %%A
echo Removing user control files
FOR %%A IN (..\src\Umbraco.Web.UI\UserControls\*.*) DO DEL %%A
echo Removing view files
FOR %%A IN (..\src\Umbraco.Web.UI\Views\*.*) DO DEL %%A
echo Removing razor files
FOR %%A IN (..\src\Umbraco.Web.UI\MacroScripts\*.*) DO DEL %%A
echo Removing media files
FOR %%A IN (..\src\Umbraco.Web.UI\Media\*.*) DO DEL %%A
echo Removing script files
FOR %%A IN (..\src\Umbraco.Web.UI\Scripts\*.*) DO DEL %%A
echo Removing css files
FOR %%A IN (..\src\Umbraco.Web.UI\Css\*.*) DO DEL %%A
echo "Umbraco install reverted to clean install"
pause
exit
:exit
exit

View File

@@ -41,6 +41,17 @@ namespace Umbraco.Core
return new DisposableTimer(callback);
}
public static DisposableTimer TraceDuration<T>(Func<string> startMessage, Func<string> completeMessage)
{
return TraceDuration(typeof(T), startMessage, completeMessage);
}
public static DisposableTimer TraceDuration(Type loggerType, Func<string> startMessage, Func<string> completeMessage)
{
LogHelper.Debug(loggerType, startMessage);
return new DisposableTimer(x => LogHelper.Info(loggerType, () => completeMessage() + " (took " + x + "ms)"));
}
/// <summary>
/// Adds a start and end log entry as Info and tracks how long it takes until disposed.
/// </summary>

View File

@@ -68,6 +68,14 @@ namespace Umbraco.Core
Directory.CreateDirectory(_tempFolder);
}
//this is a check for legacy changes, before we didn't store the TypeResolutionKind in the file which was a mistake,
//so we need to detect if the old file is there without this attribute, if it is then we delete it
if (DetectLegacyPluginListFile())
{
var filePath = GetPluginListFilePath();
File.Delete(filePath);
}
if (detectCodeChanges)
{
//first check if the cached hash is 0, if it is then we ne
@@ -120,6 +128,7 @@ namespace Umbraco.Core
#region Hash checking methods
/// <summary>
/// Returns a bool if the assemblies in the /bin have changed since they were last hashed.
/// </summary>
@@ -228,9 +237,9 @@ namespace Umbraco.Core
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
internal Attempt<IEnumerable<string>> TryGetCachedPluginsFromFile<T>()
internal Attempt<IEnumerable<string>> TryGetCachedPluginsFromFile<T>(TypeResolutionKind resolutionType)
{
var filePath = Path.Combine(_tempFolder, "umbraco-plugins.list");
var filePath = GetPluginListFilePath();
if (!File.Exists(filePath))
return Attempt<IEnumerable<string>>.False;
@@ -257,9 +266,12 @@ namespace Umbraco.Core
var typeElement = xml.Root.Elements()
.SingleOrDefault(x =>
x.Name.LocalName == "baseType"
&& ((string) x.Attribute("type")) == typeof (T).FullName);
&& ((string) x.Attribute("type")) == typeof (T).FullName
&& ((string) x.Attribute("resolutionType")) == resolutionType.ToString());
//return false but specify this exception type so we can detect it
if (typeElement == null)
return Attempt<IEnumerable<string>>.False;
return new Attempt<IEnumerable<string>>(new CachedPluginNotFoundInFile());
//return success
return new Attempt<IEnumerable<string>>(
@@ -267,10 +279,52 @@ namespace Umbraco.Core
typeElement.Elements("add")
.Select(x => (string) x.Attribute("type")));
}
catch (Exception)
catch (Exception ex)
{
//if the file is corrupted, etc... return false
return Attempt<IEnumerable<string>>.False;
return new Attempt<IEnumerable<string>>(ex);
}
}
private string GetPluginListFilePath()
{
return Path.Combine(_tempFolder, "umbraco-plugins.list");
}
/// <summary>
/// This will return true if the plugin list file is a legacy one
/// </summary>
/// <returns></returns>
/// <remarks>
/// This method exists purely due to an error in 4.11. We were writing the plugin list file without the
/// type resolution kind which will have caused some problems. Now we detect this legacy file and if it is detected
/// we remove it so it can be recreated properly.
/// </remarks>
internal bool DetectLegacyPluginListFile()
{
var filePath = GetPluginListFilePath();
if (!File.Exists(filePath))
return false;
try
{
var xml = XDocument.Load(filePath);
if (xml.Root == null)
return false;
var typeElement = xml.Root.Elements()
.FirstOrDefault(x => x.Name.LocalName == "baseType");
if (typeElement == null)
return false;
//now check if the typeElement is missing the resolutionType attribute
return typeElement.Attributes().All(x => x.Name.LocalName != "resolutionType");
}
catch (Exception)
{
//if the file is corrupted, etc... return true so it is removed
return true;
}
}
@@ -279,7 +333,8 @@ namespace Umbraco.Core
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="typesFound"></param>
/// <remarks>
///<param name="resolutionType"> </param>
///<remarks>
/// THIS METHOD IS NOT THREAD SAFE
/// </remarks>
/// <example>
@@ -292,9 +347,9 @@ namespace Umbraco.Core
/// </plugins>
/// ]]>
/// </example>
internal void UpdateCachedPluginsFile<T>(IEnumerable<Type> typesFound)
internal void UpdateCachedPluginsFile<T>(IEnumerable<Type> typesFound, TypeResolutionKind resolutionType)
{
var filePath = Path.Combine(_tempFolder, "umbraco-plugins.list");
var filePath = GetPluginListFilePath();
XDocument xml;
try
{
@@ -316,11 +371,15 @@ namespace Umbraco.Core
var typeElement = xml.Root.Elements()
.SingleOrDefault(x =>
x.Name.LocalName == "baseType"
&& ((string)x.Attribute("type")) == typeof(T).FullName);
&& ((string)x.Attribute("type")) == typeof(T).FullName
&& ((string)x.Attribute("resolutionType")) == resolutionType.ToString());
if (typeElement == null)
{
//create the type element
typeElement = new XElement("baseType", new XAttribute("type", typeof(T).FullName));
typeElement = new XElement("baseType",
new XAttribute("type", typeof(T).FullName),
new XAttribute("resolutionType", resolutionType.ToString()));
//then add it to the root
xml.Root.Add(typeElement);
}
@@ -486,9 +545,11 @@ namespace Umbraco.Core
{
using (var readLock = new UpgradeableReadLock(_lock))
{
var typesFound = new List<Type>();
using (DisposableTimer.TraceDuration<PluginManager>(
String.Format("Starting resolution types of {0}", typeof(T).FullName),
String.Format("Completed resolution of types of {0}", typeof(T).FullName)))
() => String.Format("Starting resolution types of {0}", typeof(T).FullName),
() => String.Format("Completed resolution of types of {0}, found {1}", typeof(T).FullName, typesFound.Count)))
{
//check if the TypeList already exists, if so return it, if not we'll create it
var typeList = _types.SingleOrDefault(x => x.IsTypeList<T>(resolutionType));
@@ -501,46 +562,59 @@ namespace Umbraco.Core
typeList = new TypeList<T>(resolutionType);
//we first need to look into our cache file (this has nothing to do with the 'cacheResult' parameter which caches in memory).
if (!HaveAssembliesChanged)
//if assemblies have not changed and the cache file actually exists, then proceed to try to lookup by the cache file.
if (!HaveAssembliesChanged && File.Exists(GetPluginListFilePath()))
{
var fileCacheResult = TryGetCachedPluginsFromFile<T>();
if (fileCacheResult.Success)
var fileCacheResult = TryGetCachedPluginsFromFile<T>(resolutionType);
//here we need to identify if the CachedPluginNotFoundInFile was the exception, if it was then we need to re-scan
//in some cases the plugin will not have been scanned for on application startup, but the assemblies haven't changed
//so in this instance there will never be a result.
if (fileCacheResult.Error != null && fileCacheResult.Error is CachedPluginNotFoundInFile)
{
var successfullyLoadedFromCache = true;
//we have a previous cache for this so we don't need to scan we just load what has been found in the file
foreach(var t in fileCacheResult.Result)
{
try
{
//we use the build manager to ensure we get all types loaded, this is slightly slower than
//Type.GetType but if the types in the assembly aren't loaded yet then we have problems with that.
var type = BuildManager.GetType(t, true);
typeList.AddType(type);
}
catch (Exception ex)
{
//if there are any exceptions loading types, we have to exist, this should never happen so
//we will need to revert to scanning for types.
successfullyLoadedFromCache = false;
LogHelper.Error<PluginManager>("Could not load a cached plugin type: " + t + " now reverting to re-scanning assemblies for the base type: " + typeof (T).FullName, ex);
break;
}
}
if (!successfullyLoadedFromCache )
{
//we need to manually load by scanning if loading from the file was not successful.
LoadViaScanningAndUpdateCacheFile<T>(typeList, finder);
}
else
{
LogHelper.Debug<PluginManager>("Loaded plugin types " + typeof(T).FullName + " from persisted cache");
}
//we don't have a cache for this so proceed to look them up by scanning
LoadViaScanningAndUpdateCacheFile<T>(typeList, resolutionType, finder);
}
else
{
if (fileCacheResult.Success)
{
var successfullyLoadedFromCache = true;
//we have a previous cache for this so we don't need to scan we just load what has been found in the file
foreach (var t in fileCacheResult.Result)
{
try
{
//we use the build manager to ensure we get all types loaded, this is slightly slower than
//Type.GetType but if the types in the assembly aren't loaded yet then we have problems with that.
var type = BuildManager.GetType(t, true);
typeList.AddType(type);
}
catch (Exception ex)
{
//if there are any exceptions loading types, we have to exist, this should never happen so
//we will need to revert to scanning for types.
successfullyLoadedFromCache = false;
LogHelper.Error<PluginManager>("Could not load a cached plugin type: " + t + " now reverting to re-scanning assemblies for the base type: " + typeof(T).FullName, ex);
break;
}
}
if (!successfullyLoadedFromCache)
{
//we need to manually load by scanning if loading from the file was not successful.
LoadViaScanningAndUpdateCacheFile<T>(typeList, resolutionType, finder);
}
else
{
LogHelper.Debug<PluginManager>("Loaded plugin types " + typeof(T).FullName + " from persisted cache");
}
}
}
}
else
{
//we don't have a cache for this so proceed to look them up by scanning
LoadViaScanningAndUpdateCacheFile<T>(typeList, finder);
LoadViaScanningAndUpdateCacheFile<T>(typeList, resolutionType, finder);
}
//only add the cache if we are to cache the results
@@ -550,8 +624,10 @@ namespace Umbraco.Core
_types.Add(typeList);
}
}
return typeList.GetTypes();
typesFound = typeList.GetTypes().ToList();
}
return typesFound;
}
}
@@ -560,18 +636,19 @@ namespace Umbraco.Core
/// Once the results are loaded, we update the cached type xml file
/// </summary>
/// <param name="typeList"></param>
/// <param name="resolutionKind"> </param>
/// <param name="finder"></param>
/// <remarks>
/// THIS METHODS IS NOT THREAD SAFE
/// </remarks>
private void LoadViaScanningAndUpdateCacheFile<T>(TypeList typeList, Func<IEnumerable<Type>> finder)
private void LoadViaScanningAndUpdateCacheFile<T>(TypeList typeList, TypeResolutionKind resolutionKind, Func<IEnumerable<Type>> finder)
{
//we don't have a cache for this so proceed to look them up by scanning
foreach (var t in finder())
{
typeList.AddType(t);
}
UpdateCachedPluginsFile<T>(typeList.GetTypes());
}
UpdateCachedPluginsFile<T>(typeList.GetTypes(), resolutionKind);
}
/// <summary>
@@ -683,6 +760,16 @@ namespace Umbraco.Core
return _types;
}
}
/// <summary>
/// This class is used simply to determine that a plugin was not found in the cache plugin list with the specified
/// TypeResolutionKind.
/// </summary>
internal class CachedPluginNotFoundInFile : Exception
{
}
#endregion
}
}

View File

@@ -8,6 +8,7 @@ using System.Web.Compilation;
using NUnit.Framework;
using SqlCE4Umbraco;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using umbraco;
@@ -148,6 +149,34 @@ namespace Umbraco.Tests
// Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds);
//}
[Test]
public void Detect_Legacy_Plugin_File_List()
{
var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache");
var manager = new PluginManager(false);
var filePath = Path.Combine(tempFolder, "umbraco-plugins.list");
File.WriteAllText(filePath, @"<?xml version=""1.0"" encoding=""utf-8""?>
<plugins>
<baseType type=""umbraco.interfaces.ICacheRefresher"">
<add type=""umbraco.macroCacheRefresh, umbraco, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null"" />
</baseType>
</plugins>");
Assert.IsTrue(manager.DetectLegacyPluginListFile());
File.Delete(filePath);
//now create a valid one
File.WriteAllText(filePath, @"<?xml version=""1.0"" encoding=""utf-8""?>
<plugins>
<baseType type=""umbraco.interfaces.ICacheRefresher"" resolutionType=""FindAllTypes"">
<add type=""umbraco.macroCacheRefresh, umbraco, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null"" />
</baseType>
</plugins>");
Assert.IsFalse(manager.DetectLegacyPluginListFile());
}
[Test]
public void Create_Cached_Plugin_File()
{
@@ -155,10 +184,15 @@ namespace Umbraco.Tests
var manager = new PluginManager(false);
//yes this is silly, none of these types inherit from string, but this is just to test the xml file format
manager.UpdateCachedPluginsFile<string>(types);
manager.UpdateCachedPluginsFile<string>(types, PluginManager.TypeResolutionKind.FindAllTypes);
var plugins = manager.TryGetCachedPluginsFromFile<string>(PluginManager.TypeResolutionKind.FindAllTypes);
var diffType = manager.TryGetCachedPluginsFromFile<string>(PluginManager.TypeResolutionKind.FindAttributedTypes);
var plugins = manager.TryGetCachedPluginsFromFile<string>();
Assert.IsTrue(plugins.Success);
//this will be false since there is no cache of that type resolution kind
Assert.IsFalse(diffType.Success);
Assert.AreEqual(3, plugins.Result.Count());
var shouldContain = types.Select(x => x.AssemblyQualifiedName);
//ensure they are all found
@@ -206,11 +240,11 @@ namespace Umbraco.Tests
var hash3 = PluginManager.GetAssembliesHash(list3);
//Assert
//both should be the same since we only create the hash based on the unique folder of the list passed in, yet
//all files will exist in those folders still
Assert.AreEqual(hash1, hash2);
Assert.AreNotEqual(hash1, hash2);
Assert.AreNotEqual(hash1, hash3);
Assert.AreNotEqual(hash2, hash3);
Assert.AreEqual(hash1, PluginManager.GetAssembliesHash(list1));
}
[Test]

View File

@@ -13,7 +13,8 @@ using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using Umbraco.Core;
using Umbraco.Core.Logging;
using umbraco.cms.businesslogic.web;
using umbraco.cms.businesslogic.propertytype;
using umbraco.BusinessLogic;
@@ -154,29 +155,34 @@ namespace umbraco.cms.businesslogic.packager
/// <returns></returns>
public string Import(string InputFile)
{
string tempDir = "";
if (File.Exists(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile)))
{
FileInfo fi = new FileInfo(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile));
// Check if the file is a valid package
if (fi.Extension.ToLower() == ".umb")
{
try
{
tempDir = unPack(fi.FullName);
LoadConfig(tempDir);
}
catch (Exception unpackE)
{
throw new Exception("Error unpacking extension...", unpackE);
}
}
else
throw new Exception("Error - file isn't a package (doesn't have a .umb extension). Check if the file automatically got named '.zip' upon download.");
}
else
throw new Exception("Error - file not found. Could find file named '" + IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile) + "'");
return tempDir;
using (DisposableTimer.DebugDuration<Installer>(
() => "Importing package file " + InputFile,
() => "Package file " + InputFile + "imported"))
{
string tempDir = "";
if (File.Exists(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile)))
{
FileInfo fi = new FileInfo(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile));
// Check if the file is a valid package
if (fi.Extension.ToLower() == ".umb")
{
try
{
tempDir = unPack(fi.FullName);
LoadConfig(tempDir);
}
catch (Exception unpackE)
{
throw new Exception("Error unpacking extension...", unpackE);
}
}
else
throw new Exception("Error - file isn't a package (doesn't have a .umb extension). Check if the file automatically got named '.zip' upon download.");
}
else
throw new Exception("Error - file not found. Could find file named '" + IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile) + "'");
return tempDir;
}
}
@@ -220,218 +226,259 @@ namespace umbraco.cms.businesslogic.packager
return insPack.Data.Id;
}
public void InstallFiles(int packageId, string tempDir) {
public void InstallFiles(int packageId, string tempDir)
{
using (DisposableTimer.DebugDuration<Installer>(
() => "Installing package files for package id " + packageId + " into temp folder " + tempDir,
() => "Package file installation complete for package id " + packageId))
{
//retrieve the manifest to continue installation
packager.InstalledPackage insPack = packager.InstalledPackage.GetById(packageId);
//retrieve the manifest to continue installation
packager.InstalledPackage insPack = packager.InstalledPackage.GetById(packageId);
// Move files
//string virtualBasePath = System.Web.HttpContext.Current.Request.ApplicationPath;
string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
// Move files
//string virtualBasePath = System.Web.HttpContext.Current.Request.ApplicationPath;
string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//file"))
{
//we enclose the whole file-moving to ensure that the entire installer doesn't crash
try
{
String destPath = getFileName(basePath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath")));
String sourceFile = getFileName(tempDir, xmlHelper.GetNodeValue(n.SelectSingleNode("guid")));
String destFile = getFileName(destPath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgName")));
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//file")) {
//we enclose the whole file-moving to ensure that the entire installer doesn't crash
try {
String destPath = getFileName(basePath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath")));
String sourceFile = getFileName(tempDir, xmlHelper.GetNodeValue(n.SelectSingleNode("guid")));
String destFile = getFileName(destPath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgName")));
// Create the destination directory if it doesn't exist
if (!Directory.Exists(destPath))
Directory.CreateDirectory(destPath);
//If a file with this name exists, delete it
else if (File.Exists(destFile))
File.Delete(destFile);
// Create the destination directory if it doesn't exist
if (!Directory.Exists(destPath))
Directory.CreateDirectory(destPath);
//If a file with this name exists, delete it
else if (File.Exists(destFile))
File.Delete(destFile);
// Move the file
File.Move(sourceFile, destFile);
// Move the file
File.Move(sourceFile, destFile);
//PPH log file install
insPack.Data.Files.Add(xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath")) + "/" + xmlHelper.GetNodeValue(n.SelectSingleNode("orgName")));
}
catch (Exception ex)
{
Log.Add(LogTypes.Error, -1, "Package install error: " + ex.ToString());
}
}
//PPH log file install
insPack.Data.Files.Add(xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath")) + "/" + xmlHelper.GetNodeValue(n.SelectSingleNode("orgName")));
} catch (Exception ex) {
Log.Add(LogTypes.Error, -1, "Package install error: " + ex.ToString());
}
}
insPack.Save();
insPack.Save();
}
}
public void InstallBusinessLogic(int packageId, string tempDir) {
//retrieve the manifest to continue installation
packager.InstalledPackage insPack = packager.InstalledPackage.GetById(packageId);
bool saveNeeded = false;
//Install DataTypes
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//DataType")) {
cms.businesslogic.datatype.DataTypeDefinition newDtd = cms.businesslogic.datatype.DataTypeDefinition.Import(n);
using (DisposableTimer.DebugDuration<Installer>(
() => "Installing business logic for package id " + packageId + " into temp folder " + tempDir,
() => "Package business logic installation complete for package id " + packageId))
{
//retrieve the manifest to continue installation
packager.InstalledPackage insPack = packager.InstalledPackage.GetById(packageId);
bool saveNeeded = false;
if (newDtd != null) {
insPack.Data.DataTypes.Add(newDtd.Id.ToString());
saveNeeded = true;
}
}
//Install DataTypes
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//DataType"))
{
cms.businesslogic.datatype.DataTypeDefinition newDtd = cms.businesslogic.datatype.DataTypeDefinition.Import(n);
if (saveNeeded) {insPack.Save(); saveNeeded = false;}
if (newDtd != null)
{
insPack.Data.DataTypes.Add(newDtd.Id.ToString());
saveNeeded = true;
}
}
//Install languages
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//Language")) {
language.Language newLang = language.Language.Import(n);
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (newLang != null) {
insPack.Data.Languages.Add(newLang.id.ToString());
saveNeeded = true;
}
}
//Install languages
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//Language"))
{
language.Language newLang = language.Language.Import(n);
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (newLang != null)
{
insPack.Data.Languages.Add(newLang.id.ToString());
saveNeeded = true;
}
}
//Install dictionary items
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("./DictionaryItems/DictionaryItem")) {
Dictionary.DictionaryItem newDi = Dictionary.DictionaryItem.Import(n);
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (newDi != null) {
insPack.Data.DictionaryItems.Add(newDi.id.ToString());
saveNeeded = true;
}
}
//Install dictionary items
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("./DictionaryItems/DictionaryItem"))
{
Dictionary.DictionaryItem newDi = Dictionary.DictionaryItem.Import(n);
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (newDi != null)
{
insPack.Data.DictionaryItems.Add(newDi.id.ToString());
saveNeeded = true;
}
}
// Install macros
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//macro")) {
cms.businesslogic.macro.Macro m = cms.businesslogic.macro.Macro.Import(n);
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (m != null) {
insPack.Data.Macros.Add(m.Id.ToString());
saveNeeded = true;
}
}
// Install macros
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//macro"))
{
cms.businesslogic.macro.Macro m = cms.businesslogic.macro.Macro.Import(n);
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (m != null)
{
insPack.Data.Macros.Add(m.Id.ToString());
saveNeeded = true;
}
}
// Get current user, with a fallback
User u = new User(0);
if (!string.IsNullOrEmpty(BasePages.UmbracoEnsuredPage.umbracoUserContextID)) {
if (BasePages.UmbracoEnsuredPage.ValidateUserContextID(BasePages.UmbracoEnsuredPage.umbracoUserContextID)) {
u = User.GetCurrent();
}
}
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
// Get current user, with a fallback
User u = new User(0);
if (!string.IsNullOrEmpty(BasePages.UmbracoEnsuredPage.umbracoUserContextID))
{
if (BasePages.UmbracoEnsuredPage.ValidateUserContextID(BasePages.UmbracoEnsuredPage.umbracoUserContextID))
{
u = User.GetCurrent();
}
}
// Add Templates
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) {
var t = Template.Import(n, u);
insPack.Data.Templates.Add(t.Id.ToString());
// Add Templates
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template"))
{
var t = Template.Import(n, u);
saveNeeded = true;
}
insPack.Data.Templates.Add(t.Id.ToString());
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
saveNeeded = true;
}
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
//NOTE: SD: I'm pretty sure the only thing the below script does is ensure that the Master template Id is set
// in the database, but this is also duplicating the saving of the design content since the above Template.Import
// already does this. I've left this for now because I'm not sure the reprocussions of removing it but seems there
// is a lot of excess database calls happening here.
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) {
string master = xmlHelper.GetNodeValue(n.SelectSingleNode("Master"));
template.Template t = template.Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Alias")));
if (master.Trim() != "") {
template.Template masterTemplate = template.Template.GetByAlias(master);
if (masterTemplate != null) {
t.MasterTemplate = template.Template.GetByAlias(master).Id;
//SD: This appears to always just save an empty template because the design isn't set yet
// this fixes an issue now that we have MVC because if there is an empty template and MVC is
// the default, it will create a View not a master page and then the system will try to route via
// MVC which means that the package will not work anymore.
// The code below that imports the templates should suffice because it's actually importing
// template data not just blank data.
//NOTE: SD: I'm pretty sure the only thing the below script does is ensure that the Master template Id is set
// in the database, but this is also duplicating the saving of the design content since the above Template.Import
// already does this. I've left this for now because I'm not sure the reprocussions of removing it but seems there
// is a lot of excess database calls happening here.
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template"))
{
string master = xmlHelper.GetNodeValue(n.SelectSingleNode("Master"));
template.Template t = template.Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Alias")));
if (master.Trim() != "")
{
template.Template masterTemplate = template.Template.GetByAlias(master);
if (masterTemplate != null)
{
t.MasterTemplate = template.Template.GetByAlias(master).Id;
//SD: This appears to always just save an empty template because the design isn't set yet
// this fixes an issue now that we have MVC because if there is an empty template and MVC is
// the default, it will create a View not a master page and then the system will try to route via
// MVC which means that the package will not work anymore.
// The code below that imports the templates should suffice because it's actually importing
// template data not just blank data.
//if (UmbracoSettings.UseAspNetMasterPages)
// t.SaveMasterPageFile(t.Design);
}
}
// Master templates can only be generated when their master is known
if (UmbracoSettings.UseAspNetMasterPages) {
t.ImportDesign(xmlHelper.GetNodeValue(n.SelectSingleNode("Design")));
t.SaveMasterPageFile(t.Design);
}
}
//if (UmbracoSettings.UseAspNetMasterPages)
// t.SaveMasterPageFile(t.Design);
}
}
// Master templates can only be generated when their master is known
if (UmbracoSettings.UseAspNetMasterPages)
{
t.ImportDesign(xmlHelper.GetNodeValue(n.SelectSingleNode("Design")));
t.SaveMasterPageFile(t.Design);
}
}
// Add documenttypes
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) {
ImportDocumentType(n, u, false);
saveNeeded = true;
}
// Add documenttypes
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType"))
{
ImportDocumentType(n, u, false);
saveNeeded = true;
}
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
// Add documenttype structure
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) {
DocumentType dt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Alias")));
if (dt != null) {
ArrayList allowed = new ArrayList();
foreach (XmlNode structure in n.SelectNodes("Structure/DocumentType")) {
DocumentType dtt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(structure));
if(dtt != null)
allowed.Add(dtt.Id);
}
// Add documenttype structure
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType"))
{
DocumentType dt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Alias")));
if (dt != null)
{
ArrayList allowed = new ArrayList();
foreach (XmlNode structure in n.SelectNodes("Structure/DocumentType"))
{
DocumentType dtt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(structure));
if (dtt != null)
allowed.Add(dtt.Id);
}
int[] adt = new int[allowed.Count];
for (int i = 0; i < allowed.Count; i++)
adt[i] = (int)allowed[i];
dt.AllowedChildContentTypeIDs = adt;
int[] adt = new int[allowed.Count];
for (int i = 0; i < allowed.Count; i++)
adt[i] = (int)allowed[i];
dt.AllowedChildContentTypeIDs = adt;
//PPH we log the document type install here.
insPack.Data.Documenttypes.Add(dt.Id.ToString());
saveNeeded = true;
}
}
//PPH we log the document type install here.
insPack.Data.Documenttypes.Add(dt.Id.ToString());
saveNeeded = true;
}
}
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
// Stylesheets
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) {
StyleSheet s = StyleSheet.Import(n, u);
// Stylesheets
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Stylesheets/Stylesheet"))
{
StyleSheet s = StyleSheet.Import(n, u);
insPack.Data.Stylesheets.Add(s.Id.ToString());
saveNeeded = true;
}
insPack.Data.Stylesheets.Add(s.Id.ToString());
saveNeeded = true;
}
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
if (saveNeeded) { insPack.Save(); saveNeeded = false; }
// Documents
foreach (XmlElement n in _packageConfig.DocumentElement.SelectNodes("Documents/DocumentSet [@importMode = 'root']/*")) {
insPack.Data.ContentNodeId = cms.businesslogic.web.Document.Import(-1, u, n).ToString();
}
// Documents
foreach (XmlElement n in _packageConfig.DocumentElement.SelectNodes("Documents/DocumentSet [@importMode = 'root']/*"))
{
insPack.Data.ContentNodeId = cms.businesslogic.web.Document.Import(-1, u, n).ToString();
}
//Package Actions
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Actions/Action")) {
//Package Actions
foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Actions/Action"))
{
if (n.Attributes["undo"] == null || n.Attributes["undo"].Value == "true") {
insPack.Data.Actions += n.OuterXml;
Log.Add(LogTypes.Debug, -1, HttpUtility.HtmlEncode(n.OuterXml));
}
if (n.Attributes["undo"] == null || n.Attributes["undo"].Value == "true")
{
insPack.Data.Actions += n.OuterXml;
Log.Add(LogTypes.Debug, -1, HttpUtility.HtmlEncode(n.OuterXml));
}
if (n.Attributes["runat"] != null && n.Attributes["runat"].Value == "install") {
try {
packager.PackageAction.RunPackageAction(insPack.Data.Name, n.Attributes["alias"].Value, n);
} catch {
if (n.Attributes["runat"] != null && n.Attributes["runat"].Value == "install")
{
try
{
packager.PackageAction.RunPackageAction(insPack.Data.Name, n.Attributes["alias"].Value, n);
}
catch
{
}
}
}
}
}
}
// Trigger update of Apps / Trees config.
// (These are ApplicationStartupHandlers so just instantiating them will trigger them)
new ApplicationRegistrar();
new ApplicationTreeRegistrar();
// Trigger update of Apps / Trees config.
// (These are ApplicationStartupHandlers so just instantiating them will trigger them)
new ApplicationRegistrar();
new ApplicationTreeRegistrar();
insPack.Save();
insPack.Save();
}
}
public void InstallCleanUp(int packageId, string tempDir) {

View File

@@ -6,6 +6,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2849E9D4
ProjectSection(SolutionItems) = preProject
..\build\Build.bat = ..\build\Build.bat
..\build\Build.proj = ..\build\Build.proj
..\build\RevertToCleanInstall.bat = ..\build\RevertToCleanInstall.bat
umbraco.presentation.targets = umbraco.presentation.targets
EndProjectSection
EndProject