|
22 | 22 | [string]$Isolation = 'process', # Docker isolation mode (process or hyperv). |
23 | 23 | [string]$Memory = '16g', # Docker memory limit. |
24 | 24 | [int]$Cpus = [Environment]::ProcessorCount, # Docker CPU limit (defaults to host's CPU count). |
| 25 | + [string[]]$Mount, # Additional directories to mount from host (readonly by default, append :w for writable). Supports * and ** glob patterns. |
25 | 26 | [Parameter(ValueFromRemainingArguments)] |
26 | 27 | [string[]]$BuildArgs # Arguments passed to `Build.ps1` within the container (or Claude prompt if -Claude is specified). |
27 | 28 | ) |
@@ -610,6 +611,117 @@ if ($grandparentDir -and (Test-Path $grandparentDir)) |
610 | 611 | } |
611 | 612 | } |
612 | 613 |
|
| 614 | +# Process -Mount parameter for additional directory mounts |
| 615 | +if ($Mount -and $Mount.Count -gt 0) |
| 616 | +{ |
| 617 | + foreach ($mountSpec in $Mount) |
| 618 | + { |
| 619 | + # Check if writable (ends with :w) |
| 620 | + $isWritable = $false |
| 621 | + $pattern = $mountSpec |
| 622 | + if ($mountSpec -match ':w$') |
| 623 | + { |
| 624 | + $isWritable = $true |
| 625 | + $pattern = $mountSpec -replace ':w$', '' |
| 626 | + } |
| 627 | + |
| 628 | + # Trim trailing slashes |
| 629 | + $pattern = $pattern.TrimEnd('\', '/') |
| 630 | + |
| 631 | + $mountOption = if ($isWritable) { "" } else { ":ro" } |
| 632 | + |
| 633 | + # Check if pattern contains glob characters |
| 634 | + if ($pattern -match '\*') |
| 635 | + { |
| 636 | + # Expand glob pattern to match directories only |
| 637 | + # Get the base directory (everything before the first glob) |
| 638 | + $patternParts = $pattern -split '[\\/]' |
| 639 | + $basePathParts = @() |
| 640 | + $globStartIndex = -1 |
| 641 | + |
| 642 | + for ($i = 0; $i -lt $patternParts.Count; $i++) |
| 643 | + { |
| 644 | + if ($patternParts[$i] -match '\*') |
| 645 | + { |
| 646 | + $globStartIndex = $i |
| 647 | + break |
| 648 | + } |
| 649 | + $basePathParts += $patternParts[$i] |
| 650 | + } |
| 651 | + |
| 652 | + if ($basePathParts.Count -gt 0) |
| 653 | + { |
| 654 | + $basePath = $basePathParts -join [System.IO.Path]::DirectorySeparatorChar |
| 655 | + } |
| 656 | + else |
| 657 | + { |
| 658 | + $basePath = "." |
| 659 | + } |
| 660 | + |
| 661 | + if (Test-Path $basePath) |
| 662 | + { |
| 663 | + # Determine if recursive search is needed (pattern contains **) |
| 664 | + $isRecursive = $pattern -match '\*\*' |
| 665 | + |
| 666 | + # Build the glob pattern for the part after the base path |
| 667 | + $globPart = ($patternParts[$globStartIndex..($patternParts.Count - 1)]) -join [System.IO.Path]::DirectorySeparatorChar |
| 668 | + |
| 669 | + # Get matching directories |
| 670 | + $matchingDirs = @() |
| 671 | + if ($isRecursive) |
| 672 | + { |
| 673 | + # For ** patterns, recurse and convert ** to * for -like matching |
| 674 | + # Replace ** with a regex-friendly pattern for matching |
| 675 | + $likePattern = $pattern -replace '\*\*', '*' |
| 676 | + $matchingDirs = Get-ChildItem -Path $basePath -Directory -Recurse -ErrorAction SilentlyContinue | |
| 677 | + Where-Object { $_.FullName -like $likePattern } |
| 678 | + } |
| 679 | + else |
| 680 | + { |
| 681 | + # For single * patterns, use direct matching without recursion |
| 682 | + $matchingDirs = Get-ChildItem -Path $basePath -Directory -ErrorAction SilentlyContinue | |
| 683 | + Where-Object { $_.FullName -like $pattern } |
| 684 | + } |
| 685 | + |
| 686 | + if ($matchingDirs.Count -eq 0) |
| 687 | + { |
| 688 | + Write-Host "Warning: No directories matched pattern '$pattern'" -ForegroundColor Yellow |
| 689 | + } |
| 690 | + else |
| 691 | + { |
| 692 | + foreach ($dir in $matchingDirs) |
| 693 | + { |
| 694 | + $dirPath = $dir.FullName |
| 695 | + $rwStatus = if ($isWritable) { "writable" } else { "readonly" } |
| 696 | + Write-Host "Mounting from -Mount pattern '$pattern': $dirPath ($rwStatus)" -ForegroundColor Cyan |
| 697 | + $VolumeMappings += "${dirPath}:${dirPath}${mountOption}" |
| 698 | + $MountPoints += $dirPath |
| 699 | + } |
| 700 | + } |
| 701 | + } |
| 702 | + else |
| 703 | + { |
| 704 | + Write-Host "Warning: Base path '$basePath' for pattern '$pattern' does not exist" -ForegroundColor Yellow |
| 705 | + } |
| 706 | + } |
| 707 | + else |
| 708 | + { |
| 709 | + # No glob - mount directly if it's a directory |
| 710 | + if (Test-Path $pattern -PathType Container) |
| 711 | + { |
| 712 | + $rwStatus = if ($isWritable) { "writable" } else { "readonly" } |
| 713 | + Write-Host "Mounting from -Mount: $pattern ($rwStatus)" -ForegroundColor Cyan |
| 714 | + $VolumeMappings += "${pattern}:${pattern}${mountOption}" |
| 715 | + $MountPoints += $pattern |
| 716 | + } |
| 717 | + else |
| 718 | + { |
| 719 | + Write-Host "Warning: Mount path '$pattern' does not exist or is not a directory" -ForegroundColor Yellow |
| 720 | + } |
| 721 | + } |
| 722 | + } |
| 723 | +} |
| 724 | + |
613 | 725 | # Execute auto-generated DockerMounts.g.ps1 script to add more directory mounts. |
614 | 726 | $dockerMountsScript = Join-Path $EngPath 'DockerMounts.g.ps1' |
615 | 727 | if (Test-Path $dockerMountsScript) |
@@ -1094,7 +1206,7 @@ if (-not $BuildImage) |
1094 | 1206 | { |
1095 | 1207 | # Run standard build mode |
1096 | 1208 | # Delete now and not in the container because it's much faster and lock error messages are more relevant. |
1097 | | - Write-Host "Building the product in the container." -ForegroundColor Green |
| 1209 | + Write-Host "Running the script in the container." -ForegroundColor Green |
1098 | 1210 |
|
1099 | 1211 | # Prepare Build.ps1 arguments |
1100 | 1212 | if ($StartVsmon) |
|
0 commit comments