Skip to content

Commit 4e3c95e

Browse files
Merge pull request #265 from CommunityToolkit/refactor/slngen/single-solution
Cleanup and polish single-component slngen script
2 parents 053865c + acdf690 commit 4e3c95e

File tree

2 files changed

+234
-145
lines changed

2 files changed

+234
-145
lines changed

GenerateSingleSolution.ps1

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
<#
2+
.SYNOPSIS
3+
Uses the dotnet template tool to copy and rename project heads to run sample code for different platforms.
4+
5+
.DESCRIPTION
6+
This is used to centralize configuration and reduce duplication of copying these heads for every project.
7+
This script also generates a solution for the project and will open Visual Studio.
8+
9+
.PARAMETER componentPath
10+
Folder for the project to copy the project heads to.
11+
12+
.PARAMETER MultiTargets
13+
Specifies the MultiTarget TFM(s) to include for building the components. The default value is 'uwp', 'wasm', 'wasdk'.
14+
15+
.PARAMETER ExcludeMultiTargets
16+
Specifies the MultiTarget TFM(s) to exclude for building the components. The default value excludes targets that require additional tooling or workloads to build. Run uno-check to install the required workloads.
17+
18+
.PARAMETER Component
19+
The name of the components to generate project and solution references for. Defaults to an empty string.
20+
21+
.PARAMETER WinUIMajorVersion
22+
Specifies the WinUI major version to use when building an Uno head. Also decides the package id and dependency variant. The default value is '2'.
23+
24+
.PARAMETER UseDiagnostics
25+
Add extra diagnostic output to running slngen, such as a binlog, etc...
26+
27+
.EXAMPLE
28+
C:\PS> .\GenerateSingleSampleHeads -componentPath components\testproj
29+
Builds project heads for component in testproj directory.
30+
31+
.NOTES
32+
Author: Windows Community Toolkit Labs Team
33+
Date: Feb 9, 2023
34+
#>
35+
Param (
36+
[ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android')]
37+
[Alias("mt")]
38+
[string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'),
39+
40+
[string[]]$ExcludeMultiTargets = @(),
41+
42+
[Alias("winui")]
43+
[int]$WinUIMajorVersion = 3,
44+
45+
[Alias("c")]
46+
[string]$Component,
47+
48+
[Parameter(HelpMessage = "The path to the containing folder for a component where sample heads should be generated.")]
49+
[string]$componentPath,
50+
51+
[Parameter(HelpMessage = "Add extra diagnostic output to slngen generator.")]
52+
[switch]$UseDiagnostics = $false
53+
)
54+
55+
if ($null -ne $Env:Path -and $Env:Path.ToLower().Contains("msbuild") -eq $false) {
56+
Write-Host
57+
Write-Host -ForegroundColor Red "Please run from a command window that has MSBuild.exe on the PATH"
58+
Write-Host
59+
Write-Host "Press any key to continue"
60+
[void]$host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
61+
62+
Exit
63+
}
64+
65+
# If Component (name) is provided, use a known path to find componentPath
66+
if ($null -ne $Component -and $Component -ne '')
67+
{
68+
$componentPath = Get-Item "$PSScriptRoot/../components/$Component/"
69+
}
70+
71+
# If componentPath is not provided or is an empty string, use the current directory $pwd
72+
if ($null -eq $componentPath -or $componentPath -eq '')
73+
{
74+
$componentPath = $pwd
75+
}
76+
77+
# Remove trailing slash
78+
$componentPath = $componentPath.TrimEnd('\').TrimEnd('/')
79+
80+
# Component check
81+
# -----------------
82+
83+
# Check that the component path exists
84+
if (-not (Test-Path $componentPath -PathType Container))
85+
{
86+
Write-Error "Component path '$componentPath' does not exist."
87+
Exit
88+
}
89+
90+
# Check that the path contains a src folder
91+
if (-not (Test-Path "$componentPath/src" -PathType Container))
92+
{
93+
Write-Error "Provided path '$componentPath' does not contain a 'src' folder and may not be a component."
94+
Exit
95+
}
96+
97+
# Multitarget handling
98+
# -----------------
99+
100+
if ($MultiTargets.Contains('all')) {
101+
$MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android')
102+
}
103+
104+
if ($null -eq $ExcludeMultiTargets)
105+
{
106+
$ExcludeMultiTargets = @()
107+
}
108+
109+
# Both uwp and wasdk share a targetframework. Both cannot be enabled at once.
110+
# If both are supplied, remove one based on WinUIMajorVersion.
111+
if ($MultiTargets.Contains('uwp') -and $MultiTargets.Contains('wasdk'))
112+
{
113+
if ($WinUIMajorVersion -eq 2)
114+
{
115+
$ExcludeMultiTargets = $ExcludeMultiTargets + 'wasdk'
116+
}
117+
else
118+
{
119+
$ExcludeMultiTargets = $ExcludeMultiTargets + 'uwp'
120+
}
121+
}
122+
123+
$MultiTargets = $MultiTargets | Where-Object { $_ -notin $ExcludeMultiTargets }
124+
125+
# Generate required props for preferences
126+
& $PSScriptRoot/MultiTarget/UseTargetFrameworks.ps1 -MultiTargets $MultiTargets
127+
& $PSScriptRoot/MultiTarget/UseUnoWinUI.ps1 $WinUIMajorVersion
128+
129+
# Head generation
130+
# -----------------
131+
132+
$headsFolderName = "heads"
133+
$componentName = (Get-Item $componentPath -ErrorAction Stop).Name
134+
135+
$outputHeadsDir = "$componentPath\$headsFolderName";
136+
137+
# Remove existing heads directory to refresh
138+
Write-Output "Removing existing heads directory: $outputHeadsDir"
139+
Remove-Item -Recurse -Force $outputHeadsDir -ErrorAction SilentlyContinue;
140+
141+
# Intall our heads as a temporary template
142+
Write-Output "Installing SingleComponent template"
143+
dotnet new --install "$PSScriptRoot/ProjectHeads/SingleComponent" --force
144+
145+
# We need to copy files and run slngen from the target directory path
146+
Push-Location $componentPath
147+
148+
# Copy and rename projects
149+
# Set output folder to 'heads' instead of default
150+
Write-Output "Generating heads for $componentName in $outputHeadsDir"
151+
dotnet new ct-tooling-heads -n $componentName -o $headsFolderName
152+
153+
# Remove template, as just for script
154+
Write-Output "Uninstalling SingleComponent template"
155+
dotnet new --uninstall "$PSScriptRoot/ProjectHeads/SingleComponent"
156+
157+
# Generate Solution
158+
# ------------------
159+
160+
# Projects to include
161+
$projects = [System.Collections.ArrayList]::new()
162+
163+
# Include all projects in component folder
164+
[void]$projects.Add(".\*\*.*proj")
165+
166+
# Install slgnen
167+
dotnet tool restore
168+
169+
$generatedSolutionFilePath = "$componentPath\$componentName.sln"
170+
$platforms = '"Any CPU;x64;x86;ARM64"'
171+
$slngenConfig = "--folders true --collapsefolders true --ignoreMainProject"
172+
173+
# Remove previous file if it exists
174+
if (Test-Path -Path $generatedSolutionFilePath)
175+
{
176+
Remove-Item $generatedSolutionFilePath
177+
Write-Host "Removed previous solution file"
178+
}
179+
180+
# Deployable sample gallery heads
181+
Write-Output "Generating solution for $componentName in $generatedSolutionFilePath"
182+
183+
# All heads are included by default since they reside in the same folder as the component.
184+
# Remove any heads that are not required for the solution.
185+
# TODO: this handles separate project heads, but won't directly handle the unified Skia head from Uno.
186+
# Once we have that, just do a transform on the csproj filename inside this loop to decide the same csproj for those separate MultiTargets.
187+
foreach ($multitarget in $MultiTargets) {
188+
# capitalize first letter, avoid case sensitivity issues on linux
189+
$csprojFileNamePartForMultiTarget = $multitarget.substring(0,1).ToUpper() + $multitarget.Substring(1).ToLower()
190+
191+
$path = "$outputHeadsDir\**\*$csprojFileNamePartForMultiTarget.csproj";
192+
193+
if (Test-Path $path) {
194+
# iterate the wildcards caught by $path
195+
foreach ($foundItem in Get-ChildItem $path)
196+
{
197+
$projects = $projects + $foundItem.FullName
198+
}
199+
}
200+
else {
201+
Write-Warning "No project head could be found at $path for MultiTarget $multitarget. Skipping."
202+
}
203+
}
204+
205+
# Include common dependencies required for solution to build
206+
$projects = $projects + "$PSScriptRoot\CommunityToolkit.App.Shared\**\*.*proj"
207+
$projects = $projects + "$PSScriptRoot\CommunityToolkit.Tests.Shared\**\*.*proj"
208+
$projects = $projects + "$PSScriptRoot\CommunityToolkit.Tooling.SampleGen\*.csproj"
209+
$projects = $projects + "$PSScriptRoot\CommunityToolkit.Tooling.TestGen\*.csproj"
210+
$projects = $projects + "$PSScriptRoot\CommunityToolkit.Tooling.XamlNamedPropertyRelay\*.csproj"
211+
212+
if ($UseDiagnostics.IsPresent)
213+
{
214+
$sdkoptions = " -d"
215+
$diagnostics = '-bl:slngen.binlog --consolelogger:"ShowEventId;Summary;Verbosity=Detailed" --filelogger:"LogFile=slngen.log;Append;Verbosity=Diagnostic;Encoding=UTF-8" '
216+
}
217+
else
218+
{
219+
$sdkoptions = ""
220+
$diagnostics = ""
221+
}
222+
223+
$cmd = "dotnet$sdkoptions tool run slngen -o $generatedSolutionFilePath $slngenConfig $diagnostics--platform $platforms $($projects -Join ' ')"
224+
225+
Write-Output "Running Command: $cmd"
226+
227+
Invoke-Expression $cmd
228+
229+
# go back to main working directory
230+
Pop-Location

ProjectHeads/GenerateSingleSampleHeads.ps1

+4-145
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Param (
3434
[Alias("mt")]
3535
[string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'),
3636

37-
[string[]]$ExcludeMultiTargets,
37+
[string[]]$ExcludeMultiTargets = @(),
3838

3939
[Alias("winui")]
4040
[int]$WinUIMajorVersion = 3,
@@ -46,147 +46,6 @@ Param (
4646
[switch]$UseDiagnostics = $false
4747
)
4848

49-
if ($null -ne $Env:Path -and $Env:Path.ToLower().Contains("msbuild") -eq $false) {
50-
Write-Host
51-
Write-Host -ForegroundColor Red "Please run from a command window that has MSBuild.exe on the PATH"
52-
Write-Host
53-
Write-Host "Press any key to continue"
54-
[void]$host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
55-
56-
Exit
57-
}
58-
59-
# If componentPath is not provided or is an empty string, use the $PSScriptRoot
60-
if ($null -eq $componentPath -or $componentPath -eq '')
61-
{
62-
$componentPath = $pwd
63-
}
64-
65-
# Multitarget handling
66-
# -----------------
67-
68-
if ($MultiTargets.Contains('all')) {
69-
$MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android')
70-
}
71-
72-
if ($null -eq $ExcludeMultiTargets)
73-
{
74-
$ExcludeMultiTargets = @()
75-
}
76-
77-
# Both uwp and wasdk share a targetframework. Both cannot be enabled at once.
78-
# If both are supplied, remove one based on WinUIMajorVersion.
79-
if ($MultiTargets.Contains('uwp') -and $MultiTargets.Contains('wasdk'))
80-
{
81-
if ($WinUIMajorVersion -eq 2)
82-
{
83-
$ExcludeMultiTargets = $ExcludeMultiTargets + 'wasdk'
84-
}
85-
else
86-
{
87-
$ExcludeMultiTargets = $ExcludeMultiTargets + 'uwp'
88-
}
89-
}
90-
91-
$MultiTargets = $MultiTargets | Where-Object { $_ -notin $ExcludeMultiTargets }
92-
93-
# Generate required props for preferences
94-
& $PSScriptRoot/../MultiTarget/UseTargetFrameworks.ps1 -MultiTargets $MultiTargets
95-
& $PSScriptRoot/../MultiTarget/UseUnoWinUI.ps1 $WinUIMajorVersion
96-
97-
# Head generation
98-
# -----------------
99-
100-
$headsFolderName = "heads"
101-
$componentName = (Get-Item $componentPath -ErrorAction Stop).Name
102-
103-
$outputHeadsDir = "$componentPath/$headsFolderName";
104-
105-
# Remove existing heads directory to refresh
106-
Remove-Item -Recurse -Force $outputHeadsDir -ErrorAction SilentlyContinue;
107-
108-
# Intall our heads as a temporary template
109-
dotnet new --install "$PSScriptRoot/SingleComponent" --force
110-
111-
# We need to copy files and run slngen from the target directory path
112-
Push-Location $componentPath
113-
114-
# Copy and rename projects
115-
# Set output folder to 'heads' instead of default
116-
dotnet new ct-tooling-heads -n $componentName -o $headsFolderName
117-
118-
# Remove template, as just for script
119-
dotnet new --uninstall "$PSScriptRoot/SingleComponent"
120-
121-
# Generate Solution
122-
# ------------------
123-
124-
# Projects to include
125-
$projects = [System.Collections.ArrayList]::new()
126-
127-
# Include all projects in component folder
128-
[void]$projects.Add(".\*\*.*proj")
129-
130-
# Install slgnen
131-
dotnet tool restore
132-
133-
$generatedSolutionFilePath = "$componentPath/$componentName.sln"
134-
$platforms = '"Any CPU;x64;x86;ARM64"'
135-
$slngenConfig = "--folders true --collapsefolders true --ignoreMainProject"
136-
137-
# Remove previous file if it exists
138-
if (Test-Path -Path $generatedSolutionFilePath)
139-
{
140-
Remove-Item $generatedSolutionFilePath
141-
Write-Host "Removed previous solution file"
142-
}
143-
144-
# Deployable sample gallery heads
145-
# All heads are included by default since they reside in the same folder as the component.
146-
# Remove any heads that are not required for the solution.
147-
# TODO: this handles separate project heads, but won't directly handle the unified Skia head from Uno.
148-
# Once we have that, just do a transform on the csproj filename inside this loop to decide the same csproj for those separate MultiTargets.
149-
foreach ($multitarget in $MultiTargets) {
150-
# capitalize first letter, avoid case sensitivity issues on linux
151-
$csprojFileNamePartForMultiTarget = $multitarget.substring(0,1).ToUpper() + $multitarget.Substring(1).ToLower()
152-
153-
$path = "$outputHeadsDir\**\*$csprojFileNamePartForMultiTarget.csproj";
154-
155-
if (Test-Path $path) {
156-
# iterate the wildcards caught by $path
157-
foreach ($foundItem in Get-ChildItem $path)
158-
{
159-
$projects = $projects + $foundItem.FullName
160-
}
161-
}
162-
else {
163-
Write-Warning "No project head could be found at $path for MultiTarget $multitarget. Skipping."
164-
}
165-
}
166-
167-
# Include common dependencies required for solution to build
168-
$projects = $projects + "..\..\tooling\CommunityToolkit.App.Shared\**\*.*proj"
169-
$projects = $projects + "..\..\tooling\CommunityToolkit.Tests.Shared\**\*.*proj"
170-
$projects = $projects + "..\..\tooling\CommunityToolkit.Tooling.SampleGen\*.csproj"
171-
$projects = $projects + "..\..\tooling\CommunityToolkit.Tooling.TestGen\*.csproj"
172-
$projects = $projects + "..\..\tooling\CommunityToolkit.Tooling.XamlNamedPropertyRelay\*.csproj"
173-
174-
if ($UseDiagnostics.IsPresent)
175-
{
176-
$sdkoptions = " -d"
177-
$diagnostics = '-bl:slngen.binlog --consolelogger:"ShowEventId;Summary;Verbosity=Detailed" --filelogger:"LogFile=slngen.log;Append;Verbosity=Diagnostic;Encoding=UTF-8" '
178-
}
179-
else
180-
{
181-
$sdkoptions = ""
182-
$diagnostics = ""
183-
}
184-
185-
$cmd = "dotnet$sdkoptions tool run slngen -o $generatedSolutionFilePath $slngenConfig $diagnostics--platform $platforms $($projects -Join ' ')"
186-
187-
Write-Output "Running Command: $cmd"
188-
189-
Invoke-Expression $cmd
190-
191-
# go back to main working directory
192-
Pop-Location
49+
# Use & and a separate script path variable to avoid issues with parameter passing
50+
$scriptPath = "$PSScriptRoot/../GenerateSingleSolution.ps1"
51+
& $scriptPath -MultiTargets $MultiTargets -ExcludeMultiTargets $ExcludeMultiTargets -WinUIMajorVersion $WinUIMajorVersion -UseDiagnostics:$UseDiagnostics -componentPath $componentPath

0 commit comments

Comments
 (0)