Skip to content

Commit b0529f9

Browse files
committed
Work in progress on mac install support. Restructures Install-UnitySetupInstance to handle ordering of installs slightly differently. Breaks out downloading installers into a separate function.
1 parent 9702380 commit b0529f9

File tree

1 file changed

+242
-56
lines changed

1 file changed

+242
-56
lines changed

UnitySetup/UnitySetup.psm1

Lines changed: 242 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -427,101 +427,275 @@ function Find-UnitySetupInstaller {
427427
} | Sort-Object -Property ComponentType
428428
}
429429

430+
function Test-UnitySetupInstance {
431+
[CmdletBinding()]
432+
param(
433+
[parameter(Mandatory = $false)]
434+
[UnityVersion] $Version,
435+
436+
[parameter(Mandatory = $false)]
437+
[string] $Path
438+
)
439+
440+
$instance = Get-UnitySetupInstance | Select-UnitySetupInstance -Version $Version -Path $Path
441+
return $null -ne $instance
442+
}
443+
444+
<#
445+
.Synopsis
446+
Select installers by a version and/or components.
447+
.DESCRIPTION
448+
Filters a list of `UnitySetupInstaller` down to a specific version and/or specific components.
449+
.PARAMETER Installers
450+
List of installers that needs to be reduced.
451+
.PARAMETER Version
452+
What version of UnitySetupInstaller that you want to keep.
453+
.PARAMETER Components
454+
What components should be maintained.
455+
.EXAMPLE
456+
$installers = Find-UnitySetupInstaller -Version 2017.3.0f3
457+
$installers += Find-UnitySetupInstaller -Version 2018.2.5f1
458+
$installers | Select-UnitySetupInstaller -Component Windows,Linux,Mac
459+
#>
460+
function Select-UnitySetupInstaller {
461+
[CmdletBinding()]
462+
param(
463+
[parameter(ValueFromPipeline = $true)]
464+
[UnitySetupInstaller[]] $Installers,
465+
466+
[parameter(Mandatory = $false)]
467+
[UnityVersion] $Version,
468+
469+
[parameter(Mandatory = $false)]
470+
[UnitySetupComponent] $Components = [UnitySetupComponent]::All
471+
)
472+
begin {
473+
$selectedInstallers = @()
474+
}
475+
process {
476+
# Keep only the matching version specified.
477+
if ( $PSBoundParameters.ContainsKey('Version') ) {
478+
$Installers = $Installers | Where-Object { [UnityVersion]::Compare($_.Version, $Version) -eq 0 }
479+
}
480+
481+
# Keep only the matching component(s).
482+
$Installers = $Installers | Where-Object { $Components -band $_.ComponentType } | ForEach-Object { $_ }
483+
484+
$selectedInstallers += $Installers
485+
}
486+
end {
487+
return $selectedInstallers
488+
}
489+
}
490+
491+
function Request-UnitySetupInstaller {
492+
[CmdletBinding()]
493+
param(
494+
[parameter(ValueFromPipeline = $true)]
495+
[UnitySetupInstaller[]] $Installers,
496+
497+
[parameter(Mandatory = $false)]
498+
[string]$Cache = [io.Path]::Combine("~", ".unitysetup")
499+
)
500+
begin {
501+
# Note that this has to happen before calculating the full path since
502+
# Resolve-Path throws an exception on missing paths.
503+
if (!(Test-Path $Cache -PathType Container)) {
504+
New-Item $Cache -ItemType Directory -ErrorAction Stop | Out-Null
505+
}
506+
507+
# Expanding '~' to the absolute path on the system. `WebClient` on macOS asumes
508+
# relative path. macOS also treats alt directory separators as part of the file
509+
# name and this corrects the separators to current environment.
510+
$fullCachePath = (Resolve-Path -Path $Cache).Path
511+
512+
$downloads = @()
513+
}
514+
process {
515+
$Installers | ForEach-Object {
516+
$installerFileName = [io.Path]::GetFileName($_.DownloadUrl)
517+
$destination = [io.Path]::Combine($fullCachePath, "Installers", "Unity-$($_.Version)", "$installerFileName")
518+
519+
# Already downloaded?
520+
if ( Test-Path $destination ) {
521+
$destinationItem = Get-Item $destination
522+
if ( ($destinationItem.Length -eq $_.Length ) -and
523+
($destinationItem.LastWriteTime -eq $_.LastModified) ) {
524+
Write-Verbose "Skipping download because it's already in the cache: $($_.DownloadUrl)"
525+
526+
$downloads += ,$destination
527+
return
528+
}
529+
}
530+
531+
$destinationDirectory = [io.path]::GetDirectoryName($destination)
532+
if (!(Test-Path $destinationDirectory -PathType Container)) {
533+
New-Item "$destinationDirectory" -ItemType Directory | Out-Null
534+
}
535+
536+
try
537+
{
538+
Write-Verbose "Downloading $($_.DownloadUrl) to $destination"
539+
(New-Object System.Net.WebClient).DownloadFile($_.DownloadUrl, $destination)
540+
541+
# Re-writes the last modified time for ensuring downloads cache.
542+
$downloadedFile = Get-Item $destination
543+
$downloadedFile.LastWriteTime = $_.LastModified
544+
545+
$downloads += ,$destination
546+
}
547+
catch [System.Net.WebException]
548+
{
549+
Write-Error "Failed downloading $($installerFileName): $($_.Exception.Message)"
550+
}
551+
}
552+
}
553+
end {
554+
return $downloads
555+
}
556+
}
557+
430558
<#
431559
.Synopsis
432560
Installs a UnitySetup instance.
433561
.DESCRIPTION
434562
Downloads and installs UnitySetup installers found via Find-UnitySetupInstaller.
435563
.PARAMETER Installers
436564
What installers would you like to download and execute?
565+
.PARAMETER BasePath
566+
Under what base patterns is Unity customly installed at.
437567
.PARAMETER Destination
438568
Where would you like the UnitySetup instance installed?
439569
.PARAMETER Cache
440-
Where should the installers be cached. This defaults to $env:USERPROFILE\.unitysetup.
570+
Where should the installers be cached. This defaults to ~\.unitysetup.
441571
.EXAMPLE
442572
Find-UnitySetupInstaller -Version 2017.3.0f3 | Install-UnitySetupInstance
443573
.EXAMPLE
444574
Find-UnitySetupInstaller -Version 2017.3.0f3 | Install-UnitySetupInstance -Destination D:\Unity-2017.3.0f3
575+
.EXAMPLE
576+
Find-UnitySetupInstaller -Version 2017.3.0f3 | Install-UnitySetupInstance -BasePath D:\UnitySetup\
577+
.EXAMPLE
578+
Find-UnitySetupInstaller -Version 2017.3.0f3 | Install-UnitySetupInstance -BasePath D:\UnitySetup\ -Destination Unity-2017
445579
#>
446580
function Install-UnitySetupInstance {
447581
[CmdletBinding()]
448582
param(
449583
[parameter(ValueFromPipeline = $true)]
450584
[UnitySetupInstaller[]] $Installers,
451585

586+
[parameter(Mandatory = $false)]
587+
[string]$BasePath,
588+
452589
[parameter(Mandatory = $false)]
453590
[string]$Destination,
454591

455592
[parameter(Mandatory = $false)]
456-
[string]$Cache = [io.Path]::Combine($env:USERPROFILE, ".unitysetup")
593+
[string]$Cache = [io.Path]::Combine("~", ".unitysetup")
457594
)
595+
begin {
596+
$currentOS = Get-OperatingSystem
597+
if ($currentOS == [OperatingSystem]::Linux) {
598+
throw "Install-UnitySetupInstance has not been implemented on the Linux platform. Contributions welcomed!";
599+
}
600+
601+
if ( -not $PSBoundParameters.ContainsKey('BasePath') ) {
602+
$defaultInstallPath = switch ($currentOS) {
603+
([OperatingSystem]::Windows) { 'C:\Program Files\Unity' }
604+
([OperatingSystem]::Linux) { throw "Install-UnitySetupInstance has not been implemented on the Linux platform. Contributions welcomed!"; }
605+
([OperatingSystem]::Mac) { '/Applications/Unity' }
606+
}
607+
}
608+
else {
609+
$defaultInstallPath = $BasePath
610+
}
611+
612+
$unitySetupInstances = Get-UnitySetupInstance -BasePath $BasePath
458613

614+
$versionInstallers = @{}
615+
}
459616
process {
460-
if (!(Test-Path $Cache -PathType Container)) {
461-
New-Item $Cache -ItemType Directory -ErrorAction Stop | Out-Null
617+
# Sort each installer received from the pipe into versions
618+
$Installers | ForEach-Object {
619+
$versionInstallers[$_.Version] += , $_
462620
}
621+
}
622+
end {
623+
# foreach unity version
624+
# If macOS, move previous install back to default directory
625+
# Install main Unity setup installer first
626+
# Install all components to default Unity version
627+
# If macOS, move install to versioned directory
628+
$versionInstallers.Keys | ForEach-Object {
629+
$installVersion = $_
630+
$installerInstances = $versionInstallers[$installVersion]
631+
632+
if ($currentOS == [OperatingSystem]::Mac) {
633+
# On macOS we must notify the user to take an action if the default location
634+
# is currently in use. Either there's a previous version of Unity installed
635+
# manually or another install through UnitySetup possibly failed.
636+
if (Test-UnitySetupInstance -Path /Applications/Unity/) {
637+
# TODO: Work in a `$host.ui.PromptForChoice` / -Force param for resolving this.
638+
throw "Install-UnitySetupInstance has not yet handled working around the base install directory already existing. Please move this manually and try again. Contributions welcomed!";
639+
}
463640

464-
$localInstallers = @()
465-
$localDestinations = @()
466641

467-
$downloadSource = @()
468-
$downloadDest = @()
469-
foreach ( $i in $Installers) {
470-
$fileName = [io.Path]::GetFileName($i.DownloadUrl)
471-
$destPath = [io.Path]::Combine($Cache, "Installers\Unity-$($i.Version)\$fileName")
642+
}
472643

473-
$localInstallers += , $destPath
474-
if ($Destination) {
475-
$localDestinations += , $Destination
644+
if ( $PSBoundParameters.ContainsKey('Destination') ) {
645+
# Slight API change here. If BasePath is also provided treat Destination as a relative path.
646+
if ( $PSBoundParameters.ContainsKey('BasePath') ) {
647+
$installPath = $Destination
648+
}
649+
else {
650+
$installPath = [io.path]::Combine($BasePath, $Destination)
651+
}
476652
}
477653
else {
478-
$localDestinations += , "C:\Program Files\Unity-$($i.Version)"
654+
$installPath = "$defaultInstallPath-$installVersion"
479655
}
480656

481-
if ( Test-Path $destPath ) {
482-
$destItem = Get-Item $destPath
483-
if ( ($destItem.Length -eq $i.Length ) -and ($destItem.LastWriteTime -eq $i.LastModified) ) {
484-
Write-Verbose "Skipping download because it's already in the cache: $($i.DownloadUrl)"
485-
continue
486-
}
487-
}
657+
$installerPaths = $installerInstances | Request-UnitySetupInstaller -Cache $Cache
488658

489-
$downloadSource += $i.DownloadUrl
490-
$downloadDest += $destPath
491-
}
659+
# TODO: Install Unity component first
492660

493-
if ( $downloadSource.Length -gt 0 ) {
494-
for ($i = 0; $i -lt $downloadSource.Length; $i++) {
495-
Write-Verbose "Downloading $($downloadSource[$i]) to $($downloadDest[$i])"
496-
$destDirectory = [io.path]::GetDirectoryName($downloadDest[$i])
497-
if (!(Test-Path $destDirectory -PathType Container)) {
498-
New-Item "$destDirectory" -ItemType Directory | Out-Null
661+
foreach ($componentInstallerPath in $installerPaths) {
662+
switch ($currentOS) {
663+
([OperatingSystem]::Windows) {
664+
$startProcessArgs = @{
665+
'FilePath' = $_;
666+
'ArgumentList' = @("/S", "/D=$installPath");
667+
'PassThru' = $true;
668+
'Wait' = $true;
669+
}
670+
}
671+
([OperatingSystem]::Linux) {
672+
throw "Install-UnitySetupInstance has not been implemented on the Linux platform. Contributions welcomed!";
673+
}
674+
([OperatingSystem]::Mac) {
675+
$startProcessArgs = @{
676+
'FilePath' = $installer;
677+
'ArgumentList' = @("/S", "/D=$destination");
678+
'PassThru' = $true;
679+
'Wait' = $true;
680+
}
681+
}
682+
}
683+
684+
Write-Verbose "$(Get-Date): Installing $installer to $destination."
685+
$process = Start-Process @startProcessArgs
686+
if ( $process ) {
687+
if ( $process.ExitCode -ne 0) {
688+
Write-Error "$(Get-Date): Failed with exit code: $($process.ExitCode)"
689+
}
690+
else {
691+
Write-Verbose "$(Get-Date): Succeeded."
692+
}
499693
}
500-
501-
(New-Object System.Net.WebClient).DownloadFile($downloadSource[$i], $downloadDest[$i])
502694
}
503-
}
504-
505-
for ($i = 0; $i -lt $localInstallers.Length; $i++) {
506-
$installer = $localInstallers[$i]
507-
$destination = $localDestinations[$i]
508695

509-
$startProcessArgs = @{
510-
'FilePath' = $installer;
511-
'ArgumentList' = @("/S", "/D=$destination");
512-
'PassThru' = $true;
513-
'Wait' = $true;
514-
}
515-
516-
Write-Verbose "$(Get-Date): Installing $installer to $destination."
517-
$process = Start-Process @startProcessArgs
518-
if ( $process ) {
519-
if ( $process.ExitCode -ne 0) {
520-
Write-Error "$(Get-Date): Failed with exit code: $($process.ExitCode)"
521-
}
522-
else {
523-
Write-Verbose "$(Get-Date): Succeeded."
524-
}
696+
# Move the install from the staging area to the desired destination
697+
if ($currentOS == [OperatingSystem]::Mac) {
698+
Move-Item -Path /Applications/Unity/ -Destination $installPath
525699
}
526700
}
527701
}
@@ -626,14 +800,16 @@ function Get-UnitySetupInstance {
626800
Select the latest version available.
627801
.PARAMETER Version
628802
Select only instances matching Version.
629-
.PARAMETER Project
630-
Select only instances matching the version of the project at Project.
803+
.PARAMETER Path
804+
Select only instances matching the project at the provided path.
631805
.PARAMETER instances
632806
The list of instances to Select from.
633807
.EXAMPLE
634808
Get-UnitySetupInstance | Select-UnitySetupInstance -Latest
635809
.EXAMPLE
636810
Get-UnitySetupInstance | Select-UnitySetupInstance -Version 2017.1.0f3
811+
.EXAMPLE
812+
Get-UnitySetupInstance | Select-UnitySetupInstance -Path (Get-Item /Applications/Unity*)
637813
#>
638814
function Select-UnitySetupInstance {
639815
[CmdletBinding()]
@@ -644,11 +820,21 @@ function Select-UnitySetupInstance {
644820
[parameter(Mandatory = $false)]
645821
[UnityVersion] $Version,
646822

823+
[parameter(Mandatory = $false)]
824+
[string] $Path,
825+
647826
[parameter(Mandatory = $true, ValueFromPipeline = $true)]
648827
[UnitySetupInstance[]] $Instances
649828
)
650829

651830
process {
831+
if ( $PSBoundParameters.ContainsKey('Path') ) {
832+
$Path = $Path.TrimEnd([io.path]::DirectorySeparatorChar)
833+
$Instances = $Instances | Where-Object {
834+
$Path -eq (Get-Item $_.Path).FullName.TrimEnd([io.path]::DirectorySeparatorChar)
835+
}
836+
}
837+
652838
if ( $Version ) {
653839
$Instances = $Instances | Where-Object { [UnityVersion]::Compare($_.Version, $Version) -eq 0 }
654840
}

0 commit comments

Comments
 (0)