This repository was archived by the owner on Aug 5, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdev.ps1
More file actions
240 lines (195 loc) · 8.3 KB
/
Copy pathdev.ps1
File metadata and controls
240 lines (195 loc) · 8.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#!/usr/bin/env pwsh
<#
.SYNOPSIS
One entry point for building, testing and running this repository.
.DESCRIPTION
Wraps the dotnet commands so that VS Code, CI and a bare terminal all drive the repo the
same way. Written for Windows PowerShell 5.1 as well as PowerShell 7, so it runs on
Windows without installing anything and on Linux and macOS under `pwsh`.
On a non-Windows host the WinForms client is skipped rather than failing the build:
everything else in the solution is cross-platform, and `build` has to stay usable there.
.PARAMETER Command
build Build the solution (or the cross-platform projects, off Windows).
test Run the test suite.
run Run one project: cli, gui, or server.
demo Start the test server, then open the console browser against it.
screenshots Rebuild and recapture docs/*.png. Windows only.
clean Delete build output.
help This text.
.PARAMETER Target
Which project `run` should start: cli, gui or server.
.PARAMETER Configuration
Debug (default) or Release.
.PARAMETER Rest
Arguments passed through to the application. Write them normally, after the target:
./tools/dev.ps1 run server --port 2121 --noise
Do not put a bare `--` in front of them; PowerShell 5.1 reads that as an empty
parameter name and refuses the whole call.
One caveat worth knowing about, because it fails silently: PowerShell binds a
pass-through flag to this script if the name matches one of the script's own parameters
by prefix. That is why the demo port below is `-DemoPort` and not `-Port` — `--port`
would have been captured here and never reached the application. Keep new parameters on
this script distinct from the applications' flags.
.EXAMPLE
./tools/dev.ps1 build -Configuration Release
.EXAMPLE
./tools/dev.ps1 run server --port 2121 --noise
.EXAMPLE
./tools/dev.ps1 demo
#>
[CmdletBinding()]
param(
[Parameter(Position = 0)]
[ValidateSet('build', 'test', 'run', 'demo', 'screenshots', 'clean', 'help')]
[string] $Command = 'help',
[Parameter(Position = 1)]
[ValidateSet('cli', 'gui', 'server', 'tests')]
[string] $Target,
[ValidateSet('Debug', 'Release')]
[string] $Configuration = 'Debug',
# Used by `demo` and `screenshots`. Deliberately not `-Port`: see .PARAMETER Rest.
[int] $DemoPort = 2121,
# Not named $args: that collides with the automatic variable and binds nothing.
[Parameter(ValueFromRemainingArguments = $true)]
[string[]] $Rest
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$repo = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
# $IsWindows only exists from PowerShell 6. Where it is missing we are on 5.1, which is
# Windows by definition.
$onWindows = $true
if (Test-Path 'variable:IsWindows') { $onWindows = $IsWindows }
$projects = @{
cli = 'src/FtpClient.Cli/FtpClient.Cli.csproj'
gui = 'src/FtpClient.Gui/FtpClient.Gui.csproj'
server = 'tests/FtpClient.TestServer/FtpClient.TestServer.csproj'
tests = 'tests/FtpClient.Protocol.Tests/FtpClient.Protocol.Tests.csproj'
}
function Get-ProjectPath {
param([string] $Name)
return (Join-Path $repo $projects[$Name])
}
function Invoke-Dotnet {
param([string[]] $Arguments)
Write-Host "dotnet $($Arguments -join ' ')" -ForegroundColor DarkGray
& dotnet @Arguments
if ($LASTEXITCODE -ne 0) {
throw "dotnet $($Arguments -join ' ') failed with exit code $LASTEXITCODE."
}
}
function Invoke-Build {
if ($onWindows) {
Invoke-Dotnet @('build', (Join-Path $repo 'FtpClient.sln'), '-c', $Configuration, '--nologo')
return
}
# FtpClient.Gui targets net8.0-windows. Building the solution here would fail on it, so
# build the cross-platform projects instead; their project references pull in the rest.
Write-Host 'Not on Windows: skipping FtpClient.Gui (net8.0-windows).' -ForegroundColor Yellow
Invoke-Dotnet @('build', (Get-ProjectPath 'cli'), '-c', $Configuration, '--nologo')
Invoke-Dotnet @('build', (Get-ProjectPath 'tests'), '-c', $Configuration, '--nologo')
}
function Invoke-Test {
Invoke-Dotnet @('test', (Get-ProjectPath 'tests'), '-c', $Configuration, '--nologo')
}
function Invoke-Run {
param([string] $Name, [string[]] $Arguments)
if (-not $Name) { throw "run needs a target: cli, gui or server." }
if ($Name -eq 'gui' -and -not $onWindows) {
throw 'The WinForms client only runs on Windows.'
}
$invocation = @('run', '--project', (Get-ProjectPath $Name), '-c', $Configuration, '--')
if ($Arguments) { $invocation += $Arguments }
Invoke-Dotnet $invocation
}
function Wait-ForPort {
param([int] $Number, [int] $TimeoutSeconds = 30)
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
while ((Get-Date) -lt $deadline) {
try {
$probe = New-Object System.Net.Sockets.TcpClient
$probe.Connect('127.0.0.1', $Number)
$probe.Close()
return
}
catch {
Start-Sleep -Milliseconds 250
}
}
throw "Nothing was listening on port $Number after $TimeoutSeconds seconds."
}
function Invoke-Demo {
Invoke-Build
$root = Join-Path $repo 'demo'
New-Item -ItemType Directory -Force -Path (Join-Path $root 'My Documents') | Out-Null
$report = Join-Path $root 'my report.txt'
if (-not (Test-Path -LiteralPath $report)) {
Set-Content -LiteralPath $report -Value 'Quarterly numbers.' -Encoding utf8
}
Write-Host "Starting the test server on port $DemoPort over $root" -ForegroundColor Cyan
$server = Start-Process -FilePath 'dotnet' -PassThru -ArgumentList @(
'run', '--project', (Get-ProjectPath 'server'), '-c', $Configuration, '--',
'--root', $root, '--port', $DemoPort, '--noise')
try {
Wait-ForPort -Number $DemoPort
Invoke-Run -Name 'cli' -Arguments @(
'--host', '127.0.0.1', '--port', $DemoPort,
'--user', 'test_user', '--password', 'test_password')
}
finally {
if (-not $server.HasExited) {
# /T as well: `dotnet run` starts the app as a child, and killing only the
# launcher leaves it holding a lock on bin/.
if ($onWindows) {
& taskkill.exe /T /F /PID $server.Id 2>&1 | Out-Null
}
else {
Stop-Process -Id $server.Id -Force -ErrorAction SilentlyContinue
}
}
}
}
function Invoke-Screenshots {
if (-not $onWindows) { throw 'Screenshot capture needs Windows (P/Invoke + CopyFromScreen).' }
& (Join-Path $PSScriptRoot 'capture-screenshots.ps1') -Port $DemoPort
}
function Invoke-Clean {
Invoke-Dotnet @('clean', (Join-Path $repo 'FtpClient.sln'), '-c', $Configuration, '--nologo')
}
function Show-Help {
# Written out rather than delegated to Get-Help: comment-based help is not reliably
# discoverable when the script is invoked with `powershell -File`.
Write-Host @'
dev.ps1 - build, test and run this repository
Usage:
./tools/dev.ps1 <command> [target] [-Configuration Debug|Release] [app arguments]
Commands:
build Build the solution. Off Windows, skips the WinForms client.
test Run the test suite.
run <cli|gui|server> Run one project. Trailing arguments go to the application.
demo Start the test server, then the console browser against it.
screenshots Rebuild and recapture docs/*.png. Windows only.
clean Delete build output.
help This text.
Options:
-Configuration <cfg> Debug (default) or Release.
-DemoPort <port> Port for `demo` and `screenshots`. Default 2121.
Examples:
./tools/dev.ps1 build -Configuration Release
./tools/dev.ps1 test
./tools/dev.ps1 run server --root ./demo --port 2121 --noise
./tools/dev.ps1 run cli --host 127.0.0.1 --port 2121 --user test_user --list
./tools/dev.ps1 demo
Application arguments are written plainly after the target - no `--` separator, which
PowerShell 5.1 rejects as an empty parameter name.
'@
}
switch ($Command) {
'build' { Invoke-Build }
'test' { Invoke-Test }
'run' { Invoke-Run -Name $Target -Arguments $Rest }
'demo' { Invoke-Demo }
'screenshots' { Invoke-Screenshots }
'clean' { Invoke-Clean }
default { Show-Help }
}