Search code examples
.netbuildmsbuild.net-coredotnet-cli

Having a sln file, possible to list all files from all projects under that sln?


Is there a way or an extension that does the following:

Having a *.sln file, can I list all files from all projects or all solution folders under that sln?

So if I do dotnet sln list then I get the list of the projects from that solution file, but what I need is to get all files.

My real need is to copy all those files into a different folder.


Solution

  • Here's an msbuild-based solution which is actually fairly simple and also non-intrusive. Create a file CopySource.targets in the solution directory for instance, contents:

    <Project>
      <Target Name="CopySourcesUsed" AfterTargets="AfterCompile">
        <PropertyGroup>
          <DestinationDirectory>c:\temp\dest\</DestinationDirectory>
          <SourceDirectory>$([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory)))</SourceDirectory>
        </PropertyGroup>
        <ItemGroup>
          <CompileSources Condition="!$([System.Text.RegularExpressions.Regex]::IsMatch('%(Identity)', `.*Assembly(Attributes|Info)\.cs`))" Include="@(Compile)"/>
          <AllSources Include="@(CompileSources);@(EmbeddedResource);$(MSBuildProjectFile)" />
          <AllSources>
            <Dest>$([System.String]::new('%(FullPath)').Replace($(SourceDirectory), $(DestinationDirectory)))</Dest>
          </AllSources>
        </ItemGroup>
        <Message Importance="High" Text="%(AllSources.FullPath) -> %(AllSources.Dest)"/>
        <Copy SourceFiles="@(AllSources)" DestinationFiles="@(AllSources->'%(Dest)')" />
      </Target>
    </Project>
    

    Then run a build like

    dotnet msbuild mysolution.sln /p:CustomAfterMicrosoftCSharpTargets=/path/to/CopySource.targets
    

    (note dotnet build also works for me but might not in older versions, don't know)

    This will import ListSources.Targets in each project file and run the CopySourcesUsed target after compilation. Before compilation somewhere will also work, but then you have to figure out exactly when: after compilation all items definitely have been gathered. As an example the AllSources item is filled with the compilation source files and the embedded resources. As you can see the Compile item is filtered to exclude the generated AssemblyAttributes/AssemblyInfo files since you probably don't want those. An alternative might be to have this target ran before those files are added, but again: that's just trickier. There can be other things you want to copy (xaml/config/...) in which case you have to figure out the name of the item to include. First check if it's not simply listed in the csproj. Else running the build with diagnostic verbosity can tell you the name: dotnet msbuild mysolution.sln /v:diag.

    Instead of injecting this logic on the commandline you could instead import the file in each project you have, or use another extension point like making it system-wide by putting it in some ImportAfter directory, all these solutions can be found here on SO probably.