private static bool CleanKeyedNames(IEnumerable <InstallItem> lines, ILogger logger) { var groups = lines.Where(l => l.Type == InstallType.Create) .GroupBy(l => $"{l.Reference.Unique}|{l.Reference.Type}"); var result = true; foreach (var duplicate in groups.Where(g => g.Skip(1).Any())) { result = false; logger.LogError("The package has duplicate entries for creating {Type} {Name} with ID {ID} at {Paths}", duplicate.First().Reference.Type, duplicate.First().Reference.KeyedName, duplicate.First().Reference.Unique, duplicate.Select(i => i.Path)); } var existing = groups .ToDictionary(g => g.Key, g => g.First()); InstallItem item; foreach (var line in lines.Where(l => l.Type == InstallType.Script)) { if (existing.TryGetValue(line.InstalledId, out item)) { line.Reference.KeyedName = InstallItem.RenderAttributes(line.Script, item.Reference.KeyedName); } } return(result); }
private IEnumerable <InstallItem> FillInNullsOnRequiredProperties(XmlElement[] allItems, PackageMetadataProvider metadata) { var newlyRequiredProps = allItems.Where(i => i.Attribute("type") == "Property" && i.Attribute("action") == "edit" && !string.IsNullOrEmpty(i.Attribute("id")) && i.Element("is_required", "0") == "1" && i.Element("default_value").HasValue()) .ToArray(); if (newlyRequiredProps.Length > 0) { var doc = newlyRequiredProps[0].NewDoc(); var root = doc.Elem("AML"); var idx = 0; foreach (var prop in newlyRequiredProps) { string name; metadata.PropById(prop.Attribute("id"), out name); var typeId = prop.Parent().Parent().Attribute("id"); var typeName = metadata.ItemTypes.Single(i => i.Id == typeId).Name; var script = root.Elem("Item").Attr("type", typeName).Attr("action", "edit").Attr("where", "[" + typeName + "]." + name + " is null"); script.Elem(name, prop.Element("default_value", "")); yield return(InstallItem.FromScript(script, "_Scripts/NewlyRequiredProp (" + (++idx) + ").xml")); } } }
public static InstallItem FromWarning(ItemReference itemRef, string warning) { var result = new InstallItem(); result._itemRef = itemRef; result._name = warning; result.Type = InstallType.Warning; return(result); }
private void WriteReport(InstallItem line, string path) { var dataFile = "<Result><Item></Item></Result>"; using (var writer = new StreamWriter(GetNewStream(path))) { var aml = new StringBuilder(); using (var amlWriter = new System.IO.StringWriter(aml)) { using (var xml = new ConfigurableXmlWriter(amlWriter)) { xml.ElementProcessor = (prefix, localName, ns, w) => { if (localName == "xsl_stylesheet") { return(ProcessState.DontRender); } return(ProcessState.RenderAll); }; xml.WriteStartElement("AML"); line.Script.WriteTo(xml); xml.WriteEndElement(); } } writer.WriteLine(_reportStart); writer.WriteLine(aml); writer.WriteLine(_reportEnd); var xsltElem = line.Script.SelectSingleNode(".//xsl_stylesheet") as XmlElement; if (xsltElem != null) { var xslt = xsltElem.InnerText; var dataStart = xslt.IndexOf(_reportDataStart); var dataEnd = xslt.IndexOf(_reportDataEnd); if (dataStart >= 0 && dataEnd >= 0) { dataFile = xslt.Substring(dataStart + _reportDataStart.Length, dataEnd - dataStart - _reportDataStart.Length).Trim(); xslt = xslt.Substring(0, dataStart).Trim() + Environment.NewLine + xslt.Substring(dataEnd + _reportDataEnd.Length).Trim(); } else { dataFile = xsltElem.Parent().Element("report_query", "<Result><Item></Item></Result>"); } dataFile = XmlUtils.RemoveComments(dataFile); writer.WriteLine(xslt); } } using (var writer = new StreamWriter(GetNewStream(path + ".xml"))) { writer.Write(dataFile); } }
private int DefaultInstallOrder(InstallItem line) { var itemRef = line.Reference; if (line.Reference.Type == InstallItem.ScriptType) { itemRef = ItemReference.FromElement(line.Script); } return(DefaultInstallOrder(itemRef)); }
public static string FilePath(this InstallItem line, HashSet <string> existingPaths, string extension = ".xml") { var folder = line.Type == InstallType.Script ? "_Scripts" : line.Reference.Type; var newPath = folder + "\\" + Utils.CleanFileName(line.Reference.KeyedName ?? line.Reference.Unique) + extension; if (existingPaths.Contains(newPath)) { newPath = folder + "\\" + Utils.CleanFileName((line.Reference.KeyedName ?? "") + "_" + line.Reference.Unique) + extension; } return(newPath); }
private string GetPath(InstallItem line, HashSet <string> existingPaths) { if (line.Reference.Type == "Report" && line.Type != InstallType.Script) { return(line.FilePath(existingPaths, ".xslt")); } else { return(line.FilePath(existingPaths)); } }
public InstallScript Merge(IPackage baseDir, IPackage compareDir) { var docs = new List <Tuple <XmlDocument, string> >(); var metadata = baseDir.WriteAmlMergeScripts(compareDir, (path, prog) => { ProgressChanged?.Invoke(this, new ProgressChangedEventArgs("Reading files", prog / 2)); var doc = new XmlDocument(); docs.Add(Tuple.Create(doc, path)); return(doc.CreateNavigator().AppendChild()); }); ProgressChanged?.Invoke(this, new ProgressChangedEventArgs("Performing cleanup", 50)); var allItems = docs .Where(d => d.Item1.DocumentElement != null) .SelectMany(d => d.Item1.DocumentElement .DescendantsAndSelf(el => el.LocalName == "Item")) .ToArray(); RemoveDeletesForItemsWithMultipleScripts(allItems); RemoveChangesToSystemProperties(allItems); var installScripts = docs .Where(d => d.Item1.DocumentElement != null) .SelectMany(d => XmlUtils.RootItems(d.Item1.DocumentElement) .Select(i => InstallItem.FromScript(i, d.Item2))) .ToArray(); ProgressChanged?.Invoke(this, new ProgressChangedEventArgs("Processing dependencies", 75)); var lines = (SortDependencies ? _sorter.SortByDependencies(installScripts, metadata) : installScripts).ToList(); lines.RemoveWhere(i => i.Type == InstallType.DependencyCheck); var script = new InstallScript() { Created = DateTime.Now, Creator = Environment.UserName, Title = "MergeScript", Lines = lines }; lines.InsertRange(0, FillInNullsOnRequiredProperties(allItems, metadata)); ProgressChanged?.Invoke(this, new ProgressChangedEventArgs("Processing dependencies", 80)); return(script); }
private static bool TryReadLegacyManifest(IPackageFile manifestFile, IPackage package, ILogger logger, out InstallScript installScript) { installScript = new InstallScript(); var scripts = new List <InstallItem>(); var manifest = new XmlDocument(); using (var manifestStream = manifestFile.Open()) manifest.Load(manifestStream); foreach (var pkg in manifest.DocumentElement.Elements("package")) { if (string.IsNullOrEmpty(installScript.Title)) { installScript.Title = pkg.Attribute("name", ""); } var folderPath = pkg.Attribute("path"); if (folderPath == ".\\") { folderPath = Utils.CleanFileName(pkg.Attribute("name", "")).Replace('.', '\\'); } foreach (var file in package.Files() .Where(f => f.Path.StartsWith(folderPath + "/", StringComparison.OrdinalIgnoreCase) && f.Path.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))) { try { var doc = new XmlDocument(manifest.NameTable); using (var stream = file.Open()) doc.Load(stream); var items = doc.DocumentElement.LocalName == "Item" ? new[] { doc.DocumentElement } : doc.DocumentElement.Elements("Item"); foreach (var item in items) { scripts.Add(InstallItem.FromScript(item, file.Path)); } } catch (Exception ex) { ex.Data["path"] = file.Path; throw; } } } installScript.Lines = scripts; return(CleanKeyedNames(installScript.Lines, logger)); }
public static InstallItem FromDependency(ItemReference itemRef) { var result = new InstallItem(); result._itemRef = itemRef; result._elem = new XmlDocument().CreateElement("Item"); result._elem.SetAttribute("type", result._itemRef.Type); if (result._itemRef.Unique.IsGuid()) { result._elem.SetAttribute("id", result._itemRef.Unique); } else { result._elem.SetAttribute("where", result._itemRef.Unique); } result._elem.SetAttribute("action", "get"); result._elem.SetAttribute("_dependency_check", "1"); result._elem.SetAttribute("_keyed_name", result._itemRef.KeyedName); result.Type = InstallType.DependencyCheck; return(result); }
public static void CleanKeyedNames(this IEnumerable <InstallItem> lines) { var groups = lines.Where(l => l.Type == InstallType.Create) .GroupBy(l => l.Reference.Unique); var duplicates = groups.Where(g => g.Skip(1).Any()).ToArray(); if (duplicates.Length > 0) { throw new InvalidOperationException("The package has duplicate entries for the following items: " + duplicates.GroupConcat(", ", g => g.Key)); } var existing = groups .ToDictionary(g => g.Key, g => g.First()); InstallItem item; foreach (var line in lines.Where(l => l.Type == InstallType.Script)) { if (existing.TryGetValue(line.InstalledId, out item)) { line.Reference.KeyedName = InstallItem.RenderAttributes(line.Script, item.Reference.KeyedName); } } }
public static InstallItem FromDependency(ItemReference itemRef) { var result = new InstallItem(); result._itemRef = itemRef; result._elem = new XmlDocument().CreateElement("Item"); result._elem.SetAttribute("type", result._itemRef.Type); if (result._itemRef.Unique.IsGuid()) { result._elem.SetAttribute("id", result._itemRef.Unique); } else { result._elem.SetAttribute("where", result._itemRef.Unique); } result._elem.SetAttribute("action", "get"); result._elem.SetAttribute("_dependency_check", "1"); result._elem.SetAttribute("_keyed_name", result._itemRef.KeyedName); result._type = InstallType.DependencyCheck; return result; }
public virtual InstallScript Read() { var result = new InstallScript(); XmlDocument doc; var scripts = new List <InstallItem>(); var manifest = new XmlDocument(); string currPath; IEnumerable <string> paths; manifest.Load(GetExistingStream(null)); if (manifest.DocumentElement.HasAttribute("created")) { result.Created = DateTime.Parse(manifest.DocumentElement.GetAttribute("created")); } result.Creator = manifest.DocumentElement.GetAttribute("creator"); result.Description = manifest.DocumentElement.GetAttribute("description"); if (manifest.DocumentElement.HasAttribute("modified")) { result.Modified = DateTime.Parse(manifest.DocumentElement.GetAttribute("modified")); } result.Version = manifest.DocumentElement.GetAttribute("revision"); result.Title = manifest.DocumentElement.GetAttribute("title"); if (manifest.DocumentElement.HasAttribute("website")) { result.Website = new Uri(manifest.DocumentElement.GetAttribute("website")); } foreach (var child in manifest.DocumentElement.ChildNodes.OfType <XmlElement>()) { if (child.LocalName == "Item") { scripts.Add(InstallItem.FromScript(child)); } else { currPath = child.GetAttribute("path"); paths = string.IsNullOrEmpty(currPath) ? Enumerable.Empty <string>() : (currPath == "*" ? GetPaths() : Enumerable.Repeat(currPath, 1)); if (currPath == "*") { result.DependencySorted = false; } foreach (var path in paths) { if (path.EndsWith(".xslt", StringComparison.OrdinalIgnoreCase)) { doc = ReadReport(path); } else { doc = new XmlDocument(manifest.NameTable); var stream = GetExistingStream(path); if (stream == null) { throw new FileNotFoundException("A referenced file was not found in the package", path); } doc.Load(stream); } foreach (var item in doc.DocumentElement.Elements("Item")) { scripts.Add(InstallItem.FromScript(item, path)); } } } } result.Lines = scripts; result.Lines.CleanKeyedNames(); return(result); }
public static InstallItem FromWarning(ItemReference itemRef, string warning) { var result = new InstallItem(); result._itemRef = itemRef; result._name = warning; result._type = InstallType.Warning; return result; }
public static InstallItem FromScript(XmlElement elem , Func<XmlElement, string> keyedNameGetter = null) { var result = new InstallItem(); result._elem = elem; result._itemRef = ItemReference.FromFullItem(elem, true); if (result._itemRef.Type.IsGuid()) { result.InstalledId = result._itemRef.Type; } else { result.InstalledId = elem.Attribute("id", ""); } if (elem.HasAttribute("_dependency_check")) { result._type = InstallType.DependencyCheck; } else if (elem.HasAttribute("action")) { switch (elem.Attributes["action"].Value) { case "add": case "merge": case "create": result._type = InstallType.Create; break; case "ActivateActivity": case "AddItem": case "AddHistory": case "ApplyUpdate": case "BuildProcessReport": case "CancelWorkflow": case "checkImportedItemType": case "closeWorkflow": case "copy": case "copyAsIs": case "copyAsNew": case "delete": case "edit": case "EmailItem": case "EvaluateActivity": case "exportItemType": case "get": case "getItemAllVersions": case "getAffectedItems": case "getItemConfig": case "getItemLastVersion": case "getItemNextStates": case "getItemRelationships": case "GetItemRepeatConfig": case "getItemWhereUsed": case "GetMappedPath": case "getPermissions": case "getRelatedItem": case "GetUpdateInfo": case "instantiateWorkflow": case "lock": case "New Workflow Map": case "PromoteItem": case "purge": case "recache": case "replicate": case "resetAllItemsAccess": case "resetItemAccess": case "resetLifecycle": case "setDefaultLifecycle": case "skip": case "startWorkflow": case "unlock": case "update": case "ValidateWorkflowMap": case "version": if ((elem.Attributes["type"].Value != "Form" && elem.Attributes["type"].Value != "View") || elem.Attributes["action"].Value != "delete") result._dependencies = Enumerable.Repeat(result._itemRef, 1); result._itemRef = new ItemReference(ScriptType, result._itemRef.ToString() + " " + Utils.GetChecksum(Encoding.UTF8.GetBytes(elem.OuterXml))) { KeyedName = RenderAttributes(elem) }; result._type = InstallType.Script; break; default: result._dependencies = Enumerable.Repeat(new ItemReference("Method", "[Method].[name] = '" + elem.Attributes["action"].Value + "'") { KeyedName = elem.Attributes["action"].Value }, 1); result._itemRef = new ItemReference(ScriptType, result._itemRef.ToString() + " " + Utils.GetChecksum(Encoding.UTF8.GetBytes(elem.OuterXml))) { KeyedName = RenderAttributes(elem) }; result._type = InstallType.Script; break; } } if (elem.Attribute(XmlFlags.Attr_IsScript) == "1") { if (string.IsNullOrEmpty(result._itemRef.KeyedName)) { result._itemRef.KeyedName = RenderAttributes(elem); } result._type = InstallType.Script; } return result; }
public virtual InstallScript Read() { var result = new InstallScript(); XmlDocument doc; var scripts = new List <InstallItem>(); var manifest = new XmlDocument(); string currPath; IEnumerable <string> paths; manifest.Load(GetExistingStream(null)); if (manifest.DocumentElement.HasAttribute("created")) { result.Created = DateTime.Parse(manifest.DocumentElement.GetAttribute("created")); } result.Creator = manifest.DocumentElement.GetAttribute("creator"); result.Description = manifest.DocumentElement.GetAttribute("description"); if (manifest.DocumentElement.HasAttribute("modified")) { result.Modified = DateTime.Parse(manifest.DocumentElement.GetAttribute("modified")); } result.Version = manifest.DocumentElement.GetAttribute("revision"); result.Title = manifest.DocumentElement.GetAttribute("title"); if (manifest.DocumentElement.HasAttribute("website")) { result.Website = new Uri(manifest.DocumentElement.GetAttribute("website")); } foreach (var child in manifest.DocumentElement.ChildNodes.OfType <XmlElement>()) { if (child.LocalName == "Item") { scripts.Add(InstallItem.FromScript(child)); } else { currPath = child.GetAttribute("path"); paths = string.IsNullOrEmpty(currPath) ? Enumerable.Empty <string>() : (currPath == "*" ? GetPaths() : Enumerable.Repeat(currPath, 1)); if (currPath == "*") { result.DependencySorted = false; } var reportXmlPaths = new HashSet <string>(paths .Where(p => p.EndsWith(".xslt", StringComparison.OrdinalIgnoreCase)) .Select(p => p + ".xml"), StringComparer.OrdinalIgnoreCase); foreach (var path in paths .Where(p => !reportXmlPaths.Contains(p))) { if (path.EndsWith(".xslt", StringComparison.OrdinalIgnoreCase)) { doc = ReadReport(path); } else { try { doc = new XmlDocument(manifest.NameTable); var stream = GetExistingStream(path); if (stream == null) { throw new FileNotFoundException("A referenced file was not found in the package", path); } using (stream) using (var reader = new StreamReader(stream)) { var text = reader.ReadToEnd(); doc.LoadXml(text); } } catch (Exception ex) when(ex is XmlException || ex is IOException) { throw new InvalidOperationException($"Error reading the file {path}: {ex.Message}", ex); } } var items = doc.DocumentElement.LocalName == "Item" ? new[] { doc.DocumentElement } : doc.DocumentElement.Elements("Item"); foreach (var item in items) { scripts.Add(InstallItem.FromScript(item, path)); } } } } result.Lines = scripts; result.Lines.CleanKeyedNames(); return(result); }
public static InstallItem FromScript(XmlElement elem , Func <XmlElement, string> keyedNameGetter = null) { var result = new InstallItem(); result._elem = elem; result._itemRef = ItemReference.FromFullItem(elem, true); if (result._itemRef.Type.IsGuid()) { result.InstalledId = result._itemRef.Type; } else { result.InstalledId = elem.Attribute("id", ""); } if (elem.HasAttribute("_dependency_check")) { result.Type = InstallType.DependencyCheck; } else if (elem.HasAttribute("action")) { switch (elem.Attributes["action"].Value) { case "add": case "merge": case "create": result.Type = InstallType.Create; break; case "ActivateActivity": case "AddItem": case "AddHistory": case "ApplyUpdate": case "BuildProcessReport": case "CancelWorkflow": case "checkImportedItemType": case "closeWorkflow": case "copy": case "copyAsIs": case "copyAsNew": case "delete": case "edit": case "EmailItem": case "EvaluateActivity": case "exportItemType": case "get": case "getItemAllVersions": case "getAffectedItems": case "getItemConfig": case "getItemLastVersion": case "getItemNextStates": case "getItemRelationships": case "GetItemRepeatConfig": case "getItemWhereUsed": case "GetMappedPath": case "getPermissions": case "getRelatedItem": case "GetUpdateInfo": case "instantiateWorkflow": case "lock": case "New Workflow Map": case "PromoteItem": case "purge": case "recache": case "replicate": case "resetAllItemsAccess": case "resetItemAccess": case "resetLifecycle": case "setDefaultLifecycle": case "skip": case "startWorkflow": case "unlock": case "update": case "ValidateWorkflowMap": case "version": if ((elem.Attributes["type"].Value != "Form" && elem.Attributes["type"].Value != "View") || elem.Attributes["action"].Value != "delete") { result._dependencies = Enumerable.Repeat(result._itemRef, 1); } result._itemRef = new ItemReference(ScriptType, result._itemRef + " " + Utils.GetChecksum(Encoding.UTF8.GetBytes(elem.OuterXml))) { KeyedName = RenderAttributes(elem) }; result.Type = InstallType.Script; break; default: result._dependencies = Enumerable.Repeat(new ItemReference("Method", "[Method].[name] = '" + elem.Attributes["action"].Value + "'") { KeyedName = elem.Attributes["action"].Value }, 1); result._itemRef = new ItemReference(ScriptType, result._itemRef + " " + Utils.GetChecksum(Encoding.UTF8.GetBytes(elem.OuterXml))) { KeyedName = RenderAttributes(elem) }; result.Type = InstallType.Script; break; } } if (elem.Attribute(XmlFlags.Attr_IsScript) == "1") { if (string.IsNullOrEmpty(result._itemRef.KeyedName)) { result._itemRef.KeyedName = RenderAttributes(elem); } result.Type = InstallType.Script; } return(result); }
/// <summary> /// Determine the dependencies of an install item script /// </summary> public void AddReferenceAndDependencies(InstallItem installItem) { AddReferenceAndDependencies(installItem.Script, installItem.Reference, installItem.CoreDependencies); }
private static bool TryReadPackage(IPackageFile manifestFile, IPackage package, ILogger logger, out InstallScript installScript) { installScript = new InstallScript(); var result = true; var scripts = new List <InstallItem>(); var manifest = new XmlDocument(); using (var manifestStream = manifestFile.Open()) manifest.Load(manifestStream); if (manifest.DocumentElement.HasAttribute("created")) { installScript.Created = DateTime.Parse(manifest.DocumentElement.GetAttribute("created")); } installScript.Creator = manifest.DocumentElement.GetAttribute("creator"); installScript.Description = manifest.DocumentElement.GetAttribute("description"); if (manifest.DocumentElement.HasAttribute("modified")) { installScript.Modified = DateTime.Parse(manifest.DocumentElement.GetAttribute("modified")); } installScript.Version = manifest.DocumentElement.GetAttribute("revision"); installScript.Title = manifest.DocumentElement.GetAttribute("title"); if (manifest.DocumentElement.HasAttribute("website")) { installScript.Website = new Uri(manifest.DocumentElement.GetAttribute("website")); } foreach (var child in manifest.DocumentElement.ChildNodes.OfType <XmlElement>()) { if (child.LocalName == "Item") { scripts.Add(InstallItem.FromScript(child)); } else { var currPath = child.GetAttribute("path"); var files = Enumerable.Empty <IPackageFile>(); if (currPath == "*") { files = package.Files(); installScript.DependencySorted = false; } else if (!string.IsNullOrEmpty(currPath)) { if (package.TryAccessFile(currPath, false, out var file)) { files = new[] { file }; } else { result = false; logger.LogError("The file {Path} is referenced in the manifest, but not found in the package.", currPath); continue; } } var reportXmlPaths = new HashSet <string>(files .Where(f => f.Path.EndsWith(".xslt", StringComparison.OrdinalIgnoreCase)) .Select(f => f.Path + ".xml"), StringComparer.OrdinalIgnoreCase); foreach (var file in files .Where(f => !reportXmlPaths.Contains(f.Path))) { try { var doc = new XmlDocument(manifest.NameTable); using (var writer = doc.CreateNavigator().AppendChild()) file.WriteAml(package, writer); var items = doc.DocumentElement.LocalName == "Item" ? new[] { doc.DocumentElement } : doc.DocumentElement.Elements("Item"); foreach (var item in items) { scripts.Add(InstallItem.FromScript(item, file.Path)); } } catch (XmlException ex) { result = false; logger.LogError(ex, "The AML script at {Path} is malformed", file.Path); } catch (Exception ex) { ex.Data["path"] = file.Path; throw; } } } } installScript.Lines = scripts; result = CleanKeyedNames(installScript.Lines, logger) || result; return(result); }
private void WriteReport(InstallItem line, string path) { var dataFile = "<Result><Item></Item></Result>"; using (var writer = new StreamWriter(GetNewStream(path))) { var aml = new StringBuilder(); using (var amlWriter = new System.IO.StringWriter(aml)) { using (var xml = new ConfigurableXmlWriter(amlWriter)) { xml.ElementProcessor = (prefix, localName, ns, w) => { if (localName == "xsl_stylesheet") return ProcessState.DontRender; return ProcessState.RenderAll; }; xml.WriteStartElement("AML"); line.Script.WriteTo(xml); xml.WriteEndElement(); } } writer.WriteLine(_reportStart); writer.WriteLine(aml); writer.WriteLine(_reportEnd); var xsltElem = line.Script.SelectSingleNode(".//xsl_stylesheet") as XmlElement; if (xsltElem != null) { var xslt = xsltElem.InnerText; var dataStart = xslt.IndexOf(_reportDataStart); var dataEnd = xslt.IndexOf(_reportDataEnd); if (dataStart >= 0 && dataEnd >= 0) { dataFile = xslt.Substring(dataStart + _reportDataStart.Length, dataEnd - dataStart - _reportDataStart.Length).Trim(); xslt = xslt.Substring(0, dataStart).Trim() + Environment.NewLine + xslt.Substring(dataEnd + _reportDataEnd.Length).Trim(); } else { dataFile = xsltElem.Parent().Element("report_query", "<Result><Item></Item></Result>"); } writer.WriteLine(xslt); } } using (var writer = new StreamWriter(GetNewStream(path + ".xml"))) { writer.Write(dataFile); } }
internal IEnumerable <InstallItem> GetDependencyList(DependencyAnalyzer dependAnalyzer , IEnumerable <InstallItem> values, out CycleState cycleState) { cycleState = CycleState.NoCycle; var lookup = (from i in values group i by i.Reference into refGroup select refGroup) .ToDictionary(i => i.Key, i => (IEnumerable <InstallItem>)i); IEnumerable <ItemReference> sorted = null; IList <ItemReference> cycle = new List <ItemReference>() { null }; List <XmlNode> refs; // Bias the install order initially to try and help the dependency sort properly handle anything // where explicit dependencies don't exist. Then, perform the dependency sort. var initialSort = lookup.Keys .OrderBy(DefaultInstallOrder) .ThenBy(i => i.Type.ToLowerInvariant()) .ThenBy(i => i.Unique) .ToList(); sorted = initialSort.DependencySort <ItemReference>(d => { IEnumerable <InstallItem> res = null; if (lookup.TryGetValue(d, out res)) { return(res.SelectMany(r => { var ii = r as InstallItem; if (ii == null) { return Enumerable.Empty <ItemReference>(); } return dependAnalyzer.GetDependencies(ii.Reference); })); } return(Enumerable.Empty <ItemReference>()); }, ref cycle, false); // Attempt to remove cycles by identifying a Relationships tag in one of the cycles // and moving the Relationships to the top level if (cycle.Count > 0 && (cycle[0] != null || cycle.Count > 1)) { cycleState = CycleState.UnresolvedCycle; for (int i = (cycle[0] == null ? 2 : 1); i < cycle.Count; i++) { refs = dependAnalyzer.GetReferences(cycle[i - 1], cycle[i]).ToList(); if (refs.Count == 1) { var relTag = refs[0].Parents().FirstOrDefault(e => e.LocalName == "Relationships"); if (relTag != null) { var parentTag = refs[0].Parents().Last(e => e.LocalName == "Item").Parent(); foreach (var child in relTag.Elements().ToList()) { child.Detach(); parentTag.AppendChild(child); var sourceId = (XmlElement)child.AppendChild(child.OwnerDocument.CreateElement("source_id")); sourceId.SetAttribute("type", relTag.Parent().Attribute("type")); sourceId.SetAttribute("keyed_name", relTag.Parent().Attribute("_keyed_name")); sourceId.InnerText = relTag.Parent().Attribute("id"); } relTag.Detach(); cycleState = CycleState.ResolvedCycle; //return Enumerable.Empty<InstallItem>(); } } } } var result = new List <InstallItem>(); IEnumerable <InstallItem> items = null; foreach (var sort in sorted) { if (lookup.TryGetValue(sort, out items)) { foreach (var item in items) { result.Add(item); } } else { result.Add(InstallItem.FromDependency(sort)); } } return(result); }
private static bool IsDelete(InstallItem item) { return(item.Type == InstallType.Script && item.Name.Split(' ').Contains("Delete")); }