-
Notifications
You must be signed in to change notification settings - Fork 9
/
test_update_cycle.ps1
191 lines (166 loc) · 6.69 KB
/
test_update_cycle.ps1
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
# DISCLAIMER:
# This script automatically creates files on your system, related to the example
# "my_app", and deletes them afterwards. Confirmation is requested before deleting.
# Use at your own risk.
#
# This script executes the steps from the README, both for the repo-side and the
# client-side. This is basically the same as the test-update-cycle.yml github workflow,
# except you run this on your local development system, for convenient manual testing.
#
# - initialize a new example repository in a .\temp_my_app dir (including dummy keystore)
# - create my_app v1.0 bundle using pyinstaller
# - add my_app v1.0 to tufup repository
# - install my_app v1.0 in <localappdata>\Programs\my_app with data in <localappdata>\my_app
# - mock develop my_app v2.0
# - create my_app v2.0 bundle using pyinstaller
# - add my_app v2.0 to tufup repository
# - run update server and update my_app from v1 to v2
#
# if the script won't execute, run the following command:
# `Set-ExecutionPolicy AllSigned`
# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts
#
# note we could simply run this script in the github workflow,
# but workflow failures are easier to debug when broken down into
# separate steps
# exit on cmdlet errors
$ErrorActionPreference = "stop"
# exit on executable errors (for use directly after executable call)
function Assert-ExeSuccess {
if (!$?) {
# note $? contains the execution status of the last command (true if successful)
Write-Error "failed"
}
}
# variables
$app_name = "my_app"
$enable_patch_update = $true
# directories where this script creates files and deletes files (note these must end
# with $app_name and must be consistent with myapp.settings and repo_settings)
$repo_dir = $PSScriptRoot
$temp_dir = "$repo_dir\temp_$app_name"
$app_install_dir = "$env:LOCALAPPDATA\Programs\$app_name"
$app_data_dir = "$env:LOCALAPPDATA\$app_name"
$targets_dir = "$app_data_dir\update_cache\targets"
$all_app_dirs = @($temp_dir, $app_install_dir, $app_data_dir)
function Remove-MyAppDirectory {
# remove a *my_app directory after confirmation
param($Path)
if ( $Path -match "$app_name$" ) {
if (Test-Path $Path) {
# I think recurse can be used here, despite "known issues"...
Remove-Item $Path -Recurse -Confirm
} else {
Write-Host "path does not exist: $Path" -ForegroundColor yellow
}
} else {
Write-Host "$app_name not in path: $Path" -ForegroundColor yellow
}
}
function Remove-MyApp {
$all_app_dirs | ForEach-Object { Remove-MyAppDirectory $_ }
}
function Invoke-PyInstaller {
pyinstaller.exe "$repo_dir\main.spec" --clean -y --distpath "$temp_dir\dist" --workpath "$temp_dir\build"
Assert-ExeSuccess
}
# remove leftover directories and files, if any
Remove-MyApp
# create directories if they do not exist yet
$all_app_dirs | ForEach-Object {
if (!(Test-Path $_)) {
New-Item -Path $_ -ItemType "directory" | Out-Null
Write-Host "directory created: $_" -ForegroundColor green
}
}
New-Item -Path $targets_dir -ItemType "directory" -Force | Out-Null
# this script requires an active python environment, with tufup installed
# (we'll assume there's a venv in the repo_dir)
$venv_path = "$repo_dir\venv\Scripts\activate.ps1"
if (Test-Path $venv_path) {
& $venv_path
Write-Host "venv activated" -ForegroundColor green
} else {
Write-Host "venv not found" -ForegroundColor red
}
# make sure python can find myapp
$Env:PYTHONPATH += ";$repo_dir\src"
# - initialize new repository
Write-Host "initializing tuf repository for $app_name" -ForegroundColor green
python "$repo_dir\repo_init.py"
Assert-ExeSuccess
# - create my_app v1.0 bundle using pyinstaller
Write-Host "creating $app_name v1.0 bundle" -ForegroundColor green
Invoke-PyInstaller
# - add my_app v1.0 to tufup repository
Write-Host "adding $app_name v1.0 bundle to repo" -ForegroundColor green
python "$repo_dir\repo_add_bundle.py"
Assert-ExeSuccess
# - mock install my_app v1.0
Write-Host "installing $app_name v1.0 in $app_install_dir" -ForegroundColor green
$myapp_v1_archive = "$temp_dir\repository\targets\$app_name-1.0.tar.gz"
tar -xf $myapp_v1_archive --directory=$app_install_dir
# put a copy of the archive in the targets dir, to enable patch updates
if ($enable_patch_update) {
Write-Host "enabling patch update" -ForegroundColor green
Copy-Item $myapp_v1_archive -Destination $targets_dir
}
# - mock develop my_app v2.0
# (quick and dirty, this modifies the actual source,
# but the change is rolled back later...)
Write-Host "bumping $app_name version to v2.0 (temporary)" -ForegroundColor green
$settings_path = "$repo_dir\src\myapp\settings.py"
(Get-Content $settings_path).Replace("1.0", "2.0") | Set-Content $settings_path
# - create my_app v2.0 bundle using pyinstaller
Write-Host "creating $app_name v2.0 bundle" -ForegroundColor green
Invoke-PyInstaller
# - add my_app v2.0 to tufup repository
Write-Host "adding $app_name v2.0 bundle to repo" -ForegroundColor green
python "$repo_dir\repo_add_bundle.py"
Assert-ExeSuccess
# - roll-back modified source
Write-Host "rolling back temporary source modification" -ForegroundColor green
(Get-Content $settings_path).Replace("2.0", "1.0") | Set-Content $settings_path
# - start update server
Write-Host "starting update server" -ForegroundColor green
$job = Start-Job -ArgumentList @("$temp_dir\repository") -ScriptBlock {
param($repository_path)
python -m http.server -d $repository_path
Assert-ExeSuccess
}
sleep 1 # not sure if this is required, but cannot hurt
# - run my_app to update from v1 to v2
Write-Host "running $app_name for update..." -ForegroundColor green
& "$app_install_dir\main.exe"
Assert-ExeSuccess
# - run my_app again to verify we now have v2.0
Write-Host "hit enter to proceed, after console has closed:" -ForegroundColor yellow -NoNewLine
Read-Host # no text: we use write host to add color
Write-Host "running $app_name again to verify version" -ForegroundColor green
$output = & "$app_install_dir\main.exe"
Assert-ExeSuccess
# - stop update server
Write-Host "stopping server" -ForegroundColor green
$job | Stop-Job
# - test output
$pattern = "$app_name 2.0"
if ( $output -match $pattern ) {
Write-Host "`nSUCCESS: $pattern found" -ForegroundColor green
} else {
Write-Host "`nFAIL: $pattern not found in:`n$output" -ForegroundColor red
exit 1
}
# reminder to clean up
$remaining = 0
$all_app_dirs | ForEach-Object {
if (Test-Path $_) {
Write-Host "$app_name files remain in: $_" -ForegroundColor yellow
$remaining += 1
}
}
if ($remaining) {
Write-Host "Would you like to remove these directories?" -ForegroundColor yellow
if ((Read-Host "[y]/n") -in "", "y") {
Remove-MyApp
}
}