public IEnumerable <ProjectItem> Build(Project project)
        {
            var files = project.ProjectItems.ToArray();

            LogMessage($"Scanning {files.Length} project file{(files.Length == 1 ? "" : "s")} for eventsources");

            var extensions = DiscoverExtensions(files);

            var loggerTemplates = DiscoverLoggers(files);

            var outputs = GenerateEventSources(project.ProjectBasePath, loggerTemplates, extensions, files);

            LogMessage($"\tGenerated {outputs.Count()} files");
            foreach (var output in outputs)
            {
                LogMessage($"\t{output.ItemType.Name()} {output.Name}");
            }
            return(outputs);
        }
        public IEnumerable <ProjectItem> GetProjectItems(string projectFilePath)
        {
            LogMessage($"Scanning project {projectFilePath} for eventsource definitions");
            var basePath = System.IO.Path.GetDirectoryName(projectFilePath);

            if (basePath == null)
            {
                LogMessage($"Could not find basePath of {projectFilePath}");
            }
            if (basePath != null)
            {
                var     projectName = System.IO.Path.GetFileNameWithoutExtension(projectFilePath);
                Project project     = null;
                using (var projectFileReader = XmlReader.Create(projectFilePath))
                {
                    project = new Project(projectFileReader);
                    LogMessage($"Loaded project {projectFilePath} from XML with {project.Items.Count} items");
                }

                var hasEventSource = false;
                foreach (
                    var projectItem in project.Items.Where(item => item.EvaluatedInclude.EndsWith(@".eventsource", StringComparison.InvariantCultureIgnoreCase))
                    )
                {
                    var rootNamespace = project.Properties.FirstOrDefault(property => property.Name.Equals("RootNamespace"))?.EvaluatedValue ?? projectName;

                    var projectItemFilePath = System.IO.Path.Combine(basePath, projectItem.EvaluatedInclude);
                    yield return(new ProjectItem(ProjectItemType.EventSourceDefinition, projectItemFilePath)
                    {
                        Include = projectItem.EvaluatedInclude, RootNamespace = rootNamespace
                    });

                    hasEventSource = true;
                }
                foreach (var projectItem in project.Items.Where(item =>
                                                                item.EvaluatedInclude.Matches(@"(^|\\)I[^\\]*Logger.cs", StringComparison.InvariantCultureIgnoreCase, useWildcards: false) &&
                                                                item.ItemType == "Compile"))
                {
                    var projectItemFilePath = System.IO.Path.Combine(basePath, projectItem.EvaluatedInclude);
                    yield return(new ProjectItem(ProjectItemType.LoggerInterface, projectItemFilePath)
                    {
                        Include = projectItem.EvaluatedInclude
                    });
                }

                foreach (var projectItem in project.Items.Where(item =>
                                                                item.EvaluatedInclude.Matches(@"(^|\\)[^\\]*BuilderExtension.cs", StringComparison.InvariantCultureIgnoreCase, useWildcards: false) &&
                                                                item.ItemType == "Compile"))
                {
                    var projectItemFilePath = System.IO.Path.Combine(basePath, projectItem.EvaluatedInclude);
                    yield return(new ProjectItem(ProjectItemType.BuilderExtension, projectItemFilePath)
                    {
                        Include = projectItem.EvaluatedInclude
                    });
                }
                var anyHintPath = "";
                foreach (var projectItem in project.Items.Where(item => item.ItemType == "Reference"))
                {
                    var hintPath = projectItem.HasMetadata("HintPath") ? projectItem.GetMetadataValue("HintPath") : null;
                    hintPath = hintPath != null?PathExtensions.GetAbsolutePath(basePath, hintPath) : null;

                    anyHintPath = hintPath ?? anyHintPath;

                    var projectItemFilePath = hintPath == null ? $"{projectItem.EvaluatedInclude}.dll" : System.IO.Path.Combine(basePath, hintPath);

                    yield return(new ProjectItem(ProjectItemType.Reference, projectItemFilePath)
                    {
                        Include = projectItem.EvaluatedInclude
                    });
                }

                var outputPath =
                    project.Items.FirstOrDefault(item => item.ItemType.Equals("_OutputPathItem", StringComparison.InvariantCultureIgnoreCase))?.EvaluatedInclude;
                foreach (var projectItem in project.Items.Where(item => item.ItemType == "ProjectReference"))
                {
                    var referencedProjectPath       = PathExtensions.GetAbsolutePath(basePath, projectItem.EvaluatedInclude);
                    var referencedProjectName       = System.IO.Path.GetFileNameWithoutExtension(projectItem.EvaluatedInclude);
                    var expectedDllName             = $"{referencedProjectName}.dll";
                    var referencedProjectOutputPath = PathExtensions.GetAbsolutePath(System.IO.Path.GetDirectoryName(referencedProjectPath), outputPath);
                    var projectItemFilePath         = System.IO.Path.Combine(referencedProjectOutputPath, expectedDllName);
                    if (System.IO.File.Exists(projectItemFilePath))
                    {
                        yield return(new ProjectItem(ProjectItemType.Reference, projectItemFilePath)
                        {
                            Include = projectItem.EvaluatedInclude
                        });
                    }
                }

                if (!hasEventSource)
                {
                    var rootNamespace = project.Properties.FirstOrDefault(property => property.Name.Equals("RootNamespace"))?.EvaluatedValue ?? projectName;

                    var include             = $"DefaultEventSource.eventsource";
                    var projectItemFilePath = System.IO.Path.Combine(basePath, include);
                    yield return(new ProjectItem(ProjectItemType.DefaultGeneratedEventSource, projectItemFilePath)
                    {
                        Include = include, RootNamespace = rootNamespace
                    });
                }
            }
        }
        public void AddGeneratedOutputsToProject(string projectFilePath, IEnumerable <ProjectItem> includes, bool saveChanges = true)
        {
            LogMessage($"Loading projectfile {projectFilePath} to include new files");
            var     basePath                    = System.IO.Path.GetDirectoryName(projectFilePath);
            Project project                     = null;
            var     updatedProjectFile          = false;
            var     loadedFromProjectCollection = false;

            foreach (var loadedProject in ProjectCollection.GlobalProjectCollection.LoadedProjects)
            {
                if (loadedProject.FullPath.Equals(projectFilePath, StringComparison.InvariantCultureIgnoreCase))
                {
                    project = loadedProject;
                    LogMessage($"Loaded project {projectFilePath} from GlobalProjectCollection with {project.Items.Count} items");
                    loadedFromProjectCollection = true;
                    break;
                }
            }
            if (project == null)
            {
                using (var projectFileReader = XmlReader.Create(projectFilePath))
                {
                    project = new Project(projectFileReader);
                    LogMessage($"Loaded project {projectFilePath} from XML with {project.Items.Count} items");
                }
            }
            if (project == null)
            {
                throw new NotSupportedException($"Failed to load {projectFilePath} from either XML or GlobalProjectCollection");
            }

            var existingItems = new List <Microsoft.Build.Evaluation.ProjectItem>();

            existingItems.AddRange(project.Items.Where(item => item.HasMetadata("AutoGenerated")));

            // Add or check that it alread exists
            foreach (var include in includes)
            {
                var includeName = include.Name.StartsWith(basePath) ? include.Name.Substring(basePath.Length + 1) : include.Name;

                var alreadyIncluded = false;
                var matchingItems   = project.Items.Where(item => item.EvaluatedInclude.Matches($"{includeName}", StringComparison.InvariantCultureIgnoreCase));
                alreadyIncluded = matchingItems.Any();
                if (!alreadyIncluded)
                {
                    var metadata = Enum.GetName(typeof(ProjectItemType), include.ItemType);
                    updatedProjectFile = true;
                    IList <Microsoft.Build.Evaluation.ProjectItem> addedItems = null;
                    if (include.ItemType == ProjectItemType.DefaultGeneratedEventSource)
                    {
                        var hash = include.Content.ToMD5().ToHex();
                        addedItems = project.AddItem("Compile", includeName, new KeyValuePair <string, string>[]
                        {
                            new KeyValuePair <string, string>("AutoGenerated", metadata),
                            new KeyValuePair <string, string>("Hash", hash),
                        });
                    }
                    else
                    {
                        addedItems = project.AddItem("Compile", includeName, new KeyValuePair <string, string>[]
                        {
                            new KeyValuePair <string, string>("AutoGen", "true"),
                            new KeyValuePair <string, string>("AutoGenerated", metadata),
                            new KeyValuePair <string, string>("DependentUpon", include.DependentUpon.Include.RemoveCommonPrefix(includeName, System.IO.Path.DirectorySeparatorChar)),
                        });
                    }

                    foreach (var addedItem in addedItems)
                    {
                        LogMessage($"Including project item {addedItem.EvaluatedInclude}");
                        existingItems.Remove(addedItem);
                    }
                }
                else
                {
                    foreach (var matchingItem in matchingItems)
                    {
                        LogMessage($"Matched existing project item {matchingItem.EvaluatedInclude}");
                        existingItems.Remove(matchingItem);
                    }
                }
            }
            // Check if we should remove the AutoGenerated DefaultEventSource.eventsource
            var autoGeneratedDefaultEventSource = existingItems.FirstOrDefault(
                existingItem => existingItem.HasMetadata("AutoGenerated") && existingItem.GetMetadataValue("AutoGenerated") == "DefaultEventSource");

            if (autoGeneratedDefaultEventSource != null)
            {
                if (autoGeneratedDefaultEventSource.EvaluatedInclude != "DefaultEventSource.cs")
                {
                    updatedProjectFile = true;
                    LogMessage($"Updating Project Metadata for {autoGeneratedDefaultEventSource.EvaluatedInclude} as it has been changed from it's original state");
                    autoGeneratedDefaultEventSource.RemoveMetadata("AutoGenerated");
                    existingItems.Remove(autoGeneratedDefaultEventSource);
                }
                else
                {
                    var hash = autoGeneratedDefaultEventSource.HasMetadata("Hash") ? autoGeneratedDefaultEventSource.GetMetadataValue("Hash") : "";

                    var filePath    = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(projectFilePath), autoGeneratedDefaultEventSource.EvaluatedInclude);
                    var fileContent = System.IO.File.ReadAllText(filePath);

                    var hashCheck = fileContent.ToMD5().ToHex();

                    if (hash != hashCheck)
                    {
                        updatedProjectFile = true;
                        LogMessage($"Updating Project Metadata for {autoGeneratedDefaultEventSource.EvaluatedInclude} as it's content been changed from it's original state");
                        autoGeneratedDefaultEventSource.RemoveMetadata("AutoGenerated");
                        existingItems.Remove(autoGeneratedDefaultEventSource);
                    }
                }
            }

            // Remove old items that are no longer referenced
            foreach (var existingItem in existingItems)
            {
                LogMessage($"Removing existing project item {existingItem.EvaluatedInclude}");
            }
            if (existingItems.Count > 0)
            {
                updatedProjectFile = true;
                project.RemoveItems(existingItems);
            }

            if (!updatedProjectFile)
            {
                LogMessage($"Igoring to save project file {projectFilePath} - no changes performed");
            }
            else
            {
                if (saveChanges)
                {
                    if (loadedFromProjectCollection)
                    {
                        LogMessage($"Unloading project file {projectFilePath} from Global project collection");
                        ProjectCollection.GlobalProjectCollection.UnloadProject(project);
                    }
                    LogMessage($"Saving project file {projectFilePath}");
                    project.Save(projectFilePath);
                    LogMessage($"Loading project file {projectFilePath} in Global project collection");
                    ProjectCollection.GlobalProjectCollection.LoadProject(projectFilePath);
                }
                else
                {
                    LogMessage($"Project file {projectFilePath} changed");
                    LogMessage(project.Xml.RawXml);
                }
            }
        }