/// <summary>
        /// Attempts to read project information for the given file.
        /// </summary>
        /// <param name="File">The project file to read</param>
        /// <param name="Properties">Initial set of property values</param>
        /// <param name="OutProjectInfo">If successful, the parsed project info</param>
        /// <returns>True if the project was read successfully, false otherwise</returns>
        public static bool TryRead(FileReference File, Dictionary <string, string> Properties, out CsProjectInfo OutProjectInfo)
        {
            // Read the project file
            XmlDocument Document = new XmlDocument();

            Document.Load(File.FullName);

            // Check the root element is the right type
            //			HashSet<FileReference> ProjectBuildProducts = new HashSet<FileReference>();
            if (Document.DocumentElement.Name != "Project")
            {
                OutProjectInfo = null;
                return(false);
            }

            // Parse the basic structure of the document, updating properties and recursing into other referenced projects as we go
            CsProjectInfo ProjectInfo = new CsProjectInfo(Properties, File);

            // Parse elements in the root node
            ParseNode(Document.DocumentElement, ProjectInfo);

            // Return the complete project
            OutProjectInfo = ProjectInfo;
            return(true);
        }
        /// <summary>
        /// Parses supported elements from the children of the provided note. May recurse
        /// for conditional elements.
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="ProjectInfo"></param>
        static void ParseNode(XmlNode Node, CsProjectInfo ProjectInfo)
        {
            foreach (XmlElement Element in Node.ChildNodes.OfType <XmlElement>())
            {
                switch (Element.Name)
                {
                case "PropertyGroup":
                    if (EvaluateCondition(Element, ProjectInfo))
                    {
                        ParsePropertyGroup(Element, ProjectInfo);
                    }
                    break;

                case "ItemGroup":
                    if (EvaluateCondition(Element, ProjectInfo))
                    {
                        ParseItemGroup(ProjectInfo.ProjectPath.Directory, Element, ProjectInfo);
                    }
                    break;

                case "Choose":
                case "When":
                    if (EvaluateCondition(Element, ProjectInfo))
                    {
                        ParseNode(Element, ProjectInfo);
                    }
                    break;
                }
            }
        }
        /// <summary>
        /// Adds aall input/output properties of a CSProject to a hash collection
        /// </summary>
        /// <param name="Hasher"></param>
        /// <param name="Project"></param>
        /// <returns></returns>
        public static bool AddCsProjectInfo(this HashCollection Hasher, CsProjectInfo Project, HashCollection.HashType HashType)
        {
            // Get the output assembly and pdb file
            FileReference OutputFile;

            if (!Project.TryGetOutputFile(out OutputFile))
            {
                throw new Exception(String.Format("Unable to get output file for {0}", Project.ProjectPath));
            }
            FileReference DebugFile = OutputFile.ChangeExtension("pdb");

            // build a list of all input and output files from this module
            List <FileReference> DependentFiles = new List <FileReference> {
                Project.ProjectPath, OutputFile, DebugFile
            };

            DependentFiles.AddRange(Project.CompileReferences);

            if (!Hasher.AddFiles(DependentFiles, HashType))
            {
                return(false);
            }

            return(true);
        }
 /// <summary>
 /// Parses a 'PropertyGroup' element.
 /// </summary>
 /// <param name="ParentElement">The parent 'PropertyGroup' element</param>
 /// <param name="Properties">Dictionary mapping property names to values</param>
 static void ParsePropertyGroup(XmlElement ParentElement, CsProjectInfo ProjectInfo)
 {
     // We need to know the overridden output type and output path for the selected configuration.
     foreach (XmlElement Element in ParentElement.ChildNodes.OfType <XmlElement>())
     {
         if (EvaluateCondition(Element, ProjectInfo))
         {
             ProjectInfo.Properties[Element.Name] = ExpandProperties(Element.InnerText, ProjectInfo.Properties);
         }
     }
 }
Exemple #5
0
        /// <summary>
        /// Attempts to read project information for the given file.
        /// </summary>
        /// <param name="File">The project file to read</param>
        /// <param name="Properties">Initial set of property values</param>
        /// <param name="OutProjectInfo">If successful, the parsed project info</param>
        /// <returns>True if the project was read successfully, false otherwise</returns>
        public static bool TryRead(FileReference File, Dictionary <string, string> Properties, out CsProjectInfo OutProjectInfo)
        {
            // Read the project file
            XmlDocument Document = new XmlDocument();

            Document.Load(File.FullName);

            // Check the root element is the right type
            //			HashSet<FileReference> ProjectBuildProducts = new HashSet<FileReference>();
            if (Document.DocumentElement.Name != "Project")
            {
                OutProjectInfo = null;
                return(false);
            }

            // Parse the basic structure of the document, updating properties and recursing into other referenced projects as we go
            CsProjectInfo ProjectInfo = new CsProjectInfo(Properties);

            foreach (XmlElement Element in Document.DocumentElement.ChildNodes.OfType <XmlElement>())
            {
                switch (Element.Name)
                {
                case "PropertyGroup":
                    if (EvaluateCondition(Element, ProjectInfo.Properties))
                    {
                        ParsePropertyGroup(Element, ProjectInfo.Properties);
                    }
                    break;

                case "ItemGroup":
                    if (EvaluateCondition(Element, ProjectInfo.Properties))
                    {
                        ParseItemGroup(File.Directory, Element, ProjectInfo);
                    }
                    break;
                }
            }

            // Return the complete project
            OutProjectInfo = ProjectInfo;
            return(true);
        }
        /// <summary>
        /// Adds aall input/output properties of a CSProject to a hash collection
        /// </summary>
        /// <param name="Hasher"></param>
        /// <param name="Project"></param>
        /// <returns></returns>
        public static bool AddCsProjectInfo(this HashCollection Hasher, CsProjectInfo Project, HashCollection.HashType HashType)
        {
            // Get the output assembly and pdb file
            DirectoryReference ProjectDirectory = Project.ProjectPath.Directory;
            DirectoryReference OutputDir        = Project.GetOutputDir(ProjectDirectory);
            FileReference      OutputFile       = FileReference.Combine(OutputDir, Project.GetAssemblyName() + ".dll");
            FileReference      DebugFile        = OutputFile.ChangeExtension("pdb");

            // build a list of all input and output files from this module
            List <FileReference> DependentFiles = new List <FileReference> {
                Project.ProjectPath, OutputFile, DebugFile
            };

            DependentFiles.AddRange(Project.CompileReferences);

            if (!Hasher.AddFiles(DependentFiles, HashType))
            {
                return(false);
            }

            return(true);
        }
Exemple #7
0
        /// <summary>
        /// Parses an 'ItemGroup' element.
        /// </summary>
        /// <param name="BaseDirectory">Base directory to resolve relative paths against</param>
        /// <param name="ParentElement">The parent 'ItemGroup' element</param>
        /// <param name="ProjectInfo">Project info object to be updated</param>
        static void ParseItemGroup(DirectoryReference BaseDirectory, XmlElement ParentElement, CsProjectInfo ProjectInfo)
        {
            // Parse any external assembly references
            foreach (XmlElement ItemElement in ParentElement.ChildNodes.OfType <XmlElement>())
            {
                switch (ItemElement.Name)
                {
                case "Reference":
                    // Reference to an external assembly
                    if (EvaluateCondition(ItemElement, ProjectInfo.Properties))
                    {
                        ParseReference(BaseDirectory, ItemElement, ProjectInfo.References);
                    }
                    break;

                case "ProjectReference":
                    // Reference to another project
                    if (EvaluateCondition(ItemElement, ProjectInfo.Properties))
                    {
                        ParseProjectReference(BaseDirectory, ItemElement, ProjectInfo.ProjectReferences);
                    }
                    break;

                case "Content":
                case "None":
                    // Reference to another project
                    if (EvaluateCondition(ItemElement, ProjectInfo.Properties))
                    {
                        ParseContent(BaseDirectory, ItemElement, ProjectInfo.ContentReferences);
                    }
                    break;
                }
            }
        }
        /// <summary>
        /// Evaluate whether the optional MSBuild condition on an XML element evaluates to true. Currently only supports 'ABC' == 'DEF' style expressions, but can be expanded as needed.
        /// </summary>
        /// <param name="Element">The XML element to check</param>
        /// <param name="Properties">Dictionary mapping from property names to values.</param>
        /// <returns></returns>
        static bool EvaluateCondition(XmlElement Element, CsProjectInfo ProjectInfo)
        {
            // Read the condition attribute. If it's not present, assume it evaluates to true.
            string Condition = Element.GetAttribute("Condition");

            if (String.IsNullOrEmpty(Condition))
            {
                return(true);
            }

            // Expand all the properties
            Condition = ExpandProperties(Condition, ProjectInfo.Properties);

            // Parse literal true/false values
            bool OutResult;

            if (bool.TryParse(Condition, out OutResult))
            {
                return(OutResult);
            }

            // Tokenize the condition
            string[] Tokens = Tokenize(Condition);

            char[] TokenQuotes = new[] { '\'', '(', ')', '{', '}', '[', ']' };

            // Try to evaluate it. We only support a very limited class of condition expressions at the moment, but it's enough to parse standard projects
            bool bResult;

            // Handle Exists('Platform\Windows\Gauntlet.TargetDeviceWindows.cs')
            if (Tokens[0] == "Exists")
            {
                // remove all quotes, apostrophes etc that are either tokens or wrap tokens (The Tokenize() function is a bit suspect).
                string[] Arguments = Tokens.Select(S => S.Trim(TokenQuotes)).Where(S => S.Length > 0).ToArray();

                if (Tokens.Length > 1)
                {
                    FileSystemReference Dependency = DirectoryReference.Combine(ProjectInfo.ProjectPath.Directory, Arguments[1]);

                    if (File.Exists(Dependency.FullName) || Directory.Exists(Dependency.FullName))
                    {
                        return(true);
                    }

                    return(false);
                }
            }

            if (Tokens.Length == 3 && Tokens[0].StartsWith("'") && Tokens[1] == "==" && Tokens[2].StartsWith("'"))
            {
                bResult = String.Compare(Tokens[0], Tokens[2], StringComparison.InvariantCultureIgnoreCase) == 0;
            }
            else if (Tokens.Length == 3 && Tokens[0].StartsWith("'") && Tokens[1] == "!=" && Tokens[2].StartsWith("'"))
            {
                bResult = String.Compare(Tokens[0], Tokens[2], StringComparison.InvariantCultureIgnoreCase) != 0;
            }
            else
            {
                string Msg = string.Format("Couldn't parse condition {0} in project file {1}", Element.ToString(), ProjectInfo.ProjectPath);
                throw new Exception(Msg);
            }
            return(bResult);
        }