diff --git a/build/RevertToCleanInstall.bat b/build/RevertToCleanInstall.bat new file mode 100644 index 0000000000..893b7216ee --- /dev/null +++ b/build/RevertToCleanInstall.bat @@ -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 ^^^ >..\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 ^^^ >..\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 \ No newline at end of file diff --git a/src/Umbraco.Core/DisposableTimer.cs b/src/Umbraco.Core/DisposableTimer.cs index 26a7875559..f2a6904b9f 100644 --- a/src/Umbraco.Core/DisposableTimer.cs +++ b/src/Umbraco.Core/DisposableTimer.cs @@ -41,6 +41,17 @@ namespace Umbraco.Core return new DisposableTimer(callback); } + public static DisposableTimer TraceDuration(Func startMessage, Func completeMessage) + { + return TraceDuration(typeof(T), startMessage, completeMessage); + } + + public static DisposableTimer TraceDuration(Type loggerType, Func startMessage, Func completeMessage) + { + LogHelper.Debug(loggerType, startMessage); + return new DisposableTimer(x => LogHelper.Info(loggerType, () => completeMessage() + " (took " + x + "ms)")); + } + /// /// Adds a start and end log entry as Info and tracks how long it takes until disposed. /// diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index e8670992b7..b0de40416b 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -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 + /// /// Returns a bool if the assemblies in the /bin have changed since they were last hashed. /// @@ -228,9 +237,9 @@ namespace Umbraco.Core /// /// /// - internal Attempt> TryGetCachedPluginsFromFile() + internal Attempt> TryGetCachedPluginsFromFile(TypeResolutionKind resolutionType) { - var filePath = Path.Combine(_tempFolder, "umbraco-plugins.list"); + var filePath = GetPluginListFilePath(); if (!File.Exists(filePath)) return Attempt>.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>.False; + return new Attempt>(new CachedPluginNotFoundInFile()); //return success return new Attempt>( @@ -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>.False; + return new Attempt>(ex); + } + } + + private string GetPluginListFilePath() + { + return Path.Combine(_tempFolder, "umbraco-plugins.list"); + } + + /// + /// This will return true if the plugin list file is a legacy one + /// + /// + /// + /// 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. + /// + 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 /// /// /// - /// + /// + /// /// THIS METHOD IS NOT THREAD SAFE /// /// @@ -292,9 +347,9 @@ namespace Umbraco.Core /// /// ]]> /// - internal void UpdateCachedPluginsFile(IEnumerable typesFound) + internal void UpdateCachedPluginsFile(IEnumerable 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(); + using (DisposableTimer.TraceDuration( - 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(resolutionType)); @@ -501,46 +562,59 @@ namespace Umbraco.Core typeList = new TypeList(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(); - if (fileCacheResult.Success) + var fileCacheResult = TryGetCachedPluginsFromFile(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("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(typeList, finder); - } - else - { - LogHelper.Debug("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(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("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(typeList, resolutionType, finder); + } + else + { + LogHelper.Debug("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(typeList, finder); + LoadViaScanningAndUpdateCacheFile(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 /// /// + /// /// /// /// THIS METHODS IS NOT THREAD SAFE /// - private void LoadViaScanningAndUpdateCacheFile(TypeList typeList, Func> finder) + private void LoadViaScanningAndUpdateCacheFile(TypeList typeList, TypeResolutionKind resolutionKind, Func> 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(typeList.GetTypes()); + } + UpdateCachedPluginsFile(typeList.GetTypes(), resolutionKind); } /// @@ -683,6 +760,16 @@ namespace Umbraco.Core return _types; } } + + /// + /// This class is used simply to determine that a plugin was not found in the cache plugin list with the specified + /// TypeResolutionKind. + /// + internal class CachedPluginNotFoundInFile : Exception + { + + } + #endregion } } diff --git a/src/Umbraco.Tests/PluginManagerTests.cs b/src/Umbraco.Tests/PluginManagerTests.cs index 0c47c04ba2..4dbaae98de 100644 --- a/src/Umbraco.Tests/PluginManagerTests.cs +++ b/src/Umbraco.Tests/PluginManagerTests.cs @@ -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, @" + + + + +"); + + Assert.IsTrue(manager.DetectLegacyPluginListFile()); + + File.Delete(filePath); + + //now create a valid one + File.WriteAllText(filePath, @" + + + + +"); + + 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(types); + manager.UpdateCachedPluginsFile(types, PluginManager.TypeResolutionKind.FindAllTypes); + + var plugins = manager.TryGetCachedPluginsFromFile(PluginManager.TypeResolutionKind.FindAllTypes); + var diffType = manager.TryGetCachedPluginsFromFile(PluginManager.TypeResolutionKind.FindAttributedTypes); - var plugins = manager.TryGetCachedPluginsFromFile(); 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] diff --git a/src/umbraco.cms/businesslogic/Packager/Installer.cs b/src/umbraco.cms/businesslogic/Packager/Installer.cs index b58f20290b..9f4376fdee 100644 --- a/src/umbraco.cms/businesslogic/Packager/Installer.cs +++ b/src/umbraco.cms/businesslogic/Packager/Installer.cs @@ -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 /// 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( + () => "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( + () => "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( + () => "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) { diff --git a/src/umbraco.sln b/src/umbraco.sln index bbf29e5a99..87674b9000 100644 --- a/src/umbraco.sln +++ b/src/umbraco.sln @@ -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