private void ExploreDirectory()

in src/Tasks/BootstrapperUtil/BootstrapperBuilder.cs [900:1080]


        private void ExploreDirectory(string strSubDirectory, XmlElement rootElement)
        {
            try
            {
                string packagePath = PackagePath;
                string strSubDirectoryFullPath = System.IO.Path.Combine(packagePath, strSubDirectory);

                // figure out our product file paths based on the directory full path
                string strBaseManifestFilename = System.IO.Path.Combine(strSubDirectoryFullPath, ROOT_MANIFEST_FILE);
                string strBaseManifestSchemaFileName = System.IO.Path.Combine(SchemaPath, MANIFEST_FILE_SCHEMA);

                ProductValidationResults productValidationResults = new ProductValidationResults(strBaseManifestFilename);

                // open the XmlDocument for this product.xml
                XmlDocument productDoc = LoadAndValidateXmlDocument(strBaseManifestFilename, false, strBaseManifestSchemaFileName, BOOTSTRAPPER_NAMESPACE, productValidationResults);
                if (productDoc != null)
                {
                    bool packageAdded = false;

                    XmlNode baseNode = productDoc.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":Product", _xmlNamespaceManager);
                    if (baseNode != null)
                    {
                        // Get the ProductCode attribute for this product
                        XmlAttribute productCodeAttribute = (XmlAttribute)(baseNode.Attributes.GetNamedItem("ProductCode"));
                        if (productCodeAttribute != null)
                        {
                            // now add it to our full document if it's not already present
                            XmlNode productNode = rootElement.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":Product[@ProductCode='" + productCodeAttribute.Value + "']", _xmlNamespaceManager);
                            if (productNode == null)
                            {
                                productNode = CreateProductNode(baseNode);
                            }
                            else
                            {
                                productValidationResults = (ProductValidationResults)_validationResults[productCodeAttribute];
                            }

                            // Fix-up the <PackageFiles> of the base node to include the SourcePath and TargetPath
                            XmlNode packageFilesNode = baseNode.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":PackageFiles", _xmlNamespaceManager);
                            XmlNode checksNode = baseNode.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":InstallChecks", _xmlNamespaceManager);
                            XmlNode commandsNode = baseNode.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":Commands", _xmlNamespaceManager);

                            // if there was a packageFiles node, then add it in to our full document with the rest
                            if (packageFilesNode != null)
                            {
                                UpdatePackageFileNodes(packageFilesNode, System.IO.Path.Combine(packagePath, strSubDirectory), strSubDirectory);

                                ReplacePackageFileAttributes(checksNode, "PackageFile", packageFilesNode, "PackageFile", "OldName", "Name");
                                ReplacePackageFileAttributes(commandsNode, "PackageFile", packageFilesNode, "PackageFile", "OldName", "Name");
                                ReplacePackageFileAttributes(baseNode, EULA_ATTRIBUTE, packageFilesNode, "PackageFile", "OldName", "SourcePath");
                            }

                            foreach (string strLanguageDirectory in Directory.GetDirectories(strSubDirectoryFullPath))
                            {
                                // The base node would get destroyed as we build-up this new node.
                                // Thus, we want to use a copy of the baseNode
                                XmlElement baseElement = (XmlElement)(_document.ImportNode(baseNode, true));

                                string strLangManifestFilename = System.IO.Path.Combine(strLanguageDirectory, CHILD_MANIFEST_FILE);
                                string strLangManifestSchemaFileName = System.IO.Path.Combine(SchemaPath, MANIFEST_FILE_SCHEMA);

                                if (File.Exists(strLangManifestFilename))
                                {
                                    // Load Package.xml
                                    XmlValidationResults packageValidationResults = new XmlValidationResults(strLangManifestFilename);
                                    XmlDocument langDoc = LoadAndValidateXmlDocument(strLangManifestFilename, false, strLangManifestSchemaFileName, BOOTSTRAPPER_NAMESPACE, packageValidationResults);

                                    Debug.Assert(langDoc != null, "we couldn't load package.xml in '" + strLangManifestFilename + "'...?");
                                    if (langDoc == null)
                                        continue;

                                    XmlNode langNode = langDoc.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":Package", _xmlNamespaceManager);
                                    Debug.Assert(langNode != null, string.Format(CultureInfo.CurrentCulture, "Unable to find a package node in {0}", strLangManifestFilename));
                                    if (langNode != null)
                                    {
                                        XmlElement langElement = (XmlElement)(_document.ImportNode(langNode, true));
                                        XmlElement mergeElement = _document.CreateElement("Package", BOOTSTRAPPER_NAMESPACE);

                                        // Update the "PackageFiles" section to reflect this language subdirectory
                                        XmlNode packageFilesNodePackage = langElement.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":PackageFiles", _xmlNamespaceManager);
                                        checksNode = langElement.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":InstallChecks", _xmlNamespaceManager);
                                        commandsNode = langElement.SelectSingleNode(BOOTSTRAPPER_PREFIX + ":Commands", _xmlNamespaceManager);

                                        if (packageFilesNodePackage != null)
                                        {
                                            int nStartIndex = packagePath.Length;

                                            if ((strLanguageDirectory.ToCharArray())[nStartIndex] == System.IO.Path.DirectorySeparatorChar)
                                                nStartIndex++;
                                            UpdatePackageFileNodes(packageFilesNodePackage, strLanguageDirectory, strSubDirectory);

                                            ReplacePackageFileAttributes(checksNode, "PackageFile", packageFilesNodePackage, "PackageFile", "OldName", "Name");
                                            ReplacePackageFileAttributes(commandsNode, "PackageFile", packageFilesNodePackage, "PackageFile", "OldName", "Name");
                                            ReplacePackageFileAttributes(langElement, EULA_ATTRIBUTE, packageFilesNodePackage, "PackageFile", "OldName", "SourcePath");
                                        }

                                        if (packageFilesNode != null)
                                        {
                                            ReplacePackageFileAttributes(checksNode, "PackageFile", packageFilesNode, "PackageFile", "OldName", "Name");
                                            ReplacePackageFileAttributes(commandsNode, "PackageFile", packageFilesNode, "PackageFile", "OldName", "Name");
                                            ReplacePackageFileAttributes(langElement, EULA_ATTRIBUTE, packageFilesNode, "PackageFile", "OldName", "SourcePath");
                                        }

                                        // in general, we prefer the attributes of the language document over the 
                                        //  attributes of the base document.  Copy attributes from the lang to the merged,
                                        //  and then merge all unique elements into merge
                                        foreach (XmlAttribute attribute in langElement.Attributes)
                                        {
                                            mergeElement.Attributes.Append((XmlAttribute)(mergeElement.OwnerDocument.ImportNode(attribute, false)));
                                        }

                                        foreach (XmlAttribute attribute in baseElement.Attributes)
                                        {
                                            XmlAttribute convertedAttribute = (XmlAttribute)(mergeElement.OwnerDocument.ImportNode(attribute, false));
                                            MergeAttribute(mergeElement, convertedAttribute);
                                        }

                                        // And append all of the nodes
                                        //  There is a well-known set of nodes which may have inherit children
                                        //  When merging these nodes, there may be subnodes taken from both the lang element and the base element.
                                        //  There will never be multiple nodes with the same name in the same manifest
                                        //  The function which performs this action is CombineElements(...)
                                        CombineElements(langElement, baseElement, "Commands", "PackageFile", mergeElement);
                                        CombineElements(langElement, baseElement, "InstallChecks", "Property", mergeElement);
                                        CombineElements(langElement, baseElement, "PackageFiles", "Name", mergeElement);
                                        CombineElements(langElement, baseElement, "Schedules", "Name", mergeElement);
                                        CombineElements(langElement, baseElement, "Strings", "Name", mergeElement);

                                        ReplaceStrings(mergeElement);
                                        CorrectPackageFiles(mergeElement);

                                        AppendNode(baseElement, "RelatedProducts", mergeElement);

                                        // Create a unique identifier for this package
                                        XmlAttribute cultureAttribute = (XmlAttribute)mergeElement.Attributes.GetNamedItem("Culture");
                                        if (cultureAttribute != null && !String.IsNullOrEmpty(cultureAttribute.Value))
                                        {
                                            string packageCode = productCodeAttribute.Value + "." + cultureAttribute.Value;
                                            AddAttribute(mergeElement, "PackageCode", packageCode);

                                            if (productValidationResults != null && packageValidationResults != null)
                                            {
                                                productValidationResults.AddPackageResults(cultureAttribute.Value, packageValidationResults);
                                            }

                                            // Only add this package if there is a culture apecified.
                                            productNode.AppendChild(mergeElement);
                                            packageAdded = true;
                                        }
                                    }
                                }
                            }
                            if (packageAdded)
                            {
                                rootElement.AppendChild(productNode);
                                if (!_validationResults.Contains(productCodeAttribute.Value))
                                {
                                    _validationResults.Add(productCodeAttribute.Value, productValidationResults);
                                }
                                else
                                {
                                    Debug.WriteLine(String.Format(CultureInfo.CurrentCulture, "Validation results already added for Product Code '{0}'", productCodeAttribute));
                                }
                            }
                        }
                    }
                }
            }
            catch (XmlException ex)
            {
                Debug.Fail(ex.Message);
            }
            catch (System.IO.IOException ex)
            {
                Debug.Fail(ex.Message);
            }
            catch (ArgumentException ex)
            {
                Debug.Fail(ex.Message);
            }
        }