/// <summary> /// Loads a preset from serialized items on disk. /// </summary> public void LoadTree(AdvancedLoadOptions options) { Assert.ArgumentNotNull(options, "options"); _itemsProcessed = 0; var reference = new ItemReference(options.Preset.Database, options.Preset.Path); var physicalPath = PathUtils.GetDirectoryPath(reference.ToString()); options.Progress.ReportStatus("Loading serialized items from " + physicalPath, MessageType.Info); if (!Directory.Exists(physicalPath)) throw new FileNotFoundException("The root serialization path " + physicalPath + " did not exist!", physicalPath); if (options.DisableEvents) { using (new EventDisabler()) { LoadTreePaths(physicalPath, options); } string targetDatabase = GetTargetDatabase(physicalPath, options); DeserializationFinished(targetDatabase); return; } LoadTreePaths(physicalPath, options); }
/// <summary> /// Loads a preset from serialized items on disk. /// </summary> public void LoadTree(AdvancedLoadOptions options) { Assert.ArgumentNotNull(options, "options"); _itemsProcessed = 0; var reference = new ItemReference(options.Preset.Database, options.Preset.Path); var physicalPath = PathUtils.GetDirectoryPath(reference.ToString()); options.Progress.ReportStatus("Loading serialized items from " + physicalPath, MessageType.Info); if (!Directory.Exists(physicalPath)) { throw new FileNotFoundException("The root serialization path " + physicalPath + " did not exist!", physicalPath); } if (options.DisableEvents) { using (new EventDisabler()) { LoadTreePaths(physicalPath, options); } string targetDatabase = GetTargetDatabase(physicalPath, options); DeserializationFinished(targetDatabase); return; } LoadTreePaths(physicalPath, options); }
/// <summary> /// Loads a specific path recursively, using any exclusions in the options' preset /// </summary> private void DoLoadTree(string path, AdvancedLoadOptions options) { Assert.ArgumentNotNullOrEmpty(path, "path"); Assert.ArgumentNotNull(options, "options"); var failures = new List <Failure>(); // go load the tree and see what failed, if anything LoadTreeRecursive(path, options, failures); if (failures.Count > 0) { List <Failure> originalFailures; do { foreach (Database current in Factory.GetDatabases()) { current.Engines.TemplateEngine.Reset(); } // note tricky variable handling here, 'failures' used for two things originalFailures = failures; failures = new List <Failure>(); foreach (var failure in originalFailures) { // retry loading a single item failure if (failure.Directory.EndsWith(PathUtils.Extension, StringComparison.InvariantCultureIgnoreCase)) { try { ItemLoadResult result; DoLoadItem(failure.Directory, options, out result); } catch (Exception reason) { failures.Add(new Failure(failure.Directory, reason)); } continue; } // retry loading a directory item failure (note the continues in the above ensure execution never arrives here for files) LoadTreeRecursive(failure.Directory, options, failures); } }while (failures.Count > 0 && failures.Count < originalFailures.Count); // continue retrying until all possible failures have been fixed } if (failures.Count > 0) { foreach (var failure in failures) { options.Progress.ReportStatus(string.Format("Failed to load {0} permanently because {1}", failure.Directory, failure.Reason), MessageType.Error); } throw new Exception("Some directories could not be loaded: " + failures[0].Directory, failures[0].Reason); } }
/// <summary> /// Recursive method that loads a given tree and retries failures already present if any /// </summary> private void LoadTreeRecursive(string path, AdvancedLoadOptions options, List<Failure> retryList) { Assert.ArgumentNotNullOrEmpty(path, "path"); Assert.ArgumentNotNull(options, "options"); Assert.ArgumentNotNull(retryList, "retryList"); if (options.Preset.Exclude.MatchesPath(path)) { options.Progress.ReportStatus("[SKIPPED] " + PathUtils.MakeItemPath(path) + " (and children) because it was excluded by the preset, but it was present on disk", MessageType.Warning); return; } try { // load the current level LoadOneLevel(path, options, retryList); // check if we have a directory path to recurse down if (Directory.Exists(path)) { string[] directories = PathUtils.GetDirectories(path); // make sure if a "templates" item exists in the current set, it goes first if (directories.Length > 1) { for (int i = 1; i < directories.Length; i++) { if ("templates".Equals(Path.GetFileName(directories[i]), StringComparison.OrdinalIgnoreCase)) { string text = directories[0]; directories[0] = directories[i]; directories[i] = text; } } } foreach(var directory in directories) { if (!CommonUtils.IsDirectoryHidden(directory)) { LoadTreeRecursive(directory, options, retryList); } } // pull out any standard values failures for immediate retrying List<Failure> standardValuesFailures = retryList.Where(x => x.Reason is StandardValuesException).ToList(); retryList.RemoveAll(x => x.Reason is StandardValuesException); foreach (Failure current in standardValuesFailures) { try { ItemLoadResult result; DoLoadItem(current.Directory, options, out result); } catch (Exception reason) { try { var directoryInfo = new DirectoryInfo(current.Directory); if (directoryInfo.Parent != null && string.Compare(directoryInfo.Parent.FullName, path, StringComparison.InvariantCultureIgnoreCase) == 0) { retryList.Add(new Failure(current.Directory, reason)); } else { retryList.Add(current); } } catch { retryList.Add(new Failure(current.Directory, reason)); } } } } } catch (Exception ex) { retryList.Add(new Failure(path, ex)); } }
private void LoadTreePaths(string physicalPath, AdvancedLoadOptions options) { DoLoadTree(physicalPath, options); DoLoadTree(PathUtils.GetShortPath(physicalPath), options); options.Progress.ReportStatus(string.Format("Finished loading serialized items from {0} ({1} total items synchronized)", physicalPath, _itemsProcessed), MessageType.Info); }
/// <summary> /// Loads a set of children from a serialized path /// </summary> private void LoadOneLevel(string path, AdvancedLoadOptions options, List<Failure> retryList) { Assert.ArgumentNotNullOrEmpty(path, "path"); Assert.ArgumentNotNull(options, "options"); Assert.ArgumentNotNull(retryList, "retryList"); var deleteCandidates = new Dictionary<ID, Item>(); // look for a serialized file for the root item if (File.Exists(path + PathUtils.Extension)) { var itemReference = ItemReference.Parse(PathUtils.MakeItemPath(path, options.Root)); if (itemReference != null) { // get the corresponding item from Sitecore Item rootItem = options.Database != null ? itemReference.GetItemInDatabase(options.Database) : itemReference.GetItem(); // if we're reverting, we add all of the root item's direct children to the "to-delete" list (we'll remove them as we find matching serialized children) if (rootItem != null && (options.ForceUpdate || options.DeleteOrphans)) { foreach (Item child in rootItem.Children) { // if the preset includes the child add it to the delete-candidate list (if we don't deserialize it below, it will be deleted if the right options are present) if(options.Preset.Includes(child)) deleteCandidates[child.ID] = child; else { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} (and children) because it was excluded by the preset.", child.Database.Name, child.Paths.FullPath), MessageType.Debug); } } } } } // check for a directory containing children of the target path if (Directory.Exists(path)) { string[] files = Directory.GetFiles(path, "*" + PathUtils.Extension); foreach (string fileName in files) { try { ID itemId; if (IsStandardValuesItem(fileName, out itemId)) { deleteCandidates.Remove(itemId); // avoid deleting standard values items when forcing an update retryList.Add(new Failure(fileName, new StandardValuesException(fileName))); } else { // load a child item ItemLoadResult result; Item loadedItem = DoLoadItem(fileName, options, out result); if (loadedItem != null) { deleteCandidates.Remove(loadedItem.ID); // check if we have any child directories under this loaded child item (existing children) - // if we do not, we can nuke any children of the loaded item as well if ((options.ForceUpdate || options.DeleteOrphans) && !Directory.Exists(PathUtils.StripPath(fileName))) { foreach (Item child in loadedItem.Children) { deleteCandidates.Add(child.ID, child); } } } else if (result == ItemLoadResult.Skipped) // if the item got skipped we'll prevent it from being deleted deleteCandidates.Remove(itemId); } } catch (Exception ex) { // if a problem occurs we attempt to retry later retryList.Add(new Failure(path, ex)); } } } // if we're forcing an update (ie deleting stuff not on disk) we send the items that we found that weren't on disk off to get deleted from Sitecore if ((options.ForceUpdate || options.DeleteOrphans) && deleteCandidates.Count > 0) { Database db = deleteCandidates.Values.First().Database; bool reset = DeleteItems(deleteCandidates.Values, options.Progress); if (reset) db.Engines.TemplateEngine.Reset(); } }
/// <summary> /// Loads a specific path recursively, using any exclusions in the options' preset /// </summary> private void DoLoadTree(string path, AdvancedLoadOptions options) { Assert.ArgumentNotNullOrEmpty(path, "path"); Assert.ArgumentNotNull(options, "options"); var failures = new List<Failure>(); // go load the tree and see what failed, if anything LoadTreeRecursive(path, options, failures); if (failures.Count > 0) { List<Failure> originalFailures; do { foreach (Database current in Factory.GetDatabases()) { current.Engines.TemplateEngine.Reset(); } // note tricky variable handling here, 'failures' used for two things originalFailures = failures; failures = new List<Failure>(); foreach (var failure in originalFailures) { // retry loading a single item failure if (failure.Directory.EndsWith(PathUtils.Extension, StringComparison.InvariantCultureIgnoreCase)) { try { ItemLoadResult result; DoLoadItem(failure.Directory, options, out result); } catch (Exception reason) { failures.Add(new Failure(failure.Directory, reason)); } continue; } // retry loading a directory item failure (note the continues in the above ensure execution never arrives here for files) LoadTreeRecursive(failure.Directory, options, failures); } } while (failures.Count > 0 && failures.Count < originalFailures.Count); // continue retrying until all possible failures have been fixed } if (failures.Count > 0) { foreach (var failure in failures) { options.Progress.ReportStatus(string.Format("Failed to load {0} permanently because {1}", failure.Directory, failure.Reason), MessageType.Error); } throw new Exception("Some directories could not be loaded: " + failures[0].Directory, failures[0].Reason); } }
/// <summary> /// Loads a specific item from disk /// </summary> private Item DoLoadItem(string path, AdvancedLoadOptions options, out ItemLoadResult loadResult) { Assert.ArgumentNotNullOrEmpty(path, "path"); Assert.ArgumentNotNull(options, "options"); if (File.Exists(path)) { using (TextReader fileReader = new StreamReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))) { LogLocalized("Loading item from path {0}.", new object[] { PathUtils.UnmapItemPath(path, options.Root) }); bool disabledLocally = ItemHandler.DisabledLocally; try { ItemHandler.DisabledLocally = true; Item result = null; try { var serializedItem = SyncItem.ReadItem(new Tokenizer(fileReader)); _itemsProcessed++; if(_itemsProcessed % 500 == 0 && _itemsProcessed > 1) options.Progress.ReportStatus(string.Format("Processed {0} items", _itemsProcessed), MessageType.Debug); if (options.Preset.Exclude.MatchesTemplate(serializedItem.TemplateName)) { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} because the preset excluded its template name, but the item was on disk", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Warning); loadResult = ItemLoadResult.Skipped; return null; } if (options.Preset.Exclude.MatchesTemplateId(serializedItem.TemplateID)) { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} because the preset excluded its template ID, but the item was on disk", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Warning); loadResult = ItemLoadResult.Skipped; return null; } if (options.Preset.Exclude.MatchesId(serializedItem.ID)) { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} because the preset excluded it by ID, but the item was on disk", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Warning); loadResult = ItemLoadResult.Skipped; return null; } if (options.Preset.Exclude.MatchesPath(path)) { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} because the preset excluded it by path, but the item was on disk", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Warning); loadResult = ItemLoadResult.Skipped; return null; } var newOptions = new LoadOptions(options); // in some cases we want to force an update for this item only if (!options.ForceUpdate && ShouldForceUpdate(serializedItem, options.Progress)) { options.Progress.ReportStatus(string.Format("[FORCED] {0}:{1}", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Info); newOptions.ForceUpdate = true; } result = ItemSynchronization.PasteSyncItem(serializedItem, newOptions, true); loadResult = ItemLoadResult.Success; } catch (ParentItemNotFoundException ex) { result = null; loadResult = ItemLoadResult.Error; string error = "Cannot load item from path '{0}'. Probable reason: parent item with ID '{1}' not found.".FormatWith( PathUtils.UnmapItemPath(path, options.Root), ex.ParentID); options.Progress.ReportStatus(error, MessageType.Error); LogLocalizedError(error); } catch (ParentForMovedItemNotFoundException ex2) { result = ex2.Item; loadResult = ItemLoadResult.Error; string error = "Item from path '{0}' cannot be moved to appropriate location. Possible reason: parent item with ID '{1}' not found." .FormatWith(PathUtils.UnmapItemPath(path, options.Root), ex2.ParentID); options.Progress.ReportStatus(error, MessageType.Error); LogLocalizedError(error); } return result; } finally { ItemHandler.DisabledLocally = disabledLocally; } } } loadResult = ItemLoadResult.Error; return null; }
private void LoadTreePaths(string physicalPath, AdvancedLoadOptions options) { DoLoadTree(physicalPath, options); DoLoadTree(PathUtils.GetShortPath(physicalPath), options); options.Progress.ReportStatus(string.Format("Finished loading serialized items from {0} ({1} total items synchronized)", physicalPath, _itemsProcessed), MessageType.Info); }
/// <summary> /// Loads a specific item from disk /// </summary> private Item DoLoadItem(string path, AdvancedLoadOptions options, out ItemLoadResult loadResult) { Assert.ArgumentNotNullOrEmpty(path, "path"); Assert.ArgumentNotNull(options, "options"); if (File.Exists(path)) { using (TextReader fileReader = new StreamReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))) { LogLocalized("Loading item from path {0}.", new object[] { PathUtils.UnmapItemPath(path, options.Root) }); bool disabledLocally = ItemHandler.DisabledLocally; try { ItemHandler.DisabledLocally = true; Item result = null; try { var serializedItem = SyncItem.ReadItem(new Tokenizer(fileReader)); _itemsProcessed++; if (_itemsProcessed % 500 == 0 && _itemsProcessed > 1) { options.Progress.ReportStatus(string.Format("Processed {0} items", _itemsProcessed), MessageType.Debug); } if (options.Preset.Exclude.MatchesTemplate(serializedItem.TemplateName)) { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} because the preset excluded its template name, but the item was on disk", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Warning); loadResult = ItemLoadResult.Skipped; return(null); } if (options.Preset.Exclude.MatchesTemplateId(serializedItem.TemplateID)) { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} because the preset excluded its template ID, but the item was on disk", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Warning); loadResult = ItemLoadResult.Skipped; return(null); } if (options.Preset.Exclude.MatchesId(serializedItem.ID)) { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} because the preset excluded it by ID, but the item was on disk", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Warning); loadResult = ItemLoadResult.Skipped; return(null); } if (options.Preset.Exclude.MatchesPath(path)) { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} because the preset excluded it by path, but the item was on disk", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Warning); loadResult = ItemLoadResult.Skipped; return(null); } var newOptions = new LoadOptions(options); // in some cases we want to force an update for this item only if (!options.ForceUpdate && ShouldForceUpdate(serializedItem, options.Progress)) { options.Progress.ReportStatus(string.Format("[FORCED] {0}:{1}", serializedItem.DatabaseName, serializedItem.ItemPath), MessageType.Info); newOptions.ForceUpdate = true; } result = ItemSynchronization.PasteSyncItem(serializedItem, newOptions, true); loadResult = ItemLoadResult.Success; } catch (ParentItemNotFoundException ex) { result = null; loadResult = ItemLoadResult.Error; string error = "Cannot load item from path '{0}'. Probable reason: parent item with ID '{1}' not found.".FormatWith( PathUtils.UnmapItemPath(path, options.Root), ex.ParentID); options.Progress.ReportStatus(error, MessageType.Error); LogLocalizedError(error); } catch (ParentForMovedItemNotFoundException ex2) { result = ex2.Item; loadResult = ItemLoadResult.Error; string error = "Item from path '{0}' cannot be moved to appropriate location. Possible reason: parent item with ID '{1}' not found." .FormatWith(PathUtils.UnmapItemPath(path, options.Root), ex2.ParentID); options.Progress.ReportStatus(error, MessageType.Error); LogLocalizedError(error); } return(result); } finally { ItemHandler.DisabledLocally = disabledLocally; } } } loadResult = ItemLoadResult.Error; return(null); }
/// <summary> /// Loads a set of children from a serialized path /// </summary> private void LoadOneLevel(string path, AdvancedLoadOptions options, List <Failure> retryList) { Assert.ArgumentNotNullOrEmpty(path, "path"); Assert.ArgumentNotNull(options, "options"); Assert.ArgumentNotNull(retryList, "retryList"); var deleteCandidates = new Dictionary <ID, Item>(); // look for a serialized file for the root item if (File.Exists(path + PathUtils.Extension)) { var itemReference = ItemReference.Parse(PathUtils.MakeItemPath(path, options.Root)); if (itemReference != null) { // get the corresponding item from Sitecore Item rootItem = options.Database != null ? itemReference.GetItemInDatabase(options.Database) : itemReference.GetItem(); // if we're reverting, we add all of the root item's direct children to the "to-delete" list (we'll remove them as we find matching serialized children) if (rootItem != null && (options.ForceUpdate || options.DeleteOrphans)) { foreach (Item child in rootItem.Children) { // if the preset includes the child add it to the delete-candidate list (if we don't deserialize it below, it will be deleted if the right options are present) if (options.Preset.Includes(child)) { deleteCandidates[child.ID] = child; } else { options.Progress.ReportStatus(string.Format("[SKIPPED] {0}:{1} (and children) because it was excluded by the preset.", child.Database.Name, child.Paths.FullPath), MessageType.Debug); } } } } } // check for a directory containing children of the target path if (Directory.Exists(path)) { string[] files = Directory.GetFiles(path, "*" + PathUtils.Extension); foreach (string fileName in files) { try { ID itemId; if (IsStandardValuesItem(fileName, out itemId)) { deleteCandidates.Remove(itemId); // avoid deleting standard values items when forcing an update retryList.Add(new Failure(fileName, new StandardValuesException(fileName))); } else { // load a child item ItemLoadResult result; Item loadedItem = DoLoadItem(fileName, options, out result); if (loadedItem != null) { deleteCandidates.Remove(loadedItem.ID); // check if we have any child directories under this loaded child item (existing children) - // if we do not, we can nuke any children of the loaded item as well if ((options.ForceUpdate || options.DeleteOrphans) && !Directory.Exists(PathUtils.StripPath(fileName))) { foreach (Item child in loadedItem.Children) { deleteCandidates.Add(child.ID, child); } } } else if (result == ItemLoadResult.Skipped) // if the item got skipped we'll prevent it from being deleted { deleteCandidates.Remove(itemId); } } } catch (Exception ex) { // if a problem occurs we attempt to retry later retryList.Add(new Failure(path, ex)); } } } // if we're forcing an update (ie deleting stuff not on disk) we send the items that we found that weren't on disk off to get deleted from Sitecore if ((options.ForceUpdate || options.DeleteOrphans) && deleteCandidates.Count > 0) { Database db = deleteCandidates.Values.First().Database; bool reset = DeleteItems(deleteCandidates.Values, options.Progress); if (reset) { db.Engines.TemplateEngine.Reset(); } } }
/// <summary> /// Recursive method that loads a given tree and retries failures already present if any /// </summary> private void LoadTreeRecursive(string path, AdvancedLoadOptions options, List <Failure> retryList) { Assert.ArgumentNotNullOrEmpty(path, "path"); Assert.ArgumentNotNull(options, "options"); Assert.ArgumentNotNull(retryList, "retryList"); if (options.Preset.Exclude.MatchesPath(path)) { options.Progress.ReportStatus("[SKIPPED] " + PathUtils.MakeItemPath(path) + " (and children) because it was excluded by the preset, but it was present on disk", MessageType.Warning); return; } try { // load the current level LoadOneLevel(path, options, retryList); // check if we have a directory path to recurse down if (Directory.Exists(path)) { string[] directories = PathUtils.GetDirectories(path); // make sure if a "templates" item exists in the current set, it goes first if (directories.Length > 1) { for (int i = 1; i < directories.Length; i++) { if ("templates".Equals(Path.GetFileName(directories[i]), StringComparison.OrdinalIgnoreCase)) { string text = directories[0]; directories[0] = directories[i]; directories[i] = text; } } } foreach (var directory in directories) { if (!CommonUtils.IsDirectoryHidden(directory)) { LoadTreeRecursive(directory, options, retryList); } } // pull out any standard values failures for immediate retrying List <Failure> standardValuesFailures = retryList.Where(x => x.Reason is StandardValuesException).ToList(); retryList.RemoveAll(x => x.Reason is StandardValuesException); foreach (Failure current in standardValuesFailures) { try { ItemLoadResult result; DoLoadItem(current.Directory, options, out result); } catch (Exception reason) { try { var directoryInfo = new DirectoryInfo(current.Directory); if (directoryInfo.Parent != null && string.Compare(directoryInfo.Parent.FullName, path, StringComparison.InvariantCultureIgnoreCase) == 0) { retryList.Add(new Failure(current.Directory, reason)); } else { retryList.Add(current); } } catch { retryList.Add(new Failure(current.Directory, reason)); } } } } } catch (Exception ex) { retryList.Add(new Failure(path, ex)); } }