| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- <#
- .SYNOPSIS
- BamBuddy Docker installation script for Windows (Docker Desktop).
- .DESCRIPTION
- Mirrors install/docker-install.sh for Windows. Verifies Docker Desktop is
- installed and running, downloads docker-compose.yml, rewrites it for
- Docker Desktop (no host networking), writes a .env, and starts the
- container.
- .PARAMETER InstallPath
- Installation directory. Default: $env:USERPROFILE\bambuddy
- .PARAMETER Port
- Port to expose. Default: 8000
- .PARAMETER TimeZone
- IANA timezone string (e.g. Europe/Berlin). Default: derived from
- Get-TimeZone or UTC.
- .PARAMETER Build
- Build the image from source instead of pulling the pre-built image.
- .PARAMETER Yes
- Non-interactive mode; accept defaults.
- .EXAMPLE
- Interactive install (cmd or PowerShell):
- powershell -ExecutionPolicy Bypass -Command "iwr -useb https://raw.githubusercontent.com/maziggy/bambuddy/main/install/docker-install.ps1 -OutFile docker-install.ps1; .\docker-install.ps1"
- .EXAMPLE
- Unattended install:
- .\docker-install.ps1 -InstallPath C:\bambuddy -Port 8080 -TimeZone Europe/Berlin -Yes
- #>
- [CmdletBinding()]
- param(
- [string]$InstallPath,
- [int]$Port,
- [string]$TimeZone,
- [switch]$Build,
- [switch]$Yes,
- [switch]$Help
- )
- $ErrorActionPreference = 'Stop'
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- # --- Helpers --------------------------------------------------------------
- function Write-Banner {
- Write-Host ''
- Write-Host '==========================================================' -ForegroundColor Cyan
- Write-Host ' Bambuddy - Docker Installation (Windows)' -ForegroundColor Cyan
- Write-Host '==========================================================' -ForegroundColor Cyan
- Write-Host ''
- }
- function Info { param($m) Write-Host "[INFO] $m" -ForegroundColor Blue }
- function Ok { param($m) Write-Host "[OK] $m" -ForegroundColor Green }
- function Warn { param($m) Write-Host "[WARN] $m" -ForegroundColor Yellow }
- function Fail { param($m) Write-Host "[ERR] $m" -ForegroundColor Red }
- function Read-Default {
- param([string]$Prompt, [string]$Default)
- if ($Yes) { return $Default }
- $val = Read-Host "$Prompt [$Default]"
- if ([string]::IsNullOrWhiteSpace($val)) { return $Default }
- return $val
- }
- function Read-YesNo {
- param([string]$Prompt, [string]$Default = 'y')
- if ($Yes) { return ($Default -eq 'y') }
- $hint = if ($Default -eq 'y') { '[Y/n]' } else { '[y/N]' }
- while ($true) {
- $val = Read-Host "$Prompt $hint"
- if ([string]::IsNullOrWhiteSpace($val)) { $val = $Default }
- switch -Regex ($val.Trim().ToLower()) {
- '^(y|yes)$' { return $true }
- '^(n|no)$' { return $false }
- default { Write-Host 'Please answer yes or no.' }
- }
- }
- }
- function Show-Help {
- Get-Help $PSCommandPath -Full
- exit 0
- }
- # --- Detection ------------------------------------------------------------
- function Test-Docker {
- if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
- Fail 'Docker is not installed.'
- Write-Host ''
- Write-Host ' Install Docker Desktop for Windows:' -ForegroundColor Yellow
- Write-Host ' https://www.docker.com/products/docker-desktop' -ForegroundColor Cyan
- Write-Host ''
- Write-Host ' After install, launch Docker Desktop and re-run this script.' -ForegroundColor Yellow
- exit 1
- }
- Info 'Docker found, checking daemon...'
- try {
- docker info --format '{{.ServerVersion}}' *> $null
- if ($LASTEXITCODE -ne 0) { throw 'docker info failed' }
- } catch {
- Fail 'Docker daemon is not reachable. Is Docker Desktop running?'
- Write-Host ''
- Write-Host ' Open Docker Desktop, wait for the whale icon to settle,' -ForegroundColor Yellow
- Write-Host ' then re-run this script.' -ForegroundColor Yellow
- exit 1
- }
- Ok 'Docker daemon is running'
- docker compose version *> $null
- if ($LASTEXITCODE -eq 0) {
- $script:DockerCompose = 'docker compose'
- Ok 'Found Docker Compose v2'
- } elseif (Get-Command docker-compose -ErrorAction SilentlyContinue) {
- $script:DockerCompose = 'docker-compose'
- Ok 'Found Docker Compose v1'
- } else {
- Fail 'Docker Compose not found. Install Docker Desktop 4.x+ (ships compose v2).'
- exit 1
- }
- }
- function Get-DefaultTimeZone {
- if ($TimeZone) { return $TimeZone }
- try {
- $tz = (Get-TimeZone).Id
- # Get-TimeZone returns Windows IDs ("W. Europe Standard Time"). Docker
- # expects IANA. Fall back to UTC if we can't translate.
- $iana = ConvertTo-IanaTimeZone $tz
- if ($iana) { return $iana }
- } catch {}
- return 'UTC'
- }
- function ConvertTo-IanaTimeZone {
- param([string]$WindowsId)
- # Minimal mapping of common Windows IDs to IANA. Users can override via -TimeZone.
- $map = @{
- 'UTC' = 'UTC'
- 'GMT Standard Time' = 'Europe/London'
- 'W. Europe Standard Time' = 'Europe/Berlin'
- 'Central European Standard Time' = 'Europe/Warsaw'
- 'Romance Standard Time' = 'Europe/Paris'
- 'Russian Standard Time' = 'Europe/Moscow'
- 'Eastern Standard Time' = 'America/New_York'
- 'Central Standard Time' = 'America/Chicago'
- 'Mountain Standard Time' = 'America/Denver'
- 'Pacific Standard Time' = 'America/Los_Angeles'
- 'AUS Eastern Standard Time' = 'Australia/Sydney'
- 'Tokyo Standard Time' = 'Asia/Tokyo'
- 'China Standard Time' = 'Asia/Shanghai'
- 'India Standard Time' = 'Asia/Kolkata'
- }
- return $map[$WindowsId]
- }
- function Get-LanIp {
- try {
- $ip = Get-NetIPAddress -AddressFamily IPv4 -ErrorAction Stop |
- Where-Object {
- $_.IPAddress -notmatch '^(127\.|169\.254\.)' -and
- $_.PrefixOrigin -ne 'WellKnown' -and
- $_.InterfaceAlias -notmatch '^(vEthernet|Loopback)'
- } | Select-Object -First 1
- if ($ip) { return $ip.IPAddress }
- } catch {}
- return '<your-ip>'
- }
- # --- Steps ----------------------------------------------------------------
- function Initialize-InstallDir {
- Info "Creating installation directory: $InstallPath"
- if (-not (Test-Path $InstallPath)) {
- New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null
- }
- Set-Location $InstallPath
- Ok "Directory ready: $InstallPath"
- }
- function Get-ComposeFile {
- Info 'Downloading docker-compose.yml...'
- if ($Build) {
- if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
- Fail 'git is required for --Build but was not found. Install Git for Windows: https://git-scm.com/download/win'
- exit 1
- }
- if (Test-Path '.git') {
- Info 'Existing repository found, updating...'
- git fetch origin
- git reset --hard origin/main
- } else {
- git clone https://github.com/maziggy/bambuddy.git .
- }
- } else {
- Invoke-WebRequest `
- -Uri 'https://raw.githubusercontent.com/maziggy/bambuddy/main/docker-compose.yml' `
- -OutFile 'docker-compose.yml' `
- -UseBasicParsing
- }
- Ok 'docker-compose.yml ready'
- }
- function Write-EnvFile {
- Info 'Writing .env...'
- $envBody = @"
- # BamBuddy Docker Configuration
- # Generated by docker-install.ps1 on $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
- PORT=$Port
- TZ=$TimeZone
- "@
- [System.IO.File]::WriteAllText((Join-Path $InstallPath '.env'), $envBody)
- Ok '.env written'
- }
- function Update-ComposeForDockerDesktop {
- # Docker Desktop on Windows does not support network_mode: host. Comment
- # it out and uncomment the port mappings. Mirrors what the bash script
- # does on macOS via sed.
- $path = Join-Path $InstallPath 'docker-compose.yml'
- Info 'Rewriting compose for Docker Desktop (no host networking)...'
- $content = [System.IO.File]::ReadAllText($path)
- Copy-Item $path "$path.bak" -Force
- $content = $content -replace '(?m)^(\s*)network_mode: host', '#$1network_mode: host'
- $content = $content -replace '(?m)^(\s*)#ports:', '$1ports:'
- $content = $content -replace '(?m)^(\s*)#(\s*)- "\$\{PORT:-8000\}:8000"', '$1$2- "$${PORT:-8000}:8000"'
- [System.IO.File]::WriteAllText($path, $content)
- Warn 'Printer auto-discovery (SSDP) does NOT work on Docker Desktop. Add printers manually by IP.'
- Warn 'Virtual Printer ports (322, 990, 2024-2026, 3000/3002, 6000, 8883, 50000-50100) stay commented out.'
- Warn 'If you plan to use a Virtual Printer, edit docker-compose.yml and uncomment the relevant `- "PORT:PORT"` lines under `ports:`.'
- }
- function Start-Bambuddy {
- Info 'Starting Bambuddy container...'
- if ($Build) {
- & cmd /c "$DockerCompose up -d --build"
- } else {
- & cmd /c "$DockerCompose up -d"
- }
- if ($LASTEXITCODE -ne 0) {
- Fail 'Container start failed. Inspect logs with:'
- Write-Host " cd $InstallPath" -ForegroundColor Yellow
- Write-Host " $DockerCompose logs bambuddy" -ForegroundColor Yellow
- exit 1
- }
- Info 'Waiting for container to be Up...'
- $attempts = 0
- while ($attempts -lt 15) {
- Start-Sleep -Seconds 2
- $ps = & cmd /c "$DockerCompose ps" 2>&1
- if ($ps -match 'Up') { Ok 'Bambuddy container is running'; return }
- if ($ps -match 'Exited') {
- Fail 'Container exited unexpectedly.'
- Write-Host " $DockerCompose logs bambuddy" -ForegroundColor Yellow
- exit 1
- }
- $attempts++
- }
- Warn "Container may still be starting. Check with: $DockerCompose ps"
- }
- # --- Main -----------------------------------------------------------------
- if ($Help) { Show-Help }
- Write-Banner
- Info 'Detecting environment...'
- Test-Docker
- # Defaults
- if (-not $InstallPath) { $InstallPath = Read-Default 'Installation directory' (Join-Path $env:USERPROFILE 'bambuddy') }
- if (-not $Port) { $Port = [int](Read-Default 'Port to expose' '8000') }
- if (-not $TimeZone) {
- $detected = Get-DefaultTimeZone
- $TimeZone = Read-Default 'Timezone (IANA)' $detected
- }
- if (-not $Build -and -not $Yes) {
- if (Read-YesNo 'Build from source? (No = use pre-built image)' 'n') { $Build = $true }
- }
- Write-Host ''
- Write-Host 'Installation Summary' -ForegroundColor Cyan
- Write-Host '-----------------------------------------'
- Write-Host " Install path: $InstallPath"
- Write-Host " Port: $Port"
- Write-Host " Timezone: $TimeZone"
- Write-Host " Build source: $Build"
- Write-Host ''
- if (-not (Read-YesNo 'Proceed with installation?' 'y')) {
- Write-Host 'Cancelled.' -ForegroundColor Yellow
- exit 0
- }
- Initialize-InstallDir
- Get-ComposeFile
- Write-EnvFile
- Update-ComposeForDockerDesktop
- Start-Bambuddy
- $lanIp = Get-LanIp
- Write-Host ''
- Write-Host '==========================================================' -ForegroundColor Green
- Write-Host ' Installation Complete!' -ForegroundColor Green
- Write-Host '==========================================================' -ForegroundColor Green
- Write-Host ''
- Write-Host " Access Bambuddy: http://localhost:$Port" -ForegroundColor Cyan
- Write-Host " http://${lanIp}:$Port (from other devices)" -ForegroundColor Cyan
- Write-Host ''
- Write-Host ' Manage container:'
- Write-Host " Status: cd `"$InstallPath`"; $DockerCompose ps"
- Write-Host " Logs: cd `"$InstallPath`"; $DockerCompose logs -f bambuddy"
- Write-Host " Stop: cd `"$InstallPath`"; $DockerCompose down"
- Write-Host " Start: cd `"$InstallPath`"; $DockerCompose up -d"
- Write-Host " Restart: cd `"$InstallPath`"; $DockerCompose restart"
- Write-Host ''
- Write-Host ' Update Bambuddy:'
- if ($Build) {
- Write-Host " cd `"$InstallPath`"; git pull; $DockerCompose up -d --build"
- } else {
- Write-Host " cd `"$InstallPath`"; $DockerCompose pull; $DockerCompose up -d"
- }
- Write-Host ''
- Write-Host ' Documentation: https://wiki.bambuddy.cool' -ForegroundColor Cyan
- Write-Host ''
- Write-Host ' Note: Printer discovery is unavailable on Docker Desktop.' -ForegroundColor Yellow
- Write-Host ' Add your printers manually by IP address in the UI.' -ForegroundColor Yellow
- Write-Host ''
|