/// <inheritdoc/> public void Execute(ExecutionContext context) { var mrefConfigPath = Path.Combine(builder.WorkingFolder, "MRefBuilder.config"); var mrefConfig = XDocument.Load(mrefConfigPath); var xamlAttachedMembersAddInElement = ( from addin in mrefConfig.Descendants("addin") where (String)addin.Attribute("type") == "Microsoft.Ddue.Tools.XamlAttachedMembersAddIn" select addin).SingleOrDefault(); xamlAttachedMembersAddInElement.ReplaceNodes( new XElement("dependencyPropertyTypeName", "TwistedLogik.Ultraviolet.UI.Presentation.DependencyProperty"), new XElement("dependencyPropertySuffix", "Property"), new XElement("routedEventTypeName", "TwistedLogik.Ultraviolet.UI.Presentation.RoutedEvent"), new XElement("routedEventSuffix", "Event")); mrefConfig.Save(mrefConfigPath); builder.ReportProgress("Configured MRefBuilder to use Ultraviolet Presentation Foundation dependency system types."); }
/// <inheritdoc /> public void Execute(ExecutionContext context) { // Look up the resize tool tip in the shared content resource items file if(context.BuildStep == BuildStep.GenerateSharedContent) { string sharedContentFile = Directory.EnumerateFiles(builder.PresentationStyleResourceItemsFolder, "shared*content*", SearchOption.AllDirectories).FirstOrDefault(); if(sharedContentFile != null) { XDocument doc = XDocument.Load(sharedContentFile); var toolTip = doc.XPathSelectElement("content/item[@id='resizeToolTip']"); if(toolTip != null) resizeToolTip = toolTip.Value; } if(String.IsNullOrWhiteSpace(resizeToolTip)) { builder.ReportWarning("LWW0001", "Unable to locate resizeToolTip resource item. " + "Using default text."); resizeToolTip = "Click or drag to resize"; } return; } builder.ReportProgress("Adding lightweight search and TOC elements to each topic..."); // Load the web TOC generated by SandcastleHtmlExtract XDocument webtoc = XDocument.Load(Path.Combine(builder.WorkingFolder, "WebTOC.xml")); // Remove the Id attribute from all nodes that contain a Url attribute foreach(XElement element in webtoc.XPathSelectElements("//node()[@Id and @Url]")) element.Attribute("Id").Remove(); // Generate the TOC fragments Directory.CreateDirectory(Path.Combine(builder.WorkingFolder, "Output", "Website", "toc")); List<XElement> elements = new List<XElement>(webtoc.XPathSelectElements("//node()")); // Work around the problem of the root node only showing one type if there are no conceptual topics // or they are listed after the namespaces. In such cases, expand the root node so that all // namespaces are listed on the default page. This avoids confusion caused by only seeing one // namespace when the root node is collapsed by default. var firstElement = webtoc.Root.Elements().First(); Parallel.ForEach(elements, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 20 }, element => { XDocument pageChildren = new XDocument(new XDeclaration("1.0", "utf-8", null)); XElement copy = new XElement(element); pageChildren.Add(copy); foreach(XElement child in copy.Elements()) { if(!child.HasElements) continue; child.SetAttributeValue("HasChildren", true); child.RemoveNodes(); } string uri = null; if(copy.Attribute("Url") != null) uri = copy.Attribute("Url").Value; else if(copy.Attribute("Id") != null) uri = copy.Attribute("Id").Value; else if(copy.Name.LocalName == "HelpTOC") uri = "roottoc.html"; else throw new NotImplementedException(); string fileId = Path.GetFileNameWithoutExtension(uri.Substring(uri.LastIndexOf('/') + 1)); if(element.HasElements) { using(XmlWriter writer = XmlWriter.Create(Path.Combine(builder.WorkingFolder, "Output", "Website", "toc", fileId + ".xml"))) { pageChildren.WriteTo(writer); } } if(string.IsNullOrEmpty((string)copy.Attribute("Url"))) return; // Generate the lightweight TOC pane XElement current = element; IEnumerable<XElement> parents = current.XPathSelectElements("parent::HelpTOCNode/ancestor::HelpTOCNode"); XElement parent = current.XPathSelectElement("parent::HelpTOCNode"); IEnumerable<XElement> siblings = current.Parent.Elements("HelpTOCNode"); IEnumerable<XElement> children = current.Elements("HelpTOCNode"); XElement tocNav = new XElement("div", new XAttribute("id", "tocNav")); // The documentation root tocNav.Add(GenerateTocRoot(parent == null && !children.Any())); // All the ancestors *except* the immediate parent, always collapsed by default foreach(XElement ancestor in parents) tocNav.Add(GenerateTocAncestor(ancestor, 0, false)); // The immediate parent is expanded if the current node has no children if(parent != null) { bool expanded = !current.HasElements; int level = expanded ? 1 : 0; tocNav.Add(GenerateTocAncestor(parent, level, expanded)); } // The siblings of the current node are shown if the parent is expanded, otherwise only the // current node is shown. foreach(XElement sibling in siblings) { bool showSiblings; int level; if(parent == null && !current.HasElements) { showSiblings = true; level = 1; } else { showSiblings = !current.HasElements; level = current.HasElements || parent == null ? 1 : 2; } tocNav.Add(GenerateTocSibling(current, sibling, level, showSiblings)); } // The children of the current node, if any exist, are always shown by default foreach(XElement child in children) tocNav.Add(GenerateTocChild(child)); XElement resizableBar = new XElement("div", new XAttribute("id", "tocResizableEW"), new XAttribute("onmousedown", "OnMouseDown(event);"), // Add empty text to force full start/end element. This allows for proper display in the // browser while still allowing XHTML output that's valid for post-processing. new XText(String.Empty)); XElement resizeUi = new XElement("div", new XAttribute("id", "TocResize"), new XAttribute("class", "tocResize"), new XElement("img", new XAttribute("id", "ResizeImageIncrease"), new XAttribute("src", "../icons/TocOpen.gif"), new XAttribute("onclick", "OnIncreaseToc()"), new XAttribute("alt", resizeToolTip), new XAttribute("title", resizeToolTip)), new XElement("img", new XAttribute("id", "ResizeImageReset"), new XAttribute("src", "../icons/TocClose.gif"), new XAttribute("style", "display:none"), new XAttribute("onclick", "OnResetToc()"), new XAttribute("alt", resizeToolTip), new XAttribute("title", resizeToolTip))); XElement leftNav = new XElement("div", new XAttribute("class", "leftNav"), new XAttribute("id", "leftNav"), tocNav, resizableBar, resizeUi); string path = Path.Combine(builder.WorkingFolder, @"Output\Website", current.Attribute("Url").Value); string outputFile = File.ReadAllText(path, Encoding.UTF8); // Search box int pos = outputFile.IndexOf("<div class=\"pageHeader\"", StringComparison.Ordinal); if(pos != -1) { pos = outputFile.IndexOf("</div>", pos, StringComparison.Ordinal); if(pos != -1) outputFile = outputFile.Insert(pos, "<form id=\"SearchForm\" method=\"get\" " + "action=\"#\" onsubmit=\"javascript:TransferToSearchPage(); return false;\">" + "<input id=\"SearchTextBox\" type=\"text\" maxlength=\"200\" />" + "<button id=\"SearchButton\" type=\"submit\"></button>" + "</form>"); } // Left nav pos = outputFile.IndexOf("<div class=\"topicContent\"", StringComparison.Ordinal); if(pos != -1) outputFile = outputFile.Insert(pos, leftNav.ToString(SaveOptions.DisableFormatting)); if(element == firstElement && firstElement.HasElements) { outputFile = outputFile.Replace("</html>", @"<script type=""text/javascript""> <!-- var tocNav = document.getElementById(""tocNav""); var anchor = tocNav.children[0].children[0]; Toggle(anchor); tocNav.children[0].className += "" current""; --> </script> </html>"); } File.WriteAllText(path, outputFile, Encoding.UTF8); }); }
/// <summary> /// Execute all plug-ins that need to execute in the given build step that have the given execution /// behavior. /// </summary> /// <param name="behavior">The execution behavior</param> /// <returns>True if at least one plug-in was executed or false if no plug-ins were executed.</returns> /// <remarks>Plug-ins will execute based on their execution priority. Those with a higher priority value /// will execute before those with a lower value. Plug-ins with identical priority values may execute /// in any order within their group.</remarks> private bool ExecutePlugIns(ExecutionBehaviors behavior) { List<IPlugIn> executeList; ExecutionContext context; BuildStep step; int numberExecuted = 0; if(loadedPlugIns == null) return false; step = progressArgs.BuildStep; // Find plug-ins that need to be executed executeList = loadedPlugIns.Values.Where(p => p.ExecutionPoints.RunsAt(step, behavior)).ToList(); if(executeList.Count == 0) return false; // Sort by execution priority in descending order executeList.Sort((x, y) => y.ExecutionPoints.PriorityFor(step, behavior) - x.ExecutionPoints.PriorityFor(step, behavior)); context = new ExecutionContext(step, behavior); foreach(IPlugIn plugIn in executeList) { var metadata = (HelpFileBuilderPlugInExportAttribute)plugIn.GetType().GetCustomAttributes( typeof(HelpFileBuilderPlugInExportAttribute), false).First(); try { // Wrap plug-in output in an element so that it can be formatted differently swLog.WriteLine("<plugIn name=\"{0}\" behavior=\"{1}\" priority=\"{2}\">", metadata.Id, behavior, plugIn.ExecutionPoints.PriorityFor(step, behavior)); context.Executed = true; plugIn.Execute(context); swLog.Write("</plugIn>"); } catch(Exception ex) { swLog.WriteLine("</plugIn>"); throw new BuilderException("BE0029", "Unexpected error while executing plug-in '" + metadata.Id + "': " + ex.ToString(), ex); } if(context.Executed) numberExecuted++; } return (numberExecuted != 0); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { Project msBuildProject = null; ProjectItem projectItem; Dictionary<string, string> assemblies = new Dictionary<string, string>(); string filename, projectFile = builder.WorkingFolder + "GenerateRefInfo.proj"; // If the project doesn't exist we have nothing to do. However, it could be that some other plug-in // has bypassed it so only issue a warning. if(!File.Exists(projectFile)) { builder.ReportWarning("WRP0003", "The reflection information generation project '{0}' could " + "not be found. The Wildcard References plug-in did not run.", projectFile); return; } // Find all unique references foreach(var r in referencePaths) foreach(string fullPath in Directory.EnumerateFiles(r.ReferencePath, r.Wildcard, (r.Recursive) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)) { filename = Path.GetFileNameWithoutExtension(fullPath); // "mscorlib" is ignored as it causes MRefBuilder to reset its target platform information. // For something like Silverlight, that probably isn't what we want it to do so we'll ignore // it. It'll use what is passed in the platform configuration file option. if(!assemblies.ContainsKey(filename) && !filename.Equals("mscorlib", StringComparison.OrdinalIgnoreCase)) assemblies.Add(filename, fullPath); } builder.ReportProgress("Adding wildcard references"); try { msBuildProject = new Project(projectFile); // Remove references that are already there foreach(ProjectItem r in msBuildProject.GetItems("Reference")) if(assemblies.ContainsKey(r.EvaluatedInclude)) { builder.ReportProgress(" Skipping {0} ({1}) as it appears to already be present", r.EvaluatedInclude, assemblies[r.EvaluatedInclude]); assemblies.Remove(r.EvaluatedInclude); } // Add the remaining references foreach(var r in assemblies) { projectItem = msBuildProject.AddItem("Reference", r.Key)[0]; projectItem.SetMetadataValue(BuildItemMetadata.HintPath, r.Value); builder.ReportProgress(" Added reference {0} ({1})", r.Key, r.Value); } msBuildProject.Save(projectFile); } finally { // If we loaded it, we must unload it. If not, it is cached and may cause problems later. if(msBuildProject != null) { ProjectCollection.GlobalProjectCollection.UnloadProject(msBuildProject); ProjectCollection.GlobalProjectCollection.UnloadProject(msBuildProject.Xml); } } }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { builder.ReportProgress("Multilanguage Documentation Support ..."); if (targetLanguage == null || targetLanguage.Length == 0) { builder.ReportProgress("No target language was specified."); goto DONE; } builder.ReportProgress("Target language = {0}", targetLanguage); foreach (XmlCommentsFile commentsFile in builder.CommentsFiles) { // Collect elements which have language tags. List<XmlNode> docNodeList = new List<XmlNode>(); foreach (XmlNode docNode in commentsFile.Comments.SelectNodes("doc/members/member//*[en|ja|" + targetLanguage + "]")) { docNodeList.Add(docNode); } // Process each element. bool modified = false; foreach (XmlNode docNode in docNodeList) { // Collect language tags. List<XmlNode> langNodes = new List<XmlNode>(); bool hasEnglishDoc = false; bool hasTargetDoc = false; foreach (XmlNode langNode in docNode.ChildNodes) { if (IsLangTag(langNode)) { langNodes.Add(langNode); if (langNode.LocalName == ENGLISH_TAG_NAME) hasEnglishDoc = true; if (langNode.LocalName == targetLanguage) hasTargetDoc = true; } } // Determine which language to leave. string languageToLeave; if (hasTargetDoc) { languageToLeave = targetLanguage; } else if (hasEnglishDoc) { languageToLeave = ENGLISH_TAG_NAME; builder.ReportProgress("Missing target language ... use {0} : {1}", languageToLeave, GetMemberName(docNode)); } else if (langNodes.Count > 0) { languageToLeave = langNodes[0].LocalName; } else { languageToLeave = null; builder.ReportProgress("No language tag : {0}", GetMemberName(docNode)); } // Strip targeted language tag, and remove other language tags. if (languageToLeave != null) { foreach (XmlNode langNode in langNodes) { if (langNode.LocalName == languageToLeave) { StripLangTag(docNode, langNode); modified = true; } else { docNode.RemoveChild(langNode); modified = true; } } } } if (modified) { commentsFile.Save(); } } DONE: builder.ReportProgress("Multilanguage Documentation Support Done."); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> /// <remarks>Since this runs after completion of the build and the log file is closed, any progress /// messages reported here will not appear in it, just in the output window on the main form.</remarks> public void Execute(ExecutionContext context) { MailMessage msg = null; string logFilename = null; // There is nothing to do on completion if there is no success e-mail address if(context.BuildStep == BuildStep.Completed && successEMailAddress.Length == 0) { context.Executed = false; return; } try { logFilename = builder.LogFilename; // Run the log file through an XSL transform first? if(!String.IsNullOrEmpty(xslTransformFile) && File.Exists(logFilename)) logFilename = this.TransformLogFile(); msg = new MailMessage(); msg.IsBodyHtml = false; msg.Subject = String.Format(CultureInfo.InvariantCulture, "Build {0}: {1}", context.BuildStep, builder.ProjectFilename); if(fromEMailAddress.Length != 0) msg.From = new MailAddress(fromEMailAddress); else msg.From = new MailAddress("*****@*****.**"); if(context.BuildStep == BuildStep.Completed) { msg.To.Add(successEMailAddress); if(attachLogOnSuccess && File.Exists(logFilename)) msg.Attachments.Add(new Attachment(logFilename)); } else { msg.To.Add(failureEMailAddress); if(attachLogOnFailure && File.Exists(logFilename)) msg.Attachments.Add(new Attachment(logFilename)); } msg.Body = String.Format(CultureInfo.InvariantCulture, "Build {0}: {1}{2}\r\nBuild output is located at {3}\r\n", context.BuildStep, builder.ProjectFolder, builder.ProjectFilename, builder.OutputFolder); if(context.BuildStep != BuildStep.Completed || builder.CurrentProject.KeepLogFile) msg.Body += "Build details can be found in the log file " + builder.LogFilename + "\r\n"; using(SmtpClient smtp = new SmtpClient()) { if(smtpServer.Length != 0) { smtp.Host = smtpServer; smtp.Port = smtpPort; } if(!credentials.UseDefaultCredentials) smtp.Credentials = new NetworkCredential(credentials.UserName, credentials.Password); smtp.Send(msg); } builder.ReportProgress("The build notification e-mail was sent successfully to {0}", msg.To[0].Address); } catch(FormatException) { builder.ReportProgress("Failed to send build notification e-mail! The e-mail addresses " + "'{0}' appears to be invalid.", msg.To[0]); } catch(SmtpFailedRecipientException recipEx) { builder.ReportProgress("Failed to send build notification e-mail! A problem occurred trying " + "to send the e-mail to the recipient '{0}': {1}", recipEx.FailedRecipient, recipEx.Message); } catch(SmtpException smtpEx) { System.Diagnostics.Debug.WriteLine(smtpEx.ToString()); builder.ReportProgress("Failed to send build notification e-mail! A problem occurred trying " + "to connect to the e-mail server. Details:\r\n{0}\r\n", smtpEx.ToString()); } finally { if(msg != null) msg.Dispose(); // Delete the transformed log file if it exists if(!String.IsNullOrEmpty(logFilename) && logFilename.EndsWith(".html", StringComparison.OrdinalIgnoreCase)) File.Delete(logFilename); } }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(SandcastleBuilder.Utils.BuildComponent.ExecutionContext context) { Encoding enc = Encoding.Default; Thread browserThread; XmlDocument sharedContent; XPathNavigator navContent, item; XmlCommentsFile comments; string sharedContentFilename, workingPath, content; // Copy any XML comments files from the project to the working folder. Solutions, projects, and // assemblies are ignored as they won't be used with this build type. if (context.BuildStep == BuildStep.ValidatingDocumentationSources) { builder.ExecuteBeforeStepPlugIns(); foreach (DocumentationSource ds in builder.CurrentProject.DocumentationSources) { foreach (string commentsName in DocumentationSource.CommentsFiles(ds.SourceFile, ds.IncludeSubFolders)) { workingPath = builder.WorkingFolder + Path.GetFileName(commentsName); // Warn if there is a duplicate and copy the comments file to a unique name to preserve // its content. if (File.Exists(workingPath)) { workingPath = builder.WorkingFolder + Guid.NewGuid().ToString("B"); builder.ReportWarning("BE0063", "'{0}' matches a previously copied comments " + "filename. The duplicate will be copied to a unique name to preserve the " + "comments it contains.", commentsName); } File.Copy(commentsName, workingPath, true); File.SetAttributes(workingPath, FileAttributes.Normal); // Add the file to the XML comments file collection comments = new XmlCommentsFile(workingPath); builder.CommentsFiles.Add(comments); builder.ReportProgress(" {0} -> {1}", commentsName, workingPath); } } builder.ExecuteAfterStepPlugIns(); return; } // Remove the version information items from the shared content file as the AjaxDoc reflection file // doesn't contain version information. if (context.BuildStep == BuildStep.GenerateSharedContent) { builder.ReportProgress("Removing version information items from shared content file"); sharedContentFilename = builder.WorkingFolder + "SHFBContent.xml"; sharedContent = new XmlDocument(); sharedContent.Load(sharedContentFilename); navContent = sharedContent.CreateNavigator(); item = navContent.SelectSingleNode("content/item[@id='locationInformation']"); if (item != null) { item.DeleteSelf(); } item = navContent.SelectSingleNode("content/item[@id='assemblyNameAndModule']"); if (item != null) { item.DeleteSelf(); } sharedContent.Save(sharedContentFilename); return; } builder.ReportProgress("Using project '{0}'", projectName); if (regenerateFiles) { // Regenerate the files first. This is done by starting a thread to invoke the AjaxDoc // application via a web browser control. This is necessary as the browser control needs to run // in a thread with a single-threaded apartment state. We can't just request the page as AjaxDoc // has to post back to itself in order to store the generated information. builder.ReportProgress("Generating XML comments and reflection information via AjaxDoc"); browserThread = new Thread(RunBrowser); browserThread.SetApartmentState(ApartmentState.STA); navCount = 0; browserThread.Start(); if (!browserThread.Join(11000)) { browserThread.Abort(); } if (!String.IsNullOrEmpty(errorText)) { throw new BuilderException("ADP0003", "AjaxDoc encountered a scripting error: " + errorText); } if (commentsFile == null || reflectionFile == null) { throw new BuilderException("ADP0004", "Unable to produce comments file and/or reflection file"); } builder.ReportProgress("Generated comments file '{0}' and reflection file '{1}'", commentsFile, reflectionFile); } else { // Use the existing files commentsFile = "Output/" + projectName + ".xml"; reflectionFile = "Output/" + projectName + ".org"; builder.ReportProgress("Using existing XML comments file '{0}' and reflection information " + "file '{1}'", commentsFile, reflectionFile); } // Allow Before step plug-ins to run builder.ExecuteBeforeStepPlugIns(); // Download the files using (WebClient webClient = new WebClient()) { webClient.UseDefaultCredentials = userCreds.UseDefaultCredentials; if (!userCreds.UseDefaultCredentials) { webClient.Credentials = new NetworkCredential(userCreds.UserName, userCreds.Password); } webClient.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); if (proxyCreds.UseProxyServer) { webClient.Proxy = new WebProxy(proxyCreds.ProxyServer, true); if (!proxyCreds.Credentials.UseDefaultCredentials) { webClient.Proxy.Credentials = new NetworkCredential(proxyCreds.Credentials.UserName, proxyCreds.Credentials.Password); } } // Since there are only two, download them synchronously workingPath = builder.WorkingFolder + projectName + ".xml"; builder.ReportProgress("Downloading {0}", commentsFile); webClient.DownloadFile(ajaxDocUrl + commentsFile, workingPath); builder.CommentsFiles.Add(new XmlCommentsFile(workingPath)); builder.ReportProgress("Downloading {0}", reflectionFile); webClient.DownloadFile(ajaxDocUrl + reflectionFile, builder.ReflectionInfoFilename); builder.ReportProgress("Downloads completed successfully"); } // AjaxDoc 1.1 prefixes all member names with "J#" which causes BuildAssembler's // ResolveReferenceLinksComponent component in the Sept 2007 CTP to crash. As such, we'll strip it // out. I can't see a need for it anyway. content = BuildProcess.ReadWithEncoding(workingPath, ref enc); content = content.Replace(":J#", ":"); using (StreamWriter sw = new StreamWriter(workingPath, false, enc)) { sw.Write(content); } content = BuildProcess.ReadWithEncoding(builder.ReflectionInfoFilename, ref enc); content = content.Replace(":J#", ":"); using (StreamWriter sw = new StreamWriter(builder.ReflectionInfoFilename, false, enc)) { sw.Write(content); } builder.ReportProgress("Applying visibility settings manually"); builder.ApplyVisibilityProperties(builder.ReflectionInfoFilename); // Don't apply the API filter settings in a partial build if (builder.PartialBuildType == PartialBuildType.None && builder.BuildApiFilter.Count != 0) { builder.ReportProgress("Applying API filter manually"); builder.ApplyManualApiFilter(builder.BuildApiFilter, builder.ReflectionInfoFilename); } // Allow After step plug-ins to run builder.ExecuteAfterStepPlugIns(); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { string configFilename; // Merge the reflection file info into conceptual.config configFilename = builder.WorkingFolder + "conceptual.config"; if(File.Exists(configFilename)) this.AddBibliographyParameter(configFilename); // Merge the reflection file info into sancastle.config configFilename = builder.WorkingFolder + "sandcastle.config"; if(File.Exists(configFilename)) this.AddBibliographyParameter(configFilename); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { XmlDocument config = new XmlDocument(); XmlAttribute attr; XmlNode resolver, ddue, ignoreNode, assemblyNode; config.Load(builder.WorkingFolder + "MRefBuilder.config"); resolver = config.SelectSingleNode("configuration/dduetools/resolver"); if(resolver == null) { ddue = config.SelectSingleNode("configuration/dduetools"); if(ddue == null) throw new BuilderException("ABR0002", "Unable to locate configuration/dduetools or its " + "child resolver element in MRefBuilder.config"); builder.ReportProgress("Default resolver element not found, adding new element"); resolver = config.CreateNode(XmlNodeType.Element, "resolver", null); ddue.AppendChild(resolver); attr = config.CreateAttribute("type"); attr.Value = "Microsoft.Ddue.Tools.Reflection.AssemblyResolver"; resolver.Attributes.Append(attr); attr = config.CreateAttribute("assembly"); attr.Value = builder.SubstitutionTags.TransformText(@"{@SHFBFolder}MRefBuilder.exe"); resolver.Attributes.Append(attr); attr = config.CreateAttribute("use-gac"); attr.Value = "false"; resolver.Attributes.Append(attr); } // Allow turning GAC resolution on resolver.Attributes["use-gac"].Value = useGac.ToString().ToLowerInvariant(); if(redirects.Count != 0) { builder.ReportProgress("Adding binding redirections to assembly resolver configuration:"); foreach(BindingRedirectSettings brs in redirects) builder.ReportProgress(" {0}", brs); redirects.ToXml(config, resolver, false); } if(ignoreIfUnresolved.Count != 0) { builder.ReportProgress("Adding ignored assembly names to assembly resolver configuration:"); ignoreNode = resolver.SelectSingleNode("ignoreIfUnresolved"); if(ignoreNode == null) { ignoreNode = config.CreateNode(XmlNodeType.Element, "ignoreIfUnresolved", null); resolver.AppendChild(ignoreNode); } else ignoreNode.RemoveAll(); foreach(string ignoreName in ignoreIfUnresolved) { assemblyNode = config.CreateNode(XmlNodeType.Element, "assemblyIdentity", null); ignoreNode.AppendChild(assemblyNode); attr = config.CreateAttribute("name"); attr.Value = ignoreName; assemblyNode.Attributes.Append(attr); builder.ReportProgress(" {0}", ignoreName); } } config.Save(builder.WorkingFolder + "MRefBuilder.config"); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { XmlDocument toc; XPathNavigator root, navToc, tocEntry, tocParent; bool hasParent; // Scan the XML comments files. The files aren't available soon after this step and by now // everything that other plug-ins may have added to the collection should be there. builder.ReportProgress("Searching for comment members containing <tocexclude />..."); foreach(XmlCommentsFile f in builder.CommentsFiles) foreach(XmlNode member in f.Members.SelectNodes("member[count(.//tocexclude) > 0]/@name")) exclusionList.Add(member.Value); builder.ReportProgress("Found {0} members to exclude from the TOC", exclusionList.Count); if(exclusionList.Count == 0) return; builder.ReportProgress("Removing members from the TOC"); toc = new XmlDocument(); toc.Load(builder.WorkingFolder + "toc.xml"); navToc = toc.CreateNavigator(); // If a root namespace container node is present, we need to look in it rather than the document root // node. root = navToc.SelectSingleNode("topics/topic[starts-with(@id, 'R:')]"); if(root == null) root = navToc.SelectSingleNode("topics"); foreach(string id in exclusionList) { tocEntry = root.SelectSingleNode("//topic[@id='" + id + "']"); // Ignore if null, it was probably excluded by the API filter if(tocEntry != null) { // Remove the entry. If this results in the parent being an empty node, remove it too. do { tocParent = tocEntry.Clone(); hasParent = tocParent.MoveToParent(); builder.ReportProgress(" Removing '{0}'", tocEntry.GetAttribute("id", String.Empty)); tocEntry.DeleteSelf(); } while(hasParent && !tocParent.HasChildren); } } toc.Save(builder.WorkingFolder + "toc.xml"); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { if(this.ModifyMRefBuilderConfig()) this.ModifyGenerateRefInfoProject(); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { List<string> namespaceList = new List<string>(); Dictionary<string, XmlNode> namespaceNodes = new Dictionary<string, XmlNode>(); XmlDocument toc; XPathNavigator root, navToc; XmlAttribute attr; XmlNode tocEntry = null, tocParent; string[] parts; string name, parent, topicTitle, referenceContentFile; int parentIdx, childIdx, entriesAdded; builder.ReportProgress("Retrieving namespace topic title from shared content..."); referenceContentFile = Directory.EnumerateFiles(builder.PresentationStyleResourceItemsFolder, "reference*content*", SearchOption.AllDirectories).FirstOrDefault(); if(referenceContentFile != null) { toc = new XmlDocument(); toc.Load(referenceContentFile); tocEntry = toc.SelectSingleNode("content/item[@id='namespaceTopicTitle']"); } if(tocEntry != null) topicTitle = tocEntry.InnerText; else { builder.ReportWarning("HTP0003", "Unable to locate namespace topic title in reference " + "content file. Using default."); topicTitle = "{0} Namespace"; } builder.ReportProgress("Creating namespace hierarchy..."); toc = new XmlDocument(); toc.Load(builder.WorkingFolder + "toc.xml"); navToc = toc.CreateNavigator(); // Get a list of the namespaces. If a root namespace container node is present, we need to look in // it rather than the document root node. root = navToc.SelectSingleNode("topics/topic[starts-with(@id, 'R:')]"); if(root == null) root = navToc.SelectSingleNode("topics"); foreach(XPathNavigator ns in root.Select("topic[starts-with(@id, 'N:')]")) { name = ns.GetAttribute("id", String.Empty); namespaceList.Add(name); namespaceNodes.Add(name, ((IHasXmlNode)ns).GetNode()); } // See if any container nodes need to be created for namespaces with a common root name for(parentIdx = 0; parentIdx < namespaceList.Count; parentIdx++) { parts = namespaceList[parentIdx].Split('.'); // Only do it for namespaces with a minimum number of parts if(parts.Length > minParts) { for(childIdx = minParts; childIdx < parts.Length; childIdx++) { name = String.Join(".", parts, 0, childIdx); if(!namespaceList.Contains(name)) { if(namespaceList.FindAll( ns => ns.StartsWith(name + ".", StringComparison.Ordinal)).Count > 0) { // The nodes will be created later once we know where to insert them namespaceList.Add(name); namespaceNodes.Add(name, null); } } } } } // Sort them in reverse order namespaceList.Sort((n1, n2) => String.Compare(n2, n1, StringComparison.Ordinal)); // If any container namespaces were added, create nodes for them and insert them before the namespace // ahead of them in the list. foreach(string key in namespaceList) if(namespaceNodes[key] == null) { tocEntry = toc.CreateElement("topic"); attr = toc.CreateAttribute("id"); attr.Value = String.Format(CultureInfo.InvariantCulture, topicTitle, (key.Length > 2) ? key.Substring(2) : "Global"); tocEntry.Attributes.Append(attr); parentIdx = namespaceList.IndexOf(key); tocParent = namespaceNodes[namespaceList[parentIdx - 1]]; tocParent.ParentNode.InsertBefore(tocEntry, tocParent); namespaceNodes[key] = tocEntry; } for(parentIdx = 1; parentIdx < namespaceList.Count; parentIdx++) { parent = namespaceList[parentIdx]; entriesAdded = 0; // Check each preceding namespace. If it starts with the parent's name, insert it as a child of // that one. for(childIdx = 0; childIdx < parentIdx; childIdx++) { name = namespaceList[childIdx]; if(name.StartsWith(parent + ".", StringComparison.Ordinal)) { tocEntry = namespaceNodes[name]; tocParent = namespaceNodes[parent]; if(insertBelow && entriesAdded < tocParent.ChildNodes.Count) tocParent.InsertAfter(tocEntry, tocParent.ChildNodes[ tocParent.ChildNodes.Count - entriesAdded - 1]); else tocParent.InsertBefore(tocEntry, tocParent.ChildNodes[0]); namespaceList.RemoveAt(childIdx); entriesAdded++; parentIdx--; childIdx--; } } } toc.Save(builder.WorkingFolder + "toc.xml"); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { string workingPath, configFilename; bool success; if(context.BuildStep == BuildStep.GenerateNamespaceSummaries) { // Merge the additional reference links information builder.ReportProgress("Performing partial builds on additional targets' projects"); // Build each of the projects foreach(ReferenceLinkSettings vs in otherLinks) { using(SandcastleProject tempProject = new SandcastleProject(vs.HelpFileProject, true)) { // Set the configuration and platform here so that they are evaluated properly in project // properties when the project is loaded below. tempProject.Configuration = builder.CurrentProject.Configuration; tempProject.Platform = builder.CurrentProject.Platform; // This looks odd but is necessary. If we are in Visual Studio, the above constructor // may return an instance that uses an underlying MSBuild project loaded in Visual // Studio. Since the BuildProject() method modifies the project, those changes are // propagated to the Visual Studio copy which we do not want to happen. As such, we use // this constructor to clone the MSBuild project XML thus avoiding modifications to the // original project. using(SandcastleProject project = new SandcastleProject(tempProject)) { // We'll use a working folder below the current project's working folder workingPath = builder.WorkingFolder + vs.HelpFileProject.GetHashCode().ToString("X", CultureInfo.InvariantCulture) + "\\"; success = this.BuildProject(project, workingPath); // Switch back to the original folder for the current project Directory.SetCurrentDirectory(builder.ProjectFolder); if(!success) throw new BuilderException("ARL0003", "Unable to build additional target " + "project: " + project.Filename); } } // Save the reflection file location as we need it later vs.ReflectionFilename = workingPath + "reflection.xml"; } return; } if(context.BuildStep == BuildStep.GenerateInheritedDocumentation) { this.MergeInheritedDocConfig(); return; } if(context.BuildStep == BuildStep.CreateBuildAssemblerConfigs) { builder.ReportProgress("Adding additional reference link namespaces..."); var rn = builder.ReferencedNamespaces; HashSet<string> validNamespaces = new HashSet<string>(Directory.EnumerateFiles( builder.FrameworkReflectionDataFolder, "*.xml", SearchOption.AllDirectories).Select( f => Path.GetFileNameWithoutExtension(f))); foreach(ReferenceLinkSettings vs in otherLinks) if(!String.IsNullOrEmpty(vs.ReflectionFilename)) foreach(var n in builder.GetReferencedNamespaces(vs.ReflectionFilename, validNamespaces)) rn.Add(n); return; } // Merge the reflection file info into conceptual.config configFilename = builder.WorkingFolder + "conceptual.config"; if(File.Exists(configFilename)) this.MergeReflectionInfo(configFilename, true); // Merge the reflection file info into sancastle.config configFilename = builder.WorkingFolder + "sandcastle.config"; if(File.Exists(configFilename)) this.MergeReflectionInfo(configFilename, false); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="executionContext">The current execution context</param> public void Execute(ExecutionContext executionContext) { _buildProcess.ReportProgress(Resources.PlugInBuildProgress); var messageReporter = new MessageReporter(_buildProcess); var configuration = new Configuration { OutputFolderPath = _buildProcess.WorkingFolder, DocumentRootSchemas = _configuration.DocumentRootSchemas, DocumentRootElements = _configuration.DocumentRootElements, DocumentConstraints = _configuration.DocumentConstraints, DocumentSchemas = _configuration.DocumentSchemas, DocumentSyntax = _configuration.DocumentSyntax, UseTypeDocumentationForUndocumentedAttributes = _configuration.UseTypeDocumentationForUndocumentedAttributes, UseTypeDocumentationForUndocumentedElements = _configuration.UseTypeDocumentationForUndocumentedElements, SchemaSetContainer = _configuration.SchemaSetContainer, SchemaSetTitle = _configuration.SchemaSetTitle, NamespaceContainer = _configuration.NamespaceContainer, IncludeLinkUriInKeywordK = _configuration.IncludeLinkUriInKeywordK, AnnotationTransformFileName = _configuration.AnnotationTransformFilePath.ExpandedPath, SchemaFileNames = ExpandFiles(_configuration.SchemaFilePaths), SchemaDependencyFileNames = ExpandFiles(_configuration.SchemaDependencyFilePaths), DocFileNames = ExpandFiles(_configuration.DocFilePaths) }; var contentGenerator = new ContentGenerator(messageReporter, configuration); contentGenerator.Generate(); var contentLayoutItem = AddLinkedItem(BuildAction.ContentLayout, contentGenerator.ContentFile); contentLayoutItem.SetMetadataValue("SortOrder", Convert.ToString(_configuration.SortOrder, CultureInfo.InvariantCulture)); foreach (var topicFileName in contentGenerator.TopicFiles) AddLinkedItem(BuildAction.None, topicFileName); foreach (var mediaItem in contentGenerator.MediaItems) { var mediaFileItem = AddLinkedItem(BuildAction.Image, mediaItem.FileName); mediaFileItem.SetMetadataValue("ImageId", mediaItem.ArtItem.Id); mediaFileItem.SetMetadataValue("AlternateText", mediaItem.ArtItem.AlternateText); } var componentConfig = GetComponentConfiguration(contentGenerator.IndexFile); _buildProcess.CurrentProject.ComponentConfigurations.Add(GetComponentId(), true, componentConfig); // Needed so that all links are properly evaluated before processed by SHFB. _tempProject.MSBuildProject.ReevaluateIfNecessary(); // Add the items to the conceptual content settings _buildProcess.ConceptualContent.MergeContentFrom(_tempProject); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { XmlNamespaceManager nsm; XmlDocument project; XmlNode property; string projectFile; // Localize the content when extracting keyword and TOC info if(context.BuildStep == BuildStep.ExtractingHtmlInfo) { // Since we need to localize all of the content, we must manually copy the presentation style // Help 1 content which isn't normally copied until after the current build step. This assumes // that none of the replacement tags in the standard content depend on information generated in // this step (i.e. it wouldn't work for website output in the older presentation styles which // rely on the WebTOC.xml file for the index page). builder.ReportProgress("Copying Help 1 presentation style content ready for localization"); builder.PresentationStyle.CopyHelpContent(HelpFileFormats.HtmlHelp1, String.Format( CultureInfo.InvariantCulture, @"{0}Output\{1}", builder.WorkingFolder, HelpFileFormats.HtmlHelp1), builder.ReportProgress, (name, source, dest) => builder.TransformTemplate(name, source, dest)); builder.ReportProgress("Adding DBCS Fix localization folder"); projectFile = builder.WorkingFolder + "ExtractHtmlInfo.proj"; project = new XmlDocument(); project.Load(projectFile); nsm = new XmlNamespaceManager(project.NameTable); nsm.AddNamespace("MSBuild", project.DocumentElement.NamespaceURI); property = project.SelectSingleNode("//MSBuild:LocalizedFolder", nsm); if(property == null) throw new BuilderException("DFP0004", "Unable to locate LocalizedFolder element in " + "project file"); property.InnerText = @".\Localized"; project.Save(projectFile); return; } if(builder.CurrentFormat != HelpFileFormats.HtmlHelp1) return; builder.ReportProgress("Adding localization options to build task"); projectFile = builder.WorkingFolder + "Build1xHelpFile.proj"; project = new XmlDocument(); project.Load(projectFile); nsm = new XmlNamespaceManager(project.NameTable); nsm.AddNamespace("MSBuild", project.DocumentElement.NamespaceURI); property = project.SelectSingleNode("//MSBuild:WorkingFolder", nsm); if(property == null) throw new BuilderException("DFP0005", "Unable to locate WorkingFolder element in project file"); property.InnerText = @".\Localized"; property = project.SelectSingleNode("//MSBuild:LocalizeApp", nsm); if(property == null) throw new BuilderException("DFP0006", "Unable to locate LocalizeApp element in project file"); property.InnerText = (sbAppLocalePath ?? String.Empty); project.Save(projectFile); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { XmlDocument config; XPathNavigator navConfig, item, deleteItem; bool moreItems = true; string id; if(context.BuildStep == BuildStep.MergeCustomConfigs) { builder.ReportProgress("Removing non-member topics from the build manifest..."); config = new XmlDocument(); config.Load(builder.WorkingFolder + "manifest.xml"); navConfig = config.CreateNavigator(); item = navConfig.SelectSingleNode("topics/topic"); while(item != null && moreItems) { id = item.GetAttribute("id", String.Empty); if(id.Length < 2 || id[1] != ':' || id[0] == 'R' || id[0] == 'G') { deleteItem = item.Clone(); moreItems = item.MoveToNext(); deleteItem.DeleteSelf(); } else moreItems = item.MoveToNext(); } config.Save(builder.WorkingFolder + "manifest.xml"); builder.ReportProgress("Removing irrelevant build components from the configuration file..."); config = new XmlDocument(); config.Load(builder.WorkingFolder + "sandcastle.config"); navConfig = config.CreateNavigator(); // The IntalliSense build component must be there item = navConfig.SelectSingleNode("//component[@id='IntelliSense Component']"); if(item == null) throw new BuilderException("ISO0001", "The IntelliSense Only plug-in requires that the " + "IntelliSense Component be added to the project and configured."); // Remove Syntax Component item = navConfig.SelectSingleNode("//component[@id='Syntax Component']"); if(item != null) item.DeleteSelf(); // Remove Code Block Component item = navConfig.SelectSingleNode("//component[@id='Code Block Component']"); if(item != null) item.DeleteSelf(); // Remove the XSL Transform Component and everything after it item = navConfig.SelectSingleNode("//component[@id='XSL Transform Component']"); moreItems = true; while(item != null && moreItems) { deleteItem = item.Clone(); moreItems = item.MoveToNext(); deleteItem.DeleteSelf(); } config.Save(builder.WorkingFolder + "sandcastle.config"); } // Ignore all other the steps }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { // TODO: Add your execution code here builder.ReportProgress("In $safeprojectname$PlugIn Execute() method"); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { XmlDocument configFile; XmlAttribute attr; XmlNode argument; string configFilename = builder.WorkingFolder + "sandcastle.config"; if(!File.Exists(configFilename)) return; builder.ReportProgress("\r\nAdding bibliography parameter to {0}...", configFilename); configFile = new XmlDocument(); configFile.Load(configFilename); // Find the XSL Transform Components in the configuration file and add a new argument to them: // <argument key="bibliographyData" value="C:\Path\To\bibliography.xml" /> XmlNodeList components = configFile.SelectNodes("//component[@id='XSL Transform Component']/transform"); if(components.Count == 0) throw new BuilderException("BIP0004", "Unable to locate XSL Transform Component configuration in " + configFilename); foreach(XmlNode transform in components) { argument = configFile.CreateElement("argument"); attr = configFile.CreateAttribute("key"); attr.Value = "bibliographyData"; argument.Attributes.Append(attr); attr = configFile.CreateAttribute("value"); attr.Value = bibliographyFile; argument.Attributes.Append(attr); transform.AppendChild(argument); } configFile.Save(configFilename); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { builder.ReportProgress("Fixing up member IDs in comments..."); foreach(var commentsFile in builder.CommentsFiles) { // Use the instance to get the comments in case changes were made elsewhere and not save yet string content = commentsFile.Comments.OuterXml; foreach(var matchExpr in expressions) if(matchExpr.MatchAsRegEx) content = matchExpr.RegularExpression.Replace(content, matchExpr.ReplacementValue); else content = content.Replace(matchExpr.MatchExpression, matchExpr.ReplacementValue); using(StreamWriter sw = new StreamWriter(commentsFile.SourcePath, false, commentsFile.Encoding)) { sw.Write(content); } // Force a reload so that any further references to the content get our updated content commentsFile.ForceReload(); } }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { XmlDocument refInfo = new XmlDocument(); XmlNodeList nodes; refInfo.Load(builder.ReflectionInfoFilename); foreach(string expression in expressions) { builder.ReportProgress("Removing items matching '{0}'", expression); nodes = refInfo.SelectNodes(expression); foreach(XmlNode node in nodes) node.ParentNode.RemoveChild(node); builder.ReportProgress(" Removed {0} items", nodes.Count); } refInfo.Save(builder.ReflectionInfoFilename); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { // Deploy each of the selected help file formats if(builder.CurrentFormat == HelpFileFormats.HtmlHelp1) { builder.ReportProgress("Deploying HTML Help 1 file"); this.DeployOutput(builder.Help1Files, deployHelp1); } if(builder.CurrentFormat == HelpFileFormats.MSHelp2) { builder.ReportProgress("Deploying MS Help 2 files"); this.DeployOutput(builder.Help2Files, deployHelp2); } if(builder.CurrentFormat == HelpFileFormats.MSHelpViewer) { builder.ReportProgress("Deploying MS Help Viewer files"); this.DeployOutput(builder.HelpViewerFiles, deployHelpViewer); } if(builder.CurrentFormat == HelpFileFormats.Website) { builder.ReportProgress("Deploying website files"); this.DeployOutput(builder.WebsiteFiles, deployWebsite); } if(builder.CurrentFormat == HelpFileFormats.OpenXml) { builder.ReportProgress("Deploying Open XML files"); this.DeployOutput(builder.OpenXmlFiles, deployOpenXml); } }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { string workingPath; bool success; // Update shared content version items if(context.BuildStep == BuildStep.GenerateSharedContent) { this.UpdateVersionItems(); return; } // Set the current version's reflection info filename and sort the collection so that the versions // are in ascending order. currentVersion.ReflectionFilename = builder.ReflectionInfoFilename; allVersions.Sort(); // Merge the version information builder.ReportProgress("\r\nPerforming partial builds on prior version projects"); // Build each of the projects foreach(VersionSettings vs in allVersions) { // Not needed for current project if(vs.HelpFileProject == null) continue; using(SandcastleProject tempProject = new SandcastleProject(vs.HelpFileProject, true)) { // Set the configuration and platform here so that they are evaluated property in project // properties when the project is loaded below. tempProject.Configuration = builder.CurrentProject.Configuration; tempProject.Platform = builder.CurrentProject.Platform; // This looks odd but is necessary. If we are in Visual Studio, the above constructor may // return an instance that uses an underlying MSBuild project loaded in Visual Studio. // Since the BuildProject() method modifies the project, those changes are propagated to the // Visual Studio copy which we do not want to happen. As such, we use this constructor to // clone the MSBuild project XML thus avoiding modifications to the original project. using(SandcastleProject project = new SandcastleProject(tempProject)) { // We'll use a working folder below the current project's working folder workingPath = builder.WorkingFolder + vs.HelpFileProject.GetHashCode().ToString("X", CultureInfo.InvariantCulture) + "\\"; success = this.BuildProject(project, workingPath); // Switch back to the original folder for the current project Directory.SetCurrentDirectory(builder.ProjectFolder); if(!success) throw new BuilderException("VBP0003", "Unable to build prior version project: " + project.Filename); } } // Save the reflection file location as we need it later vs.ReflectionFilename = workingPath + "reflection.org"; } // Create the Version Builder configuration and add the parameters to the transform project this.CreateVersionBuilderConfigurationFile(); this.ModifyTransformManifestProject(); }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { XmlDocument config; XPathNavigator navConfig; List<XPathNavigator> deleteTargets = new List<XPathNavigator>(); // Create a dummy reflection.org and reflection.xml file if(context.BuildStep == BuildStep.GenerateReflectionInfo) { // Allow Before step plug-ins to run builder.ExecuteBeforeStepPlugIns(); using(StreamWriter sw = new StreamWriter(builder.ReflectionInfoFilename, false, Encoding.UTF8)) { sw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); sw.WriteLine("<reflection>"); sw.WriteLine(" <assemblies/>"); sw.WriteLine(" <apis>"); sw.WriteLine(" <api id=\"N:\"/>"); sw.WriteLine(" </apis>"); sw.WriteLine("</reflection>"); } File.Copy(builder.ReflectionInfoFilename, Path.ChangeExtension(builder.ReflectionInfoFilename, ".xml"), true); // Allow After step plug-ins to run builder.ExecuteAfterStepPlugIns(); } else if(context.BuildStep == BuildStep.MergeCustomConfigs && builder.CurrentProject.HasItems(BuildAction.ContentLayout)) { // Remove the reflection.xml file from the conceptual configuration file since it isn't valid config = new XmlDocument(); config.Load(builder.WorkingFolder + "conceptual.config"); navConfig = config.CreateNavigator(); XPathNodeIterator allTargets = navConfig.Select("//targets[@files='reflection.xml']"); foreach(XPathNavigator target in allTargets) deleteTargets.Add(target); foreach(var t in deleteTargets) t.DeleteSelf(); config.Save(builder.WorkingFolder + "conceptual.config"); } // Ignore all other the steps }
/// <summary> /// This method is used to execute the plug-in during the build process /// </summary> /// <param name="context">The current execution context</param> public void Execute(ExecutionContext context) { builder.ReportProgress("Applying visibility settings manually"); this.ApplyVisibilityProperties(builder.ReflectionInfoFilename); // Don't apply the API filter settings in a partial build if(builder.PartialBuildType == PartialBuildType.None && builder.CurrentProject.ApiFilter.Count != 0) { builder.ReportProgress("Applying API filter manually"); this.ApplyManualApiFilter(builder.CurrentProject.ApiFilter, builder.ReflectionInfoFilename); } }