-
Notifications
You must be signed in to change notification settings - Fork 325
Fix dev containers to work with worktrees #4137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
mdaigle
wants to merge
5
commits into
dev/mdaigle/pwsh-via-dotnet-tool
Choose a base branch
from
dev/mdaigle/dev-containers
base: dev/mdaigle/pwsh-via-dotnet-tool
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| #!/usr/bin/env pwsh | ||
| #Requires -Version 7.0 | ||
| Set-StrictMode -Version Latest | ||
| $ErrorActionPreference = 'Stop' | ||
|
|
||
| # ============================================================================= | ||
| # Cross-platform devcontainer initialization script. | ||
| # Runs on the HOST before the container starts. Detects worktree/project | ||
| # context and generates the .env file consumed by docker-compose.yml. | ||
| # | ||
| # Git worktree support: | ||
| # The .git file in a worktree contains an absolute host path. On Windows | ||
| # hosts this is a drive-letter path (C:/...) that Linux git cannot resolve. | ||
| # We maintain two path variants: | ||
| # - Host path: raw OS path used on the source side of bind mounts | ||
| # - Container path: POSIX path (/c/... on Windows) used inside the container | ||
| # A generated docker-compose.worktree.yml bind-mounts the main .git directory | ||
| # and overlays a corrected .git file so git works inside the container. | ||
| # | ||
| # Invoked via: dotnet tool run pwsh -- -NoProfile -ExecutionPolicy Bypass -File .devcontainer/init.ps1 | ||
| # ============================================================================= | ||
|
|
||
| $devcontainerDir = $PSScriptRoot # .devcontainer/ | ||
|
|
||
| # --- Worktree and project detection --- | ||
|
|
||
| $worktreeDirName = Split-Path -Leaf (Get-Location) | ||
|
|
||
| # Sanitize worktree name for use in DB names, container names, etc. | ||
| $worktreeName = ($worktreeDirName -replace '[^a-zA-Z0-9-]', '_').ToLowerInvariant() | ||
|
|
||
| # Detect the current branch name. | ||
| $branchName = (git branch --show-current 2>$null) ?? '' | ||
| $branchName = ($branchName -replace '/', '-' -replace '[^a-zA-Z0-9-]', '_').ToLowerInvariant() | ||
|
|
||
| # Resolve the git common directory (the main .git directory). | ||
| # In a worktree this points to the main repo's .git; in a standard clone it's just .git. | ||
| $gitCommonDir = git rev-parse --git-common-dir 2>$null | ||
| if (-not [System.IO.Path]::IsPathRooted($gitCommonDir)) { | ||
| $gitCommonDir = Join-Path (Get-Location) $gitCommonDir | ||
| } | ||
| $gitCommonDir = (Resolve-Path $gitCommonDir).Path | ||
|
|
||
| # Host path: use forward slashes (Docker Desktop accepts both separators). | ||
| $gitCommonDirHost = $gitCommonDir -replace '\\', '/' | ||
|
|
||
| # Container path: on Windows convert drive-letter paths ("C:/foo") to POSIX | ||
| # ("/c/foo") so they resolve inside the Linux container. | ||
| $gitCommonDirContainer = $gitCommonDirHost | ||
| if ($gitCommonDirContainer -match '^([A-Za-z]):(.*)$') { | ||
| $gitCommonDirContainer = '/' + $Matches[1].ToLowerInvariant() + $Matches[2] | ||
| } | ||
|
|
||
| $mainRepoName = Split-Path -Leaf (Split-Path -Parent $gitCommonDirHost) | ||
| $projectName = $env:PROJECT_NAME ?? $mainRepoName | ||
|
|
||
| $composeProjectName = "$projectName-$branchName" | ||
| $localWorkspaceFolder = (Get-Location).Path | ||
|
|
||
| # Detect if this is a worktree (informational). | ||
| $dotGitPath = Join-Path (Get-Location) '.git' | ||
| if (Test-Path $dotGitPath -PathType Leaf) { | ||
| Write-Host "[devcontainer] Worktree detected. GIT_COMMON_DIR='$gitCommonDirHost' (container: '$gitCommonDirContainer')" | ||
| } else { | ||
| Write-Host "[devcontainer] Standard clone. GIT_COMMON_DIR='$gitCommonDirHost'" | ||
| } | ||
|
|
||
| # --- Git worktree container fixup --- | ||
| # In a git worktree the .git *file* contains an absolute host path. | ||
| # Two problems must be solved for the Linux container: | ||
| # 1. On Windows hosts the path uses a drive letter (C:/...) that Linux git | ||
| # cannot resolve — rewrite it to the container-side POSIX path. | ||
| # 2. The main .git directory lives outside the workspace mount and must be | ||
| # bind-mounted into the container at the container-side path. | ||
| # | ||
| # We generate: | ||
| # .git-overlay – corrected .git file referencing container paths | ||
| # docker-compose.worktree.yml – bind-mounts the main .git dir + the overlay | ||
| # | ||
| # Long-form volume syntax is used for the GIT_COMMON_DIR mount so Docker does | ||
| # not try to split the path on colons (which breaks Windows drive letters). | ||
| # | ||
| # For standard (non-worktree) clones both files are no-op stubs. | ||
|
|
||
| $worktreeComposePath = Join-Path $devcontainerDir 'docker-compose.worktree.yml' | ||
| $gitOverlayPath = Join-Path $devcontainerDir '.git-overlay' | ||
|
|
||
| if (Test-Path $dotGitPath -PathType Leaf) { | ||
| # Worktree: .git is a file — read it and rewrite with container-side paths. | ||
| $gitFileContent = (Get-Content $dotGitPath -Raw).Trim() | ||
| if ($gitFileContent -match 'gitdir:\s*(.+)') { | ||
| $originalGitdir = $Matches[1].Trim() -replace '\\', '/' | ||
| # Convert Windows drive-letter path to POSIX for the container. | ||
| $containerGitdir = $originalGitdir | ||
| if ($containerGitdir -match '^([A-Za-z]):(.*)$') { | ||
| $containerGitdir = '/' + $Matches[1].ToLowerInvariant() + $Matches[2] | ||
| } | ||
| Set-Content -Path $gitOverlayPath -Value "gitdir: $containerGitdir`n" -NoNewline | ||
|
|
||
| # Generate compose override. Long-form volume for the GIT_COMMON_DIR | ||
| # mount avoids colon-parsing issues with Windows paths. | ||
| $worktreeComposeContent = @" | ||
| # Auto-generated by init.ps1 - DO NOT EDIT. | ||
| # Bind-mounts the main .git directory and overlays a corrected .git file | ||
| # so that git works inside the container for worktree checkouts. | ||
| services: | ||
| devcontainer: | ||
| volumes: | ||
| - type: bind | ||
| source: $gitCommonDirHost | ||
| target: $gitCommonDirContainer | ||
| - ./.git-overlay:/workspaces/SqlClient/.git:ro | ||
| "@ | ||
| Set-Content -Path $worktreeComposePath -Value $worktreeComposeContent -NoNewline | ||
| Write-Host "[devcontainer] Generated git worktree overlay for container." | ||
| } else { | ||
| Write-Host "[devcontainer] WARNING: Could not parse .git file at '$dotGitPath'." | ||
| Set-Content -Path $worktreeComposePath -Value "# Auto-generated by init.ps1 - could not parse .git file.`nservices: {}" -NoNewline | ||
| if (Test-Path $gitOverlayPath) { Remove-Item $gitOverlayPath } | ||
| } | ||
| } else { | ||
| # Standard clone: .git is a directory, already covered by the workspace mount. | ||
| Set-Content -Path $worktreeComposePath -Value "# Auto-generated by init.ps1 - standard clone, no worktree fixup needed.`nservices: {}" -NoNewline | ||
| if (Test-Path $gitOverlayPath) { Remove-Item $gitOverlayPath } | ||
| } | ||
|
|
||
| # --- Local compose overrides --- | ||
| # docker-compose.local.yml is listed in devcontainer.json so it must exist. | ||
| # Create an empty stub if missing (gitignored — developers can add personal overrides). | ||
|
|
||
| $localComposePath = Join-Path $devcontainerDir 'docker-compose.local.yml' | ||
| if (-not (Test-Path $localComposePath)) { | ||
| Set-Content -Path $localComposePath -Value "# Personal Docker Compose overrides (gitignored).`n# See docker-compose.yml for the base configuration.`n" | ||
| } | ||
|
|
||
| # --- Write .env for docker-compose variable substitution --- | ||
|
|
||
| $envContent = @" | ||
| COMPOSE_PROJECT_NAME=$composeProjectName | ||
| WORKTREE_NAME=$worktreeName | ||
| BRANCH_NAME=$branchName | ||
| GIT_COMMON_DIR_HOST=$gitCommonDirHost | ||
| GIT_COMMON_DIR_CONTAINER=$gitCommonDirContainer | ||
| MAIN_REPO_NAME=$mainRepoName | ||
| PROJECT_NAME=$projectName | ||
| LOCAL_WORKSPACE_FOLDER=$localWorkspaceFolder | ||
| "@ | ||
| Set-Content -Path (Join-Path $devcontainerDir '.env') -Value $envContent -NoNewline | ||
|
|
||
| Write-Host "[devcontainer] init.ps1 complete for worktree '$worktreeName' branch '$branchName' (project: $projectName)" |
Empty file.
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDbConnectionPool.TryGetConnection now allows a nullable TaskCompletionSource and nullable out connection. At least WaitHandleDbConnectionPool still uses non-nullable annotations and assigns null in its implementation, which will trigger nullability-mismatch warnings (and the repo treats warnings as errors) and break the build. Update all IDbConnectionPool implementers to match this contract (parameter and out nullability).