示例#1
0
 /// <summary>
 /// Remove the item from the project
 /// </summary>
 public void RemoveFromProjectFile()
 {
     this.CheckProjectIsEditable();
     projectFile.MSBuildProject.RemoveItem(item);
     projectFile = null;
     item        = null;
 }
示例#2
0
        //=====================================================================

        /// <summary>
        /// Internal constructor
        /// </summary>
        /// <param name="isEnabled">The enabled state</param>
        /// <param name="configuration">The configuration</param>
        /// <param name="project">The owning project</param>
        internal PlugInConfiguration(bool isEnabled, string configuration, SandcastleProject project) :
          base(project)
        {
            enabled = isEnabled;

            config = String.IsNullOrWhiteSpace(configuration) ? "<configuration />" : configuration;
        }
示例#3
0
        /// <inheritdoc />
        protected override bool BindControlValue(string propertyName)
        {
            SandcastleProject currentProject = null;

#if !STANDALONEGUI
            if (this.ProjectMgr != null)
            {
                currentProject = ((SandcastleBuilderProjectNode)this.ProjectMgr).SandcastleProject;
            }
#else
            currentProject = this.CurrentProject;
#endif
            ucPlugInPropertiesPageContent.Project = currentProject;

            if (currentProject == null)
            {
                ucPlugInPropertiesPageContent.LoadPlugInSettings(null, null);
            }
            else
            {
                ucPlugInPropertiesPageContent.LoadPlugInSettings(currentProject.Filename,
                                                                 currentProject.ComponentSearchPaths);
            }

            return(true);
        }
        /// <summary>
        /// This method is used by the Sandcastle Help File Builder to let the plug-in perform its own
        /// configuration.
        /// </summary>
        /// <param name="project">A reference to the active project</param>
        /// <param name="currentConfig">The current configuration XML fragment</param>
        /// <returns>A string containing the new configuration XML fragment</returns>
        /// <remarks>The configuration data will be stored in the help file builder project</remarks>
        public string ConfigurePlugIn(SandcastleProject project, string currentConfig)
        {
            MessageBox.Show("This plug-in has no configurable settings", "Manual Visibility/API Filter Plug-In",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);

            return(currentConfig);
        }
示例#5
0
        /// <inheritdoc />
        public override object ConvertTo(ITypeDescriptorContext context,
                                         CultureInfo culture, object value, Type destinationType)
        {
            SandcastleProject project = value as SandcastleProject;
            int count;

            if (project == null || destinationType != typeof(string))
            {
                return(base.ConvertTo(context, culture, value, destinationType));
            }

            try
            {
                count = project.GetUserDefinedProperties().Count;
            }
            catch (Exception ex)
            {
                return("(Error: " + ex.Message + ")");
            }

            if (count == 0)
            {
                return("(None)");
            }

            return(String.Format(culture, "{0} user-defined project properties",
                                 count));
        }
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="project">The current project</param>
        /// <param name="configuration">The current configuration element</param>
        public AdditionalReferenceLinksConfigDlg(SandcastleProject project, XElement configuration)
        {
            InitializeComponent();

            cboHtmlSdkLinkType.ItemsSource = cboWebsiteSdkLinkType.ItemsSource = (new Dictionary <string, string> {
                { HtmlSdkLinkType.Msdn.ToString(), "Links to online help topics" },
                { HtmlSdkLinkType.None.ToString(), "No SDK links" }
            }).ToList();
            cboMSHelpViewerSdkLinkType.ItemsSource = (new Dictionary <string, string> {
                { MSHelpViewerSdkLinkType.Msdn.ToString(), "Links to online help topics" },
                { MSHelpViewerSdkLinkType.Id.ToString(), "ID links within the collection" },
                { MSHelpViewerSdkLinkType.None.ToString(), "No SDK links" }
            }).ToList();

            this.project       = project ?? throw new ArgumentNullException(nameof(project));
            this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));

            if (!configuration.IsEmpty)
            {
                // Load the current settings
                foreach (var reference in configuration.Descendants("target"))
                {
                    lbReferences.Items.Add(ReferenceLinkSettings.FromXml(project, reference));
                }
            }

            btnDeleteReferenceProject.IsEnabled = grpReferenceProps.IsEnabled = lbReferences.Items.Count != 0;

            if (lbReferences.Items.Count != 0)
            {
                lbReferences.SelectedIndex = 0;
            }
        }
示例#7
0
        //=====================================================================

        /// <summary>
        /// This constructor is used to wrap an existing reference
        /// </summary>
        /// <param name="project">The project that owns the reference</param>
        /// <param name="existingItem">The existing reference</param>
        /// <overloads>There are two overloads for the constructor</overloads>
        internal ProjectReferenceItem(SandcastleProject project, ProjectItem existingItem) : base(project, existingItem)
        {
            projectPath = new FilePath(this.Include, this.Project);
            projectPath.PersistablePathChanging += projectPath_PersistablePathChanging;
            this.GetProjectMetadata(false);
            this.Include = projectPath.PersistablePath;
        }
        //=====================================================================
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="project">The project file reference</param>
        public UserDefinedPropertyEditorDlg(SandcastleProject project)
        {
            PropertyItem propItem;

            InitializeComponent();

            this.Project = project;
            this.UserDefinedProperties = new Collection<PropertyItem>();

            lbProperties.Sorted = true;

            try
            {
                foreach(BuildProperty prop in this.Project.GetUserDefinedProperties())
                {
                    propItem = new PropertyItem(this, prop);
                    this.UserDefinedProperties.Add(propItem);
                    lbProperties.Items.Add(propItem);
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show("Unable to load user-defined properties.  " +
                    "Error " + ex.Message, Constants.AppName,
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            lbProperties.Sorted = false;

            if(lbProperties.Items.Count == 0)
                pgProps.Enabled = false;
            else
                lbProperties.SelectedIndex = 0;
        }
示例#9
0
        /// <summary>
        /// This method is used by the Sandcastle Help File Builder to let the plug-in perform its own configuration.
        /// </summary>
        /// <param name="project">A reference to the active project</param>
        /// <param name="currentConfig">The current configuration XML fragment</param>
        /// <returns>A string containing the new configuration XML fragment</returns>
        /// <remarks>The configuration data will be stored in the help file builder project.</remarks>
        public string ConfigurePlugIn(SandcastleProject project, string currentConfig)
        {
            //TODO przeniesc calosc do plugin.
            Form ConfigurationForm = new PluginConfig(currentConfig);

            ConfigurationForm.Show();

            //if ( currentConfig.ToLower().ToString() == "<configuration />" )
            //{
            //  StringBuilder sbWriteConfig = new StringBuilder();
            //  sbWriteConfig.AppendLine();
            //  XmlWriterSettings settingWriter = new XmlWriterSettings();
            //  settingWriter.OmitXmlDeclaration = true;
            //  XmlWriter xmlWriter = XmlWriter.Create( sbWriteConfig, settingWriter );
            //  xmlWriter.WriteStartElement( "configuration" );
            //  xmlWriter.WriteElementString( "website", Properties.Settings.Default.website );
            //  xmlWriter.WriteEndElement();
            //  xmlWriter.Flush();
            //  xmlWriter.Close();
            //  sbWriteConfig.AppendLine();
            //  currentConfig = sbWriteConfig.ToString();
            //}

            return(currentConfig);
        }
示例#10
0
        /// <summary>
        /// This is called to build a project
        /// </summary>
        /// <param name="project">The project to build</param>
        /// <returns>Returns true if successful, false if not</returns>
        private static bool BuildProject(SandcastleProject project)
        {
            lastBuildStep  = BuildStep.None;
            currentProject = project;

            Console.WriteLine("\nBuilding {0}", project.Filename);

            try
            {
                buildProcess = new BuildProcess(currentProject);
                buildProcess.BuildStepChanged +=
                    new EventHandler <BuildProgressEventArgs>(
                        buildProcess_BuildStepChanged);
                buildProcess.BuildProgress +=
                    new EventHandler <BuildProgressEventArgs>(
                        buildProcess_BuildProgress);

                // Since this is a console app, we'll run it directly rather
                // than in a background thread.
                buildProcess.Build();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Fatal error, unable to compile " +
                                  "project '{0}': {1}", project.Filename, ex.ToString());
            }

            return(lastBuildStep == BuildStep.Completed);
        }
示例#11
0
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="currentProject">The current project</param>
        /// <param name="currentConfig">The current XML configuration
        /// XML fragment</param>
        public WildcardReferencesConfigDlg(SandcastleProject currentProject, string currentConfig)
        {
            InitializeComponent();
            project = currentProject;

            lnkProjectSite.Links[0].LinkData = "https://GitHub.com/EWSoftware/SHFB";
            lbReferences.DisplayMember       = lbReferences.ValueMember = "ListDescription";

            items = new WildcardReferenceSettingsCollection();

            // Load the current settings
            config = XElement.Parse(currentConfig);

            if (!config.IsEmpty)
            {
                items.FromXml(project, config);
            }

            if (items.Count == 0)
            {
                pgProps.Enabled = btnDelete.Enabled = false;
            }
            else
            {
                // Binding the collection to the list box caused some odd problems with the property grid so
                // we'll add the items to the list box directly.
                foreach (WildcardReferenceSettings rl in items)
                {
                    lbReferences.Items.Add(rl);
                }

                lbReferences.SelectedIndex = 0;
            }
        }
示例#12
0
        //=====================================================================

        /// <summary>
        /// Internal constructor
        /// </summary>
        /// <param name="itemName">The namespace's name</param>
        /// <param name="documented">The flag indicating whether or not the
        /// namespace is to be documented.</param>
        /// <param name="summaryText">The summary text</param>
        /// <param name="project">The owning project</param>
        internal NamespaceSummaryItem(string itemName, bool documented,
                                      string summaryText, SandcastleProject project) : base(project)
        {
            name         = itemName;
            summary      = summaryText;
            isDocumented = documented;
        }
        //=====================================================================

        /// <summary>
        /// Internal constructor
        /// </summary>
        /// <param name="isEnabled">The enabled state</param>
        /// <param name="configuration">The configuration</param>
        /// <param name="project">The owning project</param>
        internal PlugInConfiguration(bool isEnabled, string configuration, SandcastleProject project) :
            base(project)
        {
            enabled = isEnabled;

            config = String.IsNullOrWhiteSpace(configuration) ? "<configuration />" : configuration;
        }
示例#14
0
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="currentProject">The current project</param>
        /// <param name="currentConfig">The current XML configuration XML fragment</param>
        public BindingRedirectResolverConfigDlg(SandcastleProject currentProject, string currentConfig)
        {
            XPathNavigator navigator, root;
            string         useGac;

            InitializeComponent();
            project = currentProject;

            lnkProjectSite.Links[0].LinkData = "https://GitHub.com/EWSoftware/SHFB";

            items = new BindingRedirectSettingsCollection();

            // Load the current settings
            config = new XmlDocument();
            config.LoadXml(currentConfig);
            navigator = config.CreateNavigator();

            root = navigator.SelectSingleNode("configuration");

            useGac = root.GetAttribute("useGAC", String.Empty);

            if (Boolean.TryParse(useGac, out bool value))
            {
                chkUseGAC.Checked = value;
            }

            if (!root.IsEmptyElement)
            {
                items.FromXml(project, root);
            }

            if (items.Count == 0)
            {
                pgProps.Enabled = btnDelete.Enabled = false;
            }
            else
            {
                // Binding the collection to the list box caused some odd problems with the property grid so
                // we'll add the items to the list box directly.
                foreach (BindingRedirectSettings brs in items)
                {
                    lbRedirects.Items.Add(brs);
                }

                lbRedirects.SelectedIndex = 0;
            }

            foreach (XPathNavigator nav in root.Select("ignoreIfUnresolved/assemblyIdentity/@name"))
            {
                lbIgnoreIfUnresolved.Items.Add(nav.Value);
            }

            if (lbIgnoreIfUnresolved.Items.Count == 0)
            {
                lbIgnoreIfUnresolved.Items.Add("BusinessObjects.Licensing.KeycodeDecoder");
                lbIgnoreIfUnresolved.Items.Add("Microsoft.VisualStudio.TestTools.UITest.Playback");
            }

            lbIgnoreIfUnresolved.SelectedIndex = 0;
        }
示例#15
0
        /// <summary>
        /// Launch the Launch Help Viewer 2.x Content Manager for interactive use based on the current project's
        /// settings.
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void LaunchContentMgrExecuteHandler(object sender, EventArgs e)
        {
            Version version;

            try
            {
                SandcastleProject project = CurrentSandcastleProject;

                if (project != null)
                {
                    if (project.CatalogName == "VisualStudio11")
                    {
                        version = new Version(2, 0);
                    }
                    else
                    {
                        version = new Version(2, 1);
                    }

                    HelpLibraryManager hlm = new HelpLibraryManager(version);

                    hlm.LaunchInteractive(String.Format(CultureInfo.InvariantCulture,
                                                        "/catalogName \"{0}\" /locale {1} /manage", project.CatalogName, project.Language.Name));
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
                Utility.ShowMessageBox(OLEMSGICON.OLEMSGICON_CRITICAL, "Unable to launch Help Viewer 2.x " +
                                       "Content Manager.  Reason:\r\n{0}\r\n\r\nIs the catalog name correct in the project?",
                                       ex.Message);
            }
        }
示例#16
0
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="oldProjectFile">The old project filename</param>
        /// <param name="folder">The folder in which to place the new project and its related files.  This
        /// cannot be the same folder as the old project file.</param>
        /// <overloads>There are two overloads for the constructor</overloads>
        protected ConvertToMSBuildFormat(string oldProjectFile, string folder)
        {
            string projectFilename;

            oldProject    = oldProjectFile;
            oldFolder     = FolderPath.TerminatePath(Path.GetDirectoryName(Path.GetFullPath(oldProjectFile)));
            projectFolder = FolderPath.TerminatePath(folder);

            if (folder == oldFolder)
            {
                throw new ArgumentException("The new project folder cannot be the same as the old project " +
                                            "file's folder", "folder");
            }

            if (!Directory.Exists(projectFolder))
            {
                Directory.CreateDirectory(projectFolder);
            }

            projectFilename = Path.Combine(projectFolder,
                                           Path.GetFileNameWithoutExtension(oldProjectFile) + ".shfbproj");

            if (File.Exists(projectFilename))
            {
                File.Delete(projectFilename);
            }

            project = new SandcastleProject(projectFilename, false);
        }
示例#17
0
 /// <inheritdoc />
 public bool EditConfiguration(SandcastleProject project, XElement configuration)
 {
     using (var dlg = new WindowsFormsExampleConfigDlg(configuration))
     {
         return(dlg.ShowDialog() == DialogResult.OK);
     }
 }
示例#18
0
        /// <inheritdoc />
        protected override void LoadFile(string fileName)
        {
            SandcastleProject project = null;
            bool disposeOfProject     = false;

            resourceItemFilename = fileName;

            try
            {
                // Get the current project so that the editor knows what presentation style items to load
                project = SandcastleBuilderPackage.CurrentSandcastleProject;

                if (project == null)
                {
                    // If there is no current project, create a dummy project to use
                    disposeOfProject = true;
                    project          = new SandcastleProject("__TempProject__.shfbproj", false, false);
                }

                base.UIControl.LoadResourceItemsFile(fileName, project);
            }
            finally
            {
                if (disposeOfProject)
                {
                    project.Dispose();
                }
            }
        }
        /// <summary>
        /// This constructor is used to create a new build item and add it to the project
        /// </summary>
        /// <param name="project">The project that will own the item</param>
        /// <param name="itemType">The type of build item to create</param>
        /// <param name="itemPath">The path to the item.  This can be relative or absolute and may contain
        /// variable references.</param>
        protected ProjectElement(SandcastleProject project, string itemType, string itemPath)
        {
            if (project == null)
            {
                throw new ArgumentNullException("project");
            }

            if (String.IsNullOrEmpty(itemPath))
            {
                throw new ArgumentException("Cannot be null or empty", "itemPath");
            }

            if (String.IsNullOrEmpty(itemType))
            {
                throw new ArgumentException("Cannot be null or empty", "itemType");
            }

            projectFile = project;

            if (itemType == Utils.BuildAction.Folder.ToString() && itemPath[itemPath.Length - 1] != '\\')
            {
                itemPath += @"\";
            }

            item = project.MSBuildProject.AddItem(itemType, itemPath)[0];
            projectFile.MSBuildProject.ReevaluateIfNecessary();
        }
        /// <inheritdoc />
        public string ConfigurePlugIn(SandcastleProject project, string currentConfig)
        {
            MessageBox.Show("This plug-in has no configurable settings", "Lightweight Website Style Plug-In",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);

            return(currentConfig);
        }
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="project">The current project</param>
        /// <param name="configuration">The current configuration element</param>
        public VersionBuilderConfigDlg(SandcastleProject project, XElement configuration)
        {
            InitializeComponent();

            this.project       = project ?? throw new ArgumentNullException(nameof(project));
            this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));

            if (!configuration.IsEmpty)
            {
                var currentProject = configuration.Element("currentProject");

                if (currentProject != null)
                {
                    txtLabel.Text           = currentProject.Attribute("label").Value;
                    txtVersion.Text         = currentProject.Attribute("version").Value;
                    chkRipOldAPIs.IsChecked = (bool)currentProject.Attribute("ripOldApis");
                }

                // Load the current settings
                foreach (var reference in configuration.Descendants("version"))
                {
                    lbVersionInfo.Items.Add(VersionSettings.FromXml(project, reference));
                }
            }

            btnDeleteProject.IsEnabled = grpVersionInfoProps.IsEnabled = lbVersionInfo.Items.Count != 0;

            if (lbVersionInfo.Items.Count != 0)
            {
                lbVersionInfo.SelectedIndex = 0;
            }
        }
示例#22
0
        /// <summary>
        /// This method is used by the Sandcastle Help File Builder to let the plug-in perform its own
        /// configuration.
        /// </summary>
        /// <param name="project">A reference to the active project</param>
        /// <param name="currentConfig">The current configuration XML fragment</param>
        /// <returns>A string containing the new configuration XML fragment</returns>
        /// <remarks>The configuration data will be stored in the help file builder project</remarks>
        public string ConfigurePlugIn(SandcastleProject project, string currentConfig)
        {
            MessageBox.Show("This plug-in has no configurable settings", "IntelliSense Only Plug-In",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);

            return(currentConfig);
        }
示例#23
0
        /// <summary>
        /// This constructor is used to create a new build item and add it to
        /// the project.
        /// </summary>
        /// <param name="project">The project that will own the item</param>
        /// <param name="itemType">The type of build item to create</param>
        /// <param name="itemPath">The path to the item.  This can be relative
        /// or absolute and may contain variable references.</param>
        internal ProjectElement(SandcastleProject project, string itemType,
                                string itemPath)
        {
            if (project == null)
            {
                throw new ArgumentNullException("project");
            }

            if (String.IsNullOrEmpty(itemPath))
            {
                throw new ArgumentException("Cannot be null or empty",
                                            "itemPath");
            }

            if (String.IsNullOrEmpty(itemType))
            {
                throw new ArgumentException("Cannot be null or empty",
                                            "itemType");
            }

            projectFile = project;
            this.CheckProjectIsEditable();

            if (itemType == Utils.BuildAction.Folder.ToString() &&
                itemPath[itemPath.Length - 1] != '\\')
            {
                itemPath += @"\";
            }

            item = project.MSBuildProject.AddItem(itemType, itemPath)[0];
            projectFile.MarkAsDirty();
        }
        /// <summary>
        /// This method is used by the Sandcastle Help File Builder to let the plug-in perform its own
        /// configuration.
        /// </summary>
        /// <param name="project">A reference to the active project</param>
        /// <param name="currentConfig">The current configuration XML fragment</param>
        /// <returns>A string containing the new configuration XML fragment</returns>
        /// <remarks>The configuration data will be stored in the help file builder project</remarks>
        public string ConfigurePlugIn(SandcastleProject project, string currentConfig)
        {
            MessageBox.Show("This plug-in has no configurable settings", "Script# Reflection File Fixer Plug-In",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);

            return(currentConfig);
        }
示例#25
0
        /// <summary>
        /// This method can be used by plug-ins to merge content from another Sandcastle Help File Builder
        /// project file.
        /// </summary>
        /// <param name="project">The project file from which to merge content</param>
        /// <remarks>Auto-generated content can be added to a temporary SHFB project and then added to the
        /// current project's content at build time using this method.  Such content cannot always be added to
        /// the project being built as it may alter the underlying MSBuild project which is not wanted.</remarks>
        public void MergeContentFrom(SandcastleProject project)
        {
            var otherImageFiles         = new ImageReferenceCollection(project);
            var otherCodeSnippetFiles   = new FileItemCollection(project, BuildAction.CodeSnippets);
            var otherTokenFiles         = new FileItemCollection(project, BuildAction.Tokens);
            var otherContentLayoutFiles = new FileItemCollection(project, BuildAction.ContentLayout);

            foreach (var image in otherImageFiles)
            {
                imageFiles.Add(image);
            }

            foreach (var snippets in otherCodeSnippetFiles)
            {
                codeSnippetFiles.Add(snippets);
            }

            foreach (var tokens in otherTokenFiles)
            {
                tokenFiles.Add(tokens);
            }

            foreach (FileItem file in otherContentLayoutFiles)
            {
                topics.Add(new TopicCollection(file));
            }
        }
        /// <inheritdoc />
        protected override bool BindControlValue(string propertyName)
        {
            SandcastleProject currentProject = null;

#if !STANDALONEGUI
            if (this.ProjectMgr == null)
            {
                ucBuildPropertiesPageContent.LoadBuildFormatInfo(null, null);
                return(false);
            }

            currentProject = ((SandcastleBuilderProjectNode)this.ProjectMgr).SandcastleProject;
#else
            if (this.CurrentProject == null)
            {
                ucBuildPropertiesPageContent.LoadBuildFormatInfo(null, null);
                return(false);
            }

            currentProject = this.CurrentProject;
#endif
            if (propertyName == "FrameworkVersion")
            {
                ucBuildPropertiesPageContent.LoadReflectionDataSetInfo(currentProject);
                return(false);
            }

            // Get the selected help file formats
            if (propertyName == "HelpFileFormat")
            {
                HelpFileFormats formats;

                ProjectProperty projProp = currentProject.MSBuildProject.GetProperty("HelpFileFormat");

                if (projProp == null || !Enum.TryParse <HelpFileFormats>(projProp.UnevaluatedValue, out formats))
                {
                    formats = HelpFileFormats.HtmlHelp1;
                }

                ucBuildPropertiesPageContent.SelectedHelpFileFormats = formats;
                return(true);
            }

            // Load the presentation styles and syntax filters
            if (propertyName == "SyntaxFilters")
            {
                ucBuildPropertiesPageContent.LoadBuildFormatInfo(currentProject.Filename,
                                                                 new[] { currentProject.ComponentPath, Path.GetDirectoryName(currentProject.Filename) });

                return(true);
            }

            // This is loaded along with the syntax filters after the components are determined
            if (propertyName == "PresentationStyle")
            {
                return(true);
            }

            return(false);
        }
示例#27
0
        //=====================================================================
        // Build methods

        /// <summary>
        /// This kicks off the build process in a background thread
        /// </summary>
        private void BuildConceptualTopics()
        {
            PlugInConfiguration pc;
            string tempPath;

            try
            {
                // Set up the project using information from the current project
                tempProject = new SandcastleProject(currentProject, true);

                // The temporary project resides in the same folder as the
                // current project (by filename only, it isn't saved) to
                // maintain relative paths.  However, build output is stored
                // in a temporary folder and it keeps the intermediate files.
                tempProject.CleanIntermediates = false;
                tempPath = Path.GetTempFileName();

                File.Delete(tempPath);
                tempPath = Path.Combine(Path.GetDirectoryName(tempPath), "SHFBPartialBuild");

                if (!Directory.Exists(tempPath))
                {
                    Directory.CreateDirectory(tempPath);
                }

                tempProject.OutputPath = tempPath;

                // Force website output so that we know where to find the output
                tempProject.HelpFileFormat = HelpFileFormat.Website;

                // Add the Additional Content Only plug-in or update the it if
                // already there to only do a preview build.
                if (tempProject.PlugInConfigurations.TryGetValue("Additional Content Only", out pc))
                {
                    pc.Enabled       = true;
                    pc.Configuration = "<configuration previewBuild='true' />";
                }
                else
                {
                    tempProject.PlugInConfigurations.Add("Additional Content Only", true,
                                                         "<configuration previewBuild='true' />");
                }

                buildProcess = new BuildProcess(tempProject);
                buildProcess.BuildStepChanged += buildProcess_BuildStepChanged;

                buildThread              = new Thread(new ThreadStart(buildProcess.Build));
                buildThread.Name         = "Help file builder thread";
                buildThread.IsBackground = true;
                buildThread.Start();
            }
            catch (Exception ex)
            {
                Directory.SetCurrentDirectory(Path.GetDirectoryName(currentProject.Filename));

                System.Diagnostics.Debug.WriteLine(ex.ToString());
                MessageBox.Show("Unable to build project to preview topic.  " + "Error: " + ex.Message,
                                Constants.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
示例#28
0
        /// <summary>
        /// This gets all possible content files from the project and attempts
        /// to match them to the topics in the collection by ID.
        /// </summary>
        public void MatchProjectFilesToTopics()
        {
            SandcastleProject project = fileItem.ProjectElement.Project;
            FileItem          topicItem;
            TopicFile         topicFile;

            string ext, none = BuildAction.None.ToString(),
                   content = BuildAction.Content.ToString();

            foreach (ProjectItem item in project.MSBuildProject.AllEvaluatedItems)
            {
                if (item.ItemType == none || item.ItemType == content)
                {
                    ext = Path.GetExtension(item.EvaluatedInclude).ToLowerInvariant();

                    if (ext == ".aml" || ext == ".htm" || ext == ".html" || ext == ".topic")
                    {
                        topicItem = new FileItem(new ProjectElement(project, item));
                        topicFile = new TopicFile(topicItem);

                        if (topicFile.Id != null)
                        {
                            this.SetTopic(topicFile);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Try to load information about all available framework reflection data sets
        /// </summary>
        /// <param name="currentProject">The current Sandcastle project</param>
        public void LoadReflectionDataSetInfo(SandcastleProject currentProject)
        {
            if (reflectionDataSets != null && currentProject != null && currentProject.Filename != lastProjectName)
            {
                return;
            }

            lastProjectName = currentProject?.Filename;

            try
            {
                Mouse.OverrideCursor = Cursors.Wait;

                if (currentProject != null)
                {
                    reflectionDataSets = new ReflectionDataSetDictionary(currentProject.ComponentSearchPaths);
                }
                else
                {
                    reflectionDataSets = new ReflectionDataSetDictionary(null);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());

                MessageBox.Show("Unexpected error loading reflection data set info: " + ex.Message, Constants.AppName,
                                MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                Mouse.OverrideCursor = null;
            }

            cboFrameworkVersion.Items.Clear();

            if (reflectionDataSets.Keys.Count == 0)
            {
                imgFrameworkWarning.Visibility = Visibility.Visible;

                MessageBox.Show("No valid reflection data sets found", Constants.AppName, MessageBoxButton.OK,
                                MessageBoxImage.Information);
                reflectionDataSets.Add(ReflectionDataSetDictionary.DefaultFrameworkTitle,
                                       new ReflectionDataSet {
                    Title = ReflectionDataSetDictionary.DefaultFrameworkTitle
                });
            }
            else
            {
                imgFrameworkWarning.Visibility = Visibility.Hidden;

                foreach (string dataSetName in reflectionDataSets.Keys.OrderBy(k => k))
                {
                    cboFrameworkVersion.Items.Add(dataSetName);
                }

                cboFrameworkVersion.SelectedItem = ReflectionDataSetDictionary.DefaultFrameworkTitle;
            }
        }
示例#30
0
        //=====================================================================

        /// <summary>
        /// Internal constructor
        /// </summary>
        /// <param name="itemName">The namespace's name</param>
        /// <param name="isGroup">This indicates whether or not the namespace is a group namespace</param>
        /// <param name="isDocumented">This indicates whether or not the namespace is to be documented</param>
        /// <param name="summaryText">The summary text</param>
        /// <param name="project">The owning project</param>
        internal NamespaceSummaryItem(string itemName, bool isGroup, bool isDocumented, string summaryText,
                                      SandcastleProject project) : base(project)
        {
            this.IsGroup      = isGroup;
            this.name         = itemName;
            this.summary      = summaryText;
            this.isDocumented = isDocumented;
        }
        /// <summary>
        /// Remove the item from the project
        /// </summary>
        public void RemoveFromProjectFile()
        {
            projectFile.MSBuildProject.RemoveItem(item);
            projectFile.MSBuildProject.ReevaluateIfNecessary();

            projectFile = null;
            item        = null;
        }
示例#32
0
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="project">The project from which to load the settings</param>
        public ConceptualContentSettings(SandcastleProject project)
        {
            imageFiles         = project.ImagesReferences.ToList();
            codeSnippetFiles   = project.ContentFiles(BuildAction.CodeSnippets).OrderBy(f => f.LinkPath).ToList();
            tokenFiles         = project.ContentFiles(BuildAction.Tokens).OrderBy(f => f.LinkPath).ToList();
            contentLayoutFiles = project.ContentFiles(BuildAction.ContentLayout).ToList();
            topics             = project.ContentFiles(BuildAction.ContentLayout).Select(file => new TopicCollection(file)).ToList();
        }
        //=====================================================================

        /// <summary>
        /// Internal constructor
        /// </summary>
        /// <param name="isEnabled">The enabled state</param>
        /// <param name="configuration">The configuration</param>
        /// <param name="project">The owning project</param>
        internal BuildComponentConfiguration(bool isEnabled, string configuration, SandcastleProject project) :
          base(project)
        {
            if(String.IsNullOrWhiteSpace(configuration))
                throw new ArgumentException("A configuration value is required", "configuration");

            enabled = isEnabled;
            config = configuration;
        }
        //=====================================================================
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="project">The project from which to load the settings</param>
        public ConceptualContentSettings(SandcastleProject project)
        {
            imageFiles = new ImageReferenceCollection(project);
            codeSnippetFiles = new FileItemCollection(project, BuildAction.CodeSnippets);
            tokenFiles = new FileItemCollection(project, BuildAction.Tokens);
            contentLayoutFiles = new FileItemCollection(project, BuildAction.ContentLayout);
            topics = new Collection<TopicCollection>();

            foreach(FileItem file in contentLayoutFiles)
                topics.Add(new TopicCollection(file));
        }
        //=====================================================================
        /// <summary>
        /// Internal constructor
        /// </summary>
        /// <param name="isEnabled">The enabled state</param>
        /// <param name="configuration">The configuration</param>
        /// <param name="project">The owning project</param>
        internal BuildComponentConfiguration(bool isEnabled,
          string configuration, SandcastleProject project)
            : base(project)
        {
            enabled = isEnabled;

            if(String.IsNullOrEmpty(configuration))
                config = "<configuration />";
            else
                config = configuration;
        }
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="currentBuild">The current build for which to perform substitution tag replacement</param>
        public SubstitutionTagReplacement(BuildProcess currentBuild)
        {
            this.currentBuild = currentBuild;

            sandcastleProject = currentBuild.CurrentProject;
            msbuildProject = sandcastleProject.MSBuildProject;
            presentationStyle = currentBuild.PresentationStyle;

            replacementValue = new StringBuilder(10240);

            fieldMatchEval = new MatchEvaluator(OnFieldMatch);

            // Get the substitution tag methods so that we can invoke them.  The dictionary keys are the method
            // names and are case-insensitive.  Substitution tag methods take no parameters and return a value
            // that is convertible to a string.
            methodCache = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).Where(
                m => m.GetCustomAttribute(typeof(SubstitutionTagAttribute)) != null).ToDictionary(
                m => m.Name, m => m, StringComparer.OrdinalIgnoreCase);
        }
示例#37
0
        //=====================================================================

        /// <summary>
        /// This is used to execute the task and perform the build
        /// </summary>
        /// <returns>True on success or false on failure.</returns>
        public override bool Execute()
        {
            Project msBuildProject = null;
            ProjectInstance projectInstance = null;
            bool removeProjectWhenDisposed = false;
            string line;

            // If canceled already, just return
            if(buildCancelled)
                return false;

            try
            {
                if(!this.AlwaysLoadProject)
                {
                    // Use the current project if possible.  This is preferable as we can make use
                    // of command line property overrides and any other user-defined properties.
                    this.ProjectFile = Path.GetFullPath(this.ProjectFile);

                    // This collection is new to the MSBuild 4.0 API.  If you load a project, it appears
                    // in the collection.  However, if you run MSBuild.exe, it doesn't put the project in
                    // this collection.  As such, we must still resort to reflection to get the executing
                    // project.  I'm leaving this here in case that ever changes as this is preferable to
                    // using Reflection to get at the current project.
                    var matchingProjects = ProjectCollection.GlobalProjectCollection.GetLoadedProjects(
                        this.ProjectFile);

                    if(matchingProjects.Count != 0)
                    {
                        if(matchingProjects.Count != 1)
                            Log.LogWarning(null, "BHT0004", "BHT0004", "SHFB", 0, 0, 0, 0, "Multiple matching " +
                                "projects were found.  Only the first one found will be built.");

                        msBuildProject = matchingProjects.First();
                    }
                    else
                        projectInstance = this.GetCurrentProjectInstance();
                }
            }
            catch(Exception ex)
            {
                // Ignore exceptions but issue a warning and fall back to using
                // the passed project filename instead.
                Log.LogWarning(null, "BHT0001", "BHT0001", "SHFB", 0, 0, 0, 0, "Unable to get executing " +
                    "project: {0}.  The specified project will be loaded but command line property " +
                    "overrides will be ignored.", ex.Message);
            }

            try
            {
                if(msBuildProject == null)
                {
                    removeProjectWhenDisposed = true;

                    if(projectInstance != null)
                    {
                        msBuildProject = new Project(projectInstance.ToProjectRootElement());

                        // ToProjectRootElement() will not add properties in the global collection to the
                        // project.  One problem with this is that command line overrides get missed.  As such,
                        // we'll add them back to the project as long as they are not reserved names and are not
                        // there already.
                        foreach(var p in projectInstance.GlobalProperties)
                            if(!SandcastleProject.restrictedProps.Contains(p.Key) &&
                              !msBuildProject.AllEvaluatedProperties.Any(ep => ep.Name == p.Key))
                                msBuildProject.SetProperty(p.Key, p.Value);

                        msBuildProject.FullPath = this.ProjectFile;
                    }
                    else
                    {
                        if(!File.Exists(this.ProjectFile))
                            throw new BuilderException("BHT0003", "The specified project file does not exist: " +
                                this.ProjectFile);

                        Log.LogWarning(null, "BHT0001", "BHT0001", "SHFB", 0, 0, 0, 0, "Unable to get " +
                            "executing project:  Unable to obtain matching project from the global " +
                            "collection.  The specified project will be loaded but command line property " +
                            "overrides will be ignored.");

                        // Create the project and set the configuration and platform options
                        msBuildProject = new Project(this.ProjectFile);
                    }

                    msBuildProject.SetGlobalProperty(ProjectElement.Configuration, this.Configuration);
                    msBuildProject.SetGlobalProperty(ProjectElement.Platform, this.Platform);

                    // Override the OutDir property if defined for Team Build.  Ignore ".\" as that's our default.
                    if(!String.IsNullOrEmpty(this.OutDir) && this.OutDir != @".\")
                        msBuildProject.SetGlobalProperty(ProjectElement.OutDir, this.OutDir);

                    msBuildProject.ReevaluateIfNecessary();
                }

                // Associate the MSBuild project with a SHFB project instance and build it
                using(sandcastleProject = new SandcastleProject(msBuildProject))
                {
                    buildProcess = new BuildProcess(sandcastleProject);
                    buildProcess.BuildStepChanged += buildProcess_BuildStepChanged;
                    buildProcess.BuildProgress += buildProcess_BuildProgress;

                    // Since this is an MSBuild task, we'll run it directly rather than in a background thread
                    Log.LogMessage(MessageImportance.High, "Building {0}", msBuildProject.FullPath);
                    buildProcess.Build();
                }
            }
            catch(Exception ex)
            {
                Log.LogError(null, "BHT0002", "BHT0002", "SHFB", 0, 0, 0, 0,
                    "Unable to build project '{0}': {1}", msBuildProject.FullPath, ex);
            }
            finally
            {
                // If we loaded it, we must unload it.  If not, it is cached and may cause problems later.
                if(removeProjectWhenDisposed && msBuildProject != null)
                {
                    ProjectCollection.GlobalProjectCollection.UnloadProject(msBuildProject);
                    ProjectCollection.GlobalProjectCollection.UnloadProject(msBuildProject.Xml);
                }
            }

            if(this.DumpLogOnFailure && lastBuildStep == BuildStep.Failed)
                using(StreamReader sr = new StreamReader(buildProcess.LogFilename))
                {
                    Log.LogMessage(MessageImportance.High, "Log Content:");

                    do
                    {
                        line = sr.ReadLine();

                        // Don't output the XML elements, just the text
                        if(line != null && (line.Trim().Length == 0 || line.Trim()[0] != '<'))
                            Log.LogMessage(MessageImportance.High, line);

                    } while(line != null);
                }

            return (lastBuildStep == BuildStep.Completed);
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="oldProjectFile">The old project filename</param>
        /// <param name="newProject">The new project into which the converted elements are inserted</param>
        protected ConvertToMSBuildFormat(string oldProjectFile, SandcastleProject newProject)
        {
            oldProject = oldProjectFile;
            oldFolder = FolderPath.TerminatePath(Path.GetDirectoryName(Path.GetFullPath(oldProjectFile)));
            projectFolder = FolderPath.TerminatePath(Path.GetDirectoryName(newProject.Filename));

            if(projectFolder == oldFolder)
                throw new ArgumentException("The new project folder cannot be the same as the old project " +
                    "file's folder", "newProject");

            project = new SandcastleProject(newProject.MSBuildProject);
        }
示例#39
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="buildProject">The project to build</param>
 /// <param name="partialBuild">Pass true to perform a partial build</param>
 public BuildProcess(SandcastleProject buildProject, bool partialBuild)
     : this(buildProject)
 {
     isPartialBuild = partialBuild;
 }
        /// <summary>
        /// This method can be used by plug-ins to merge content from another Sandcastle Help File Builder
        /// project file.
        /// </summary>
        /// <param name="project">The project file from which to merge content</param>
        /// <remarks>Auto-generated content can be added to a temporary SHFB project and then added to the
        /// current project's content at build time using this method.  Such content cannot always be added to
        /// the project being built as it may alter the underlying MSBuild project which is not wanted.</remarks>
        public void MergeContentFrom(SandcastleProject project)
        {
            var otherImageFiles = new ImageReferenceCollection(project);
            var otherCodeSnippetFiles = new FileItemCollection(project, BuildAction.CodeSnippets);
            var otherTokenFiles = new FileItemCollection(project, BuildAction.Tokens);
            var otherContentLayoutFiles = new FileItemCollection(project, BuildAction.ContentLayout);

            foreach(var image in otherImageFiles)
                imageFiles.Add(image);

            foreach(var snippets in otherCodeSnippetFiles)
                codeSnippetFiles.Add(snippets);

            foreach(var tokens in otherTokenFiles)
                tokenFiles.Add(tokens);

            foreach(FileItem file in otherContentLayoutFiles)
                topics.Add(new TopicCollection(file));
        }
示例#41
0
        //=====================================================================
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="buildProject">The project to build</param>
        /// <overloads>There are two overloads for the constructor.</overloads>
        public BuildProcess(SandcastleProject buildProject)
        {
            // If the project isn't using final values suitable for the build,
            // create a new project that is using final values.
            if(buildProject.UsingFinalValues)
                project = buildProject;
            else
                project = new SandcastleProject(buildProject, true);

            // Save a copy of the project filename.  If using a temporary
            // project, it won't match the passed project's name.
            originalProjectName = buildProject.Filename;

            apiTocOrder = -1;
            apiTocParentId = rootContentContainerId = String.Empty;

            progressArgs = new BuildProgressEventArgs();

            fieldMatchEval = new MatchEvaluator(OnFieldMatch);
            contentMatchEval = new MatchEvaluator(OnContentMatch);
            linkMatchEval = new MatchEvaluator(OnLinkMatch);
            codeBlockMatchEval = new MatchEvaluator(OnCodeBlockMatch);
            excludeElementEval = new MatchEvaluator(OnExcludeElement);

            help1Files = new Collection<string>();
            help2Files = new Collection<string>();
            helpViewerFiles = new Collection<string>();
            websiteFiles = new Collection<string>();
            helpFormatOutputFolders = new Collection<string>();
        }
        //=====================================================================
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="oldProjectFile">The old project filename</param>
        /// <param name="folder">The folder in which to place the new project
        /// and its related files.  This cannot be the same folder as the
        /// old project file.</param>
        protected ConvertToMSBuildFormat(string oldProjectFile, string folder)
        {
            string projectFilename;

            oldProject = oldProjectFile;
            oldFolder = Path.GetDirectoryName(Path.GetFullPath(
                oldProjectFile));

            projectFolder = FolderPath.TerminatePath(folder);
            oldFolder = FolderPath.TerminatePath(oldFolder);

            if(folder == oldFolder)
                throw new ArgumentException("The new project folder cannot " +
                    "be the same as the old project file's folder",
                    "folder");

            if(!Directory.Exists(projectFolder))
                Directory.CreateDirectory(projectFolder);

            projectFilename = Path.Combine(projectFolder,
                Path.GetFileNameWithoutExtension(oldProjectFile) + ".shfbproj");

            if(File.Exists(projectFilename))
                File.Delete(projectFilename);

            project = new SandcastleProject(projectFilename, false);
        }
示例#43
0
        /// <summary>
        /// Shut down the build process thread and clean up on exit
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void ApiFilterEditorDlg_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(cancellationTokenSource != null && this.DialogResult != DialogResult.Cancel)
            {
                if(MessageBox.Show("A build is currently taking place to obtain API information.  Do you want " +
                  "to abort it and close this form?", Constants.AppName, MessageBoxButtons.YesNo,
                  MessageBoxIcon.Question) == DialogResult.No)
                {
                    e.Cancel = true;
                    return;
                }

                if(cancellationTokenSource != null)
                {
                    cancellationTokenSource.Cancel();
                    e.Cancel = true;
                }

                return;
            }

            if(wasModified)
            {
                apiFilter.Clear();

                // Add documented namespace filters
                this.AddNamespaceFilter(tvApiList.Nodes[0]);

                // Add filters for inherited types
                this.AddNamespaceFilter(tvApiList.Nodes[1]);
            }

            if(tempProject != null)
            {
                try
                {
                    // Delete the temporary project's working files
                    if(!String.IsNullOrEmpty(tempProject.OutputPath) && Directory.Exists(tempProject.OutputPath))
                        Directory.Delete(tempProject.OutputPath, true);
                }
                catch
                {
                    // Eat the exception.  We'll ignore it if the temporary files cannot be deleted.
                }

                tempProject.Dispose();
                tempProject = null;
            }
        }
 /// <inheritdoc />
 public ConvertFromMSExampleGui(string oldProjectFile, SandcastleProject newProject) :
   base(oldProjectFile, newProject)
 {
 }
示例#45
0
        //=====================================================================

        /// <summary>
        /// Call this method to perform the build on the project.
        /// </summary>
        public void Build()
        {
            Project msBuildProject = null;
            ProjectItem projectItem;
            string resolvedPath, helpFile, languageFile, scriptFile, hintPath, message = null;
            SandcastleProject originalProject = null;

            System.Diagnostics.Debug.WriteLine("Build process starting\r\n");

            try
            {
                taskRunner = new TaskRunner(this);

                // If the project isn't using final values suitable for the build, create a copy of the
                // project that is using final values.
                if(!project.UsingFinalValues)
                {
                    originalProject = project;
                    project = new SandcastleProject(originalProject.MSBuildProject);
                }

                Assembly asm = Assembly.GetExecutingAssembly();

                FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(asm.Location);
                this.ReportProgress(BuildStep.Initializing, "[{0}, version {1}]", fvi.ProductName, fvi.ProductVersion);

                buildStart = stepStart = DateTime.Now;

                // The version of MSBuild to use is based on the tools version set in the project
                msBuildExePath = Path.Combine(ProjectCollection.GlobalProjectCollection.Toolsets.First(
                    t => t.ToolsVersion == project.MSBuildProject.ToolsVersion).ToolsPath, "MSBuild.exe");

                // Get the location of the template files
                templateFolder = ComponentUtilities.ToolsFolder + @"Templates\";

                // Make sure we start out in the project's output folder in case the output folder is relative
                // to it.
                projectFolder = Path.GetDirectoryName(originalProjectName);

                if(projectFolder.Length == 0)
                    projectFolder = Directory.GetCurrentDirectory();

                projectFolder += @"\";

                Directory.SetCurrentDirectory(projectFolder);

                this.ReportProgress("Creating output and working folders...");

                outputFolder = project.OutputPath;

                if(String.IsNullOrEmpty(outputFolder))
                    outputFolder = Directory.GetCurrentDirectory();
                else
                    outputFolder = Path.GetFullPath(outputFolder);

                if(!Directory.Exists(outputFolder))
                    Directory.CreateDirectory(outputFolder);

                if(outputFolder[outputFolder.Length - 1] != '\\')
                    outputFolder += @"\";

                // Create the log file.  The log may be in a folder other than the output so make sure it exists
                // too.
                if(!Directory.Exists(Path.GetDirectoryName(this.LogFilename)))
                    Directory.CreateDirectory(Path.GetDirectoryName(this.LogFilename));

                swLog = new StreamWriter(this.LogFilename);

                swLog.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<shfbBuild product=\"{0}\" " +
                    "version=\"{1}\" projectFile=\"{2}\" started=\"{3}\">\r\n<buildStep step=\"{4}\">",
                    fvi.ProductName, fvi.ProductVersion, originalProjectName, DateTime.Now,
                    BuildStep.Initializing);

                if(project.WorkingPath.Path.Length == 0)
                    workingFolder = outputFolder + @"Working\";
                else
                    workingFolder = project.WorkingPath;

                if((project.HelpFileFormat & HelpFileFormats.Website) != 0)
                    BuildProcess.VerifySafePath("OutputPath", outputFolder, projectFolder);

                // The output folder and the working folder cannot be the same
                if(workingFolder == outputFolder)
                    throw new BuilderException("BE0030", "The OutputPath and WorkingPath properties cannot be " +
                        "set to the same path");

                // Make sure we can find the tools
                this.FindTools();

                // Check for the SHFBROOT environment variable.  It may not be present yet if a reboot hasn't
                // occurred after installation.  In such cases, set it to the proper folder for this process so
                // that projects can be loaded and built.
                if(Environment.GetEnvironmentVariable("SHFBROOT") == null)
                {
                    // We won't issue a warning since it may not be defined in some build environments such as
                    // on a build server.  In such cases, it is passed in as a command line option to MSBuild.
                    // Storing it in the environment here lets the SHFB build projects work as expected.
                    this.ReportProgress("The SHFBROOT system environment variable was not found.  This " +
                        "variable is usually created during installation and may require a reboot.  It has " +
                        "been defined temporarily for this process as: SHFBROOT={0}",
                        ComponentUtilities.ToolsFolder);

                    Environment.SetEnvironmentVariable("SHFBROOT", ComponentUtilities.ToolsFolder);
                }

                this.ReportProgress("Locating components in the following folder(s):");

                if(!String.IsNullOrEmpty(project.ComponentPath))
                    this.ReportProgress("    {0}", project.ComponentPath);

                this.ReportProgress("    {0}", Path.GetDirectoryName(project.Filename));

                this.ReportProgress("    {0}", ComponentUtilities.ComponentsFolder);
                this.ReportProgress("    {0}", ComponentUtilities.ToolsFolder);

                // Get the framework reflection data settings to use for the build
                reflectionDataDictionary = new ReflectionDataSetDictionary(new[] { project.ComponentPath,
                    Path.GetDirectoryName(project.Filename) });
                frameworkReflectionData = reflectionDataDictionary.CoreFrameworkByTitle(project.FrameworkVersion, true);

                if(frameworkReflectionData == null)
                    throw new BuilderException("BE0071", String.Format(CultureInfo.CurrentCulture,
                        "Unable to locate information for the project framework version '{0}' or a suitable " +
                        "redirected version on this system.  See error number help topic for details.",
                        project.FrameworkVersion));

                this.ReportProgress("Framework reflection data location: {0}", this.FrameworkReflectionDataFolder);

                if(!Directory.EnumerateFiles(this.FrameworkReflectionDataFolder, "*.xml").Any())
                    throw new BuilderException("BE0032", "Reflection data files for the selected framework " +
                        "do not exist yet (" + frameworkReflectionData.Title + ").  See help file for " +
                        "details about this error number.");

                // Warn if a different framework is being used for the build
                if(frameworkReflectionData.Title != project.FrameworkVersion)
                    this.ReportWarning("BE0072", "Project framework version '{0}' not found.  It has been " +
                        "redirected and will use '{1}' instead.", project.FrameworkVersion,
                        frameworkReflectionData.Title);

                // Get the composition container used to find build components in the rest of the build process
                componentContainer = ComponentUtilities.CreateComponentContainer(new[] { project.ComponentPath,
                    Path.GetDirectoryName(project.Filename) }, this.CancellationToken);

                syntaxGenerators = componentContainer.GetExports<ISyntaxGeneratorFactory,
                    ISyntaxGeneratorMetadata>().Select(sf => sf.Metadata).ToList();
                buildComponents = componentContainer.GetExports<BuildComponentFactory,
                    IBuildComponentMetadata>().GroupBy(c => c.Metadata.Id).Select(g => g.First()).ToDictionary(
                        key => key.Metadata.Id, value => value.Value);

                // Figure out which presentation style to use
                var style = componentContainer.GetExports<PresentationStyleSettings,
                    IPresentationStyleMetadata>().FirstOrDefault(s => s.Metadata.Id.Equals(
                        project.PresentationStyle, StringComparison.OrdinalIgnoreCase));

                if(style == null)
                    throw new BuilderException("BE0001", "The PresentationStyle property value of '" +
                        project.PresentationStyle + "' is not recognized as a valid presentation style definition");

                presentationStyle = style.Value;

                this.ReportProgress("Using presentation style '{0}' located in '{1}'", style.Metadata.Id,
                    Path.Combine(presentationStyle.Location, presentationStyle.BasePath ?? String.Empty));

                var psErrors = presentationStyle.CheckForErrors();

                if(psErrors.Any())
                    throw new BuilderException("BE0004", String.Format(CultureInfo.CurrentCulture,
                        "The selected presentation style ({0}) is not valid.  Reason(s):\r\n{1}",
                        style.Metadata.Id, String.Join("\r\n", psErrors)));

                // If the presentation style does not support one or more of the selected help file formats,
                // stop now.
                if((project.HelpFileFormat & ~presentationStyle.SupportedFormats) != 0)
                    throw new BuilderException("BE0074", String.Format(CultureInfo.CurrentCulture,
                        "The selected presentation style ({0}) does not support one or more of the selected " +
                        "help file formats.  Supported formats: {1}", style.Metadata.Id,
                        presentationStyle.SupportedFormats));

                // Create the substitution tag replacement handler now as we have everything it needs
                substitutionTags = new SubstitutionTagReplacement(this);

                // Load the plug-ins if necessary
                if(project.PlugInConfigurations.Count != 0 || presentationStyle.PlugInDependencies.Count != 0)
                    this.LoadPlugIns();

                this.ExecutePlugIns(ExecutionBehaviors.After);

                try
                {
                    if(Directory.Exists(workingFolder))
                    {
                        // Clear any data from a prior run
                        this.ReportProgress(BuildStep.ClearWorkFolder, "Clearing working folder...");
                        BuildProcess.VerifySafePath("WorkingPath", workingFolder, projectFolder);

                        if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                        {
                            this.ExecutePlugIns(ExecutionBehaviors.Before);

                            try
                            {
                                Directory.Delete(workingFolder, true);
                            }
                            catch(IOException ioEx)
                            {
                                this.ReportProgress("    Not all prior output was removed from '{0}': {1}",
                                    workingFolder, ioEx.Message);
                            }
                            catch(UnauthorizedAccessException uaEx)
                            {
                                this.ReportProgress("    Not all prior output was removed from '{0}': {1}",
                                    workingFolder, uaEx.Message);
                            }

                            this.ExecutePlugIns(ExecutionBehaviors.After);
                        }
                    }

                    // For MS Help Viewer, the HTML Help Name cannot contain periods, ampersands, or pound signs
                    if((project.HelpFileFormat & HelpFileFormats.MSHelpViewer) != 0 &&
                      this.ResolvedHtmlHelpName.IndexOfAny(new[] { '.', '#', '&' }) != -1)
                        throw new BuilderException("BE0075", "For MS Help Viewer builds, the HtmlHelpName property " +
                            "cannot contain periods, ampersands, or pound signs as they are not valid in the " +
                            "help file name.");

                    // If the help file is open, it will fail to build so try to get rid of it now before we
                    // get too far into it.
                    helpFile = outputFolder + this.ResolvedHtmlHelpName + ".chm";

                    if((project.HelpFileFormat & HelpFileFormats.HtmlHelp1) != 0 && File.Exists(helpFile))
                        File.Delete(helpFile);

                    helpFile = Path.ChangeExtension(helpFile, ".mshc");

                    if((project.HelpFileFormat & HelpFileFormats.MSHelpViewer) != 0 && File.Exists(helpFile))
                        File.Delete(helpFile);

                    if((project.HelpFileFormat & HelpFileFormats.Website) != 0)
                    {
                        helpFile = outputFolder + "Index.aspx";

                        if(File.Exists(helpFile))
                            File.Delete(helpFile);

                        helpFile = Path.ChangeExtension(helpFile, ".html");

                        if(File.Exists(helpFile))
                            File.Delete(helpFile);
                    }

                    helpFile = outputFolder + this.ResolvedHtmlHelpName + ".docx";

                    if((project.HelpFileFormat & HelpFileFormats.OpenXml) != 0 && File.Exists(helpFile))
                        File.Delete(helpFile);
                }
                catch(IOException ex)
                {
                    throw new BuilderException("BE0025", "Unable to remove prior build output: " + ex.Message);
                }
                catch
                {
                    throw;
                }

                if((project.HelpFileFormat & (HelpFileFormats.Website | HelpFileFormats.Markdown)) != 0)
                {
                    this.ReportProgress("-------------------------------");
                    this.ReportProgress("Clearing any prior web/markdown output...");

                    // Purge all files and folders from the output path except for the working folder and the
                    // build log.  Read-only and/or hidden files and folders are ignored as they are assumed to
                    // be under source control.
                    foreach(string file in Directory.EnumerateFiles(outputFolder))
                        if(!file.EndsWith(Path.GetFileName(this.LogFilename), StringComparison.Ordinal))
                            if((File.GetAttributes(file) & (FileAttributes.ReadOnly | FileAttributes.Hidden)) == 0)
                                File.Delete(file);
                            else
                                this.ReportProgress("    Ignoring read-only/hidden file {0}", file);

                    foreach(string folder in Directory.EnumerateDirectories(outputFolder))
                        try
                        {
                            // Ignore the working folder in case it wasn't removed above
                            if(!folder.Equals(workingFolder.Substring(0, workingFolder.Length - 1), StringComparison.OrdinalIgnoreCase))
                            {
                                // Some source control providers have a mix of read-only/hidden files within a
                                // folder that isn't read-only/hidden (i.e. Subversion).  In such cases, leave
                                // the folder alone.
                                if(Directory.EnumerateFileSystemEntries(folder, "*", SearchOption.AllDirectories).Any(
                                  f => (File.GetAttributes(f) & (FileAttributes.ReadOnly | FileAttributes.Hidden)) != 0))
                                {
                                    this.ReportProgress("    Did not delete folder '{0}' as it contains " +
                                        "read-only or hidden folders/files", folder);
                                }
                                else
                                    if((File.GetAttributes(folder) & (FileAttributes.ReadOnly | FileAttributes.Hidden)) == 0)
                                        Directory.Delete(folder, true);
                                    else
                                        this.ReportProgress("    Ignoring read-only/hidden folder {0}", folder);
                            }
                        }
                        catch(IOException ioEx)
                        {
                            this.ReportProgress("    Ignoring folder '{0}': {1}", folder, ioEx.Message);
                        }
                        catch(UnauthorizedAccessException uaEx)
                        {
                            this.ReportProgress("    Ignoring folder '{0}': {1}", folder, uaEx.Message);
                        }
                }

                Directory.CreateDirectory(workingFolder);

                // Validate the documentation source information, gather assembly and reference info, and copy
                // XML comments files to the working folder.
                this.ValidateDocumentationSources();

                // Transform the shared builder content files
                language = project.Language;
                languageFile = Path.Combine(presentationStyle.ResolvePath(presentationStyle.ToolResourceItemsPath),
                    language.Name + ".xml");

                this.ReportProgress(BuildStep.GenerateSharedContent, "Generating shared content files ({0}, {1})...",
                    language.Name, language.DisplayName);

                if(!File.Exists(languageFile))
                {
                    languageFile = Path.Combine(presentationStyle.ResolvePath(presentationStyle.ToolResourceItemsPath),
                        "en-US.xml");

                    // Warn the user about the default being used
                    this.ReportWarning("BE0002", "Help file builder content for the '{0}, {1}' language could " +
                        "not be found.  Using 'en-US, English (US)' defaults.", language.Name, language.DisplayName);
                }

                // See if the user has translated the Sandcastle resources.  If not found, default to US English.
                languageFolder = Path.Combine(presentationStyle.ResolvePath(presentationStyle.ResourceItemsPath),
                    language.Name);

                if(Directory.Exists(languageFolder))
                    languageFolder = language.Name + @"\";
                else
                {
                    // Warn the user about the default being used.  The language will still be used for the help
                    // file though.
                    if(language.Name != "en-US")
                        this.ReportWarning("BE0003", "Sandcastle shared content for the '{0}, {1}' language " +
                            "could not be found.  Using 'en-US, English (US)' defaults.", language.Name,
                            language.DisplayName);

                    languageFolder = String.Empty;
                }

                if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                {
                    this.ExecutePlugIns(ExecutionBehaviors.Before);

                    substitutionTags.TransformTemplate(Path.GetFileName(languageFile), Path.GetDirectoryName(languageFile),
                        workingFolder);
                    File.Move(workingFolder + Path.GetFileName(languageFile), workingFolder + "SHFBContent.xml");

                    // Copy the stop word list
                    languageFile = Path.Combine(ComponentUtilities.ToolsFolder, @"PresentationStyles\Shared\" +
                        @"StopWordList\" + Path.GetFileNameWithoutExtension(languageFile) +".txt");
                    File.Copy(languageFile, workingFolder + "StopWordList.txt");
                    File.SetAttributes(workingFolder + "StopWordList.txt", FileAttributes.Normal);

                    this.ExecutePlugIns(ExecutionBehaviors.After);
                }

                // Generate the API filter used by MRefBuilder
                this.GenerateApiFilter();

                // Generate the reflection information
                this.ReportProgress(BuildStep.GenerateReflectionInfo, "Generating reflection information...");

                reflectionFile = workingFolder + "reflection.org";

                if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                {
                    substitutionTags.TransformTemplate("MRefBuilder.config", templateFolder, workingFolder);
                    scriptFile = substitutionTags.TransformTemplate("GenerateRefInfo.proj", templateFolder, workingFolder);

                    try
                    {
                        msBuildProject = new Project(scriptFile);

                        // Add the references
                        foreach(var r in referenceDictionary.Values)
                        {
                            projectItem = msBuildProject.AddItem(r.Item1, r.Item2, r.Item3)[0];

                            // Make sure hint paths are correct by adding the project folder to any relative
                            // paths.  Skip any containing MSBuild variable references.
                            if(projectItem.HasMetadata(BuildItemMetadata.HintPath))
                            {
                                hintPath = projectItem.GetMetadataValue(BuildItemMetadata.HintPath);

                                if(!Path.IsPathRooted(hintPath) && hintPath.IndexOf("$(",
                                  StringComparison.Ordinal) == -1)
                                {
                                    hintPath = FilePath.GetFullPath(Path.Combine(projectFolder, hintPath));

                                    // If the full path length would exceed the system maximums, make it relative
                                    // to keep it under the maximum lengths.
                                    if(hintPath.Length > 259 || Path.GetDirectoryName(hintPath).Length > 247)
                                        hintPath = FolderPath.AbsoluteToRelativePath(workingFolder, hintPath);

                                    projectItem.SetMetadataValue(BuildItemMetadata.HintPath, hintPath);
                                }
                            }
                        }

                        // Add the assemblies to document
                        foreach(string assemblyName in assembliesList)
                            msBuildProject.AddItem("Assembly", assemblyName);

                        msBuildProject.Save(scriptFile);
                    }
                    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);
                        }
                    }

                    this.ExecutePlugIns(ExecutionBehaviors.Before);

                    // Silverlight build targets are only available for 32-bit builds regardless of the framework
                    // version and require the 32-bit version of MSBuild in order to load the target file correctly.
                    if(project.FrameworkVersion.StartsWith("Silverlight", StringComparison.OrdinalIgnoreCase))
                        taskRunner.Run32BitProject("GenerateRefInfo.proj", false);
                    else
                        taskRunner.RunProject("GenerateRefInfo.proj", false);

                    this.ExecutePlugIns(ExecutionBehaviors.After);
                }

                // If this was a partial build used to obtain API information, stop now
                if(this.PartialBuildType == PartialBuildType.GenerateReflectionInfo)
                {
                    commentsFiles.Save();
                    goto AllDone;       // Yeah, I know it's evil but it's quick
                }

                // Transform the reflection output based on the document model and create the topic manifest
                this.ReportProgress(BuildStep.TransformReflectionInfo, "Transforming reflection output...");

                if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                {
                    scriptFile = substitutionTags.TransformTemplate("TransformManifest.proj", templateFolder, workingFolder);

                    this.ExecutePlugIns(ExecutionBehaviors.Before);

                    taskRunner.RunProject("TransformManifest.proj", false);

                    // Change the reflection file extension before running the ExecutionBehaviors.After plug-ins
                    // so that the plug-ins (if any) get the correct filename.
                    reflectionFile = Path.ChangeExtension(reflectionFile, ".xml");

                    this.ExecutePlugIns(ExecutionBehaviors.After);
                }
                else
                    reflectionFile = Path.ChangeExtension(reflectionFile, ".xml");

                // If this was a partial build used to obtain information for namespace and namespace group
                // comments, stop now.
                if(this.PartialBuildType == PartialBuildType.TransformReflectionInfo)
                {
                    commentsFiles.Save();
                    goto AllDone;       // Yeah, I know it's evil but it's quick
                }

                // Load the transformed reflection information file
                reflectionFile = workingFolder + "reflection.xml";

                // If there is nothing to document, stop the build
                if(!ComponentUtilities.XmlStreamAxis(reflectionFile, "api").Any())
                    throw new BuilderException("BE0033", "No APIs found to document.  See error topic in " +
                        "help file for details.");

                // Generate namespace summary information
                this.GenerateNamespaceSummaries();

                // Expand <inheritdoc /> tags?
                if(commentsFiles.ContainsInheritedDocumentation)
                {
                    commentsFiles.Save();

                    // Transform the reflection output.
                    this.ReportProgress(BuildStep.GenerateInheritedDocumentation,
                        "Generating inherited documentation...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        substitutionTags.TransformTemplate("GenerateInheritedDocs.config", templateFolder, workingFolder);
                        scriptFile = substitutionTags.TransformTemplate("GenerateInheritedDocs.proj", templateFolder,
                            workingFolder);

                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        taskRunner.RunProject("GenerateInheritedDocs.proj", true);
                        
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    // This should always be last so that it overrides comments in the project XML comments files
                    commentsFiles.Add(new XmlCommentsFile(workingFolder + "_InheritedDocs_.xml"));
                }

                commentsFiles.Save();

                this.EnsureOutputFoldersExist(null);

                // Copy conceptual content files if there are topics or tokens.  Tokens can be replaced in
                // XML comments files so we check for them too.
                if(this.ConceptualContent.ContentLayoutFiles.Count != 0 || this.ConceptualContent.TokenFiles.Count != 0)
                {
                    this.ReportProgress(BuildStep.CopyConceptualContent, "Copying conceptual content...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        this.ConceptualContent.CopyContentFiles(this);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    this.ReportProgress(BuildStep.CreateConceptualTopicConfigs,
                        "Creating conceptual topic configuration files...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        this.ConceptualContent.CreateConfigurationFiles(this);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }
                }
                else    // Create an empty xmlComp folder required by the build configuration
                    Directory.CreateDirectory(Path.Combine(workingFolder, "xmlComp"));

                // Copy the additional content
                this.CopyAdditionalContent();

                // Merge the conceptual and additional content TOC info
                this.MergeConceptualAndAdditionalContentTocInfo();

                // Generate the intermediate table of contents file.  This
                // must occur prior to running BuildAssembler as the MS Help
                // Viewer build component is dependent on the toc.xml file.
                this.ReportProgress(BuildStep.GenerateIntermediateTableOfContents,
                    "Generating intermediate table of contents file...");

                if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                {
                    scriptFile = substitutionTags.TransformTemplate("GenerateIntermediateTOC.proj", templateFolder,
                        workingFolder);

                    this.ExecutePlugIns(ExecutionBehaviors.Before);

                    taskRunner.RunProject("GenerateIntermediateTOC.proj", false);

                    // Determine the API content placement
                    this.DetermineApiContentPlacement();

                    // If there is conceptual content, generate the conceptual intermediate TOC
                    if(toc != null)
                    {
                        this.ReportProgress("Generating conceptual content intermediate TOC file...");

                        toc.SaveToIntermediateTocFile((project.HelpFileFormat & HelpFileFormats.MSHelpViewer) != 0 ?
                            this.RootContentContainerId : null, project.TocOrder, workingFolder + "_ConceptualTOC_.xml");
                    }

                    this.ExecutePlugIns(ExecutionBehaviors.After);
                }

                // Create the Sandcastle configuration file
                this.ReportProgress(BuildStep.CreateBuildAssemblerConfigs, "Creating Sandcastle configuration files...");

                // Add referenced namespaces to the hash set.  These are used to ensure just the needed set of
                // reflection target files are loaded by BuildAssembler and nothing more to save some time and
                // memory.
                var rn = this.ReferencedNamespaces;

                // These are all of the valid namespaces we are interested in.  This prevents the methods below
                // from returning nested types as potential namespaces since they can't tell the difference.
                HashSet<string> validNamespaces = new HashSet<string>(Directory.EnumerateFiles(
                    this.FrameworkReflectionDataFolder, "*.xml", SearchOption.AllDirectories).Select(
                        f => Path.GetFileNameWithoutExtension(f)));

                // Get namespaces referenced in the XML comments of the documentation sources
                foreach(var n in commentsFiles.GetReferencedNamespaces(validNamespaces))
                    rn.Add(n);

                // Get namespaces referenced in the reflection data (plug-ins are responsible for adding
                // additional namespaces if they add other reflection data files).
                foreach(string n in GetReferencedNamespaces(reflectionFile, validNamespaces))
                    rn.Add(n);

                // Get namespaces from the Framework comments files of the referenced namespaces.  This adds
                // references for stuff like designer and support classes not directly referenced anywhere else.
                foreach(string n in frameworkReflectionData.GetReferencedNamespaces(language, rn, validNamespaces).ToList())
                    rn.Add(n);

                // If F# syntax is being generated, add some of the F# namespaces as the syntax sections generate
                // references to types that may not be there in non-F# projects.
                if(ComponentUtilities.SyntaxFiltersFrom(syntaxGenerators, project.SyntaxFilters).Any(
                  f => f.Id == "F#"))
                {
                    rn.Add("Microsoft.FSharp.Core");
                    rn.Add("Microsoft.FSharp.Control");
                }

                // If there are no referenced namespaces, add System as a default to prevent the build components
                // from loading the entire set.
                if(rn.Count == 0)
                    rn.Add("System");

                if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                {
                    this.ExecutePlugIns(ExecutionBehaviors.Before);

                    this.ReportProgress("    sandcastle.config");

                    // The configuration varies based on the style.  We'll use a common name (sandcastle.config).
                    resolvedPath = presentationStyle.ResolvePath(presentationStyle.ReferenceBuildConfiguration);
                    substitutionTags.TransformTemplate(Path.GetFileName(resolvedPath), Path.GetDirectoryName(resolvedPath),
                        workingFolder);

                    if(!Path.GetFileName(resolvedPath).Equals("sandcastle.config", StringComparison.OrdinalIgnoreCase))
                        File.Move(workingFolder + Path.GetFileName(resolvedPath), workingFolder + "sandcastle.config");

                    // The conceptual content configuration file is only created if needed.
                    if(this.ConceptualContent.ContentLayoutFiles.Count != 0)
                    {
                        this.ReportProgress("    conceptual.config");

                        resolvedPath = presentationStyle.ResolvePath(presentationStyle.ConceptualBuildConfiguration);

                        substitutionTags.TransformTemplate(Path.GetFileName(resolvedPath), Path.GetDirectoryName(resolvedPath),
                            workingFolder);

                        if(!Path.GetFileName(resolvedPath).Equals("conceptual.config", StringComparison.OrdinalIgnoreCase))
                            File.Move(workingFolder + Path.GetFileName(resolvedPath), workingFolder + "conceptual.config");
                    }

                    this.ExecutePlugIns(ExecutionBehaviors.After);
                }

                // Merge the build component custom configurations
                this.MergeComponentConfigurations();

                commentsFiles = null;

                // Build the conceptual help topics
                if(this.ConceptualContent.ContentLayoutFiles.Count != 0)
                {
                    this.ReportProgress(BuildStep.BuildConceptualTopics, "Building conceptual help topics...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        scriptFile = substitutionTags.TransformTemplate("BuildConceptualTopics.proj", templateFolder,
                            workingFolder);

                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        taskRunner.RunProject("BuildConceptualTopics.proj", false);
                        
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }
                }

                // Build the reference help topics
                this.ReportProgress(BuildStep.BuildReferenceTopics, "Building reference help topics...");

                if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                {
                    scriptFile = substitutionTags.TransformTemplate("BuildReferenceTopics.proj", templateFolder,
                        workingFolder);

                    this.ExecutePlugIns(ExecutionBehaviors.Before);
                                        
                    taskRunner.RunProject("BuildReferenceTopics.proj", false);
                    
                    this.ExecutePlugIns(ExecutionBehaviors.After);
                }

                // Combine the conceptual and API intermediate TOC files into one
                this.CombineIntermediateTocFiles();

                // The last part differs based on the help file format
                if((project.HelpFileFormat & (HelpFileFormats.HtmlHelp1 | HelpFileFormats.Website)) != 0)
                {
                    this.ReportProgress(BuildStep.ExtractingHtmlInfo,
                        "Extracting HTML info for HTML Help 1 and/or website...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        scriptFile = substitutionTags.TransformTemplate("ExtractHtmlInfo.proj", templateFolder,
                            workingFolder);

                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        taskRunner.RunProject("ExtractHtmlInfo.proj", true);

                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }
                }

                // Copy the standard help file content.  This is done just before compiling the help so that
                // template files from the presentation style can take advantage of tag substitution.  By this
                // point, we should have everything we could possibly need.
                this.CopyStandardHelpContent();

                if((project.HelpFileFormat & HelpFileFormats.HtmlHelp1) != 0)
                {
                    // Generate the table of contents and set the default topic
                    this.ReportProgress(BuildStep.GenerateHelpFormatTableOfContents,
                        "Generating HTML Help 1 table of contents file...");

                    currentFormat = HelpFileFormats.HtmlHelp1;

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        // It got created in the ExtractingHtmlInfo step above
                        // so there is actually nothing to do here.

                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    // Generate the help file index
                    this.ReportProgress(BuildStep.GenerateHelpFileIndex, "Generating HTML Help 1 index file...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        // It got created in the ExtractingHtmlInfo step above
                        // so there is actually nothing to do here.

                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    // Generate the help project file
                    this.ReportProgress(BuildStep.GenerateHelpProject, "Generating HTML Help 1 project file...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        substitutionTags.TransformTemplate("Help1x.hhp", templateFolder, workingFolder);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    // Build the HTML Help 1 help file
                    this.ReportProgress(BuildStep.CompilingHelpFile, "Compiling HTML Help 1 file...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        scriptFile = substitutionTags.TransformTemplate("Build1xHelpFile.proj", templateFolder,
                            workingFolder);

                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        taskRunner.RunProject("Build1xHelpFile.proj", true);
                        
                        this.GatherBuildOutputFilenames();
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }
                }

                if((project.HelpFileFormat & HelpFileFormats.MSHelpViewer) != 0)
                {
                    // The following build steps are executed to allow plug-ins to handle any necessary processing
                    // but nothing actually happens here:
                    //
                    //      BuildStep.GenerateHelpFormatTableOfContents
                    //      BuildStep.GenerateHelpProject
                    //
                    // For the MS Help Viewer format, there is no project file to compile and the TOC layout is
                    // generated when the help file is ultimately installed using metadata within each topic file.
                    // All of the necessary TOC info is stored in the intermediate TOC file generated prior to
                    // building the topics.  The BuildAssembler MSHCComponent inserts the TOC info into each topic
                    // as it is built.

                    this.ReportProgress(BuildStep.GenerateHelpFormatTableOfContents,
                        "Executing informational Generate Table of Contents " +
                        "build step for plug-ins (not used for MS Help Viewer)");

                    currentFormat = HelpFileFormats.MSHelpViewer;

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    this.ReportProgress(BuildStep.GenerateHelpProject,
                        "Executing informational Generate Help Project " +
                        "build step for plug-ins (not used for MS Help Viewer)");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    // Build the MS Help Viewer help file
                    this.ReportProgress(BuildStep.CompilingHelpFile, "Generating MS Help Viewer file...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        substitutionTags.TransformTemplate("HelpContentSetup.msha", templateFolder, workingFolder);

                        // Rename the content setup file to use the help filename to keep them related and
                        // so that multiple output files can be sent to the same output folder.
                        File.Move(workingFolder + "HelpContentSetup.msha", workingFolder + this.ResolvedHtmlHelpName + ".msha");

                        // Generate the example install and remove scripts
                        substitutionTags.TransformTemplate("InstallMSHC.bat", templateFolder, workingFolder);
                        File.Move(workingFolder + "InstallMSHC.bat", workingFolder + "Install_" +
                            this.ResolvedHtmlHelpName + ".bat");

                        substitutionTags.TransformTemplate("RemoveMSHC.bat", templateFolder, workingFolder);
                        File.Move(workingFolder + "RemoveMSHC.bat", workingFolder + "Remove_" +
                            this.ResolvedHtmlHelpName + ".bat");

                        // Copy the launcher utility
                        File.Copy(ComponentUtilities.ToolsFolder + "HelpLibraryManagerLauncher.exe",
                            workingFolder + "HelpLibraryManagerLauncher.exe");
                        File.SetAttributes(workingFolder + "HelpLibraryManagerLauncher.exe", FileAttributes.Normal);

                        scriptFile = substitutionTags.TransformTemplate("BuildHelpViewerFile.proj", templateFolder,
                            workingFolder);

                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        taskRunner.RunProject("BuildHelpViewerFile.proj", true);

                        this.GatherBuildOutputFilenames();
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }
                }

                if((project.HelpFileFormat & HelpFileFormats.Website) != 0)
                {
                    // Generate the table of contents and set the default topic
                    this.ReportProgress(BuildStep.GenerateHelpFormatTableOfContents,
                        "Generating website table of contents file...");

                    currentFormat = HelpFileFormats.Website;

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        // It got created in the ExtractingHtmlInfo step above
                        // so there is actually nothing to do here.

                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    this.GenerateWebsite();
                }

                if((project.HelpFileFormat & HelpFileFormats.OpenXml) != 0)
                {
                    // The following build steps are executed to allow plug-ins to handle any necessary processing
                    // but nothing actually happens here:
                    //
                    //      BuildStep.GenerateHelpFormatTableOfContents
                    //      BuildStep.GenerateHelpProject
                    //
                    // For the Open XML format, there is no project file to compile and the TOC layout is
                    // generated when the document is opened.  All of the necessary TOC info is stored in the
                    // intermediate TOC file generated prior to building the topics.  The process used to merge
                    // the topics into a single document uses it to define the order in which the topics are
                    // combined.

                    this.ReportProgress(BuildStep.GenerateHelpFormatTableOfContents, "Executing informational " +
                        "Generate Table of Contents build step for plug-ins (not used for Open XML)");

                    currentFormat = HelpFileFormats.OpenXml;

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    this.ReportProgress(BuildStep.GenerateHelpProject, "Executing informational Generate Help " +
                        "Project build step for plug-ins (not used for Open XML)");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    // Build the Open XML document
                    this.ReportProgress(BuildStep.CompilingHelpFile, "Generating Open XML document file...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        scriptFile = substitutionTags.TransformTemplate("BuildOpenXmlFile.proj", templateFolder,
                            workingFolder);

                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        taskRunner.RunProject("BuildOpenXmlFile.proj", true);

                        this.GatherBuildOutputFilenames();
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }
                }

                if((project.HelpFileFormat & HelpFileFormats.Markdown) != 0)
                {
                    // The following build steps are executed to allow plug-ins to handle any necessary processing
                    // but nothing actually happens here:
                    //
                    //      BuildStep.GenerateHelpFormatTableOfContents
                    //      BuildStep.GenerateHelpProject
                    //
                    // For the Markdown format, there is no project file to compile and the TOC layout is
                    // generated by the build task.  All of the necessary TOC info is stored in the intermediate
                    // TOC file generated prior to building the topics.  The build task uses it to find the
                    // topics to finalize and generate the sidebar TOC file.
                    this.ReportProgress(BuildStep.GenerateHelpFormatTableOfContents, "Executing informational " +
                        "Generate Table of Contents build step for plug-ins (not used for Markdown)");

                    currentFormat = HelpFileFormats.Markdown;

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    this.ReportProgress(BuildStep.GenerateHelpProject, "Executing informational Generate Help " +
                        "Project build step for plug-ins (not used for Markdown)");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }

                    // Generate the markdown content
                    this.ReportProgress(BuildStep.CompilingHelpFile, "Generating markdown content...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        scriptFile = substitutionTags.TransformTemplate("GenerateMarkdownContent.proj",
                            templateFolder, workingFolder);

                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        taskRunner.RunProject("GenerateMarkdownContent.proj", true);

                        this.GatherBuildOutputFilenames();
                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }
                }

                // All done
                if(project.CleanIntermediates)
                {
                    this.ReportProgress(BuildStep.CleanIntermediates, "Removing intermediate files...");

                    if(!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                    {
                        this.ExecutePlugIns(ExecutionBehaviors.Before);

                        try
                        {
                            Directory.Delete(workingFolder, true);
                        }
                        catch(IOException ioEx)
                        {
                            this.ReportProgress("    Not all build output was removed from '{0}': {1}",
                                workingFolder, ioEx.Message);
                        }
                        catch(UnauthorizedAccessException uaEx)
                        {
                            this.ReportProgress("    Not all build output was removed from '{0}': {1}",
                                workingFolder, uaEx.Message);
                        }

                        this.ExecutePlugIns(ExecutionBehaviors.After);
                    }
                }
AllDone:
                TimeSpan runtime = DateTime.Now - buildStart;

                this.ReportProgress(BuildStep.Completed, "\r\nBuild completed successfully at {0}.  " +
                    "Total time: {1:00}:{2:00}:{3:00.0000}\r\n", DateTime.Now, Math.Floor(runtime.TotalSeconds / 3600),
                    Math.Floor((runtime.TotalSeconds % 3600) / 60), (runtime.TotalSeconds % 60));

                System.Diagnostics.Debug.WriteLine("Build process finished successfully\r\n");
            }
            catch(OperationCanceledException )
            {
                buildCancelling = true;

                this.ReportError(BuildStep.Canceled, "BE0064", "BUILD CANCELLED BY USER");

                System.Diagnostics.Debug.WriteLine("Build process aborted\r\n");
            }
            catch(Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);

                var agEx = ex as AggregateException;

                if(agEx != null)
                    foreach(var inEx in agEx.InnerExceptions)
                    {
                        if(message != null)
                            message += "\r\n\r\n";

                        message += inEx.Message + "\r\n" + inEx.StackTrace;
                    }

                var bex = ex as BuilderException;

                do
                {
                    if(message != null)
                        message += "\r\n\r\n";

                    message += ex.Message + "\r\n" + ex.StackTrace;
                    ex = ex.InnerException;

                } while(ex != null);

                // NOTE: Message may contain format markers so pass it as a format argument
                if(bex != null)
                    this.ReportError(BuildStep.Failed, bex.ErrorCode, "{0}", message);
                else
                    this.ReportError(BuildStep.Failed, "BE0065", "BUILD FAILED: {0}", message);

                System.Diagnostics.Debug.WriteLine("Build process failed\r\n");
            }
            finally
            {
                try
                {
                    this.ExecutePlugIns(ExecutionBehaviors.Before);
                }
                catch(Exception ex)
                {
                    // Not much we can do at this point...
                    this.ReportProgress(ex.ToString());
                }

                try
                {
                    this.ExecutePlugIns(ExecutionBehaviors.After);

                    if(componentContainer != null)
                        componentContainer.Dispose();
                }
                catch(Exception ex)
                {
                    // Not much we can do at this point...
                    this.ReportProgress(ex.ToString());
                }
                finally
                {
                    if(swLog != null)
                    {
                        swLog.WriteLine("</buildStep>\r\n</shfbBuild>");
                        swLog.Close();
                        swLog = null;
                    }

                    // If we created a copy of the project, dispose of it and return to the original
                    if(originalProject != null)
                    {
                        project.Dispose();
                        project = originalProject;
                    }

                    if(this.CurrentBuildStep == BuildStep.Completed && !project.KeepLogFile)
                        File.Delete(this.LogFilename);
                }
            }
        }
示例#46
0
        /// <summary>
        /// Shut down the build process thread and clean up on exit
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void ApiFilterEditorDlg_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(buildThread != null && buildThread.IsAlive)
            {
                if(MessageBox.Show("A build is currently taking place to " +
                  "obtain API information.  Do you want to abort it and " +
                  "close this form?", Constants.AppName,
                  MessageBoxButtons.YesNo, MessageBoxIcon.Question) ==
                  DialogResult.No)
                {
                    e.Cancel = true;
                    return;
                }

                try
                {
                    this.Cursor = Cursors.WaitCursor;

                    if(buildThread != null)
                        buildThread.Abort();

                    while(buildThread != null && !buildThread.Join(1000))
                        Application.DoEvents();

                    // Give it a short wait.  Sometimes we're still faster shutting down
                    // than the thread is.
                    Thread.Sleep(500);
                    System.Diagnostics.Debug.WriteLine("Thread stopped");
                }
                finally
                {
                    this.Cursor = Cursors.Default;
                    buildThread = null;
                    buildProcess = null;
                }
            }

            if(wasModified)
            {
                apiFilter.Clear();

                // Add documented namespace filters
                this.AddNamespaceFilter(tvApiList.Nodes[0]);

                // Add filters for inherited types
                this.AddNamespaceFilter(tvApiList.Nodes[1]);
            }

            if(tempProject != null)
            {
                try
                {
                    // Delete the temporary project's working files
                    if(!String.IsNullOrEmpty(tempProject.OutputPath) &&
                      Directory.Exists(tempProject.OutputPath))
                        Directory.Delete(tempProject.OutputPath, true);
                }
                catch
                {
                    // Eat the exception.  We'll ignore it if the temporary files cannot be deleted.
                }

                tempProject.Dispose();
                tempProject = null;
            }

            GC.Collect(2);
            GC.WaitForPendingFinalizers();
            GC.Collect(2);
        }
示例#47
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="buildProject">The project to build</param>
 /// <param name="partialBuildType">The partial build type to perform</param>
 public BuildProcess(SandcastleProject buildProject, PartialBuildType partialBuildType) : this(buildProject)
 {
     this.PartialBuildType = partialBuildType;
 }
示例#48
0
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="buildProject">The project to build</param>
        /// <overloads>There are two overloads for the constructor.</overloads>
        public BuildProcess(SandcastleProject buildProject)
        {
            project = buildProject;

            // Save a copy of the project filename.  If using a temporary project, it won't match the passed
            // project's name.
            originalProjectName = buildProject.Filename;

            apiTocOrder = -1;
            apiTocParentId = rootContentContainerId = String.Empty;

            help1Files = new Collection<string>();
            helpViewerFiles = new Collection<string>();
            websiteFiles = new Collection<string>();
            openXmlFiles = new Collection<string>();
            markdownFiles = new Collection<string>();
            helpFormatOutputFolders = new Collection<string>();
        }
示例#49
0
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="buildProject">The project to build</param>
        /// <overloads>There are two overloads for the constructor.</overloads>
        public BuildProcess(SandcastleProject buildProject)
        {
            project = buildProject;

            // Save a copy of the project filename.  If using a temporary project, it won't match the passed
            // project's name.
            originalProjectName = buildProject.Filename;

            apiTocOrder = -1;
            apiTocParentId = rootContentContainerId = String.Empty;

            progressArgs = new BuildProgressEventArgs();

            fieldMatchEval = new MatchEvaluator(OnFieldMatch);
            contentMatchEval = new MatchEvaluator(OnContentMatch);
            linkMatchEval = new MatchEvaluator(OnLinkMatch);
            codeBlockMatchEval = new MatchEvaluator(OnCodeBlockMatch);
            excludeElementEval = new MatchEvaluator(OnExcludeElement);

            help1Files = new Collection<string>();
            help2Files = new Collection<string>();
            helpViewerFiles = new Collection<string>();
            websiteFiles = new Collection<string>();
            openXmlFiles = new Collection<string>();
            helpFormatOutputFolders = new Collection<string>();
        }
        //=====================================================================
        /// <summary>
        /// This is used to start the background build process from which
        /// we will get the information to load the tree view.
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void ApiFilterEditorDlg_Load(object sender, EventArgs e)
        {
            string tempPath;

            tvApiList.Enabled = splitContainer.Panel2.Enabled =
                btnReset.Enabled = false;

            try
            {
                // Clone the project for the build and adjust its properties
                // for our needs.
                tempProject = new SandcastleProject(apiFilter.Project, true);

                // The temporary project resides in the same folder as the
                // current project (by filename only, it isn't saved) to
                // maintain relative paths.  However, build output is stored
                // in a temporary folder and it keeps the intermediate files.
                tempProject.CleanIntermediates = false;
                tempPath = Path.GetTempFileName();

                File.Delete(tempPath);
                tempPath = Path.Combine(Path.GetDirectoryName(tempPath),
                    "SHFBPartialBuild");

                if(!Directory.Exists(tempPath))
                    Directory.CreateDirectory(tempPath);

                tempProject.OutputPath = tempPath;

                buildProcess = new BuildProcess(tempProject, true);

                // We must suppress the current API filter for this build
                buildProcess.SuppressApiFilter = true;

                buildProcess.BuildStepChanged +=
                    new EventHandler<BuildProgressEventArgs>(
                    buildProcess_BuildStepChanged);
                buildProcess.BuildProgress +=
                    new EventHandler<BuildProgressEventArgs>(
                    buildProcess_BuildProgress);

                buildThread = new Thread(new ThreadStart(buildProcess.Build));
                buildThread.Name = "API fitler partial build thread";
                buildThread.IsBackground = true;
                buildThread.Start();
            }
            catch(Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
                MessageBox.Show("Unable to build project to obtain " +
                    "API information.  Error: " + ex.Message,
                    Constants.AppName, MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }
示例#51
0
        //=====================================================================

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="project">The project from which to load the settings</param>
        public ConceptualContentSettings(SandcastleProject project)
        {
            imageFiles = project.ImagesReferences.ToList();
            codeSnippetFiles = project.ContentFiles(BuildAction.CodeSnippets).OrderBy(f => f.LinkPath).ToList();
            tokenFiles = project.ContentFiles(BuildAction.Tokens).OrderBy(f => f.LinkPath).ToList();
            contentLayoutFiles = project.ContentFiles(BuildAction.ContentLayout).ToList();
            topics = project.ContentFiles(BuildAction.ContentLayout).Select(file => new TopicCollection(file)).ToList();
        }
示例#52
0
        //=====================================================================

        /// <summary>
        /// This is used to start the background build process from which we will get the information to load the
        /// tree view.
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private async void ApiFilterEditorDlg_Load(object sender, EventArgs e)
        {
            string tempPath;

            tvApiList.Enabled = splitContainer.Panel2.Enabled = btnReset.Enabled = false;

            try
            {
                // Clone the project for the build and adjust its properties for our needs
                tempProject = new SandcastleProject(apiFilter.Project.MSBuildProject);

                // Build output is stored in a temporary folder and it keeps the intermediate files
                tempProject.CleanIntermediates = false;
                tempPath = Path.GetTempFileName();

                File.Delete(tempPath);
                tempPath = Path.Combine(Path.GetDirectoryName(tempPath), "SHFBPartialBuild");

                if(!Directory.Exists(tempPath))
                    Directory.CreateDirectory(tempPath);

                tempProject.OutputPath = tempPath;

                cancellationTokenSource = new CancellationTokenSource();

                buildProcess = new BuildProcess(tempProject, PartialBuildType.GenerateReflectionInfo)
                {
                    ProgressReportProvider = new Progress<BuildProgressEventArgs>(buildProcess_ReportProgress),
                    CancellationToken = cancellationTokenSource.Token,
                    SuppressApiFilter = true        // We must suppress the current API filter for this build
                };

                await Task.Run(() => buildProcess.Build(), cancellationTokenSource.Token);

                if(!cancellationTokenSource.IsCancellationRequested)
                {
                    // Restore the current project's base path
                    Directory.SetCurrentDirectory(Path.GetDirectoryName(apiFilter.Project.Filename));

                    // If successful, load the namespace nodes, and enable the UI
                    if(buildProcess.CurrentBuildStep == BuildStep.Completed)
                    {
                        reflectionFile = buildProcess.ReflectionInfoFilename;

                        // Convert the build API filter to a dictionary to make it easier to find entries
                        buildFilterEntries = new Dictionary<string, ApiFilter>();

                        this.ConvertApiFilter(buildProcess.CurrentProject.ApiFilter);
                        this.LoadNamespaces();

                        tvApiList.Enabled = splitContainer.Panel2.Enabled = btnReset.Enabled = true;
                    }
                    else
                        MessageBox.Show("Unable to build project to obtain API information.  Please perform a " +
                            "normal build to identify and correct the problem.", Constants.AppName,
                            MessageBoxButtons.OK, MessageBoxIcon.Error);

                    pbWait.Visible = lblLoading.Visible = false;
                }
                else
                {
                    this.DialogResult = DialogResult.Cancel;
                    this.Close();
                }

                buildProcess = null;
            }
            catch(Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.ToString());
                MessageBox.Show("Unable to build project to obtain API information.  Error: " +
                    ex.Message, Constants.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                if(cancellationTokenSource != null)
                {
                    cancellationTokenSource.Dispose();
                    cancellationTokenSource = null;
                }
            }
        }
        /// <summary>
        /// Convert a conceptual content topic and all of its children
        /// </summary>
        /// <param name="xr">The XML reader containing the topics</param>
        /// <param name="xw">The XML writer to which they are written</param>
        /// <param name="project">The project to which the files are added</param>
        private void ConvertTopic(XmlReader xr, XmlWriter xw,
          SandcastleProject project)
        {
            FileItem newFile = null;
            string id, file, title, tocTitle, linkText, destFile, ext, name,
                value, oldFolder = converter.OldFolder, projectFolder =
                converter.ProjectFolder;
            bool visible;
            int revision;

            id = xr.GetAttribute("id");

            // If not set, an ID will be created when needed
            if(id == null || id.Trim().Length == 0)
                id = new Guid(id).ToString();

            file = xr.GetAttribute("file");
            title = xr.GetAttribute("title");
            tocTitle = xr.GetAttribute("tocTitle");
            linkText = xr.GetAttribute("linkText");

            if(!Int32.TryParse(xr.GetAttribute("revision"), out revision) ||
              revision < 1)
                revision = 1;

            if(!Boolean.TryParse(xr.GetAttribute("visible"), out visible))
                visible = true;

            // Add the topic to the content file and the project
            xw.WriteStartElement("Topic");
            xw.WriteAttributeString("id", id);

            if(file != null && file.Trim().Length > 0)
            {
                file = converter.FullPath(file);

                // Maintain any additional path info beyond the old base
                // project folder.
                if(file.StartsWith(oldFolder, StringComparison.OrdinalIgnoreCase))
                    destFile = projectFolder + file.Substring(oldFolder.Length);
                else
                    destFile = Path.Combine(projectFolder, Path.GetFileName(file));

                ext = Path.GetExtension(destFile).ToLowerInvariant();

                // Change the extension on .xml files to .aml and add the
                // root topic element.
                if(ext == ".xml")
                {
                    destFile = Path.ChangeExtension(destFile, ".aml");
                    ConvertTopic(file, destFile, id, revision);
                    file = destFile;
                }

                // Add meta elements for the ID and revision number
                if(ext == ".htm" || ext == ".html" || ext == ".topic")
                {
                    ConvertTopic(file, destFile, id, revision);
                    file = destFile;
                }

                newFile = project.AddFileToProject(file, destFile);
                newFile.BuildAction = BuildAction.None;
            }
            else
                xw.WriteAttributeString("noFile", "True");

            if(title != null)
                xw.WriteAttributeString("title", title);

            if(tocTitle != null)
                xw.WriteAttributeString("tocTitle", tocTitle);

            if(linkText != null)
                xw.WriteAttributeString("linkText", linkText);

            xw.WriteAttributeString("visible",
                visible.ToString(CultureInfo.InvariantCulture));

            // Add child elements, if any
            if(!xr.IsEmptyElement)
                while(!xr.EOF)
                {
                    xr.Read();

                    if(xr.NodeType == XmlNodeType.EndElement &&
                      xr.Name == "topic")
                        break;

                    if(xr.NodeType == XmlNodeType.Element)
                        if(xr.Name == "helpAttributes")
                        {
                            xw.WriteStartElement("HelpAttributes");

                            while(!xr.EOF && xr.NodeType != XmlNodeType.EndElement)
                            {
                                if(xr.NodeType == XmlNodeType.Element &&
                                  xr.Name == "helpAttribute")
                                {
                                    name = xr.GetAttribute("name");
                                    value = xr.GetAttribute("value");

                                    if(!String.IsNullOrEmpty(name))
                                    {
                                        xw.WriteStartElement("HelpAttribute");
                                        xw.WriteAttributeString("name", name);
                                        xw.WriteAttributeString("value", value);
                                        xw.WriteEndElement();
                                    }
                                }

                                xr.Read();
                            }

                            xw.WriteEndElement();
                        }
                        else
                            if(xr.Name == "helpKeywords")
                            {
                                xw.WriteStartElement("HelpKeywords");

                                while(!xr.EOF && xr.NodeType != XmlNodeType.EndElement)
                                {
                                    if(xr.NodeType == XmlNodeType.Element &&
                                      xr.Name == "helpKeyword")
                                    {
                                        name = xr.GetAttribute("index");
                                        value = xr.GetAttribute("term");

                                        if(!String.IsNullOrEmpty(name))
                                        {
                                            xw.WriteStartElement("HelpKeyword");
                                            xw.WriteAttributeString("index", name);
                                            xw.WriteAttributeString("term", value);
                                            xw.WriteEndElement();
                                        }
                                    }

                                    xr.Read();
                                }

                                xw.WriteEndElement();
                            }
                            else
                                if(xr.Name == "topic")
                                    this.ConvertTopic(xr, xw, project);
                }

            xw.WriteEndElement();
        }
示例#54
0
        //=====================================================================
        /// <summary>
        /// This is used to execute the task and perform the build
        /// </summary>
        /// <returns>True on success or false on failure.</returns>
        public override bool Execute()
        {
            Project msBuildProject = null;
            string line;

            try
            {
                if(!alwaysLoadProject)
                {
                    // Use the current project if possible.  This is preferable
                    // as we can make use of command line property overrides
                    // and any other user-defined properties.
                    msBuildProject = this.GetCurrentProject();

                    if(msBuildProject == null)
                    {
                        // We can't use a prior MSBuild version
                        if(isPriorMSBuildVersion)
                        {
                            Log.LogError(null, "BHT0004", "BHT0004", "SHFB",
                                0, 0, 0, 0, "An older MSBuild version is " +
                                "being used.  Unable to build help project.");
                            return false;
                        }

                        Log.LogWarning(null, "BHT0001", "BHT0001", "SHFB",
                            0, 0, 0, 0, "Unable to get executing project: " +
                            "Unable to obtain internal reference.  The " +
                            "specified project will be loaded but command " +
                            "line property overrides will be ignored.");
                    }
                }
            }
            catch(Exception ex)
            {
                // Ignore exceptions but issue a warning and fall back to using
                // the passed project filename instead.
                Log.LogWarning(null, "BHT0001", "BHT0001", "SHFB", 0, 0, 0, 0,
                    "Unable to get executing project: {0}.  The specified " +
                    "project will be loaded but command line property " +
                    "overrides will be ignored.", ex.Message);
            }

            if(msBuildProject == null)
            {
                // Create the project and set the configuration and platform
                // options.
                msBuildProject = new Project(Engine.GlobalEngine);
                msBuildProject.GlobalProperties.SetProperty(
                    ProjectElement.Configuration, configuration);
                msBuildProject.GlobalProperties.SetProperty(
                    ProjectElement.Platform, platform);

                // Override the OutDir property if defined for Team Build
                if(!String.IsNullOrEmpty(outDir))
                    msBuildProject.GlobalProperties.SetProperty(
                        ProjectElement.OutDir, outDir);

                if(!File.Exists(projectFile))
                    throw new BuilderException("BHT0003", "The specified " +
                        "project file does not exist: " + projectFile);

                msBuildProject.Load(projectFile);
            }

            // Load the MSBuild project and associate it with a SHFB
            // project instance.
            sandcastleProject = new SandcastleProject(msBuildProject, true);

            try
            {
                buildProcess = new BuildProcess(sandcastleProject);
                buildProcess.BuildStepChanged +=
                    new EventHandler<BuildProgressEventArgs>(
                        buildProcess_BuildStepChanged);
                buildProcess.BuildProgress +=
                    new EventHandler<BuildProgressEventArgs>(
                        buildProcess_BuildProgress);

                // Since this is an MSBuild task, we'll run it directly rather
                // than in a background thread.
                Log.LogMessage("Building {0}", msBuildProject.FullFileName);
                buildProcess.Build();
            }
            catch(Exception ex)
            {
                Log.LogError(null, "BHT0002", "BHT0002", "SHFB", 0, 0, 0, 0,
                  "Unable to build project '{0}': {1}",
                  msBuildProject.FullFileName, ex);
            }

            if(dumpLogOnFailure && lastBuildStep == BuildStep.Failed)
                using(StreamReader sr = new StreamReader(buildProcess.LogFilename))
                {
                    Log.LogMessage(MessageImportance.High, "Log Content:");

                    do
                    {
                        line = sr.ReadLine();

                        // Don't output the XML elements, just the text
                        if(line != null && (line.Trim().Length == 0 ||
                          line.Trim()[0] != '<'))
                            Log.LogMessage(MessageImportance.High, line);

                    } while(line != null);
                }

            return (lastBuildStep == BuildStep.Completed);
        }
        //=====================================================================
        /// <summary>
        /// This is used to perform the actual conversion
        /// </summary>
        /// <returns>The new project filename on success.  An exception is
        /// thrown if the conversion fails.</returns>
        public override string ConvertProject()
        {
            XPathNavigator navProject;
            Topic t;
            string lastProperty = null;

            try
            {
                project = base.Project;
                project.HelpTitle = project.HtmlHelpName =
                    Path.GetFileNameWithoutExtension(base.OldProjectFile);

                // We'll process it as XML rather than an MSBuild project as
                // it may contain references to target files that don't exist
                // which would prevent it from loading.
                docProject = new XmlDocument();
                docProject.Load(base.OldProjectFile);
                nsm = new XmlNamespaceManager(docProject.NameTable);
                nsm.AddNamespace("prj", docProject.DocumentElement.NamespaceURI);
                navProject = docProject.CreateNavigator();

                lastProperty = "ProjectExtensions/VisualStudio";
                this.ImportProjectExtensionProperties();

                // Parse each build item to look for stuff we need to add
                // to the project.
                foreach(XPathNavigator buildItem in navProject.Select(
                  "//prj:Project/prj:ItemGroup/*", nsm))
                {
                    lastProperty = String.Format(CultureInfo.InvariantCulture,
                        "{0} ({1})", buildItem.Name,
                        buildItem.GetAttribute("Include", String.Empty));

                    switch(buildItem.Name)
                    {
                        case "Content":
                        case "None":
                            this.ImportFile(buildItem);
                            break;

                        case "ProjectReference":
                            project.DocumentationSources.Add(base.FullPath(
                                buildItem.GetAttribute("Include", String.Empty)),
                                null, null, false);
                            break;

                        default:    // Ignore
                            break;
                    }
                }

                // Add project-level help attributes if any
                if(topicSettings.TryGetValue("*", out t))
                    foreach(MSHelpAttr ha in t.HelpAttributes)
                        project.HelpAttributes.Add(ha);

                if(topicLayoutFilename != null)
                    this.CreateContentLayoutFile();
                else
                    if(topicSettings.Count != 0)
                        this.CreateDefaultContentLayoutFile();

                base.CreateFolderItems();
                project.SaveProject(project.Filename);
            }
            catch(Exception ex)
            {
                throw new BuilderException("CVT0005", String.Format(
                    CultureInfo.CurrentCulture, "Error reading project " +
                    "from '{0}' (last property = {1}):\r\n{2}",
                    base.OldProjectFile, lastProperty, ex.Message), ex);
            }

            return project.Filename;
        }
示例#56
0
 /// <inheritdoc />
 public ConvertFromNDoc(string oldProjectFile, SandcastleProject newProject) :
   base(oldProjectFile, newProject)
 {
 }
示例#57
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="project">The project into which the converted elements will be inserted</param>
 /// <remarks>This constructor is used by the VSPackage to convert an old project after it creates
 /// a new project instance.</remarks>
 public NewFromOtherFormatDlg(SandcastleProject project) : this()
 {
     currentProject = project;
     txtNewProjectFolder.Text = project.Filename;
     txtNewProjectFolder.Enabled = btnSelectNewFolder.Enabled = false;
 }