-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.ps1
More file actions
705 lines (617 loc) · 24.7 KB
/
install.ps1
File metadata and controls
705 lines (617 loc) · 24.7 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
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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
# install.ps1
# Logging functions
function Write-InfoLog { param($Message) Write-Host "[INFO] $Message" -ForegroundColor Green }
function Write-WarnLog { param($Message) Write-Host "[WARN] $Message" -ForegroundColor Yellow }
function Write-ErrorLog { param($Message) Write-Host "[ERROR] $Message" -ForegroundColor Red }
$ScriptVersion = "1.5.1"
Write-InfoLog "Running Script Version $ScriptVersion"
for ($i = 0; $i -lt $args.Count; $i++) {
switch ($args[$i]) {
'--start-dir' { $startDir = $args[++$i] }
}
}
if ($startDir -and (Test-Path $startDir)) {
Set-Location $startDir
} elseif ($startDir) {
Write-WarnLog "Start directory is not set or does not exist: $startDir"
}
# Default ports
$DEFAULT_HTTP_PORT = 80
$DEFAULT_HTTPS_PORT = 443
$DEFAULT_XGT_PORT = 4367
$DEFAULT_INSTALL_DIR = Get-Location
$DEFAULT_LICENSE_LOCATION = Join-Path $DEFAULT_INSTALL_DIR 'xgt.lic'
# Initialize variables with default values
$HTTP_PORT = $DEFAULT_HTTP_PORT
$HTTPS_PORT = $DEFAULT_HTTPS_PORT
$XGT_PORT = $DEFAULT_XGT_PORT
$INSTALL_DIR = $DEFAULT_INSTALL_DIR
$LICENSE_LOCATION = $DEFAULT_LICENSE_LOCATION
$ENTERPRISE_INSTALL = $false
# Minimum required Docker Compose version
$MIN_COMPOSE_VERSION = "2.0.0"
# Pause script if running in pop-up terminal
$PAUSE_AT_END = $true
# Launch browser on success
$LAUNCH_BROWSER = $true
# Install docker if it's not installed'
$INSTALL_DOCKER = $true
$EXISTING_ENV = $false
$USE_SSL = $false
$ERROR_CODE = 0
# Function to display help
function Show-Help {
Write-Host "Usage: install.ps1 [OPTIONS]"
Write-Host "Available options:"
Write-Host " --http-port PORT Specify custom HTTP port (default: $DEFAULT_HTTP_PORT)"
Write-Host " --https-port PORT Specify custom HTTPS port (default: $DEFAULT_HTTPS_PORT)"
Write-Host " --install-dir DIR Specify custom install location (default: $DEFAULT_INSTALL_DIR)"
Write-Host " --license-file DIR Specify custom license location (default: $LICENSE_LOCATION)"
Write-Host " --xgt-port PORT Specify custom XGT port (default: $DEFAULT_XGT_PORT)"
Write-Host " --enterprise Enable multi-user enterprise installation"
Write-Host " --no-docker Do not install docker if it's missing"
Write-Host " --no-browser Do not launch the browser after setup"
Write-Host " --no-pause Do not wait for input at the end"
Write-Host " -h, --help Show this help message"
}
function Exit-Script {
param (
[int]$Code = 1
)
if ($PAUSE_AT_END) {
Read-Host "Press Enter to exit..."
}
[System.Environment]::Exit($Code)
}
# Parse command-line arguments
for ($i = 0; $i -lt $args.Count; $i++) {
switch ($args[$i]) {
'--http-port' {
if ($i + 1 -lt $args.Count -and $args[$i + 1] -notmatch '^-') {
$HTTP_PORT = $args[$i + 1]
$i++
} else {
Write-ErrorLog "Error: Argument for --http-port is missing"
Read-Host "Press Enter to exit..."
exit 1
}
}
'--https-port' {
if ($i + 1 -lt $args.Count -and $args[$i + 1] -notmatch '^-') {
$HTTPS_PORT = $args[$i + 1]
$i++
} else {
Write-ErrorLog "Error: Argument for --https-port is missing"
Read-Host "Press Enter to exit..."
exit 1
}
}
'--install-dir' {
if ($i + 1 -lt $args.Count -and $args[$i + 1] -notmatch '^-') {
$INSTALL_DIR = $args[$i + 1]
$i++
} else {
Write-ErrorLog "Error: Argument for --install-dir is missing"
Read-Host "Press Enter to exit..."
exit 1
}
}
'--license-file' {
if ($i + 1 -lt $args.Count -and $args[$i + 1] -notmatch '^-') {
$LICENSE_LOCATION = $args[$i + 1]
$i++
} else {
Write-ErrorLog "Error: Argument for --install-dir is missing"
Read-Host "Press Enter to exit..."
exit 1
}
}
'--xgt-port' {
if ($i + 1 -lt $args.Count -and $args[$i + 1] -notmatch '^-') {
$XGT_PORT = $args[$i + 1]
$i++
} else {
Write-ErrorLog "Error: Argument for --xgt-port is missing"
Read-Host "Press Enter to exit..."
exit 1
}
}
'--enterprise' {
$ENTERPRISE_INSTALL = $true
}
'--no-docker' {
$INSTALL_DOCKER = $false
}
'--no-browser' {
$LAUNCH_BROWSER = $false
}
'--no-pause' {
$PAUSE_AT_END = $false
}
'-h' {
Show-Help
exit 0
}
'--help' {
Show-Help
exit 0
}
'--start-dir' {
$i++
#Ignore
}
default {
Write-Error "Unknown option: $($args[$i])"
Write-Host "Use -h or --help to see available options"
Read-Host "Press Enter to exit..."
exit 1
}
}
}
function Get-OSPlatform {
# Try PowerShell Core method first
if (Test-Path variable:IsWindows) {
if ($IsWindows) { return "Windows" }
elseif ($IsLinux) { return "Linux" }
elseif ($IsMacOS) { return "MacOS" }
}
# Fall back to .NET method for PowerShell 5.1
else {
$platform = [System.Environment]::OSVersion.Platform
if ($platform -match "Win") { return "Windows" }
# This will never execute in PS 5.1, but included for completeness
elseif ($platform -match "Unix") { return "Linux/Unix" }
elseif ($platform -match "MacOS") { return "MacOS" }
}
return "Unknown"
}
$script:isWindowsPlat = (Get-OSPlatform) -eq "Windows"
# Check if script is run as administrator
$isAdmin = $false
if ($isWindowsPlat) {
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
} elseif ($IsLinux -or $IsMacOS) {
$isAdmin = [int](id -u) -eq 0
}
if (-not $isAdmin) {
if ($isWindowsPlat) {
# Determine script content source
$scriptPath = $MyInvocation.MyCommand.Path
if (-not $scriptPath) {
# Script was run via iex/iwr, so re-download it manually
$response = Invoke-WebRequest -Uri 'https://install.rocketgraph.com/install.ps1' -UseBasicParsing
$reader = New-Object System.IO.StreamReader($response.RawContentStream)
$scriptContent = $reader.ReadToEnd()
$reader.Close()
} else {
$scriptContent = Get-Content -Raw -Path $scriptPath
}
# Save to temp file and elevate
$tempFile = [IO.Path]::Combine($env:TEMP, "rocketgraph_installer.ps1")
Set-Content -Path $tempFile -Value $scriptContent -Encoding UTF8 > $null
$quotedArgs = @()
foreach ($arg in $args) { $quotedArgs += "`"$arg`"" }
$quotedArgs += "`"--start-dir`""
$quotedArgs += "`"$DEFAULT_INSTALL_DIR`""
$allArgs = @("-ExecutionPolicy", "Bypass", "-File", "`"$tempFile`"") + $quotedArgs
Start-Process powershell -ArgumentList $allArgs -WorkingDirectory $DEFAULT_INSTALL_DIR -Verb RunAs
exit 1
} else {
Write-ErrorLog "This script must be run as Administrator"
}
exit 1
}
# Function to check if a command exists
function Test-Command {
param($CommandName)
$null -ne (Get-Command $CommandName -ErrorAction SilentlyContinue)
}
# Function to compare versions
function Test-VersionGreaterOrEqual {
param($Version1, $Version2)
return ([System.Version]$Version1 -ge [System.Version]$Version2)
}
function Install-Docker {
if ((-not (Test-WSL2))) {
Exit-Script 1
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$url = "https://desktop.docker.com/win/main/amd64/Docker Desktop Installer.exe"
$dockerInstaller = "$env:TEMP\DockerDesktopInstaller.exe"
Write-InfoLog "Downloading Docker Desktop..."
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($url, $dockerInstaller)
Write-InfoLog "Installing Docker Desktop (may require reboot)..."
Write-InfoLog "Follow the prompts in the Docker installer and close the window when it finishes by clicking X. Usually you do not need to log out or restart, even if prompted. If you do, simply rerun this setup after logging back in."
Start-Process -FilePath $dockerInstaller -ArgumentList "install", '--accept-license' -Wait
# Refresh environment variables from registry
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" +
[System.Environment]::GetEnvironmentVariable("Path", "User")
}
function Test-RebootPending {
try {
$baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey(
[Microsoft.Win32.RegistryHive]::LocalMachine,
[Microsoft.Win32.RegistryView]::Registry64
)
$subKey = $baseKey.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending")
return $subKey -ne $null
} catch {
return $false
}
}
function Test-WSL2 {
# Minimum Windows build for WSL2 is 19041
if ([System.Environment]::OSVersion.Version.Build -lt 19041) {
Write-ErrorLog "WSL2 requires Windows 10 version 2004 (build 19041) or later."
return $false
}
$wslFeature = Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
$vmFeature = Get-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
$needsEnable = $false
if ($wslFeature.State -ne "Enabled") {
Write-InfoLog "Enabling WSL feature..."
try {
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -NoRestart -ErrorAction Stop
$needsEnable = $true
} catch {
Write-ErrorLog ("Failed to enable WSL. The component store may be unavailable in this environment (e.g., Windows Sandbox or VM without nested virtualization).`nError details: {0}" -f $_.Exception.Message)
return $false
}
}
if ($vmFeature.State -ne "Enabled") {
Write-InfoLog "Enabling VirtualMachinePlatform for WSL2..."
try {
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -NoRestart -ErrorAction Stop
$needsEnable = $true
} catch {
Write-ErrorLog ("Failed to enable VirtualMachinePlatform. This may be due to missing virtualization support or a restricted environment.`nError details: {0}" -f $_.Exception.Message)
return $false
}
}
# Try setting WSL2 as the default
try {
wsl --set-default-version 2 > $null 2>&1
if ($LASTEXITCODE -ne 0) {
throw "wsl.exe exited with code $LASTEXITCODE"
}
Write-InfoLog "WSL2 set as the default version."
} catch {
Write-WarnLog "wsl --set-default-version failed. Attempting to detect if 'wsl --update' is supported..."
# Check if 'wsl --update' exists
$hasWSLUpdate = $false
try {
$wslHelp = & wsl --help 2>&1
if ($wslHelp -match '--update') {
$hasWSLUpdate = $true
}
} catch {
Write-ErrorLog "WSL is not available: $_"
return $false
}
if ($hasWSLUpdate) {
try {
Write-InfoLog "Running 'wsl --update'..."
$output = & wsl --update 2>&1
if ($LASTEXITCODE -ne 0) {
Write-WarnLog "wsl --update failed with exit code $LASTEXITCODE.`n$output"
}
Write-InfoLog "WSL updated successfully."
} catch {
Write-ErrorLog "Failed to run 'wsl --update'. Error: $_"
return $false
}
} else {
try {
Write-InfoLog "'wsl --update' not supported. Attempting 'wsl --install --no-distribution'..."
$output = & wsl --install --no-distribution 2>&1
if ($LASTEXITCODE -ne 0) {
Write-WarnLog "wsl --install failed with exit code $LASTEXITCODE.`n$output"
}
Write-InfoLog "WSL installed successfully (no distribution)."
} catch {
Write-ErrorLog "Failed to run 'wsl --install --no-distribution'. Error: $_"
return $false
}
}
}
if ($needsEnable) {
Write-ErrorLog "WSL2 features were just enabled. Please restart your system to complete installation."
if (Test-RebootPending) {
Write-ErrorLog "A system reboot is required to finalize the WSL2 setup."
Exit-Script 2
}
return $false
}
return $true
}
# Check system requirements
function Test-Requirements {
Write-InfoLog "Checking system requirements..."
if ($isWindowsPlat) {
$inHyperV = Test-Path 'HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters'
$inVMware = Test-Path 'HKLM:\SOFTWARE\VMware, Inc.\VMware Tools'
$inVBox = Test-Path 'HKLM:\SOFTWARE\Oracle\VirtualBox Guest Additions'
$insideVM = $inHyperV -or $inVMware -or $inVBox
if ($insideVM) {
$script:ERROR_CODE = 3
Write-WarnLog "Running inside a VM is not recommended. Some features may not work as expected. Ensure nested virtualization is enabled!"
}
}
# Check Docker
if (-not (Get-Command "docker" -ErrorAction SilentlyContinue)) {
if ($isWindowsPlat -and $INSTALL_DOCKER) {
Write-InfoLog "Docker not found..."
Install-Docker
} else {
Write-ErrorLog "Docker is not installed. Please install Docker Desktop for Windows first."
Write-InfoLog "Visit https://docs.docker.com/desktop/windows/install/ for installation instructions"
Exit-Script 1
}
}
# Ensure Docker is running
Write-InfoLog "Ensuring Docker is running..."
& docker info > $null 2>&1
if ($LASTEXITCODE -ne 0) {
if(-not $isWindowsPlat) {
Write-ErrorLog "Docker not running."
Exit-Script 1
}
Write-InfoLog "Docker is not running. Attempting to start Docker Desktop..."
# Try to start Docker Desktop
Start-Process "C:\Program Files\Docker\Docker\Docker Desktop.exe"
# Wait for it to become responsive
$maxAttempts = 60
$attempt = 0
$secondsToWait = 2
while ($attempt -lt $maxAttempts) {
Start-Sleep -Seconds $secondsToWait
& docker info > $null 2>&1
if ($LASTEXITCODE -eq 0) {
Write-InfoLog "Docker is now running."
break
}
$attempt++
$remaining = ($maxAttempts * $secondsToWait) - ($attempt * $secondsToWait)
Write-Host "Waiting for Docker to start... Attempt $($attempt + 1)/$maxAttempts ($remaining seconds left)"
}
if ($LASTEXITCODE -ne 0) {
Write-ErrorLog "Docker failed to start or become ready within timeout ($($maxAttempts * 2) seconds)."
Write-ErrorLog "Try starting Docker Desktop manually and re-run the script/installer."
Exit-Script 1
}
} else {
Write-InfoLog "Docker is already running."
}
if ($isWindowsPlat) {
try {
$kernel = docker info --format '{{.KernelVersion}}' 2>$null
Write-Verbose "KernelVersion='$kernel'"
if ($kernel -match 'microsoft|WSL2')
{
Write-InfoLog "Detected Docker is using WSL2."
} elseif ($kernel -match 'linuxkit') {
$script:ERROR_CODE = 4
Write-WarnLog "Detected Docker is using Hyper-V, please reinstall Docker with WSL2. Hyper-V is not supported. Use at your own risk!"
} else {
$script:ERROR_CODE = 5
Write-WarnLog "Cannot determine if Docker is using WSL2. Please ensure Docker is using WSL2."
}
} catch {
$script:ERROR_CODE = 5
Write-WarnLog "docker info failed. Cannot determine if Docker is using WSL2. Please ensure Docker is using WSL2."
}
}
# Check Docker Compose version (with output suppression)
$composeVersion = @(docker compose version --short 2>$null)[0] -replace '[^0-9.]'
if (-not (Test-VersionGreaterOrEqual $composeVersion $MIN_COMPOSE_VERSION)) {
Write-ErrorLog "Docker Compose version $composeVersion is too old. Please install Docker Compose version $MIN_COMPOSE_VERSION or higher."
Exit-Script 1
}
# Check disk space (1GB = 1073741824 bytes)
$drive = Get-PSDrive -Name (Get-Location).Drive.Name
if ($drive.Free -lt 1GB) {
Write-ErrorLog "Insufficient disk space. Please ensure at least 1GB of free space."
Exit-Script 1
}
# Check network connectivity
try {
$response = Invoke-WebRequest -Uri "https://install.rocketgraph.com" -Method Head -UseBasicParsing
if ($response.StatusCode -ne 200) {
throw "Non-200 status code"
}
}
catch {
Write-ErrorLog "Network connectivity issue. Unable to reach https://install.rocketgraph.com"
Exit-Script 1
}
}
# Function to check Windows requirements
function Test-WindowsRequirements {
Write-InfoLog "Checking Windows requirements..."
# Check Windows version
$osInfo = Get-WmiObject -Class Win32_OperatingSystem
$version = [System.Version]$osInfo.Version
if ($version.Major -lt 10) {
Write-ErrorLog "Windows 10 or higher is required"
Exit-Script 1
}
if ($version.Build -lt 18362) {
Write-ErrorLog "Windows 10 version 1903 or higher is required"
Exit-Script 1
}
}
# Check for port conflicts
function Test-Settings {
Write-InfoLog "Checking settings for issues..."
if (-not (Test-Path $LICENSE_LOCATION) -and ($LICENSE_LOCATION -ne $DEFAULT_LICENSE_LOCATION)) {
Write-ErrorLog "Missing license file at: $LICENSE_LOCATION (custom path)"
Exit-Script 1
}
}
# Create installation directory
function Initialize-InstallationDirectory {
New-Item -ItemType Directory -Path $INSTALL_DIR -Force | Out-Null
Set-Location -Path $INSTALL_DIR
Write-InfoLog "Using installation directory at $INSTALL_DIR..."
}
function Set-EnvVariables {
if ($EXISTING_ENV -eq 1) {
Write-InfoLog "Existing .env file found. Ignoring any new configuration values passed to the script."
Write-InfoLog "To apply new values, edit the .env file manually."
return
}
Write-InfoLog "Setting up .env configuration file..."
$envFile = ".env"
if (Test-Path $envFile) {
$envContent = Get-Content $envFile
if ($envContent -match '^#MC_PORT=' -and $HTTP_PORT -ne $DEFAULT_HTTP_PORT) {
Write-InfoLog "Using non-standard HTTP_PORT=$HTTP_PORT"
$envContent = $envContent -replace "^#MC_PORT=$DEFAULT_HTTP_PORT", "MC_PORT=$HTTP_PORT"
}
if ($envContent -match '^#MC_SSL_PORT=' -and $HTTPS_PORT -ne $DEFAULT_HTTPS_PORT) {
Write-InfoLog "Using non-standard HTTPS_PORT=$HTTPS_PORT"
$envContent = $envContent -replace "^#MC_SSL_PORT=$DEFAULT_HTTPS_PORT", "MC_SSL_PORT=$HTTPS_PORT"
}
if ($envContent -match '^#XGT_PORT=' -and $XGT_PORT -ne $DEFAULT_XGT_PORT) {
Write-InfoLog "Using non-standard XGT_PORT=$XGT_PORT"
$envContent = $envContent -replace "^#XGT_PORT=$DEFAULT_XGT_PORT", "XGT_PORT=$XGT_PORT"
}
if ($envContent -match '^#XGT_LICENSE_FILE=' -and (Test-Path $LICENSE_LOCATION)) {
Write-InfoLog "Custom license file found."
$escapedPath = $LICENSE_LOCATION -replace '\\', '\\\\'
$envContent = $envContent -replace '^#XGT_LICENSE_FILE=.*', "XGT_LICENSE_FILE=`"$escapedPath`""
}
if ($ENTERPRISE_INSTALL) {
Write-InfoLog "Enterprise mode enabled."
$envContent = $envContent -replace '^XGT_AUTH_TYPES=', '#XGT_AUTH_TYPES='
}
if ($envContent -match '^MC_SSL_PUBLIC_CERT=' -and $envContent -match '^MC_SSL_PRIVATE_KEY=') {
$script:USE_SSL = $true
}
$envContent | Set-Content $envFile
} else {
Write-WarnLog ".env file not found."
}
}
# Download configuration files
function Get-ConfigurationFiles {
$downloadUrl = "https://raw.githubusercontent.com/Rocketgraphai/rocketgraph/main"
Write-InfoLog "Downloading configuration files from ${downloadUrl}..."
try {
Invoke-WebRequest "${downloadUrl}/docker-compose.yml" -OutFile "docker-compose.yml"
}
catch {
Write-ErrorLog "Failed to download docker-compose.yml"
Exit-Script 1
}
try {
Invoke-WebRequest "${downloadUrl}/env.template" -OutFile "env.template"
if (Test-Path ".env") {
$script:EXISTING_ENV = $true
$changes = $false
Write-InfoLog "Checking for potentially new keys added to env.template since initial install."
Write-InfoLog "This may help identify missing entries in .env, but some may be false positives."
$existing = Get-Content ".env"
$template = Get-Content "env.template"
foreach ($line in $template) {
if ($line -match '^\s*$|^\s*#') { continue } # Skip empty lines and comments
$key = ($line -split '=')[0]
if (-not ($existing -match "^$key=")) {
Write-WarnLog "Key '$key' is present in env.template but not found in .env. If this key is new, consider adding it:"
Write-WarnLog $line
$changes = $true
}
}
Remove-Item "env.template"
if (-not $changes) {
Write-InfoLog "No new keys were detected."
}
} else {
Write-InfoLog "Creating .env file from env.template."
Move-Item -Path "env.template" -Destination ".env"
}
}
catch {
Write-WarnLog "Failed to download env.template"
}
Set-EnvVariables
}
# Pull and start containers (with output suppression)
function Start-Containers {
Write-InfoLog "Pulling latest container images..."
# Run in foreground so you see streaming logs
docker compose pull
if ($LASTEXITCODE -ne 0) {
Write-ErrorLog "Failed to pull container images."
Exit-Script 1
}
Write-InfoLog "Starting containers..."
docker compose up -d
if ($LASTEXITCODE -ne 0) {
Write-ErrorLog "Failed to start containers."
Exit-Script 1
}
# Extract site-config templates from the running backend container
$containerId = docker ps --filter "ancestor=rocketgraph/mission-control-backend:latest" --format "{{.ID}}" | Select-Object -First 1
if (-not $containerId) {
Write-ErrorLog "Backend container not found for template extraction."
return
}
Write-InfoLog "Attempting to copy site-config templates from container..."
docker cp "${containerId}:/app/templates" "$INSTALL_DIR" 2>$null
if ($LASTEXITCODE -eq 0) {
Write-InfoLog "Site-config templates extracted successfully."
} else {
Write-InfoLog "No site-config templates found in the container or copy failed."
}
}
# Main installation process
function Start-Installation {
Write-InfoLog "Starting installation process..."
if ($isWindowsPlat) {
Test-WindowsRequirements
}
Test-Requirements
Test-Settings
Initialize-InstallationDirectory
Get-ConfigurationFiles
Start-Containers
Write-InfoLog "Installation completed successfully!"
Write-InfoLog "Your application is now running at http://localhost:$HTTP_PORT"
Write-InfoLog "To check the status, run: docker compose ps"
Write-InfoLog "To view logs, run: docker compose logs"
if ($LAUNCH_BROWSER) {
Write-InfoLog "Launching browser..."
$timeout = 30
for ($i = 0; $i -lt $timeout; $i++) {
try {
$tcpClient = New-Object System.Net.Sockets.TcpClient
$tcpClient.Connect("localhost", $HTTP_PORT)
$tcpClient.Close()
break
} catch {
Start-Sleep -Seconds 1
}
}
if ($USE_SSL -eq $true) {
# Start the process on HTTPS
Start-Process "https://localhost:$HTTPS_PORT"
} else {
# Start the process on HTTP
Start-Process "http://localhost:$HTTP_PORT"
}
}
}
try {
# Run main function
Start-Installation
} catch {
Write-ErrorLog "Script error: $_"
exit 1
} finally {
if ($PAUSE_AT_END) {
Read-Host "Press Enter to exit..."
}
}
exit $ERROR_CODE