ChocolateyVersion.psm1
class ChocolateyVersion : System.IComparable { [int] $Major = 0 [int] $Minor = 0 [int] $Patch = 0 [int] $Revision = -1 # See this GitHub issue https://github.com/PowerShell/PowerShell/issues/7294 # assigning $null to the strings doesn't make any difference, they are still set to empty strings (tested in PS Core 7.3.6). # Using [NullString]::Value seems to do the job. [string]$PreRelease = [NullString]::Value [string]$Build = [NullString]::Value ChocolateyVersion ([string]$Version) { # Borrowed from https://github.com/maxhauser/semver/blob/v2.3.0/Semver/SemVersion.cs#L43-L48 $versionRegex = "^(?<major>\d+)(?>\.(?<minor>\d+))?(?>\.(?<patch>\d+))?(?>\.(?<revision>\d+))?(?>\-(?<prerelease>[0-9A-Za-z\-\.]+))?(?>\+(?<build>[0-9A-Za-z\-\.]+))?$" if ($Version -match $versionRegex) { 'major', 'minor', 'patch', 'revision', 'prerelease', 'build' | ForEach-Object { if ($matches.$($_)) { # We need the first 3 parts, ALWAYS. If revision (the 4th part) is 0, just ignore it. if ($_ -eq 'revision' -and [int]($matches.$($_)) -eq 0) { $this.$_ = -1 } else { $this.$_ = $matches.$_ } } } } else { throw "Cannot parse $Version. Is it a valid ChocolateyVersion?" } } [string] ToString () { # I used a loop here and things go complex so kept it simple and used multiple if's # the first three parts must have values for a Chocolatey Version # $this.Major will always have a value $versionString = "$($this.Major)" if ($this.Minor -ne -1) { $versionString += ".$($this.Minor)" } else { $versionString += ".0" } if ($this.Patch -ne -1) { $versionString += ".$($this.Patch)" } else { $versionString += ".0" } if ($this.Revision -ne -1) { $versionString += ".$($this.Revision)" } if ($null -ne $this.PreRelease) { $versionString += "-$($this.PreRelease)" } if ($null -ne $this.Build) { $versionString += "+$($this.Build)" } return $versionString } [string] hidden ToVersionTypeString () { # I used a loop here and things go complex so kept it simple and used multiple if's # the first three parts must have values for a Chocolatey Version # $this.Major will always have a value $versionString = "$($this.Major)" if ($this.Minor -ne -1) { $versionString += ".$($this.Minor)" } else { $versionString += ".0" } if ($this.Patch -ne -1) { $versionString += ".$($this.Patch)" } else { $versionString += ".0" } if ($this.Revision -ne -1) { $versionString += ".$($this.Revision)" } return $versionString } # Custom-define -eq / -ne, by overriding Object.Equals() # Note that I don't think we need a GetHashCode method here. # https://stackoverflow.com/questions/59290037/overloading-operator-in-powershell-classes/59294529#59294529 [bool] Equals([object] $Other) { # We can't just use the version strings for comparison, as they will not be normalized. # For example, '1.2.3' is the same as '1.2.00003' in version number, but not as a string. # The prelease and build we CAN compare as a string [version]$thisVersion = [version]($this.ToVersionTypeString()) [version]$otherVersion = [version]($other.ToVersionTypeString()) # first compare the [version] objects and if they are the same compare the prerelease and build. if ($thisVersion -eq $otherVersion) { if (($this.PreRelease -eq $other.PreRelease) -and ($this.Build -eq $other.Build)) { # everything matches so these are the same return $true } else { return $false } } else { return $false } } # Custom-define -lt / -le and -gt / -ge, via the System.IComparable interface. # See https://stackoverflow.com/questions/59290037/overloading-operator-in-powershell-classes/59294529#59294529 # if it's equal, should return 0 # -lt should return -1 # gt should return 1 [int] CompareTo([object] $Other) { # lets check if they are equal first of all if ($this.Equals($Other)) { return 0 } # if we get here, the versions are not equal [version]$thisVersion = [version]($this.ToString()) [version]$otherVersion = [version]($other.ToString()) $thisVersionExtra = "$($this.PreRelease)+$($this.Build)" $otherVersionExtra = "$($other.PreRelease)+$($other.Build)" if ($thisVersion -eq $otherVersion) { if ($thisVersionExtra -eq $otherVersionExtra) { return 0 } elseif ($thisVersionExtra -lt $otherVersionExtra) { return -1 } else { return 1 } } elseif ($thisversion -lt $otherVersion) { return -1 } else { return 1 } } } |