public TemplatingContext(ObjectCache cache, CompositionContainer container, IFileProvider outputFileProvider, TemplateData data, IEnumerable<IAssetUriResolver> resolvers, IFileProvider templateFileProvider) { this.Container = container; this.OutputFileProvider = outputFileProvider; this.TemplateData = data; this.AssetUriResolvers = resolvers.ToArray(); this.TemplateFileProvider = templateFileProvider; this.Cache = cache; XPathDocument xpathDoc; using (var reader = data.Document.CreateReader(ReaderOptions.OmitDuplicateNamespaces)) xpathDoc = new XPathDocument(reader); this.Document = xpathDoc.CreateNavigator(); this.DocumentIndex = new XPathNavigatorIndex(this.Document.Clone()); }
private IEnumerable<UnitOfWork> DiscoverWork(TemplateData templateData, XPathVariable[] parameters, Resource[] resources) { CustomXsltContext xpathContext = CreateCustomXsltContext(templateData.IgnoredVersionComponent); xpathContext.PushVariableScope(templateData.Document.Root, parameters); for (int i = 0; i < resources.Length; i++) { xpathContext.PushVariableScope(templateData.Document.Root, resources[i].Variables); if (EvalCondition(xpathContext, templateData.Document.Root, resources[i].ConditionExpression)) { string expandedSource = EvalValue(xpathContext, templateData.Document.Root, resources[i].Source); string expandedOutput = EvalValue(xpathContext, templateData.Document.Root, resources[i].Output); List<IResourceTransform> transforms = new List<IResourceTransform>(); foreach (var resourceTransform in resources[i].Transforms) { using (CompositionContainer localContainer = new CompositionContainer(this._container.Catalog)) { string dirName = Path.GetDirectoryName(expandedSource); CompositionBatch batch = new CompositionBatch(); var exportMetadata = new Dictionary<string, object>(); exportMetadata.Add(CompositionConstants.ExportTypeIdentityMetadataName, AttributedModelServices.GetTypeIdentity(typeof(IFileProvider))); exportMetadata.Add(CompositionConstants.PartCreationPolicyMetadataName, CreationPolicy.Shared); batch.AddExport(new Export(ContractNames.ResourceFileProvider, exportMetadata, () => new ScopedFileProvider(resources[i].FileProvider, dirName))); // TODO export resourceTransform.Parameters into localContainer using CompositionBatch localContainer.Compose(batch); var requiredMetadata = new[] { new Tuple<string, object, IEqualityComparer>("Name", resourceTransform.Name, StringComparer.OrdinalIgnoreCase) }; ImportDefinition importDefinition = new MetadataContractBasedImportDefinition( typeof(IResourceTransform), null, requiredMetadata, ImportCardinality.ExactlyOne, false, true, CreationPolicy.NonShared); Export transformExport = localContainer.GetExports(importDefinition).Single(); transforms.Add((IResourceTransform)transformExport.Value); } } yield return new ResourceDeployment(resources[i].FileProvider, expandedSource, expandedOutput, // TODO this needs a 'writable' file provider transforms.ToArray()); } xpathContext.PopVariableScope(); } xpathContext.PopVariableScope(); }
/// <summary> /// This method will construct a three folder structure inside <paramref name="targetDirectory"/> containing: Html, Index, and Source /// </summary> /// <param name="sourceDirectory"> /// Directory containing ldoc files /// </param> /// <param name="targetDirectory"> /// Output directory /// </param> public void Build(string sourceDirectory, string targetDirectory) { if (Directory.Exists(targetDirectory) && Directory.EnumerateFileSystemEntries(targetDirectory).Any()) throw new InvalidOperationException("Target path is not empty."); this.OnStateChanged(State.Preparing); string htmlRoot = Path.Combine(targetDirectory, "Html"); string indexRoot = Path.Combine(targetDirectory, "Index"); string sourceRoot = Path.Combine(targetDirectory, "Source"); string logRoot = Path.Combine(targetDirectory, "Logs"); DirectoryInfo htmlDir = Directory.CreateDirectory(htmlRoot); DirectoryInfo indexDir = Directory.CreateDirectory(indexRoot); DirectoryInfo sourceDir = Directory.CreateDirectory(sourceRoot); DirectoryInfo logDir = Directory.CreateDirectory(logRoot); var sourceFiles = Directory.EnumerateFiles(sourceDirectory, "*.ldoc", SearchOption.TopDirectoryOnly); // copy all source files to output directory and add to bundle Bundle bundle = new Bundle(this.IgnoreVersionComponent); foreach (var sourceFile in sourceFiles) { string targetFile = Path.Combine(sourceDir.FullName, Path.GetFileName(sourceFile)); File.Copy(sourceFile, targetFile); bundle.Add(XDocument.Load(targetFile)); } TemplateOutput templateOutput; // wire up logging string templateLogFile = Path.Combine(logDir.FullName, string.Format("template_{0:yyyy'_'MM'_'dd'__'HH'_'mm'_'ss}.log", DateTime.Now)); using (TextWriterTraceListener traceListener = new TextWriterTraceListener(templateLogFile)) { // log everything traceListener.Filter = new EventTypeFilter(SourceLevels.All); LostDoc.Diagnostics.TraceSources.TemplateSource.Switch.Level = SourceLevels.All; LostDoc.Diagnostics.TraceSources.BundleSource.Switch.Level = SourceLevels.All; LostDoc.Diagnostics.TraceSources.AssetResolverSource.Switch.Level = SourceLevels.All; LostDoc.Diagnostics.TraceSources.TemplateSource.Listeners.Add(traceListener); LostDoc.Diagnostics.TraceSources.BundleSource.Listeners.Add(traceListener); LostDoc.Diagnostics.TraceSources.AssetResolverSource.Listeners.Add(traceListener); // merge ldoc files this.OnStateChanged(State.Merging); AssetRedirectCollection assetRedirects; var mergedDoc = bundle.Merge(out assetRedirects); // generate output var templateData = new TemplateData(mergedDoc) { AssetRedirects = assetRedirects, IgnoredVersionComponent = this.IgnoreVersionComponent, OutputFileProvider = new ScopedFileProvider(new DirectoryFileProvider(), htmlDir.FullName), //TargetDirectory = htmlDir.FullName, Arguments = new Dictionary<string, object> { { "SearchUri", "/search/" } }, KeepTemporaryFiles = true, TemporaryFilesPath = Path.Combine(logDir.FullName, "temp") }; this.OnStateChanged(State.Templating); templateOutput = this.Template.Generate(templateData); LostDoc.Diagnostics.TraceSources.TemplateSource.Listeners.Remove(traceListener); LostDoc.Diagnostics.TraceSources.BundleSource.Listeners.Remove(traceListener); LostDoc.Diagnostics.TraceSources.AssetResolverSource.Listeners.Remove(traceListener); } this.OnStateChanged(State.Indexing); string indexLogFile = Path.Combine(logDir.FullName, string.Format("index_{0:yyyy'_'MM'_'dd'__'HH'_'mm'_'ss}.log", DateTime.Now)); using (TextWriterTraceListener traceListener = new TextWriterTraceListener(indexLogFile)) { // log everything traceListener.Filter = new EventTypeFilter(SourceLevels.All); TraceSources.ContentBuilderSource.Switch.Level = SourceLevels.All; TraceSources.ContentBuilderSource.Listeners.Add(traceListener); // one stop-word per line StringReader stopWordsReader = new StringReader(@"missing"); // index output using (var directory = FSDirectory.Open(indexDir)) using (stopWordsReader) { Analyzer analyzer = new StandardAnalyzer(global::Lucene.Net.Util.Version.LUCENE_30, stopWordsReader); Analyzer titleAnalyzer = new TitleAnalyzer(); IDictionary<string, Analyzer> fieldAnalyzers = new Dictionary<string, Analyzer> { { "title", titleAnalyzer } }; PerFieldAnalyzerWrapper analyzerWrapper = new PerFieldAnalyzerWrapper(analyzer, fieldAnalyzers); using ( var writer = new IndexWriter(directory, analyzerWrapper, IndexWriter.MaxFieldLength.UNLIMITED)) { var saResults = templateOutput.Results.Select(wur => wur.WorkUnit).OfType<StylesheetApplication>(); var saDict = saResults.ToDictionary(sa => sa.Asset); var indexResults = saDict.Values.Where(sa => sa.SaveAs.EndsWith(".xml")); foreach (var sa in indexResults) { string absPath = Path.Combine(htmlDir.FullName, sa.SaveAs); XDocument indexDoc = XDocument.Load(absPath); string assetId = indexDoc.Root.Attribute("assetId").Value; string title = indexDoc.Root.Element("title").Value.Trim(); string summary = indexDoc.Root.Element("summary").Value.Trim(); string text = indexDoc.Root.Element("text").Value.Trim(); var ssApplication = saDict[AssetIdentifier.Parse(assetId)]; var doc = new Document(); doc.Add(new Field("uri", new Uri(ssApplication.SaveAs, UriKind.Relative).ToString(), Field.Store.YES, Field.Index.NO)); doc.Add(new Field("aid", ssApplication.Asset, Field.Store.YES, Field.Index.NOT_ANALYZED)); foreach (AssetIdentifier aid in ssApplication.Aliases) doc.Add(new Field("alias", aid, Field.Store.NO, Field.Index.NOT_ANALYZED)); foreach (var section in ssApplication.Sections) { doc.Add(new Field("section", section.AssetIdentifier, Field.Store.NO, Field.Index.NOT_ANALYZED)); } doc.Add(new Field("title", title, Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field("summary", summary, Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field("content", text, Field.Store.NO, Field.Index.ANALYZED)); TraceSources.ContentBuilderSource.TraceVerbose("Indexing document: {0}", doc.ToString()); writer.AddDocument(doc); } writer.Optimize(); writer.Commit(); } analyzerWrapper.Close(); analyzer.Close(); } TraceSources.ContentBuilderSource.Listeners.Remove(traceListener); } this.OnStateChanged(State.Finalizing); var infoDoc = new XDocument( new XElement("content", new XAttribute("created", XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc)), templateOutput.Results.Select(this.ConvertToXml))); infoDoc.Save(Path.Combine(targetDirectory, "info.xml")); this.OnStateChanged(State.Idle); }
protected virtual ParsedTemplate PrepareTemplate(TemplateData templateData, Stack<IFileProvider> providers = null) { // set up temp file container TempFileCollection tempFiles = new TempFileCollection(templateData.TemporaryFilesPath, templateData.KeepTemporaryFiles); if (!Directory.Exists(tempFiles.TempDir)) Directory.CreateDirectory(tempFiles.TempDir); if (providers == null) { providers = new Stack<IFileProvider>(); providers.Push(new HttpFileProvider()); providers.Push(new DirectoryFileProvider()); } // clone orig doc XDocument workingDoc; // this is required to preserve the line information using (var xmlReader = this._templateDefinition.CreateReader()) workingDoc = XDocument.Load(xmlReader, LoadOptions.SetLineInfo); // template inheritence //XAttribute templateInheritsAttr = workingDoc.Root.Attribute("inherits"); if (this._templateInfo.Inherits != null) { int depth = providers.Count + 1; Template inheritedTemplate = _templateInfo.Inherits.Load(this._container); ParsedTemplate parsedTemplate = inheritedTemplate.PrepareTemplate(templateData, providers); providers.Push(inheritedTemplate.GetScopedFileProvider()); // a little hacky but it should work with the Reverse()/AddFirst() foreach (XElement elem in parsedTemplate.Source.Root.Elements().Reverse()) { workingDoc.Root.AddFirst(new XElement(elem)); } // create and register temp file (this can be overriden later if there are meta-template directives // in the template this._templateSourcePath = this.SaveTempFile(tempFiles, workingDoc, "inherited." + depth + '.' + _templateInfo.Name); } // add our file provider to the top of the stack providers.Push(this.GetScopedFileProvider()); // create stacked provider IFileProvider provider = new StackedFileProvider(providers); // start by loading any parameters as they are needed for meta-template evaluation CustomXsltContext customContext = CreateCustomXsltContext(templateData.IgnoredVersionComponent); XElement[] paramNodes = workingDoc.Root.Elements("parameter").ToArray(); List<XPathVariable> globalParams = new List<XPathVariable>(); foreach (XElement paramNode in paramNodes) { string name = this.GetAttributeValue(paramNode, "name"); object argValue; if (templateData.Arguments.TryGetValue(name, out argValue)) globalParams.Add(new ConstantXPathVariable(name, argValue)); else { string expr = this.GetAttributeValueOrDefault(paramNode, "select"); globalParams.Add(new ExpressionXPathVariable(name, expr)); } } customContext.PushVariableScope(workingDoc, globalParams.ToArray()); var arguments = templateData.Arguments .Select(argument => new ConstantXPathVariable(argument.Key, argument.Value)) .ToArray(); customContext.PushVariableScope(workingDoc, arguments); // expand any meta-template directives workingDoc = ApplyMetaTransforms(workingDoc, customContext, provider, tempFiles); // there was neither inheretance, nor any meta-template directives if (this._templateSourcePath == null) { // save current template to disk this._templateSourcePath = this.SaveTempFile(tempFiles, workingDoc); } // loading template List<Stylesheet> stylesheets = new List<Stylesheet>(); List<Resource> resources = new List<Resource>(); List<Index> indices = new List<Index>(); foreach (XElement elem in workingDoc.Root.Elements()) { // we alread proessed the parameters if (elem.Name.LocalName == "parameter") continue; if (elem.Name.LocalName == "apply-stylesheet") { stylesheets.Add(this.ParseStylesheet(provider, stylesheets, elem)); } else if (elem.Name.LocalName == "index") { indices.Add(this.ParseIndexDefinition(elem)); } else if (elem.Name.LocalName == "include-resource") { resources.Add(ParseResouceDefinition(provider, elem)); } else { throw new Exception("Unknown element: " + elem.Name.LocalName); } } return new ParsedTemplate { Parameters = globalParams.ToArray(), Source = workingDoc, Resources = resources.ToArray(), Stylesheets = stylesheets.ToArray(), Indices = indices.ToArray(), TemporaryFiles = tempFiles, }; }
/// <summary> /// Applies the loaded templates to <paramref name="templateData"/>. /// </summary> /// <param name="templateData"> /// Instance of <see cref="TemplateData"/> containing the various input data needed. /// </param> public virtual TemplateOutput Generate(TemplateData templateData) { Stopwatch timer = Stopwatch.StartNew(); this._fileResolver.Clear(); ParsedTemplate tmpl = this.PrepareTemplate(templateData); // collect all work that has to be done List<UnitOfWork> work = new List<UnitOfWork>(); // resource work units work.AddRange(this.DiscoverWork(templateData, tmpl.Parameters, tmpl.Resources)); // stylesheet work units { List<StylesheetApplication> stylesheetApplications = new List<StylesheetApplication>(); foreach (Stylesheet stylesheet in tmpl.Stylesheets) { stylesheetApplications.AddRange(this.DiscoverWork(templateData, tmpl.Parameters, stylesheet)); } var duplicates = stylesheetApplications.GroupBy(sa => sa.SaveAs, StringComparer.OrdinalIgnoreCase) .Where(g => g.Count() > 1); foreach (var group in duplicates) { TraceSources.TemplateSource.TraceError("Duplicate work unit target ({0}) generated from: {1}", group.Key, string.Join(", ", group.Select(sa => '\'' + sa.StylesheetName + '\''))); foreach (var workunit in group.Skip(1)) { stylesheetApplications.Remove(workunit); } } work.AddRange(stylesheetApplications); } TraceSources.TemplateSource.TraceInformation("Generating {0:N0} documents from {1:N0} stylesheets.", work.Count, tmpl.Stylesheets.Length); ConcurrentBag<WorkUnitResult> results = new ConcurrentBag<WorkUnitResult>(); // create context ITemplatingContext context = new TemplatingContext(this._cache, this._container, templateData.OutputFileProvider, // TODO fix this (this._basePath) templateData, this._resolvers, this._templateInfo.Source); // fill indices using (TraceSources.TemplateSource.TraceActivity("Indexing input document")) { var customXsltContext = CreateCustomXsltContext(templateData.IgnoredVersionComponent); foreach (var index in tmpl.Indices) { TraceSources.TemplateSource.TraceVerbose("Adding index {0} (match: '{1}', key: '{1}')", index.Name, index.MatchExpr, index.KeyExpr); context.DocumentIndex.AddKey(index.Name, index.MatchExpr, index.KeyExpr, customXsltContext); } TraceSources.TemplateSource.TraceInformation("Indexing..."); context.DocumentIndex.BuildIndexes(); } int totalCount = work.Count; long lastProgress = Stopwatch.GetTimestamp(); int processed = 0; // process all units of work ParallelOptions parallelOptions = new ParallelOptions { //MaxDegreeOfParallelism = 1 }; IEnumerable<UnitOfWork> unitsOfWork = work; if (templateData.Filter != null) { unitsOfWork = unitsOfWork .Where(uow => { if (templateData.Filter(uow)) return true; TraceSources.TemplateSource.TraceInformation("Filtered unit of work: [{0}] {1}", uow.GetType().Name, uow.ToString()); return false; }); } Parallel.ForEach(unitsOfWork, parallelOptions, uow => { results.Add(uow.Execute(context)); int c = Interlocked.Increment(ref processed); long lp = Interlocked.Read(ref lastProgress); if ((Stopwatch.GetTimestamp() - lp) / (double)Stopwatch.Frequency > 5.0) { if (Interlocked.CompareExchange(ref lastProgress, Stopwatch.GetTimestamp(), lp) == lp) { TraceSources.TemplateSource.TraceInformation( "Progress: {0:P1} ({1:N0}/{2:N0})", c / (double)totalCount, c, totalCount); } } }); // stop timing timer.Stop(); Stopwatch statsTimer = new Stopwatch(); // prepare stats Dictionary<Type, WorkUnitResult[]> resultGroups = results.GroupBy(ps => ps.WorkUnit.GetType()).ToDictionary(g => g.Key, g => g.ToArray()); var stylesheetStats = resultGroups[typeof(StylesheetApplication)] .GroupBy(r => ((StylesheetApplication)r.WorkUnit).StylesheetName); foreach (var statGroup in stylesheetStats) { long min = statGroup.Min(ps => ps.Duration); long max = statGroup.Max(ps => ps.Duration); TraceSources.TemplateSource.TraceInformation("Applied stylesheet '{0}' {1:N0} times in {2:N0} ms (min: {3:N0}, mean {4:N0}, max {5:N0}, avg: {6:N0})", statGroup.Key, statGroup.Count(), statGroup.Sum(ps => ps.Duration) / 1000.0, min / 1000.0, statGroup.Skip(statGroup.Count() / 2).Take(1).Single().Duration / 1000.0, max / 1000.0, statGroup.Average(ps => ps.Duration) / 1000.0); // TODO this is quick and dirty, should be cleaned up long[] buckets = new long[20]; int rows = 6; /* ┌────────────────────┐ ◄ 230 │█ █│ │█ █│ │█ █│ │█ █│ │█ █│ │█__________________█│ └────────────────────┘ ◄ 0 ▲ 12ms ▲ 12ms */ // this is a little hacky, but it will do for now WorkUnitResult[] sortedResults = statGroup.OrderBy(r => r.Duration).ToArray(); double bucketSize = (max - min) / (double)buckets.Length; int bucketNum = 0; long bucketMax = 0; foreach (WorkUnitResult result in sortedResults) { while ((result.Duration - min) > (bucketNum + 1) * bucketSize) bucketNum++; buckets[bucketNum] += 1; bucketMax = Math.Max(buckets[bucketNum], bucketMax); } double rowHeight = bucketMax / (double)rows; StringBuilder graph = new StringBuilder(); graph.AppendLine("Graph:"); const int gutter = 2; int columnWidth = graph.Length; graph.Append('┌').Append('─', buckets.Length).Append('┐').Append('◄').Append(' ').Append(bucketMax.ToString("N0")); int firstLineLength = graph.Length - columnWidth; columnWidth = graph.Length - columnWidth + gutter; StringBuilder lastLine = new StringBuilder(); lastLine.Append('▲').Append(' ').Append((min / 1000.0).ToString("N0")).Append("ms"); lastLine.Append(' ', (buckets.Length + 2) - lastLine.Length - 1); lastLine.Append('▲').Append(' ').Append((max / 1000.0).ToString("N0")).Append("ms"); columnWidth = Math.Max(columnWidth, lastLine.Length + gutter); if (columnWidth > firstLineLength) graph.Append(' ', columnWidth - firstLineLength); graph.AppendLine("Percentage of the applications processed within a certain time (ms)"); for (int row = 0; row < rows; row++) { // │┌┐└┘─ graph.Append('│'); for (int col = 0; col < buckets.Length; col++) { if (buckets[col] > (rowHeight * (rows - (row + 1)) + rowHeight / 2.0)) graph.Append('█'); else if (buckets[col] > rowHeight * (rows - (row + 1))) graph.Append('▄'); else if (row == rows - 1) graph.Append('_'); else graph.Append(' '); } graph.Append('│'); graph.Append(' ', columnWidth - (buckets.Length + 2)); switch (row) { case 0: graph.Append(" 100% ").Append((max / 1000.0).ToString("N0")); break; case 1: graph.Append(" 95% ").Append((sortedResults[((int)Math.Floor(sortedResults.Length * 0.95))].Duration / 1000.0).ToString("N0")); break; case 2: graph.Append(" 90% ").Append((sortedResults[((int)Math.Floor(sortedResults.Length * .9))].Duration / 1000.0).ToString("N0")); break; case 3: graph.Append(" 80% ").Append((sortedResults[((int)Math.Floor(sortedResults.Length * 0.8))].Duration / 1000.0).ToString("N0")); break; case 4: graph.Append(" 70% ").Append((sortedResults[((int)Math.Floor(sortedResults.Length * 0.7))].Duration / 1000.0).ToString("N0")); break; case 5: graph.Append(" 50% ").Append((sortedResults[((int)Math.Floor(sortedResults.Length * 0.5))].Duration / 1000.0).ToString("N0")); break; } graph.AppendLine(); } int len = graph.Length; graph.Append('└').Append('─', buckets.Length).Append('┘').Append('◄').Append(" 0"); len = graph.Length - len; if (columnWidth > len) graph.Append(' ', columnWidth - len); graph.Append(" 10% ").Append((sortedResults[((int)Math.Floor(sortedResults.Length * .1))].Duration / 1000.0).ToString("N0")); graph.AppendLine(); lastLine.Append(' ', columnWidth - lastLine.Length); lastLine.Append(" 1% ").Append((sortedResults[((int)Math.Floor(sortedResults.Length * .01))].Duration / 1000.0).ToString("N0")); graph.Append(lastLine.ToString()); TraceSources.TemplateSource.TraceVerbose(graph.ToString()); } var resourceStats = resultGroups[typeof(ResourceDeployment)]; foreach (var statGroup in resourceStats) { TraceSources.TemplateSource.TraceInformation("Deployed resource '{0}' in {1:N0} ms", ((ResourceDeployment)statGroup.WorkUnit).ResourcePath, statGroup.Duration); } TraceSources.TemplateSource.TraceInformation("Documentation generated in {0:N1} seconds (processing time: {1:N1} seconds)", timer.Elapsed.TotalSeconds, results.Sum(ps => ps.Duration) / 1000000.0); TraceSources.TemplateSource.TraceInformation("Statistics generated in {0:N1} seconds", statsTimer.Elapsed.TotalSeconds); return new TemplateOutput(results.ToArray(), tmpl.TemporaryFiles); }
protected virtual IEnumerable<StylesheetApplication> DiscoverWork(TemplateData templateData, XPathVariable[] parameters, Stylesheet stylesheet) { TraceSources.TemplateSource.TraceInformation("Processing stylesheet instructions: {0}", (object)stylesheet.Name); CustomXsltContext xpathContext = CreateCustomXsltContext(templateData.IgnoredVersionComponent); xpathContext.PushVariableScope(templateData.Document.Root, parameters); // 1 XElement[] inputElements = templateData.Document.XPathSelectElements(stylesheet.SelectExpression, xpathContext).ToArray(); foreach (XElement inputElement in inputElements) { xpathContext.PushVariableScope(inputElement, stylesheet.Variables); // 2 string saveAs = ResultToString(inputElement.XPathEvaluate(stylesheet.OutputExpression, xpathContext)); string version = ResultToString(inputElement.XPathEvaluate(stylesheet.VersionExpression, xpathContext)); string assetId = ResultToString(inputElement.XPathEvaluate(stylesheet.AssetIdExpression, xpathContext)); List<AssetIdentifier> aliases = new List<AssetIdentifier>(); List<AssetSection> sections = new List<AssetSection>(); // eval condition, shortcut and log instead of wrapping entire loop in if if (!EvalCondition(xpathContext, inputElement, stylesheet.ConditionExpression)) { TraceSources.TemplateSource.TraceVerbose("{0}, {1} => Condition not met", assetId, version); xpathContext.PopVariableScope(); // 2 continue; } Uri newUri = new Uri(saveAs, UriKind.RelativeOrAbsolute); // register url this._fileResolver.Add(assetId, new Version(version), ref newUri); TraceSources.TemplateSource.TraceVerbose("{0}, {1} => {2}", assetId, version, newUri.ToString()); // aliases foreach (AliasRegistration alias in stylesheet.AssetAliases) { XElement[] aliasInputElements = inputElement.XPathSelectElements(alias.SelectExpression, xpathContext).ToArray(); foreach (XElement aliasInputElement in aliasInputElements) { xpathContext.PushVariableScope(aliasInputElement, alias.Variables); // 3 string aliasVersion = ResultToString(aliasInputElement.XPathEvaluate(alias.VersionExpression, xpathContext)); string aliasAssetId = ResultToString(aliasInputElement.XPathEvaluate(alias.AssetIdExpression, xpathContext)); // eval condition if (EvalCondition(xpathContext, aliasInputElement, alias.ConditionExpression)) { this._fileResolver.Add(aliasAssetId, new Version(aliasVersion), newUri); aliases.Add(AssetIdentifier.Parse(aliasAssetId)); TraceSources.TemplateSource.TraceVerbose("{0}, {1} (Alias) => {2}", aliasAssetId, aliasVersion, newUri.ToString()); } else { TraceSources.TemplateSource.TraceVerbose("{0}, {1} (Alias) => Condition not met", assetId, version); } xpathContext.PopVariableScope(); // 3 } } // sections foreach (SectionRegistration section in stylesheet.Sections) { XElement[] sectionInputElements = inputElement.XPathSelectElements(section.SelectExpression, xpathContext).ToArray(); foreach (XElement sectionInputElement in sectionInputElements) { xpathContext.PushVariableScope(sectionInputElement, section.Variables); // 4 string sectionName = ResultToString(sectionInputElement.XPathEvaluate(section.NameExpression, xpathContext)); string sectionVersion = ResultToString(sectionInputElement.XPathEvaluate(section.VersionExpression, xpathContext)); string sectionAssetId = ResultToString(sectionInputElement.XPathEvaluate(section.AssetIdExpression, xpathContext)); // eval condition if (EvalCondition(xpathContext, sectionInputElement, section.ConditionExpression)) { Uri sectionUri = new Uri(newUri + "#" + sectionName, UriKind.Relative); this._fileResolver.Add(sectionAssetId, new Version(sectionVersion), sectionUri); TraceSources.TemplateSource.TraceVerbose("{0}, {1}, (Section: {2}) => {3}", sectionAssetId, sectionVersion, sectionName, sectionUri.ToString()); sections.Add(new AssetSection(AssetIdentifier.Parse(sectionAssetId), sectionName, sectionUri)); } else { TraceSources.TemplateSource.TraceVerbose("{0}, {1}, (Section: {2}) => Condition not met", sectionAssetId, sectionVersion, sectionName); } xpathContext.PopVariableScope(); // 4 } } var xsltParams = ResolveXsltParams(stylesheet.XsltParams, inputElement, xpathContext).ToArray(); xpathContext.PopVariableScope(); // 2 yield return new StylesheetApplication { StylesheetName = stylesheet.Name, Asset = new AssetIdentifier(assetId, new Version(version)), Aliases = aliases, /* list of AssetIdentifiers */ Sections = sections, /* list of AssetSection */ SaveAs = newUri.ToString(), Transform = stylesheet.Transform, InputElement = inputElement, XsltParams = xsltParams }; } xpathContext.PopVariableScope(); // 1 }
public override void Invoke(CompositionContainer container) { var traceListener = new ConsolidatedConsoleTraceListener { { TraceSources.TemplateSource, "Template" }, { TraceSources.BundleSource, "Bundle" }, { TraceSources.AssetResolverSource, "Resolve" } }; using (traceListener) { this.ConfigureTraceLevels(traceListener); LinkedList<FileInfo> includedFiles = new LinkedList<FileInfo>(); if (File.Exists(this.Path)) includedFiles.AddLast(new FileInfo(this.Path)); else if (Directory.Exists(this.Path)) { Directory.GetFiles(this.Path, "*.ldoc", SearchOption.AllDirectories) .Aggregate(includedFiles, (l, f) => l.AddLast(new FileInfo(f)).List); } else throw new FileNotFoundException(System.IO.Path.GetFullPath(this.Path)); Bundle bundle = new Bundle(this.IgnoreVersionComponent); TraceSources.TemplateSource.TraceInformation("Merging LostDoc files into bundle."); foreach (FileInfo file in includedFiles) { TraceSources.TemplateSource.TraceEvent(TraceEventType.Information, 0, "Source: {0}", file.Name); XDocument fileDoc = XDocument.Load(file.FullName); bundle.Add(fileDoc); } var lazyProviders = container.GetExports<IFileProvider>(ContractNames.TemplateProvider); var realProviders = lazyProviders.Select(lazy => lazy.Value); TemplateResolver templateResolver = new TemplateResolver(realProviders.ToArray()); TemplateInfo templateInfo = templateResolver.Resolve(this.Template); Template template = templateInfo.Load(container); string outputDir = this.Output ?? (Directory.Exists(this.Path) ? this.Path : System.IO.Path.GetDirectoryName(this.Path)); AssetRedirectCollection assetRedirects; XDocument mergedDoc = bundle.Merge(out assetRedirects); var templateData = new TemplateData(mergedDoc) { AssetRedirects = assetRedirects, OverwriteExistingFiles = this.Force.IsPresent, IgnoredVersionComponent = this.IgnoreVersionComponent, Arguments = this.Arguments, OutputFileProvider = new ScopedFileProvider(new DirectoryFileProvider(), outputDir) }; template.Generate(templateData); } }
public void Invoke(CompositionContainer container) { var traceListener = new ConsolidatedConsoleTraceListener( new Dictionary<string, string> { { "LostDoc.Core.Template", "Template" }, { "LostDoc.Core.Bundle", "Bundle" }, { "LostDoc.Core.Template.AssetResolver", "Resolve" } }); TraceSources.TemplateSource.Listeners.Add(traceListener); TraceSources.AssetResolverSource.Listeners.Add(traceListener); try { if (this.Quiet.IsPresent) { const SourceLevels quietLevel = SourceLevels.Error | SourceLevels.Warning | SourceLevels.Critical; TraceSources.TemplateSource.Switch.Level = quietLevel; TraceSources.AssetResolverSource.Switch.Level = quietLevel; TraceSources.BundleSource.Listeners.Add(traceListener); } else if (this.Verbose.IsPresent) { const SourceLevels verboseLevel = SourceLevels.All; TraceSources.TemplateSource.Switch.Level = verboseLevel; TraceSources.AssetResolverSource.Switch.Level = verboseLevel; TraceSources.BundleSource.Listeners.Add(traceListener); } else { const SourceLevels normalLevel = SourceLevels.Information | SourceLevels.Warning | SourceLevels.Error | SourceLevels.ActivityTracing; TraceSources.TemplateSource.Switch.Level = normalLevel; TraceSources.AssetResolverSource.Switch.Level = normalLevel; } LinkedList<FileInfo> includedFiles = new LinkedList<FileInfo>(); if (File.Exists(this.Path)) includedFiles.AddLast(new FileInfo(this.Path)); else if (Directory.Exists(this.Path)) { Directory.GetFiles(this.Path, "*.ldoc", SearchOption.AllDirectories) .Aggregate(includedFiles, (l, f) => l.AddLast(new FileInfo(f)).List); } else throw new FileNotFoundException(System.IO.Path.GetFullPath(this.Path)); Bundle bundle = new Bundle(this.IgnoreVersionComponent); TraceSources.TemplateSource.TraceInformation("Merging LostDoc files into bundle."); foreach (FileInfo file in includedFiles) { TraceSources.TemplateSource.TraceEvent(TraceEventType.Information, 0, "Source: {0}", file.Name); XDocument fileDoc = XDocument.Load(file.FullName); bundle.Add(fileDoc); } var lazyProviders = container.GetExports<IFileProvider>(ContractNames.TemplateProvider); var realProviders = lazyProviders.Select(lazy => lazy.Value); TemplateResolver templateResolver = new TemplateResolver(realProviders.ToArray()); Template template = new Template(container); template.Load(templateResolver, this.Template); string outputDir = this.Output ?? (Directory.Exists(this.Path) ? this.Path : System.IO.Path.GetDirectoryName(this.Path)); AssetRedirectCollection assetRedirects; XDocument mergedDoc = bundle.Merge(out assetRedirects); var templateData = new TemplateData(mergedDoc) { AssetRedirects = assetRedirects, OverwriteExistingFiles = this.Force.IsPresent, IgnoredVersionComponent = this.IgnoreVersionComponent, Arguments = this.Arguments, OutputFileProvider = new ScopedFileProvider(new DirectoryFileProvider(), outputDir) }; template.Generate(templateData); } finally { TraceSources.TemplateSource.Listeners.Remove(traceListener); TraceSources.AssetResolverSource.Listeners.Remove(traceListener); } }
private IEnumerable<UnitOfWork> DiscoverWork(TemplateData templateData, XPathVariable[] parameters, Resource[] resources) { CustomXsltContext xpathContext = CreateCustomXsltContext(templateData.IgnoredVersionComponent); xpathContext.PushVariableScope(templateData.Document.Root, parameters); for (int i = 0; i < resources.Length; i++) { xpathContext.PushVariableScope(templateData.Document.Root, resources[i].Variables); if (EvalCondition(xpathContext, templateData.Document.Root, resources[i].ConditionExpression)) { List<IResourceTransform> transforms = new List<IResourceTransform>(); foreach (var resourceTransform in resources[i].Transforms) { CompositionContainer paramContainer = new CompositionContainer(this._container); // TODO export resourceTransform.Parameters into paramContainer ImportDefinition importDefinition = new MetadataContractBasedImportDefinition( typeof(IResourceTransform), null, new[] {new Tuple<string, object, IEqualityComparer>("Name", resourceTransform.Name, StringComparer.OrdinalIgnoreCase) }, ImportCardinality.ExactlyOne, false, false, CreationPolicy.NonShared); Export transformExport = paramContainer.GetExports(importDefinition).Single(); transforms.Add((IResourceTransform)transformExport.Value); } yield return new ResourceDeployment(resources[i].FileProvider, resources[i].Source, resources[i].Output, // TODO this needs a 'writable' file provider transforms.ToArray()); } xpathContext.PopVariableScope(); } xpathContext.PopVariableScope(); }
public TemplatingContext(ObjectCache cache, CompositionContainer container, IFileProvider outputFileProvider, TemplateData data, IEnumerable <IAssetUriResolver> resolvers, IFileProvider templateFileProvider) { this.Container = container; this.OutputFileProvider = outputFileProvider; this.TemplateData = data; this.AssetUriResolvers = resolvers.ToArray(); this.TemplateFileProvider = templateFileProvider; this.Cache = cache; XPathDocument xpathDoc; using (var reader = data.Document.CreateReader(ReaderOptions.OmitDuplicateNamespaces)) xpathDoc = new XPathDocument(reader); this.Document = xpathDoc.CreateNavigator(); this.DocumentIndex = new XPathNavigatorIndex(this.Document.Clone()); }