/// <summary> /// Finds all templates for a field ID. /// </summary> /// <param name="files">The files.</param> /// <param name="fieldId">The field identifier.</param> /// <returns></returns> public static IEnumerable <RainbowFile> FindAllTemplatesForField(IEnumerable <AdditionalText> files, Guid fieldId) { List <RainbowFile> result = new List <RainbowFile>(); lock (readAllFilesLock) { RainbowFile file; Evaluate(files, null, out file); var allRainbowFiles = rainbowFiles.Values; RainbowFile potentialTemplateFile = allRainbowFiles.FirstOrDefault(f => Guid.Equals(f.Id, fieldId)); while (potentialTemplateFile != null) { if (Guid.Equals(potentialTemplateFile.TemplateId, SitecoreConstants.SitecoreTemplateTemplateId)) { break; } potentialTemplateFile = allRainbowFiles.FirstOrDefault(f => Guid.Equals(f.Id, potentialTemplateFile.ParentId)); } if (potentialTemplateFile != null) { result.Add(potentialTemplateFile); var allTemplateFiles = allRainbowFiles.Where(f => Guid.Equals(f.TemplateId, SitecoreConstants.SitecoreTemplateTemplateId)).ToList(); result.AddRange(FindDerivedTemplates(allTemplateFiles, potentialTemplateFile, 200)); } } return(result.Distinct()); }
/// <summary> /// Parses the rainbow (.yml) file. /// </summary> /// <param name="text">The text of the .yml file.</param> /// <returns></returns> public static RainbowFile ParseRainbowFile(AdditionalText text) { const string idParseKey = "ID: "; const string pathParseKey = "Path: "; const string templateParseKey = "Template: "; const string parentParseKey = "Parent: "; const string baseTemplateIntroLine = "- ID: \"12c33f3f-86c5-43a5-aeb4-5598cec45116\""; const string baseTemplateIntroLineNoQuotes = "- ID: 12c33f3f-86c5-43a5-aeb4-5598cec45116"; const string baseTemplateParseKey = "Value: "; var textLines = text.GetText().ToString().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (textLines.Any()) { var result = new RainbowFile(); string textLineId = textLines.FirstOrDefault(l => l.StartsWith(idParseKey)); Guid idGuid; if (textLineId != null && Guid.TryParse(textLineId.Substring(idParseKey.Length).Trim(' ', '"'), out idGuid)) { result.Id = idGuid; } var textLineParent = textLines.FirstOrDefault(l => l.StartsWith(parentParseKey)); Guid parentIdGuid; if (textLineParent != null && Guid.TryParse(textLineParent.Substring(parentParseKey.Length).Trim(' ', '"'), out parentIdGuid)) { result.ParentId = parentIdGuid; } var textLinePath = textLines.FirstOrDefault(l => l.StartsWith(pathParseKey)); if (textLinePath != null) { result.Path = textLinePath.Substring(pathParseKey.Length).Trim(); } string textLineTemplate = textLines.FirstOrDefault(l => l.StartsWith(templateParseKey)); Guid templateGuid; if (textLineTemplate != null && Guid.TryParse(textLineTemplate.Substring(templateParseKey.Length).Trim(' ', '"'), out templateGuid)) { result.TemplateId = templateGuid; // Parse base template(s) if the item is a template if (Guid.Equals(result.TemplateId, SitecoreConstants.SitecoreTemplateTemplateId)) { result.BaseTemplates = new List <Guid>(); ////int? lineIndex = textLines //// .Select((l, i) => new { Index = i, Line = l }) //// .FirstOrDefault(l => string.Equals(baseTemplateIntroLine, l.Line.Trim()) || string.Equals(baseTemplateIntroLineNoQuotes, l.Line.Trim()))?.Index; var baseTemplateIdLines = textLines .SkipWhile(l => !(string.Equals(baseTemplateIntroLine, l.Trim()) || string.Equals(baseTemplateIntroLineNoQuotes, l.Trim()))) .SkipWhile(l => !l.TrimStart().StartsWith(baseTemplateParseKey)) .TakeWhile(l => l.StartsWith(" ")); foreach (string baseTemplateIdLine in baseTemplateIdLines) { string line = baseTemplateIdLine.Trim(); if (line.StartsWith(baseTemplateParseKey)) { line = line.Substring(baseTemplateParseKey.Length); } line = line.Trim(' ', '|', '"'); Guid baseTemplateId; if (Guid.TryParse(line, out baseTemplateId)) { result.BaseTemplates.Add(baseTemplateId); } } } } return(result); } // Not a valid result, but return an empty object anyway so it won't have to be parsed more often return(new RainbowFile()); }
/// <summary> /// Evaluates if any of the .yml files match the specified function. /// </summary> /// <param name="files">The .yml files.</param> /// <param name="evaluateFunction">The evaluation function.</param> /// <param name="matchingFile">The matching file.</param> /// <returns></returns> public static bool Evaluate(IEnumerable <AdditionalText> files, Func <RainbowFile, bool> evaluateFunction, out RainbowFile matchingFile) { matchingFile = null; foreach (AdditionalText text in files) { RainbowFile file; // This code will probably not run in parallel, but ensure that the dictionaries remain in sync just in case lock (rainbowFileHashes) { if (rainbowFileHashes.ContainsKey(text.Path)) { // We have already parsed this file, so check if our cache is up to date if (rainbowFileHashes[text.Path] == text.GetHashCode()) { // The cache is up to date, so use the cached version file = rainbowFiles[text.Path]; } else { // Update the cache rainbowFileHashes[text.Path] = text.GetHashCode(); file = RainbowParserUtil.ParseRainbowFile(text); rainbowFiles[text.Path] = file; } } else { // Parse the file and add it to the cache rainbowFileHashes.Add(text.Path, text.GetHashCode()); file = RainbowParserUtil.ParseRainbowFile(text); rainbowFiles.Add(text.Path, file); } } // Only stop evaluating if something matches if (evaluateFunction != null && evaluateFunction(file)) { matchingFile = file; return(true); } } return(false); }
/// <summary> /// Finds derived templates recursively. /// </summary> /// <param name="allTemplateFiles">All template files.</param> /// <param name="templateFile">The template.</param> /// <param name="maxDepth">The maximum depth, to prevent stack overflow if there are circular references.</param> /// <returns></returns> private static IEnumerable <RainbowFile> FindDerivedTemplates(List <RainbowFile> allTemplateFiles, RainbowFile templateFile, int maxDepth) { if (maxDepth > 0) { foreach (RainbowFile derivedTemplate in allTemplateFiles.Where(t => t.BaseTemplates != null && t.BaseTemplates.Contains(templateFile.Id))) { yield return(derivedTemplate); foreach (var derived in FindDerivedTemplates(allTemplateFiles, derivedTemplate, maxDepth - 1)) { yield return(derived); } } } }