Code Monkey home page Code Monkey logo

subsolution's Introduction

SubSolution

Visual Studio Extension Command Line Nuget

Change Release

SubSolution is a tool set giving you control on your Visual Studio solutions.

It includes various tools:

  • .Subsln files able to generate .sln files.
  • A Visual Studio extension using .subsln files to update your solutions.
  • A command line tool working with .subsln files.
  • .NET libraries to read/write/edit solutions in many ways.

Configuration files: .subsln

SubSolution use XML files with the extension .subsln to describe the content of Visual Studio solutions in a user-friendly syntax.

You can find the .subsln format documentation at this address: https://subsln.github.io.

That address is also the XML namespace used by .subsln files so you will always be a click away from the doc!

<Subsln xmlns="http://subsln.github.io">
    <Root>
        <Folder Name="Tools">
            <Files Path="tools/*.bat" />
        </Folder>
        <Folder Name="Tests">
            <Projects Path="**/*.Tests.csproj" />
        </Folder>
        <Projects Path="src/">
    </Root>
</Subsln>

Syntax overview

  • Describe your item hierarchy: <Root>
    • Add projects with glob patterns: <Projects>
    • Add files for quick-access: <Files>
    • Create folders to organize your items: <Folder>
    • Find project dependencies and dependents: <Dependencies> / <Dependents>
    • Include the content of existing solutions: <Solutions> / <SubSolutions>
    • Select what you want to keep from other solutions: <KeepOnly>
    • Apply complex filters on your item sources: <Where>
  • Setup your solution configuration-platforms: <Configurations> / <Platforms>
    • Ignore them to auto-generate from projects.
    • Create new ones: <SolutionConfiguration> / <SolutionPlatform>
    • Match them with project configurations and platforms: <ProjectConfiguration> / <ProjectPlatform>
  • And a lot more options as XML attributes !

The complete documentation is available on https://subsln.github.io.

Why use a .subsln file ?

  • It allows you to express your solution organization rules ("those projects in that folder, unit tests in that one...") and ensure they are respected on solution changes.
  • It acts as a substitute or edition assistant of .sln files, to describe the solution content with a user-friendly structure similar to the Visual Studio "Solution Explorer" representation.
  • It can also be used as a punctual tool, to apply a one-time update.
  • It allows to quickly iterate on your solution structure until it matches your needs, without requiring to run Visual Studio.
  • It can build an entirely customized hierarchy, or at contrary mirror your file system structure.
  • It can find and fill your solution with dependencies of your central projects.
  • It can describe solutions in a modular way by including the content of a solution into another.
  • It makes it easier to apply changes to multiple solutions sharing the same projects.
  • It can create a smaller solution from a big one to have a better environment or performances in Visual Studio.

Visual Studio extension

Visual Studio 2019 Visual Studio 2022

The Visual Studio extension includes the following features:

  • You can create/open the .subsln file associated to the current solution from the Solution Explorer context menu.

    Command

  • When saving a .subsln file, you can see a preview of the updated solution and decide if you want to apply it or not.

    Save

  • When opening a solution, it automatically checks if your solution is up-to-date.

    Load

Command line tool: subsln

Command Line Tool

"subsln" is a command line tool using .subsln configuration files to build Visual Studio solutions.

> subsln create MySolution
> subsln generate MySolution.subsln
> subsln validate MySolution.subsln
> subsln show MySolution.sln

Install it with the .NET SDK command line:

> dotnet tool install subsln --global 

Check the Releases page for standalone executables.

By default, subsln will try to find MSBuild binaries on your machine. There are multiple options to specify which MSBuild binaries use to read projects. Use subsln help or subsln [command] --help for more details on commands.

.NET libraries

SubSolution Nuget Nuget Nuget

You can use SubSolution .NET libraries as Nuget packages:

The API is structured around 3 representations of solutions:

  • Solution:
    • Match the Visual Studio edition experience.
    • Edit the item hierarchy as it show in the Solution Explorer.
    • Automatically fill solution configurations-platforms with your projects.
    • Use ManualSolution to manually fill configuration-platforms.
  • RawSolution:
    • Match the .sln format.
    • Dedicated to input/ouput files (but hard to edit).
    • Convert to/from Solution with RawSolutionConverter/SolutionConverter.
  • Subsln:
    • Match the .subsln format.
    • Dedicated to build patterns & modular usages.
    • Build Solution with SolutionBuilder.

SubSolution is currently released as version v0. All core features are already implemented but it needs to be tested in more practical cases.

Also be aware of the following:

  • Some small API breaking changes might happen until version v1.
  • Some MSBuild project types are not supported yet. (Supported project types)

About MSBuild usage

SubSolution.MsBuild implements MsBuildProjectReader to read projects with MSBuild. But core MSBuild DLLs are not enough to read every project types because some dependencies are installed by Visual Studio modular setup. The MSBuild setup coming with .NET SDK also mostly support .NET projects only.

For that reason, SubSolution.MsBuild package does not come with MSBuild DLLs to let you choose between multiple strategies if you need a project reader:

  1. Use Microsoft.Build.Locator to use existing MSBuild binaries on the user machine. For example, it can use MSBuild from a local Visual Studio or a .NET SDK install.
    • It is recommended to target a framework compatible with the MSBuild binaries you are trying to use in that case.
  2. Use Microsoft.Build NuGet package to get only the core DLLs + set MsBuildProjectReader.ImportFallback to true to read project even on missing import/SDKs.
  3. Implement your own IProjectReader if you don't want to depends on MSBuild.

Contribute

  • Install .NET SDK
  • Make a fork of the repo.
  • Clone it locally (including submodules if you are using ReSharper in Visual Studio).
  • Build the solution.
    • It will automatically install LinqToXsdCore to generate C# from the XML schema.
  • Make your changes.
  • Submit a pull request.

subsolution's People

Contributors

reminoer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

subsolution's Issues

Support for dtproj and rptproj project file types

Hi.

If I have an sln file which contains a dtproj or rptproj and a subsln file which includes the sln file, I get one of the following errors:

With dtproj:

ERROR: Failed to read project "C:\Work\Team\dev\MyApplication\Database.IntegrationServices\Database.IntegrationServices.dtproj".
---> Microsoft.Build.Exceptions.InvalidProjectFileException: The element <DeploymentModel> beneath element <Project> is unrecognized.  C:\Work\Team\dev\MyApplication\Database.IntegrationServices\Database.IntegrationServices.dtproj
   at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject(String errorSubCategoryResourceName, IElementLocation elementLocation, String resourceName, Object[] args)
   at Microsoft.Build.Construction.ProjectParser.Parse()
   at Microsoft.Build.Construction.ProjectParser.Parse(XmlDocumentWithLocation document, ProjectRootElement projectRootElement)
   at Microsoft.Build.Construction.ProjectRootElement..ctor(String path, ProjectRootElementCacheBase projectRootElementCache, Boolean preserveFormatting)
   at Microsoft.Build.Construction.ProjectRootElement.CreateProjectFromPath(String projectFile, ProjectRootElementCacheBase projectRootElementCache, Boolean preserveFormatting)
   at Microsoft.Build.Evaluation.ProjectRootElementCache.Get(String projectFile, OpenProjectRootElement openProjectRootElement, Boolean isExplicitlyLoaded, Nullable`1 preserveFormatting)
   at Microsoft.Build.Construction.ProjectRootElement.OpenProjectOrSolution(String fullPath, IDictionary`2 globalProperties, String toolsVersion, ProjectRootElementCacheBase projectRootElementCache, Boolean isExplicitlyLoaded)
   at Microsoft.Build.Evaluation.Project.ProjectImpl..ctor(Project owner, String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext)
   at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext)
   at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, ProjectCollection projectCollection)
   at SubSolution.MsBuild.MsBuildProjectReader.ReadProject(String absoluteProjectPath) in /_/Sources/SubSolution.MsBuild/MsBuildProjectReader.cs:line 94
   at SubSolution.MsBuild.MsBuildProjectReader.<>c__DisplayClass13_0.<ReadProjectAsync>b__0() in /_/Sources/SubSolution.MsBuild/MsBuildProjectReader.cs:line 54
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at SubSolution.MsBuild.MsBuildProjectReader.ReadProjectAsync(String absoluteProjectPath) in /_/Sources/SubSolution.MsBuild/MsBuildProjectReader.cs:line 54
   at SubSolution.MsBuild.MsBuildProjectReader.ReadAsync(String absoluteProjectPath) in /_/Sources/SubSolution.MsBuild/MsBuildProjectReader.cs:line 37

With rptproj:

ERROR: Failed to read project "C:\Work\Team\dev\MyApplication\Reports\Reports.rptproj".
---> Microsoft.Build.Exceptions.InvalidProjectFileException: The project file could not be loaded. 'Windows-1252' is not a supported encoding name. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method. (Parameter 'name')  C:\Work\Team\dev\MyApplication\Reports\Reports.rptproj
 ---> System.ArgumentException: 'Windows-1252' is not a supported encoding name. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method. (Parameter 'name')
   at System.Text.EncodingTable.InternalGetCodePageFromName(String name)
   at System.Text.EncodingTable.GetCodePageFromName(String name)
   at System.Text.Encoding.GetEncoding(String name)
   at Microsoft.Build.Internal.XmlReaderExtension..ctor(String file, Boolean loadAsReadOnly)
   at Microsoft.Build.Construction.ProjectRootElement.LoadDocument(String fullPath, Boolean preserveFormatting, Boolean loadAsReadOnly)
   --- End of inner exception stack trace ---
   at Microsoft.Build.Shared.ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(Boolean condition, String errorSubCategoryResourceName, BuildEventFileInfo projectFile, Exception innerException, String resourceName, Object[] args)
   at Microsoft.Build.Shared.ProjectFileErrorUtilities.ThrowInvalidProjectFile(BuildEventFileInfo projectFile, Exception innerException, String resourceName, Object[] args)
   at Microsoft.Build.Construction.ProjectRootElement.LoadDocument(String fullPath, Boolean preserveFormatting, Boolean loadAsReadOnly)
   at Microsoft.Build.Construction.ProjectRootElement..ctor(String path, ProjectRootElementCacheBase projectRootElementCache, Boolean preserveFormatting)
   at Microsoft.Build.Construction.ProjectRootElement.CreateProjectFromPath(String projectFile, ProjectRootElementCacheBase projectRootElementCache, Boolean preserveFormatting)
   at Microsoft.Build.Evaluation.ProjectRootElementCache.Get(String projectFile, OpenProjectRootElement openProjectRootElement, Boolean isExplicitlyLoaded, Nullable`1 preserveFormatting)
   at Microsoft.Build.Construction.ProjectRootElement.OpenProjectOrSolution(String fullPath, IDictionary`2 globalProperties, String toolsVersion, ProjectRootElementCacheBase projectRootElementCache, Boolean isExplicitlyLoaded)
   at Microsoft.Build.Evaluation.Project.ProjectImpl..ctor(Project owner, String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext)
   at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext)
   at SubSolution.MsBuild.MsBuildProjectReader.ReadProject(String absoluteProjectPath) in /_/Sources/SubSolution.MsBuild/MsBuildProjectReader.cs:line 113
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at SubSolution.MsBuild.MsBuildProjectReader.ReadProjectAsync(String absoluteProjectPath) in /_/Sources/SubSolution.MsBuild/MsBuildProjectReader.cs:line 88
   at SubSolution.MsBuild.MsBuildProjectReader.ReadAsync(String absoluteProjectPath) in /_/Sources/SubSolution.MsBuild/MsBuildProjectReader.cs:line 47

These errors occur even when I try to exclude the projects in the subsln file:

<?xml version="1.0"?>
<Subsln xmlns="http://subsln.github.io">
    <Root>
        <Folder Name="MyApplication">
            <Solutions Path="C:\Work\Team\dev\MyApplication\MyApplication.sln">
                <WhereProjects>
                    <ProjectNot>
                        <ProjectPath Match="**\*.dtproj" />
                        <ProjectPath Match="**\*.rptproj" />
                    </ProjectNot>
                </WhereProjects>
            </Solutions>
        </Folder>
    </Root>
</Subsln>

I ran subsln as follows:
subsln generate Test.subsln --import-fallback --debug --verbose --detailed

Ideally, I would like subsln to be able to keep the dtproj and rptproj projects in the generated sln file.

Support for dtproj and rptproj in Visual Studio 2022 are available using the following Visual Studio extensions:
https://marketplace.visualstudio.com/items?itemName=SSIS.MicrosoftDataToolsIntegrationServices
https://marketplace.visualstudio.com/items?itemName=ProBITools.MicrosoftReportProjectsforVisualStudio2022

Is there a way to allow subsln to read these projects?
If reading these project file types are not supported in subsln, can subsln still be able to generate an sln file, excluding these project files?
For example, can these errors be treated as warnings?
If so, maybe there should be a command line option to ignore these errors and continue generating the sln file.

Any other ideas?

Thank you!

Should CreateFolders="true" create folders starting from WorkspaceDirectory?

At SolutionBuilder.cs, Line 723, it computes the folders to be created as a relative path from the solution directory.

If any project is not inside the solution folder or any of its subfolders, it will cause some ".." folders to be created in the solution structure. Is that how it's supposed to be?

Apparently changing that line to _fileSystem.GetParentDirectoryPath(workspaceRelativeFilePath) changes this behavior with no side effects.

P.S.: Sorry if I'm bothering you, perhaps I should just fork the project.

Resolving $(SolutionDir) when including other solution files

Hi.

Thank you for SubSolution.

I'm wondering if there's a way to dynamically resolve the MSBuild $(SolutionDir) macro/property correctly, relative to the new/generated solution file and the original one that was included?

I've attached an example set of files that illustrates the issue I'm experiencing.

SubSolutionTest.zip

Steps to reproduce:

  1. Download and extract SubSolutionTest.zip to a folder called SubSolutionTest
  2. Open Solution1\ClassLibrary1\ClassLibrary1.csproj in notepad and notice the line at the end of the file: <Import Project="$(SolutionDir)MyPropertyFiles\MyPropertyFile.props" />.
  3. Open Solution1\Solution1.sln in Visual Studio and notice ClassLibrary1 can be loaded correctly.
  4. run cd SubSolutionTest
  5. run subsln generate Test.subsln --import-fallback --force
  6. Open the generated Test.sln in Visual Studio and notice ClassLibrary1 cannot be loaded and Visual Studio displays the following error:
The imported project ".\SubSolutionTest\MyPropertyFiles\MyPropertyFile.props" was not found. Confirm that the expression in the Import declaration ".\SubSolutionTest\MyPropertyFiles\MyPropertyFile.props" is correct, and that the file exists on disk.  .\SubSolutionTest\Solution1\ClassLibrary1\ClassLibrary1.csproj

Is it possible for ClassLibrary1 to be loaded correctly by both solution files without modification to the original solution or project files?

For example, could a Directory.Build.props file resolve this issue?

Thank you.

subsln 0.5.2+5debbb70b73093b9bd6ae2c0684ff2751e29980a
SubSolution (2022) 0.5.2
Visual Studio 2022 17.2.2

No projects are found when WorkspaceDirectory is different than solution directory.

At SolutionBuilder.cs, Line 269, it takes the resolved paths from GetMatchingProjectPaths (which are relative paths), and tries to make absolute paths using _solution.OutputDirectoryPath as the root. It should use _workspaceDirectoryPath instead.

Because of that, the patterns are resolved correctly, but the reading task doesn't find the files, unless both directories are the same, which defeats the whole purpose of WorkspaceDirectory.

ERROR: File not found on Linux

Description

This tool does not appear to run correctly on Linux. Suspect this is is a problem with path rooting as the printed out path is not correctly rooted (should be /home, not home), see output below.

Steps to Reproduce

$ cd ~/projects/Example
$ subsln generate Example.subsln
ERROR: File home/user/projects/Example/Example.subsln not found.

Discrepancy between the subsln CLI and Visual Studio extension

Hi.

Thank you for SubSolution.

There seems to be a discrepancy between the behavior of the subsln CLI and the Visual Studio extension.

I've attached a set of files that can reproduce the issue.

SubSolutionTest.zip

Steps to reproduce:

  1. Download and extract SubSolutionTest.zip to a folder called SubSolutionTest
  2. Open a command prompt
  3. run cd SubSolutionTest
  4. run subsln generate Test.subsln --import-fallback --force
  5. Notice the CLI added the projects ClassLibrary1 and Dll1 to the generated solution file, as expected.
  6. Open the generated Test.sln in Visual Studio.
  7. Click Preview in the message "We detected new changes to apply to your solution after generation of your .subsln file." which appear at the top of the Solution Explorer window
  8. Notice the Visual Studio extension wants to remove the Dll1 project

I didn't expect the Visual Studio extension to want to remove the Dll1 project.

Any ideas?

Thank you.

subsln 0.5.2+5debbb70b73093b9bd6ae2c0684ff2751e29980a
SubSolution (2022) 0.5.2
Visual Studio 2022 17.2.2

Add support to Visual Studio 2022

Visual Studio 2022 is now a 64-bit application, and will not install any extensions packaged for previous versions, even with open-ended versioning.

According to Microsoft's documentation, it's now required to specify 2 installation targets like this:

<Installation>
   <InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[16.0,17.0)">
      <ProductArchitecture>x86</ProductArchitecture>
   </InstallationTarget>
   <InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0,)">
      <ProductArchitecture>amd64</ProductArchitecture>
   </InstallationTarget>
</Installation>

Also I have tested this change by manually replacing the vsixmanifest with 7-zip and was able to install the extension. But there are still some erros in the execution (I see the log messages of solution building, but no dialog appears). Maybe I can debug these errors later, when I get some time.

Btw, this project is really awesome! I'm surprised there are no forks or any other open issues. This thing really deserves more attention.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.