[CmdletBinding(SupportsShouldProcess)]param( [ArgumentCompleter({ param ( $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters ) [DockerComposeDirs]::_GetValidValues($wordToComplete,$true) })] [string[]]$ProjectPath=@($PWD), [switch]$Recurse, [int]$Depth=1, [switch]$Force, [switch]$OneLine, [Parameter(Position = 0, ValueFromRemainingArguments = $true, mandatory)] [array]$CliParams ) $script:JobQueue = @() $script:CleanupJobQueue = @() function CompleteJobs { if( -not $JobQueue ) { return } $local:currentJobQueue = $JobQueue $JobQueue = @() $CleanupJobQueue += $currentJobQueue.Job $local:sw = [System.Diagnostics.StopWatch]::StartNew() $local:progress = [ordered]@{ Activity = "Waiting for docker-compose..." ItemCount = $currentJobQueue.Count } while( $true ) { $local:activeJobs = $($currentJobQueue | Where-Object Done -eq $false) $progress.CurrentOperation = "Processing: $($activeJobs.Name -join ', ')..." $progress.ItemProgress = $currentJobQueue.Count - $activeJobs.Count $progress.Elapsed = $sw.Elapsed Show-Progress @progress $local:doneJobs = $activeJobs | Select-Object -ExpandProperty Job | Wait-Job -Any -Timeout 3 if( $doneJobs ) { $doneJobs | ForEach-Object { $_ | Receive-Job | ForEach-Object { Write-Host "---: $($_.Path) | $($_.Params)" -ForegroundColor Cyan $_.Results foreach( $local:j in $currentJobQueue ) { if( $j.Path -eq $_.Path ) { $j.Done = $true } } } } } if( -not $($currentJobQueue.Done -contains $false) ) { break } } Write-Host '--- Background jobs completed' -ForegroundColor Green Show-Progress -Activity $progress.Activity -Completed } if( $CliParams[0] -is [string] ) { $CliParams = @($CliParams,@($null)) } $local:ext = ".yml" $local:dcPathList = @() $ProjectPath | ForEach-Object { while( $true ) { if( (Test-Path (Join-Path $_ "docker-compose$ext")) -and -not $Recurse ) { $dcPathList += Resolve-Path $_ } elseif( $Recurse ) { $local:gciParams = [ordered]@{ Recurse = $true } if( $Depth ) { $gciParams.Depth = $Depth } $dcPathList += Get-ChildItem -Path $_ -Include "docker-compose$ext" @gciParams | Select-Object -ExpandProperty Directory | Where-Object { $Force -or -not (Test-Path $(Join-Path $_ .noauto.all)) } } if( ($dcPathList -and -not $Recure) -or $ext -eq '.yaml' ) { break } $ext = '.yaml' } } if( -not $dcPathList ) { return } $local:SingleProject = $dcPathList.Length -eq 1 foreach( $local:p in $CliParams ) { if( -not $p ) { continue } $local:AsJob = $false; $local:Wait = $false; if( $p -isnot [String] -or $p.Length -eq 1 ) { $local:skipFirst = $true switch( $p[0] ) { '&' { $AsJob = -not $SingleProject } '!' { $Wait = -not $SingleProject } default { $skipFirst = $false } } if( $skipFirst ) { $p = $p | Select-Object -Skip 1 } } $local:dcParams=@() $local:dcParams = $p | Where-Object { $_ } | ForEach-Object { if( $_ -match "(?:^'[^']+'$)|(?:^`"[^`"]+`"$)|(?:^[^\s]+$)" ) { $_ } else { "'$($_.Replace( "'", "''" ))'" } } $dcPathList | ForEach-Object { $local:dcPath = Join-Path $_ 'docker-compose.yaml' if( -not (Test-Path $dcPath) ) { $dcPath = Join-Path $_ 'docker-compose.yml' } if( -not (Test-Path $dcPath) ) { if( $Recurse ) { return } else { throw "ERROR: dcPath ($dcPath) does not exists" } } if( $Wait ) { if( $WhatIfPreference ) { Write-Host -ForegroundColor DarkCyan "Wait for bg jobs to complete !" } else { CompleteJobs } } if( -not $dcParams ) { continue } $local:nextActionDescription = "In $dcPath Run $(if($AsJob){"(bg) "})with: $dcParams" if( $WhatIfPreference ) { Write-Host -ForegroundColor DarkYellow $nextActionDescription } else { Write-Verbose $nextActionDescription if( $AsJob ) { $JobQueue += ([PSCustomObject]([ordered]@{ Path = $dcPath Name = Split-Path -Leaf $(Split-Path -Parent $dcPath) Job = Start-Job -ArgumentList @($dcPath,$dcParams) -ScriptBlock { param($dcPath,$dcParams) [PSCustomObject] $([ordered]@{ Path = $dcPath Params = $dcParams Results = $(& docker-compose --file $dcPath $dcParams) })} Done = $false })) } else { & docker-compose --file $dcPath $dcParams } } } } # if( $WhatIfPreference ) { return } CompleteJobs if( $CleanupJobQueue ) { $CleanupJobQueue | Remove-Job }