-
Notifications
You must be signed in to change notification settings - Fork 0
/
devtool.ps1
303 lines (269 loc) · 8.64 KB
/
devtool.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
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#!/usr/bin/env powershell
param (
[switch]$skipWSLImport,
[switch]$skipWSLDefault,
[switch]$ImportForce
)
$env:WSL_UTF8=1
function Get-LatestReleaseInfo {
param (
[string]$owner,
[string]$repo
)
$apiUrl = "https://api.github.com/repos/$owner/$repo/releases/latest"
$headers = @{
"User-Agent" = "PowerShell"
}
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers
return $response
}
function Download-Assets {
param (
[array]$assets,
[string]$downloadPath
)
Add-Type -AssemblyName System.Net.Http
$httpClient = [System.Net.Http.HttpClient]::new()
$totalAssets = $assets.Count
$currentAssetIndex = 0
foreach ($asset in $assets) {
if ($asset.name -like "*.tar.gz.part*" -or $asset.name -eq "sha256sum.txt") {
$currentAssetIndex++
$assetUrl = $asset.browser_download_url
$outputFile = Join-Path $downloadPath $asset.name
Write-Host "Downloading $($asset.name)"
try {
$response = $httpClient.GetAsync($assetUrl, [System.Net.Http.HttpCompletionOption]::ResponseHeadersRead).Result
$response.EnsureSuccessStatusCode() | Out-Null
$totalBytes = $response.Content.Headers.ContentLength
$stream = $response.Content.ReadAsStreamAsync().Result
$fileStream = [System.IO.File]::Create($outputFile)
$buffer = New-Object byte[] 8388608 # 8MB
$totalRead = 0
$read = 0
$lastProgress = 0
while (($read = $stream.Read($buffer, 0, $buffer.Length)) -gt 0) {
$fileStream.Write($buffer, 0, $read)
$totalRead += $read
$percentComplete = [math]::Round(($totalRead / $totalBytes) * 100, 2)
if ($percentComplete -ge $lastProgress + 1) {
Write-Progress `
-Activity "Downloading $($asset.name) ($currentAssetIndex of $totalAssets)" `
-Status "$percentComplete% Complete" `
-PercentComplete $percentComplete
$lastProgress = $percentComplete
}
}
$fileStream.Close()
$stream.Close()
# Check the file size after download
$downloadedFileSize = (Get-Item $outputFile).Length
if ($downloadedFileSize -eq $totalBytes) {
Write-Host "Download Complete: $($asset.name)"
} else {
Write-Error "Download incomplete or corrupted: $($asset.name). Expected size: $totalBytes, Actual size: $downloadedFileSize"
}
} catch [System.Net.Http.HttpRequestException] {
Write-Error "Network or DNS error occurred while downloading $($asset.name): $_"
} catch {
Write-Error "An error occurred while downloading $($asset.name): $_"
} finally {
if ($fileStream) {
$fileStream.Close()
}
if ($stream) {
$stream.Close()
}
}
}
}
$httpClient.Dispose()
}
function Verify-Hashes {
param (
[string]$downloadPath
)
$sha256sumFile = Join-Path $downloadPath "sha256sum.txt"
if (Test-Path $sha256sumFile) {
$hashes = @(Get-Content $sha256sumFile | Where-Object { $_.Trim() -ne "" } | ForEach-Object {
$parts = $_ -split ' ' # Note the double space
@{
Hash = $parts[0]
File = $parts[1].Trim()
}
})
$totalFiles = $hashes.Count
$matchedFiles = 0
for ($i = 0; $i -lt $totalFiles; $i++) {
$hash = $hashes[$i]
$filePath = Join-Path $downloadPath $hash.File
if (Test-Path $filePath) {
$fileHash = Get-FileHash -Path $filePath -Algorithm SHA256
if ($fileHash.Hash -eq $hash.Hash) {
Write-Host "[$($i + 1)/$totalFiles] $($hash.File) hash matches."
$matchedFiles++
} else {
Write-Host "[$($i + 1)/$totalFiles] $($hash.File) hash does not match."
}
} else {
Write-Host "[$($i + 1)/$totalFiles] $($hash.File) not found."
}
}
if ($matchedFiles -eq $totalFiles) {
Write-Host "`nAll file hashes match."
return $true
} else {
Write-Host "`nSome file hashes do not match." -ForegroundColor Red
return $false
}
} else {
Write-Host "`nsha256sum.txt file not found." -ForegroundColor Red
return $false
}
}
function Combine-Parts {
param (
[string]$downloadPath
)
$partFiles = Get-ChildItem -Path $downloadPath -Filter "*.tar.gz.part*" | Sort-Object Name
if ($partFiles.Count -gt 0) {
$baseFileName = [System.IO.Path]::GetFileNameWithoutExtension($partFiles[0].Name).Replace(".part", "")
$outputFile = Join-Path $downloadPath $baseFileName
Write-Host "Combining parts into $outputFile"
$outputStream = [System.IO.File]::Create($outputFile)
foreach ($partFile in $partFiles) {
$inputStream = [System.IO.File]::OpenRead($partFile.FullName)
$buffer = New-Object byte[] 8388608 # 8MB
$read = 0
while (($read = $inputStream.Read($buffer, 0, $buffer.Length)) -gt 0) {
$outputStream.Write($buffer, 0, $read)
}
$inputStream.Close()
}
$outputStream.Close()
Write-Host "Combination Complete"
return $outputFile
} else {
Write-Host "No part files found to combine."
return $null
}
}
function Import-WSL {
param (
[string]$wslPath,
[string]$tag_name,
[string]$tarGzFile,
[bool]$skipWSLDefault = $false,
[bool]$ImportForce = $false
)
if ($ImportForce) {
Write-Host "[ImportForce] is enabled. Listing WSL instances..."
$wslOutput = wsl --list --quiet
$wslLines = $wslOutput -split "`n"
foreach ($line in $wslLines) {
$_line = $line.Trim()
if ($_line -match '^dwsl2-*') {
try {
wsl --unregister $_line | Out-Null
Write-Host "[ImportForce] Successfully unregistered [$_line]"
} catch {
Write-Host "[ImportForce] Failed to unregister [$_line] : $_"
}
}
}
}
$importPath = Join-Path $wslPath $tag_name
if (-Not (Test-Path -Path $importPath)) {
New-Item -ItemType Directory -Path $importPath | Out-Null
}
Write-Host "`nImporting WSL"
wsl --import dwsl2-$tag_name $importPath $tarGzFile --version 2
Write-Host "`nWSL imported successfully."
if (-not $skipWSLDefault) {
Write-Host "`nSetting WSL default Distribution"
wsl --set-default dwsl2-$tag_name
}
}
function Create-Dir {
param (
[string]$wslPath,
[string]$downloadPath
)
if (-Not (Test-Path -Path $wslPath)) {
Write-Host "Create WSL2 path $wslPath"
New-Item -ItemType Directory -Path $wslPath | Out-Null
}
if (-Not (Test-Path -Path $downloadPath)) {
Write-Host "Create downloaded path $downloadPath"
New-Item -ItemType Directory -Path $downloadPath | Out-Null
}
}
function Cleanup-DownloadPath {
param (
[string]$downloadPath
)
Write-Host "Cleanup ..."
Remove-Item -Path $downloadPath -Recurse
Write-Host "`nCleaned up parent directory: $downloadPath"
}
function Main {
param (
[switch]$skipWSLImport,
[switch]$skipWSLDefault,
[switch]$ImportForce
)
$owner = "naa0yama"
$repo = "devtool-wsl2"
try {
$response = Get-LatestReleaseInfo -owner $owner -repo $repo
$assets = $response.assets
$tag_name = $response.tag_name
$html_url = $response.html_url
$wslPath = "$env:USERPROFILE\Documents\WSL2"
$downloadPath = "$wslPath\dl\$tag_name"
Clear-Host
Write-Host "////////////////////////////////////////////////////////////////////////////////"
Write-Host "//`t _ _ _ _ _____ "
Write-Host "//`t | | | | | | | |/ __ \"
Write-Host "//`t __| | _____ _| |_ ___ ___ | |________ _____| |`' / /'"
Write-Host "//`t / _` |/ _ \ \ / / __/ _ \ / _ \| |______\ \ /\ / / __| | / / "
Write-Host "//`t| (_| | __/\ V /| || (_) | (_) | | \ V V /\__ \ |./ /___"
Write-Host "//`t \__,_|\___| \_/ \__\___/ \___/|_| \_/\_/ |___/_|\_____/"
Write-Host "//"
Write-Host "//"
Write-Host "// The latest tag is`t`t$tag_name"
Write-Host "// The latest Release Pages is`t$html_url"
Write-Host "// WSL2 Path`t`t`t$wslPath"
Write-Host "// Downloaded Path`t`t$downloadPath"
Write-Host "//"
Write-Host "// Options:"
Write-Host "//`tskipWSLImport`t`t$skipWSLImport"
Write-Host "//`tskipWSLDefault`t`t$skipWSLDefault"
Write-Host "//`tImportForce`t`t$ImportForce"
Write-Host "//"
Create-Dir $wslPath $downloadPath
# Run the download
Download-Assets -assets $assets -downloadPath $downloadPath
# Perform hash verification
if (Verify-Hashes -downloadPath $downloadPath) {
# Executes the combination of part files
$tarGzFile = Combine-Parts -downloadPath $downloadPath
if (-not $skipWSLImport -and $tarGzFile) {
Import-WSL -wslPath $wslPath -tag_name $tag_name `
-tarGzFile $tarGzFile -skipWSLDefault:$skipWSLDefault -ImportForce:$ImportForce
}
} else {
Write-Host "`n`nHash verification failed. Aborting combination process." -ForegroundColor Red
exit 1
}
} catch {
Write-Host "`nAn error occurred: $_" -ForegroundColor Red
exit 1
} finally {
if (-not $skipWSLImport) {
Cleanup-DownloadPath -downloadPath $downloadPath
}
}
}
# Call the main function with parameters passed to the script
Main -skipWSLImport:$skipWSLImport -skipWSLDefault:$skipWSLDefault -ImportForce:$ImportForce