RubyInstaller.psm1
#Region '.\Private\Get-ChocolateyTools.ps1' 0 Function Get-ChocolateyTools { # TODO: This SHOULD NOT be hardcoded!! Write-Output 'C:\tools' } #EndRegion '.\Private\Get-ChocolateyTools.ps1' 4 #Region '.\Private\Get-DestinationDir.ps1' 0 Function Get-DestinationDir($RubyVersion) { Write-Output ("C:\tools\ruby" + $RubyVersion.Replace(' ','').Replace('(','').Replace(')','')) } #EndRegion '.\Private\Get-DestinationDir.ps1' 3 #Region '.\Private\Get-UruTag.ps1' 0 function Get-UruTag($RubyVersion) { $bareRubyVersion = ($RubyVersion -split ' ')[0] if ($RubyVersion -match 'x64') { Write-Output "$($bareRubyVersion)-x64" } else { Write-Output "$($bareRubyVersion)-x86" } } #EndRegion '.\Private\Get-UruTag.ps1' 9 #Region '.\Private\Install-7zip.ps1' 0 function Install-7zip { [cmdletBinding()] $7zExists = $false try { Get-Command '7z.exe' -ErrorAction 'Stop' | Out-Null $7zExists = $true } catch { $7zExists = $false } If (-not $7zExists) { Write-Verbose "Installing 7Zip command line..." Write-Progress -Activity "Installing 7Zip command line" & choco install 7zip.commandline -y Write-Progress -Activity "Installing 7Zip command line" -Completed } else { Write-Verbose "7Zip is installed" } } #EndRegion '.\Private\Install-7zip.ps1' 19 #Region '.\Private\Install-Chocolatey.ps1' 0 function Install-Chocolatey { [cmdletBinding()] $ChocoExists = $false try { Get-Command 'choco.exe' -ErrorAction 'Stop' | Out-Null $ChocoExists = $true } catch { $ChocoExists = $false } If (-not $ChocoExists) { Write-Verbose "Installing Chocolatey..." Write-Progress -Activity "Installing Chocolatey" Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) Write-Progress -Activity "Installing Chocolatey" -Completed } else { Write-Verbose "Chocolatey is installed" } } #EndRegion '.\Private\Install-Chocolatey.ps1' 18 #Region '.\Private\Install-URU.ps1' 0 function Install-URU { [cmdletBinding()] $ChocoInstall = $ENV:ChocolateyInstall # The env var may not be set yet. Do a best guess. if ($null -eq $ChocoInstall) { $ChocoInstall = Join-Path -Path $ENV:ALLUSERSPROFILE -ChildPath 'chocolatey' } $URUPath = Join-Path $ChocoInstall -Child "\bin\uru.ps1" if (-not (Test-Path -Path $URUPath)) { Write-Verbose "Installing URU..." Write-Progress -Activity "Installing URU" Write-Verbose "Determining the current version of URU..." $uruver = (Invoke-WebRequest 'https://bitbucket.org/jonforums/uru/downloads/uru.json' -UseBasicParsing -ErrorAction 'Stop' | ConvertFrom-JSON).version if ($null -eq $uruver) { Throw "Could not determine the current version of URU"; return } $downloadURL = "https://bitbucket.org/jonforums/uru/downloads/uru.${uruver}.nupkg" $uruRoot = Get-ChocolateyTools $uruInstall = Join-Path -Path $uruRoot -ChildPath 'URUInstall' $uruInstallNuget = Join-Path -Path $uruInstall -ChildPath 'uru.0.8.5.nupkg' if (Test-Path -Path $uruInstall) { Remove-Item -Path $uruInstall -Force -Recurse -Confirm:$false | Out-Null } New-Item -Path $uruInstall -ItemType Directory | Out-Null Write-Verbose "Downloading URU installer..." (New-Object System.Net.WebClient).DownloadFile($downloadURL, $uruInstallNuget) Write-Verbose "Running the URU installer..." & choco install uru -source $uruInstall -f -y # Cleaning up... if (Test-Path -Path $uruInstall) { Remove-Item -Path $uruInstall -Force -Recurse -Confirm:$false | Out-Null } Write-Progress -Activity "Installing URU" -Completed } else { Write-Verbose "Uru is installed" } } #EndRegion '.\Private\Install-URU.ps1' 36 #Region '.\Private\Invoke-InteractiveRubyVersions.ps1' 0 Function Invoke-InteractiveRubyVersions { param( [ValidateNotNull()] [string[]] $RubyList ) # Sometimes single element arrays come through as a string. Convert it into an array if ($RubyList.GetType().ToString() -eq 'System.String') { $RubyList = @($RubyList) } # Prompt the user for which ruby versions to install $itemsToInstall = @() do { Write-Host "" Write-Host "" Write-Host "A. Install all versions ('$($RubyList -join "', '")')" For($index = 0; $index -lt $RubyList.Count; $index++) { Write-Host "$([char]($index + 66)). Install '$($RubyList[$index])'" } Write-Host "----" Write-Host "Z. Install custom version" Write-Host "" $misc = (Read-Host "Select an option").ToUpper() } until ( ($misc -ge 'A') -and $misc -le 'Z') $option = ([int][char]$misc - 65) switch ($option) { 0 { $itemsToInstall = $RubyList break; } 25 { # Ask the user for the version string do { $misc = '' Write-Host "" Write-Host "Note, the version must match one on the Ruby Installer archive website" Write-Host " https://rubyinstaller.org/downloads/archives/" $misc = (Read-Host "Enter Ruby version to install (e.g. '2.4.3-2 (x64)')") } until ($misc -ne '') $itemsToInstall = @($misc) } default { $itemsToInstall = @($RubyList[$option - 1]) } } if ( ($itemsToInstall -join '') -eq '' ) { Throw "Nothing to install!!"; return; } Write-Output $itemsToInstall } #EndRegion '.\Private\Invoke-InteractiveRubyVersions.ps1' 50 #Region '.\Public\Get-Ruby.ps1' 0 Function Get-Ruby { [cmdletBinding(SupportsShouldProcess=$false,ConfirmImpact='Low')] param() process { $uruResult = & uru ls # Use a simple text parser to extract what we want and emit PS Objects $uruResult | ForEach-Object { $result = $_ -split ':', 2 if (($result[0] -ne '') -and ($result[1] -ne '')) { Write-Output (New-Object -TypeName PSCustomObject -Property @{ 'Tag' = $result[0].Trim() 'Description' = $result[1].Trim() } ) } } } } #EndRegion '.\Public\Get-Ruby.ps1' 20 #Region '.\Public\Install-Ruby.ps1' 0 Function Install-Ruby { [cmdletBinding(SupportsShouldProcess=$false,ConfirmImpact='High',DefaultParameterSetName='Interactive')] param( [Parameter(ValueFromPipeline=$true, Mandatory=$true, Position = 0, ParameterSetName="SpecificVersions")] [ValidateNotNull()] [Alias("Version", "Versions")] [String[]] $RubyVersions ) begin { $is64bit = ([System.IntPtr]::Size -eq 8) if (-not $is64bit) { Throw "Install-Ruby is not supported on 32bit operating systems"; return } if ($Host.Name -eq 'ServerRemoteHost') { Throw "Install-Ruby is not supported over remote connections due to Ruby DevKit failing to install correctly"; return } # Remember and fiddle with the allowed protocols for web requests $CurrentProtocol = [System.Net.ServicePointManager]::SecurityProtocol # Workaround for https://github.com/majkinetor/au/issues/142 [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor [System.Net.SecurityProtocolType]::Tls -bor [System.Net.SecurityProtocolType]::Ssl3 try { # Preflight checks... Install-Chocolatey -ErrorAction 'Stop' Install-7zip -ErrorAction 'Stop' Install-URU -ErrorAction 'Stop' # Opinionated Ruby List (mainly for Puppet Developers) # TODO: Update for 2.5, 2.4 and 2.6? Drop 2.1? $rubyList = @( '2.1.9', '2.1.9 (x64)', '2.4.4-2 (x86)', '2.4.4-2 (x64)', '2.5.1-2 (x86)', '2.5.1-2 (x64)' ) $ChocolateyTools = Get-ChocolateyTools $devKit2_64 = Join-Path -Path $ChocolateyTools -ChildPath 'DevKit2-x64' $devKit2_32 = Join-Path -Path $ChocolateyTools -ChildPath 'DevKit2' $msys_64 = Join-Path -Path $ChocolateyTools -ChildPath 'msys64' $msys_32 = Join-Path -Path $ChocolateyTools -ChildPath 'msys32' if ($PsCmdlet.ParameterSetName -eq 'Interactive') { $RubyVersions = Invoke-InteractiveRubyVersions -RubyList $rubyList } # Sometimes single element arrays come through as a string. Convert it into an array if ($RubyVersions.GetType().ToString() -eq 'System.String') { $RubyVersions = @($RubyVersions) } # Now we have the names of the rubies, time to install! $ProgressActivity = 'Install Ruby' Write-Progress -Activity $ProgressActivity $RubyVersions | ForEach-Object -Process { $rubyVersionString = $_ Write-Verbose "Installing Ruby ${rubyVersionString} ..." Write-Progress -Activity $ProgressActivity -CurrentOperation "Installing Ruby ${rubyVersionString}" $rubyIs64 = $rubyVersionString -match 'x64' $rubyVersionString -match '^([\d.-]+)' | Out-Null $rubyVersion = $matches[1] $rubyURL = $null $32bitDevKit = $false $64bitDevKit = $false $RIDKDevKit = $false $destDir = Get-DestinationDir -RubyVersion $rubyVersionString $uruTag = Get-UruTag -RubyVersion $rubyVersionString # URL base page # https://rubyinstaller.org/downloads/archives/ switch -Regex ($rubyVersion) { '^2\.[0123]\.' { # Example URL # 32bit 'https://dl.bintray.com/oneclick/rubyinstaller/ruby-2.3.3-i386-mingw32.7z' # 64bit 'https://dl.bintray.com/oneclick/rubyinstaller/ruby-2.3.3-x64-mingw32.7z' if ($rubyIs64) { $rubyURL = "https://dl.bintray.com/oneclick/rubyinstaller/ruby-${rubyVersion}-x64-mingw32.7z" $64bitDevKit = $true } else { $rubyURL = "https://dl.bintray.com/oneclick/rubyinstaller/ruby-${rubyVersion}-i386-mingw32.7z" $32bitDevKit = $true } } '^2\.4\.1\-' { # Example URL # 2.4.1 only # 32bit 'https://github.com/oneclick/rubyinstaller2/releases/download/2.4.1-2/rubyinstaller-2.4.1-2-x86.7z' # 64bit 'https://github.com/oneclick/rubyinstaller2/releases/download/2.4.1-2/rubyinstaller-2.4.1-2-x64.7z' if ($rubyIs64) { $rubyURL = "https://github.com/oneclick/rubyinstaller2/releases/download/${rubyVersion}/rubyinstaller-${rubyVersion}-x64.7z" } else { $rubyURL = "https://github.com/oneclick/rubyinstaller2/releases/download/${rubyVersion}/rubyinstaller-${rubyVersion}-x86.7z" } $RIDKDevKit = $true } '^2\.[56789]\.|^2\.4\.[23456789]-' { # Example URL # 2.4.2+ and 2.5+ only # 32bit 'https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.5.1-1/rubyinstaller-2.5.1-1-x86.7z' # 64bit 'https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.5.1-1/rubyinstaller-2.5.1-1-x64.7z' if ($rubyIs64) { $rubyURL = "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-${rubyVersion}/rubyinstaller-${rubyVersion}-x64.7z" } else { $rubyURL = "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-${rubyVersion}/rubyinstaller-${rubyVersion}-x86.7z" } $RIDKDevKit = $true } default { Throw "Unknown Ruby Version $rubyVersion"; return } } # Install the ruby files if (-not (Test-Path -Path $destDir)) { $tempFile = Join-Path -path $ENV:Temp -ChildPath 'rubydl.7z' $tempExtract = Join-Path -path $ENV:Temp -ChildPath ('rubydl_extracted' + [guid]::NewGuid().ToString()) if (Test-Path -Path $tempExtract) { Start-Sleep -Seconds 2; Remove-Item -Path $tempExtract -Recurse -Confirm:$false -Force | Out-Null } Write-Verbose "Downloading from $rubyURL ..." if (Test-Path -Path $tempFile) { Start-Sleep -Seconds 2; Remove-Item -Path $tempFile -Confirm:$false -Force | Out-Null } Invoke-WebRequest -URI $rubyURL -OutFile $tempFile -UseBasicParsing & 7z x $tempFile "`"-o$tempExtract`"" -y # Get the root directory from the extract $misc = (Get-ChildItem -Path $tempExtract | ? { $_.PSIsContainer } | Select -First 1).Fullname Write-Verbose "Install ruby to $destDir ..." if (Test-Path -Path $destDir) { Remove-Item -Path $destDir -Recurse -Confirm:$false -Force | Out-Null } Move-Item -Path $misc -Destination $destDir -Force -Confirm:$false | Out-Null Write-Verbose "Adding to URU..." & uru admin add "$($destDir)\bin" --tag $uruTag Write-Verbose "Cleaning up..." if (Test-Path -Path $tempFile) { Remove-Item -Path $tempFile -Confirm:$false -Force | Out-Null } if (Test-Path -Path $tempExtract) { Remove-Item -Path $tempExtract -Recurse -Confirm:$false -Force | Out-Null } } else { Write-Verbose "Ruby ${rubyVersionString} is already installed to $destDir"} # Configure the ruby installation Write-Progress -Activity $ProgressActivity -CurrentOperation "Configuring Ruby ${rubyVersionString}" & uru $uruTag # Write-Output "Ruby version..." # & ruby -v # Write-Output "Gem version..." # & gem -v # Update the system gems $tempRC = Join-Path -path $ENV:Temp -ChildPath 'gem.rc' @" --- :backtrace: false :bulk_threshold: 1000 :sources: - http://rubygems.org :update_sources: true :verbose: true gem: --no-document "@ | Set-Content -Encoding Ascii -Path $tempRC -Force -Confirm:$false $extraGemUpdate = '' if ($rubyVersion -match '^(?:1\.|2\.[012]\.)') { # Rubygems 3.x requires Ruby 2.3.0, so pin to latest in 2.x $extraGemUpdate += ' 2.7.10' } Write-Progress -Activity $ProgressActivity -CurrentOperation "Updating System Gems for Ruby ${rubyVersionString} (via HTTP)" Write-Verbose "Updating system gems (via HTTP)..." & gem update --system --config-file $tempRC $extraGemUpdate Remove-Item -Path $tempRC -Force -Confirm:$false | Out-Null # Install bundler if it's not already there $BundleExists = $false try { Get-Command 'bundle' -ErrorAction 'Stop' | Out-Null $BundleExists = $true } catch { $BundleExists = $false } if (-not $BundleExists) { Write-Progress -Activity $ProgressActivity -CurrentOperation "Installing Bundler" Write-Verbose "Installing bundler..." if ($rubyVersion -match '^1\.') { # Bundler 2.x requires Ruby 2.3.0, so pin to latest in 1.x & gem install bundler --no-ri --no-rdoc --version 1.17.3 } elseif ($rubyVersion -match '2\.[012]\.') { # Bundler 2.x requires Ruby 2.3.0, so pin to latest in 1.x & gem install bundler --no-document --force --version 1.17.3 } else { & gem install bundler --no-document --force } } else { Write-Verbose "Bundler already installed" } # MSYS2 dev kit (Ruby 2.4+) if ($RIDKDevKit) { if ($rubyIs64) { # DevKit for Ruby 2.4+ 64bit if (-not (Test-Path -Path $msys_64)) { Write-Verbose "Installing DevKit 2.4+ x64" Write-Progress -Activity $ProgressActivity -CurrentOperation "Installing DevKit 2.4+ x64" Start-Process -FilePath 'choco' -ArgumentList (@('install','msys2','-y','--params','/NoUpdate')) -NoNewWindow -Wait | Out-Null } else { Write-Verbose "DevKit 2.4+ 64bit is installed" } } else { # DevKit for Ruby 2.4+ 32bit if (-not (Test-Path -Path $msys_32)) { Write-Verbose "Installing DevKit 2.4+ x86" Write-Progress -Activity $ProgressActivity -CurrentOperation "Installing DevKit 2.4+ x86" Start-Process -FilePath 'choco' -ArgumentList (@('install','msys2','-y','-x86','-f','--params','/NoUpdate')) -NoNewWindow -Wait | Out-Null } else { Write-Verbose "DevKit 2.4+ 32bit is installed" } } & ridk install 2 3 } # 64 and 32 bit legacy DevKit if ($64bitDevKit -or $32bitDevKit) { #****************** # ORDER IS VERY IMPORTANT - 64bit Devkit MUST be installed before 32bit #****************** # DevKit for Ruby 2.x 64bit if ($is64bit -and (-not (Test-Path -Path $devKit2_64))) { Write-Verbose "Installing DevKit 2.x x64. NOTE - Errors are expected" Write-Progress -Activity $ProgressActivity -CurrentOperation "Installing DevKit 2.x x64" Start-Process -FilePath 'choco' -ArgumentList (@('install','ruby2.devkit','-y')) -NoNewWindow -Wait | Out-Null if (-not (Test-Path -Path $devKit2_32)) { Throw "DevKit 2.x x64 did not install" } Move-Item $devKit2_32 $devKit2_64 -Force -EA Stop } else { Write-Verbose "DevKit 2.x 64bit is installed" } # DevKit for Ruby 2.x 32bit if (-not (Test-Path -Path $devKit2_32)) { Write-Verbose "Installing DevKit 2.x x86. NOTE - Errors are expected" Write-Progress -Activity $ProgressActivity -CurrentOperation "Installing DevKit 2.x x86" Start-Process -FilePath 'choco' -ArgumentList (@('install','ruby2.devkit','-y','-x86','-f')) -NoNewWindow -Wait | Out-Null if (-not (Test-Path -Path $devKit2_32)) { Throw "DevKit 2.x x86 did not install" } } else { Write-Verbose "DevKit 2.x 32bit is installed" } # 64bit legacy devkit if ($64bitDevKit) { @" --- - $( $destDir -replace '\\','/' ) "@ | Set-Content -Path "$($devKit2_64)\config.yml" Push-Location $devKit2_64 Write-Verbose "Installing DevKit $devKit2_64 for $rubyVersion" & ruby dk.rb install Pop-Location } # 32bit legacy devkit if ($32bitDevKit) { @" --- - $( $destDir -replace '\\','/' ) "@ | Set-Content -Path "$($devKit2_32)\config.yml" Push-Location $devKit2_32 Write-Verbose "Installing DevKit $devKit2_32 for $rubyVersion" & ruby dk.rb install Pop-Location } } } Write-Progress -Activity $ProgressActivity -Completed Write-Verbose "Cleanup URU assignment" & uru nil } finally { # Restore the old security protocol [System.Net.ServicePointManager]::SecurityProtocol = $CurrentProtocol } } end { & uru list } } #EndRegion '.\Public\Install-Ruby.ps1' 279 #Region '.\Public\Select-Ruby.ps1' 0 Function Select-Ruby { [cmdletBinding(SupportsShouldProcess=$false,ConfirmImpact='Medium')] param( [Parameter(ValueFromPipeline=$true, Mandatory=$true, Position = 0)] [ValidateNotNullOrEmpty()] [String] $RubyTag ) begin { $uruResult = & uru $RubyTag if ($LASTEXITCODE -ne 0) { throw "Error selecting ruby ${RubyTag}: $uruResult" } else { Write-Verbose $uruResult } } } #EndRegion '.\Public\Select-Ruby.ps1' 19 |