From cc6c7badc0d8a4b0d0b6e297d283d0b4471dc866 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sat, 2 Jan 2021 21:00:25 +0300 Subject: add an option to get rid of symlinks in /bin --- .github/workflows/test.yml | 37 ++++++++++++++++++++++------- action.yml | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4cb74e7..5866f16 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,19 +13,20 @@ jobs: strategy: fail-fast: false matrix: - os: [windows-2019] platform: [x86, x64] env: ['', 'winsymlinks:nativestrict'] + hardlinks: [0, 1] include: - - {os: windows-2019, name: 'Windows 2019'} + - {env: '', env_descr: 'nativestrict: 0'} + - {env: 'winsymlinks:nativestrict', env_descr: 'nativestrict: 1'} - - {env: '', env_descr: 'Empty %CYGWIN%'} - - {env: 'winsymlinks:nativestrict', env_descr: 'Custom %CYGWIN%'} + - {hardlinks: 0, hardlinks_descr: 'Hardlinks: 0'} + - {hardlinks: 1, hardlinks_descr: 'Hardlinks: 1'} - runs-on: '${{ matrix.os }}' + runs-on: windows-2019 - name: '${{ matrix.name }} / ${{ matrix.platform }} / ${{ matrix.env_descr }}' + name: '${{ matrix.platform }} / ${{ matrix.env_descr }} / ${{ matrix.hardlinks_descr }}' defaults: run: @@ -35,25 +36,43 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: Clean up PATH + uses: egor-tensin/cleanup-path@v1 + if: runner.os == 'Windows' + - name: Set up Cygwin id: setup uses: ./ with: platform: '${{ matrix.platform }}' install-dir: C:\cg - packages: cmake gcc + packages: cmake gcc python3 env: '${{ matrix.env }}' + symlinks-to-hardlinks: '${{ matrix.hardlinks }}' - name: Run bash run: | - $output = C:\cg\bin\bash.exe --login -c 'echo foobar' + $((Get-Command bash.exe).Path -eq 'C:\cg\bin\bash.exe') -or $(throw (Get-Command bash.exe)) + $output = bash.exe --login -c 'echo foobar' $($output -eq 'foobar') -or $(throw $output) - name: Run cmake run: | - C:\cg\bin\cmake.exe --version + $((Get-Command cmake.exe).Path -eq 'C:\cg\bin\cmake.exe') -or $(throw (Get-Command cmake.exe)) + cmake.exe --version - name: Check CYGWIN environment variable run: | $(Test-Path env:CYGWIN) -or $(throw '%CYGWIN% is not set!') $($env:CYGWIN -eq '${{ matrix.env }}') -or $(throw "Unexpected %CYGWIN% value: $env:CYGWIN") + + - name: python3 is a symlink + run: | + $(Get-Command python3.exe -ErrorAction SilentlyContinue) -and $(throw (Get-Command python3.exe)) + if: '!matrix.hardlinks' + + - name: python3 is a hardlink + run: | + $((Get-Command python3.exe).Path -eq 'C:\cg\bin\python3.exe') -or $(throw (Get-Command python3.exe)) + python3.exe --version + if: matrix.hardlinks diff --git a/action.yml b/action.yml index 9de9583..62d021a 100644 --- a/action.yml +++ b/action.yml @@ -16,6 +16,10 @@ inputs: env: description: Value to set as the CYGWIN environment variable required: false + symlinks-to-hardlinks: + description: Convert symlinks in /usr/bin to hardlinks + required: false + default: 0 runs: using: composite @@ -28,6 +32,14 @@ runs: New-Variable x64 -Value ('${{ inputs.platform }}' -eq 'x64') -Option Constant New-Variable install_dir -Value '${{ inputs.install-dir }}' -Option Constant New-Variable packages -Value '${{ inputs.packages }}' -Option Constant + New-Variable symlinks_to_hardlinks -Value ('${{ inputs.symlinks-to-hardlinks }}' -eq '1') -Option Constant + + New-Variable bin_dir -Value (Join-Path $install_dir bin) -Option Constant + New-Variable realpath -Value (Join-Path $bin_dir realpath.exe) -Option Constant + New-Variable readlink -Value (Join-Path $bin_dir readlink.exe) -Option Constant + New-Variable dirname -Value (Join-Path $bin_dir dirname.exe) -Option Constant + New-Variable cygpath -Value (Join-Path $bin_dir cygpath.exe) -Option Constant + New-Variable find -Value (Join-Path $bin_dir find.exe) -Option Constant function Locate-Choco { $path = Get-Command 'choco' -ErrorAction SilentlyContinue @@ -38,6 +50,48 @@ runs: } } + function Convert-CygwinPath { + # Like cygpath -wa, but don't resolve symlinks. + param( + [Parameter(Mandatory=$true)] + [string] $Path + ) + + $realpath = & $script:realpath --no-symlinks -- $Path + $dirname = & $script:dirname -- $realpath + $dirname = & $script:cygpath -wa $dirname + Join-Path $dirname (Split-Path $realpath -Leaf) + } + + function Fix-CygwinLink { + # Replace a Cygwin symlink with a hardlink. + param( + [Parameter(Mandatory=$true)] + [string] $Path + ) + + $link_path = $Path + $link_winpath = Convert-CygwinPath $link_path + $link_ext = [System.IO.Path]::GetExtension($link_path) + + $dest_path = & $script:readlink --canonicalize-existing -- $link_path + $dest_winpath = Convert-CygwinPath $dest_path + $dest_ext = [System.IO.Path]::GetExtension($dest_path) + + echo "Removing symlink: $link_winpath" + Remove-Item $link_winpath -Force + + # If target is an executable (i.e. its name contains one of the + # PATHEXT extensions), make sure the hardlink has the same + # extension. + $exe_exts = $env:PATHEXT.ToLower().Split(';', [System.StringSplitOptions]::RemoveEmptyEntries) + if ($exe_exts -contains $dest_ext.ToLower() -and $dest_ext.ToLower() -ne $link_ext.ToLower()) { + $link_winpath += $dest_ext + } + echo "Creating hardlink '$link_winpath', pointing to '$dest_winpath'" + New-Item -ItemType HardLink -Path $link_winpath -Value $dest_winpath | Out-Null + } + if ($windows_host) { echo 'CYGWIN=${{ inputs.env }}' >> $env:GITHUB_ENV @@ -66,6 +120,10 @@ runs: if ($pkg_list.Count -gt 0) { & $choco install -y --no-progress --source=cygwin $pkg_list } + + if ($symlinks_to_hardlinks) { + & $find /usr/bin -type l | %{ Fix-CygwinLink $_ } + } } else { throw "Sorry, installing Cygwin is unsupported on $os" } -- cgit v1.2.3