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); } } }