/// <summary> /// Retrieve metadata for all tasks defined in the project. /// </summary> /// <param name="cancellationToken"> /// An optional cancellation token that can be used to cancel the operation. /// </param> /// <returns> /// A dictionary of task assembly metadata, keyed by assembly path. /// </returns> /// <remarks> /// Cache metadata (and persist cache to file). /// </remarks> public async Task <List <MSBuildTaskAssemblyMetadata> > GetMSBuildProjectTaskAssemblies(CancellationToken cancellationToken = default(CancellationToken)) { if (!HasMSBuildProject) { throw new InvalidOperationException($"MSBuild project '{ProjectFile.FullName}' is not loaded."); } List <string> taskAssemblyFiles = new List <string> { // Include "built-in" tasks. Path.Combine(DotNetRuntimeInfo.GetCurrent().BaseDirectory, "Microsoft.Build.Tasks.Core.dll"), Path.Combine(DotNetRuntimeInfo.GetCurrent().BaseDirectory, "Roslyn", "Microsoft.Build.Tasks.CodeAnalysis.dll") }; taskAssemblyFiles.AddRange( MSBuildProject.GetAllUsingTasks() .Where(usingTask => !String.IsNullOrWhiteSpace(usingTask.AssemblyFile)) .Distinct(UsingTaskAssemblyEqualityComparer.Instance) // Ensure each assembly path is only evaluated once. .Select(usingTask => Path.GetFullPath( Path.Combine( usingTask.ContainingProject.DirectoryPath, MSBuildProject.ExpandString(usingTask.AssemblyFile) .Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar) ) )) .Distinct(StringComparer.OrdinalIgnoreCase) ); cancellationToken.ThrowIfCancellationRequested(); List <MSBuildTaskAssemblyMetadata> metadata = new List <MSBuildTaskAssemblyMetadata>(); foreach (string taskAssemblyFile in taskAssemblyFiles) { Log.Verbose("Scanning assembly {TaskAssemblyFile} for task metadata...", taskAssemblyFile); if (!File.Exists(taskAssemblyFile)) { Log.Information("Skipped scan of task metadata for assembly {TaskAssemblyFile} (file not found).", taskAssemblyFile); continue; } cancellationToken.ThrowIfCancellationRequested(); MSBuildTaskAssemblyMetadata assemblyMetadata = await Workspace.TaskMetadataCache.GetAssemblyMetadata(taskAssemblyFile); metadata.Add(assemblyMetadata); Log.Verbose("Completed scanning of assembly {TaskAssemblyFile} for task metadata ({DiscoveredTaskCount} tasks discovered).", taskAssemblyFile, assemblyMetadata.Tasks.Count); } // Persist any changes to cached metadata. Workspace.PersistTaskMetadataCache(); return(metadata); }
public async Task Scan_FrameworkTaskAssembly_Success(string fileName) { string taskAssemblyFile = GetFrameworkTaskAssemblyFile(fileName); Assert.True(File.Exists(taskAssemblyFile), "Task assembly exists"); MSBuildTaskAssemblyMetadata metadata = await MSBuildTaskScanner.GetAssemblyTaskMetadata(taskAssemblyFile); Assert.NotNull(metadata); Assert.NotEqual(0, metadata.Tasks.Count); foreach (MSBuildTaskMetadata taskMetadata in metadata.Tasks.OrderBy(task => task.TypeName)) { TestOutput.WriteLine("Found task '{0}'.", taskMetadata.TypeName); } }