solution

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2025 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package solution provides parsers and utilities for working with .NET solution files

Index

Examples

Constants

View Source
const (
	// ProjectTypeCSProject identifies a C# project (classic)
	ProjectTypeCSProject = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"

	// ProjectTypeCSProjectSDK identifies a SDK-style C# project (.NET Core/.NET 5+)
	ProjectTypeCSProjectSDK = "{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"

	// ProjectTypeVBProject identifies a VB.NET project
	ProjectTypeVBProject = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"

	// ProjectTypeFSProject identifies an F# project
	ProjectTypeFSProject = "{F2A71F9B-5D33-465A-A702-920D77279786}"

	// ProjectTypeSolutionFolder identifies a solution folder
	ProjectTypeSolutionFolder = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}"

	// ProjectTypeSharedProject identifies a shared project
	ProjectTypeSharedProject = "{D954291E-2A0B-460D-934E-DC6B0785DB48}"

	// ProjectTypeWebSite identifies a website project
	ProjectTypeWebSite = "{E24C65DC-7377-472B-9ABA-BC803B73C61A}"
)

ProjectType GUIDs for common project types

Variables

This section is empty.

Functions

func ConvertToSystemPath

func ConvertToSystemPath(path string) string

ConvertToSystemPath converts a path to the current OS format

func GetSolutionFormat

func GetSolutionFormat(path string) string

GetSolutionFormat returns the solution format based on file extension

func IsProjectFile

func IsProjectFile(path string) bool

IsProjectFile checks if a file path has a project file extension

func IsSolutionFile

func IsSolutionFile(path string) bool

IsSolutionFile checks if a file path has a solution file extension

func NormalizePath

func NormalizePath(path string) string

NormalizePath converts Windows-style paths to forward slash format

func ResolveProjectPath

func ResolveProjectPath(solutionDir, projectPath string) string

ResolveProjectPath resolves a project path from a solution file

func ValidateSolutionFile

func ValidateSolutionFile(path string) error

ValidateSolutionFile checks if a solution file exists and is readable

Types

type DetectionResult

type DetectionResult struct {
	// Found indicates if any solution file was found
	Found bool

	// Ambiguous indicates if multiple solution files were found
	Ambiguous bool

	// SolutionPath is the path to the found solution file
	SolutionPath string

	// FoundFiles lists all solution files found
	FoundFiles []string

	// Format is the detected solution format
	Format string
}

DetectionResult contains the result of solution file detection

type Detector

type Detector struct {
	// SearchDir is the directory to search for solution files
	SearchDir string
}

Detector helps detect and identify solution files

func NewDetector

func NewDetector(searchDir string) *Detector

NewDetector creates a new solution file detector

Example

ExampleNewDetector demonstrates how to automatically detect solution files in a directory.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/willibrandon/gonuget/solution"
)

func main() {
	// Create a temporary directory for the example
	tempDir, err := os.MkdirTemp("", "detector-example-*")
	if err != nil {
		panic(err)
	}
	defer func() { _ = os.RemoveAll(tempDir) }()

	// Create a sample .sln file
	slnPath := filepath.Join(tempDir, "MyApp.sln")
	slnContent := `
Microsoft Visual Studio Solution File, Format Version 12.00
Global
EndGlobal
`
	if err := os.WriteFile(slnPath, []byte(slnContent), 0644); err != nil {
		panic(err)
	}

	// Create a detector for the directory
	detector := solution.NewDetector(tempDir)

	// Detect solution files
	result, err := detector.DetectSolution()
	if err != nil {
		panic(err)
	}

	// Check detection results
	if result.Found {
		fmt.Printf("Found solution: %s\n", filepath.Base(result.SolutionPath))
		fmt.Printf("Format: %s\n", result.Format)
	}

	if result.Ambiguous {
		fmt.Printf("Multiple solutions found: %d\n", len(result.FoundFiles))
	}

}
Output:

Found solution: MyApp.sln
Format: sln

func (*Detector) DetectSolution

func (d *Detector) DetectSolution() (*DetectionResult, error)

DetectSolution searches for solution files in the configured directory

type Filter

type Filter struct {
	// SolutionPath is the path to the parent .sln file
	SolutionPath string

	// Projects lists the project paths to include
	Projects []string
}

Filter represents a .slnf filter file

type Folder

type Folder struct {
	// Name is the display name of the folder
	Name string

	// GUID is the unique identifier for this folder
	GUID string

	// ParentFolderGUID is the GUID of the parent folder (for nested folders)
	ParentFolderGUID string

	// Items contains file references in SolutionItems folders
	Items []string
}

Folder represents a virtual folder in the solution

type ParseError

type ParseError struct {
	// FilePath is the path to the file being parsed
	FilePath string

	// Line is the line number where the error occurred
	Line int

	// Column is the column number where the error occurred
	Column int

	// Message describes what went wrong
	Message string
}

ParseError represents an error during solution file parsing

func (*ParseError) Error

func (e *ParseError) Error() string

Error implements the error interface

type Parser

type Parser interface {
	// Parse reads and parses a solution file
	Parse(path string) (*Solution, error)

	// CanParse checks if this parser supports the given file
	CanParse(path string) bool
}

Parser defines the interface for parsing solution files

func GetParser

func GetParser(path string) (Parser, error)

GetParser returns the appropriate parser for a solution file

Example

ExampleGetParser demonstrates how to get a parser for different solution file formats.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/willibrandon/gonuget/solution"
)

func main() {
	// Create a temporary directory for the example
	tempDir, err := os.MkdirTemp("", "solution-example-*")
	if err != nil {
		panic(err)
	}
	defer func() { _ = os.RemoveAll(tempDir) }()

	// Create a sample .sln file
	slnPath := filepath.Join(tempDir, "Example.sln")
	slnContent := `
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyApp", "src\MyApp\MyApp.csproj", "{11111111-1111-1111-1111-111111111111}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
EndGlobal
`
	if err := os.WriteFile(slnPath, []byte(slnContent), 0644); err != nil {
		panic(err)
	}

	// Get the appropriate parser for the solution file
	parser, err := solution.GetParser(slnPath)
	if err != nil {
		panic(err)
	}

	// Parse the solution file
	sol, err := parser.Parse(slnPath)
	if err != nil {
		panic(err)
	}

	// Display solution information
	fmt.Printf("Solution format version: %s\n", sol.FormatVersion)
	fmt.Printf("Number of projects: %d\n", len(sol.Projects))
	if len(sol.Projects) > 0 {
		fmt.Printf("First project: %s\n", sol.Projects[0].Name)
	}

}
Output:

Solution format version: 12.00
Number of projects: 1
First project: MyApp

type PathResolver

type PathResolver struct {
	// SolutionDir is the directory containing the solution file
	SolutionDir string
}

PathResolver handles cross-platform path resolution

func NewPathResolver

func NewPathResolver(solutionDir string) *PathResolver

NewPathResolver creates a new path resolver

func (*PathResolver) ResolvePath

func (r *PathResolver) ResolvePath(projectPath string) string

ResolvePath resolves a project path relative to the solution directory

type Project

type Project struct {
	// Name is the display name of the project
	Name string

	// Path is the file system path to the project file (relative or absolute)
	Path string

	// GUID is the unique identifier for this project instance
	GUID string

	// TypeGUID identifies the project type (C#, VB.NET, F#, etc.)
	TypeGUID string

	// ParentFolderGUID is the GUID of the containing solution folder (if any)
	ParentFolderGUID string
}

Project represents a project reference in a solution

func (*Project) GetAbsolutePath

func (p *Project) GetAbsolutePath(solutionDir string) string

GetAbsolutePath returns the absolute path to the project file

func (*Project) IsNETProject

func (p *Project) IsNETProject() bool

IsNETProject returns true if this is a .NET project type

func (*Project) IsProjectFile

func (p *Project) IsProjectFile() bool

IsProjectFile returns true if the path looks like a project file

type SlnParser

type SlnParser struct{}

SlnParser parses text-based .sln files (MSBuild format)

func NewSlnParser

func NewSlnParser() *SlnParser

NewSlnParser creates a new .sln file parser

func (*SlnParser) CanParse

func (p *SlnParser) CanParse(path string) bool

CanParse checks if this parser supports the given file

func (*SlnParser) Parse

func (p *SlnParser) Parse(path string) (*Solution, error)

Parse reads and parses a .sln file

type SlnfParser

type SlnfParser struct{}

SlnfParser parses JSON-based .slnf solution filter files

func NewSlnfParser

func NewSlnfParser() *SlnfParser

NewSlnfParser creates a new .slnf file parser

func (*SlnfParser) CanParse

func (p *SlnfParser) CanParse(path string) bool

CanParse checks if this parser supports the given file

func (*SlnfParser) Parse

func (p *SlnfParser) Parse(path string) (*Solution, error)

Parse reads and parses a .slnf file

type SlnxParser

type SlnxParser struct{}

SlnxParser parses XML-based .slnx files (introduced in .NET 9)

func NewSlnxParser

func NewSlnxParser() *SlnxParser

NewSlnxParser creates a new .slnx file parser

func (*SlnxParser) CanParse

func (p *SlnxParser) CanParse(path string) bool

CanParse checks if this parser supports the given file

func (*SlnxParser) Parse

func (p *SlnxParser) Parse(path string) (*Solution, error)

Parse reads and parses a .slnx file

type Solution

type Solution struct {
	// FilePath is the absolute path to the solution file
	FilePath string

	// FormatVersion is the solution file format version (e.g., "12.00" for VS 2013+)
	FormatVersion string

	// VisualStudioVersion is the Visual Studio version that created the file
	VisualStudioVersion string

	// MinimumVisualStudioVersion is the minimum VS version required
	MinimumVisualStudioVersion string

	// Projects contains all projects in the solution (excludes solution folders)
	Projects []Project

	// SolutionFolders contains virtual folders for organizing projects
	SolutionFolders []Folder

	// SolutionDir is the directory containing the solution file
	SolutionDir string
}

Solution represents a parsed solution file (.sln, .slnx, or .slnf)

func ParseSolution

func ParseSolution(path string) (*Solution, error)

ParseSolution is a convenience function that automatically selects the right parser

func (*Solution) GetProjectByName

func (s *Solution) GetProjectByName(name string) (*Project, bool)

GetProjectByName finds a project by its name

func (*Solution) GetProjectByPath

func (s *Solution) GetProjectByPath(path string) (*Project, bool)

GetProjectByPath finds a project by its path

func (*Solution) GetProjects

func (s *Solution) GetProjects() []string

GetProjects returns all project paths from the solution

Example

ExampleSolution_GetProjects demonstrates how to get project paths from a parsed solution.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/willibrandon/gonuget/solution"
)

func main() {
	// Create a temporary directory structure
	tempDir, err := os.MkdirTemp("", "projects-example-*")
	if err != nil {
		panic(err)
	}
	defer func() { _ = os.RemoveAll(tempDir) }()

	// Create a sample .sln file with multiple projects
	slnPath := filepath.Join(tempDir, "MySolution.sln")
	slnContent := `
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp", "src\WebApp\WebApp.csproj", "{11111111-1111-1111-1111-111111111111}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{22222222-2222-2222-2222-222222222222}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{33333333-3333-3333-3333-333333333333}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
	EndGlobalSection
EndGlobal
`
	if err := os.WriteFile(slnPath, []byte(slnContent), 0644); err != nil {
		panic(err)
	}

	// Parse the solution
	parser, err := solution.GetParser(slnPath)
	if err != nil {
		panic(err)
	}

	sol, err := parser.Parse(slnPath)
	if err != nil {
		panic(err)
	}

	// Get all project paths (excludes solution folders)
	projectPaths := sol.GetProjects()

	fmt.Printf("Total projects: %d\n", len(projectPaths))
	for i, path := range projectPaths {
		// Show relative path for consistent output
		relPath, _ := filepath.Rel(tempDir, path)
		fmt.Printf("Project %d: %s\n", i+1, filepath.ToSlash(relPath))
	}

}
Output:

Total projects: 2
Project 1: src/WebApp/WebApp.csproj
Project 2: src/Core/Core.csproj

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL