using Microsoft.Build.Construction; using System.Collections.Generic; using System.IO; using System.Linq; namespace Semmle.BuildAnalyser { /// /// Access data in a .sln file. /// class SolutionFile { readonly Microsoft.Build.Construction.SolutionFile solutionFile; /// /// Read the file. /// /// The filename of the .sln. public SolutionFile(string filename) { // SolutionFile.Parse() expects a rooted path. var fullPath = Path.GetFullPath(filename); solutionFile = Microsoft.Build.Construction.SolutionFile.Parse(fullPath); } /// /// Projects directly included in the .sln file. /// public IEnumerable MsBuildProjects { get { return solutionFile.ProjectsInOrder. Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat). Select(p => p.AbsolutePath). Select(p => Path.DirectorySeparatorChar == '/' ? p.Replace("\\", "/") : p); } } /// /// Projects included transitively via a subdirectory. /// public IEnumerable NestedProjects { get { return solutionFile.ProjectsInOrder. Where(p => p.ProjectType == SolutionProjectType.SolutionFolder). Where(p => Directory.Exists(p.AbsolutePath)). SelectMany(p => new DirectoryInfo(p.AbsolutePath).EnumerateFiles("*.csproj", SearchOption.AllDirectories)). Select(f => f.FullName); } } /// /// List of projects which were mentioned but don't exist on disk. /// public IEnumerable MissingProjects => // Only projects in the solution file can be missing. // (NestedProjects are located on disk so always exist.) MsBuildProjects.Where(p => !File.Exists(p)); /// /// The list of project files. /// public IEnumerable Projects => MsBuildProjects.Concat(NestedProjects); } }