Example #1
0
        /// <summary>
        /// Load the build components found in the Components and Plug-Ins
        /// folder and its subfolders.
        /// </summary>
        private static void LoadBuildComponents()
        {
            List <string>      allFiles = new List <string>();
            XPathDocument      configFile;
            XPathNavigator     navConfig;
            BuildComponentInfo info;
            string             componentPath;

            SetPaths();

            buildComponents = new Dictionary <string, BuildComponentInfo>();

            // Give precedence to components in the optional SHFBCOMPONENTROOT
            // environment variable folder.
            componentPath = Environment.ExpandEnvironmentVariables("%SHFBCOMPONENTROOT%");

            if (!String.IsNullOrEmpty(componentPath) && Directory.Exists(componentPath))
            {
                allFiles.AddRange(Directory.GetFiles(componentPath, "*.components",
                                                     SearchOption.AllDirectories));
            }

            // Add the standard component config file and any third-party
            // component config files in the installation folder.  This
            // allows for XCOPY deployments of SHFB to build servers.
            allFiles.AddRange(Directory.GetFiles(shfbFolder, "*.components",
                                                 SearchOption.AllDirectories));

            // Finally, check the common app data build components folder
            if (Directory.Exists(buildComponentFolder))
            {
                allFiles.AddRange(Directory.GetFiles(buildComponentFolder,
                                                     "*.components", SearchOption.AllDirectories));
            }

            foreach (string file in allFiles)
            {
                configFile = new XPathDocument(file);
                navConfig  = configFile.CreateNavigator();

                foreach (XPathNavigator component in navConfig.Select("components/component"))
                {
                    info = new BuildComponentInfo(component);

                    // Ignore components with duplicate IDs
                    if (!buildComponents.ContainsKey(info.Id))
                    {
                        buildComponents.Add(info.Id, info);
                    }
                }
            }
        }
        /// <summary>
        /// This handles merging of the custom component configurations into
        /// the configuration file including dependencies.
        /// </summary>
        /// <param name="id">The ID of the component to merge</param>
        /// <param name="info">The build component definition</param>
        /// <param name="rootNode">The root container node</param>
        /// <param name="configNode">The configuration node to merge</param>
        /// <param name="isConceptualConfig">True if this is a conceptual
        /// content configuration file or false if it is a reference build
        /// configuration file.</param>
        private void MergeComponent(string id, BuildComponentInfo info, XmlNode rootNode, XmlNode configNode,
          bool isConceptualConfig)
        {
            BuildComponentInfo depInfo;
            ComponentPosition position;
            XmlNodeList matchingNodes;
            XmlNode node;
            string replaceId;

            // Merge dependent component configurations first
            if(info.Dependencies.Count != 0)
                foreach(string dependency in info.Dependencies)
                {
                    node = rootNode.SelectSingleNode("component[@id='" + dependency + "']");

                    // If it's already there or would create a circular
                    // dependency, ignore it.
                    if(node != null || mergeStack.Contains(dependency))
                        continue;

                    // Add the dependency with a default configuration
                    if(!BuildComponentManager.BuildComponents.TryGetValue(dependency, out depInfo))
                        throw new BuilderException("BE0023", String.Format(
                            CultureInfo.InvariantCulture, "The project contains " +
                            "a reference to a custom build component '{0}' that " +
                            "has a dependency '{1}' that could not be found.",
                            id, dependency));

                    node = rootNode.OwnerDocument.CreateDocumentFragment();
                    node.InnerXml = reField.Replace(depInfo.DefaultConfiguration, fieldMatchEval);

                    this.ReportProgress("    Merging '{0}' dependency for '{1}'", dependency, id);

                    mergeStack.Push(dependency);
                    this.MergeComponent(dependency, depInfo, rootNode, node, isConceptualConfig);
                    mergeStack.Pop();
                }

            position = (!isConceptualConfig) ? info.ReferenceBuildPosition : info.ConceptualBuildPosition;

            // Find all matching components by ID or type name
            if(!String.IsNullOrEmpty(position.Id))
            {
                replaceId = position.Id;
                matchingNodes = rootNode.SelectNodes("component[@id='" + replaceId + "']");
            }
            else
            {
                replaceId = position.TypeName;
                matchingNodes = rootNode.SelectNodes("component[@type='" + replaceId + "']");
            }

            // If replacing another component, search for that by ID or
            // type and replace it if found.
            if(position.Place == ComponentPosition.Placement.Replace)
            {
                if(matchingNodes.Count < position.AdjustedInstance)
                {
                    this.ReportProgress("    Could not find configuration '{0}' (instance {1}) to replace with " +
                        "configuration for '{2}' so it will be omitted.", replaceId, position.AdjustedInstance, id);

                    // If it's a dependency, that's a problem
                    if(mergeStack.Count != 0)
                        throw new BuilderException("BE0024", "Unable to add dependent configuration: " + id);

                    return;
                }

                rootNode.ReplaceChild(configNode, matchingNodes[position.AdjustedInstance - 1]);

                this.ReportProgress("    Replaced configuration for '{0}' (instance {1}) with configuration " +
                    "for '{2}'", replaceId, position.AdjustedInstance, id);

                // Adjust instance values on matching components
                foreach(BuildComponentInfo component in BuildComponentManager.BuildComponents.Values)
                  if(!isConceptualConfig)
                  {
                    if(((!String.IsNullOrEmpty(component.ReferenceBuildPosition.Id) &&
                      component.ReferenceBuildPosition.Id == replaceId) ||
                      (String.IsNullOrEmpty(component.ReferenceBuildPosition.Id) &&
                      component.ReferenceBuildPosition.TypeName == replaceId)) &&
                      component.ReferenceBuildPosition.AdjustedInstance >
                      position.AdjustedInstance)
                        component.ReferenceBuildPosition.AdjustedInstance--;
                  }
                  else
                      if(((!String.IsNullOrEmpty(component.ConceptualBuildPosition.Id) &&
                        component.ConceptualBuildPosition.Id == replaceId) ||
                        (String.IsNullOrEmpty(component.ConceptualBuildPosition.Id) &&
                        component.ConceptualBuildPosition.TypeName == replaceId)) &&
                        component.ConceptualBuildPosition.AdjustedInstance >
                        position.AdjustedInstance)
                          component.ConceptualBuildPosition.AdjustedInstance--;

                return;
            }

            // See if the configuration already exists.  If so, replace it.
            // We'll assume it's already in the correct location.
            node = rootNode.SelectSingleNode("component[@id='" + id + "']");

            if(node != null)
            {
                this.ReportProgress("    Replacing default configuration for '{0}' with the custom configuration", id);
                rootNode.ReplaceChild(configNode, node);
                return;
            }

            // Create the node and add it in the correct location
            switch(position.Place)
            {
                case ComponentPosition.Placement.Start:
                    rootNode.InsertBefore(configNode, rootNode.ChildNodes[0]);
                    this.ReportProgress("    Added configuration for '{0}' to the start of the configuration file", id);
                    break;

                case ComponentPosition.Placement.End:
                    rootNode.InsertAfter(configNode,
                        rootNode.ChildNodes[rootNode.ChildNodes.Count - 1]);
                    this.ReportProgress("    Added configuration for '{0}' to the end of the configuration file", id);
                    break;

                case ComponentPosition.Placement.Before:
                    if(matchingNodes.Count < position.AdjustedInstance)
                        this.ReportProgress("    Could not find configuration '{0}' (instance {1}) to add " +
                            "configuration for '{2}' so it will be omitted.", replaceId, position.AdjustedInstance, id);
                    else
                    {
                        rootNode.InsertBefore(configNode, matchingNodes[position.AdjustedInstance - 1]);
                        this.ReportProgress("    Added configuration for '{0}' before '{1}' (instance {2})",
                            id, replaceId, position.AdjustedInstance);
                    }
                    break;

                default:    // After
                    if(matchingNodes.Count < position.AdjustedInstance)
                        this.ReportProgress("    Could not find configuration '{0}' (instance {1}) to add " +
                            "configuration for '{2}' so it will be omitted.", replaceId, position.AdjustedInstance, id);
                    else
                    {
                        rootNode.InsertAfter(configNode, matchingNodes[position.AdjustedInstance - 1]);
                        this.ReportProgress("    Added configuration for '{0}' after '{1}' (instance {2})",
                            id, replaceId, position.AdjustedInstance);
                    }
                    break;
            }
        }
        /// <summary>
        /// Load the build components found in the Components and Plug-Ins
        /// folder and its subfolders.
        /// </summary>
        private static void LoadBuildComponents()
        {
            List<string> allFiles = new List<string>();
            XPathDocument configFile;
            XPathNavigator navConfig;
            BuildComponentInfo info;
            string componentPath;

            SetPaths();

            buildComponents = new Dictionary<string, BuildComponentInfo>();

            // Give precedence to components in the optional SHFBCOMPONENTROOT
            // environment variable folder.
            componentPath = Environment.ExpandEnvironmentVariables("%SHFBCOMPONENTROOT%");

            if(!String.IsNullOrEmpty(componentPath) && Directory.Exists(componentPath))
                allFiles.AddRange(Directory.GetFiles(componentPath, "*.components",
                    SearchOption.AllDirectories));

            // Add the standard component config file and any third-party
            // component config files in the installation folder.  This
            // allows for XCOPY deployments of SHFB to build servers.
            allFiles.AddRange(Directory.GetFiles(shfbFolder, "*.components",
                SearchOption.AllDirectories));

            // Finally, check the common app data build components folder
            if(Directory.Exists(buildComponentFolder))
                allFiles.AddRange(Directory.GetFiles(buildComponentFolder,
                    "*.components", SearchOption.AllDirectories));

            foreach(string file in allFiles)
            {
                configFile = new XPathDocument(file);
                navConfig = configFile.CreateNavigator();

                foreach(XPathNavigator component in navConfig.Select("components/component"))
                {
                    info = new BuildComponentInfo(component);

                    // Ignore components with duplicate IDs
                    if(!buildComponents.ContainsKey(info.Id))
                        buildComponents.Add(info.Id, info);
                }
            }
        }