Skip to content
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

feat(install): Add unpacker for 'wix', 'nsis' and 'inno' installer #3502

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions lib/core.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,45 @@ function movedir($from, $to) {
}
}

function Confirm-IsEmptyDirectory {
param (
[String]
$Path
)
return @(Get-ChildItem -Path $Path -File -Recurse -Force -ErrorAction SilentlyContinue).Length -eq 0
}

function Remove-Directory {
[CmdletBinding(SupportsShouldProcess = $true)]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Switch]
$OnlyEmpty
)
if (Test-Path $Path) {
if ($OnlyEmpty) {
(Get-ChildItem $Path -Directory -Recurse -Force -ErrorAction SilentlyContinue).FullName | ForEach-Object {
if (Confirm-IsEmptyDirectory -Path $_) {
Remove-Directory -Path $_
}
}
if (Confirm-IsEmptyDirectory -Path $Path) {
Remove-Directory -Path $Path
}
} else {
try {
Remove-Item $Path -Recurse -Force -ErrorAction Stop
} catch [System.IO.PathTooLongException] {
& "$env:COMSPEC" /c "rmdir /s /q $Path"
} catch [System.UnauthorizedAccessException] {
warn "Couldn't remove '$Path': unauthorized access."
}
}
}
}

function get_app_name($path) {
if ($path -match '([^/\\]+)[/\\]current[/\\]') {
return $matches[1].tolower()
Expand Down
221 changes: 204 additions & 17 deletions lib/decompress.ps1
Original file line number Diff line number Diff line change
@@ -1,40 +1,79 @@
function Test-7zipRequirement {
[CmdletBinding(DefaultParameterSetName = "URL")]
[CmdletBinding(DefaultParameterSetName = "Manifest")]
[OutputType([Boolean])]
param (
[Parameter(Mandatory = $true, ParameterSetName = "URL")]
[String[]]
$URL,
[Parameter(Mandatory = $true, Position = 0, ParameterSetName = "Manifest")]
[PSObject]
$Manifest,
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "Manifest")]
[String]
$Architecture,
[Parameter(Mandatory = $true, ParameterSetName = "File")]
[String]
$File
)
if ($URL) {
if ($File) {
return $File -match '\.((gz)|(tar)|(tgz)|(lzma)|(bz)|(bz2)|(7z)|(rar)|(iso)|(xz)|(lzh)|(nupkg))$'
} else {
$URL = url $Manifest $Architecture
$Installer = installer $Manifest $Architecture
if ((get_config 7ZIPEXTRACT_USE_EXTERNAL)) {
return $false
} elseif (($Installer.type -eq "nsis")) {
return $true
} else {
return ($URL | Where-Object { Test-7zipRequirement -File $_ }).Count -gt 0
}
} else {
return $File -match '\.((gz)|(tar)|(tgz)|(lzma)|(bz)|(bz2)|(7z)|(rar)|(iso)|(xz)|(lzh)|(nupkg))$'
}
}

function Test-LessmsiRequirement {
[CmdletBinding()]
[OutputType([Boolean])]
param (
[Parameter(Mandatory = $true)]
[String[]]
$URL
[Parameter(Mandatory = $true, Position = 0)]
[PSObject]
$Manifest,
[Parameter(Mandatory = $true, Position = 1)]
[String]
$Architecture
)
$URL = url $Manifest $Architecture
if ((get_config MSIEXTRACT_USE_LESSMSI)) {
return ($URL | Where-Object { $_ -match '\.msi$' }).Count -gt 0
} else {
return $false
}
}

function Test-InnounpRequirement {
[CmdletBinding()]
[OutputType([Boolean])]
param (
[Parameter(Mandatory = $true, Position = 0)]
[PSObject]
$Manifest,
[Parameter(Mandatory = $true, Position = 1)]
[String]
$Architecture
)
return (installer $Manifest $Architecture).type -eq 'inno'
}

function Test-DarkRequirement {
[CmdletBinding()]
[OutputType([Boolean])]
param (
[Parameter(Mandatory = $true, Position = 0)]
[PSObject]
$Manifest,
[Parameter(Mandatory = $true, Position = 1)]
[String]
$Architecture
)
return (installer $Manifest $Architecture).type -eq 'wix'
}

function Expand-7zipArchive {
[CmdletBinding()]
param (
Expand Down Expand Up @@ -143,10 +182,10 @@ function Expand-MsiArchive {
}
if ($ExtractDir -and (Test-Path "$DestinationPath\SourceDir")) {
movedir "$DestinationPath\SourceDir\$ExtractDir" $OriDestinationPath | Out-Null
Remove-Item $DestinationPath -Recurse -Force
Remove-Directory -Path $DestinationPath
} elseif ($ExtractDir) {
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
Remove-Item $DestinationPath -Recurse -Force
Remove-Directory -Path $DestinationPath
} elseif (Test-Path "$DestinationPath\SourceDir") {
movedir "$DestinationPath\SourceDir" $DestinationPath | Out-Null
}
Expand Down Expand Up @@ -182,9 +221,10 @@ function Expand-InnoArchive {
$LogPath = "$(Split-Path $Path)\innounp.log"
$ArgList = @('-x', "-d`"$DestinationPath`"", "`"$Path`"", '-y')
switch -Regex ($ExtractDir) {
"^[^{].*" { $ArgList += "-c{app}\$ExtractDir" }
"^{.*" { $ArgList += "-c$ExtractDir" }
Default { $ArgList += "-c{app}" }
"^\.$" { break } # Suppress '-cDIR' param
"^[^{].*" { $ArgList += "-c`"{app}\$ExtractDir`""; break }
"^{.*" { $ArgList += "-c`"$ExtractDir`""; break }
Default { $ArgList += "-c`"{app}`"" }
}
if ($Switches) {
$ArgList += (-split $Switches)
Expand Down Expand Up @@ -250,7 +290,7 @@ function Expand-ZipArchive {
}
if ($ExtractDir) {
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
Remove-Item $DestinationPath -Recurse -Force
Remove-Directory -Path $DestinationPath
}
if ($Removal) {
# Remove original archive file
Expand Down Expand Up @@ -298,7 +338,7 @@ function extract_7zip($path, $to, $removal) {

function extract_msi($path, $to, $removal) {
Show-DeprecatedWarning $MyInvocation 'Expand-MsiArchive'
Expand-MsiArchive -Path $path -DestinationPath $to -Removal:$removal
Expand-MsiArchive -Path $path -DestinationPath $to -Removal:$removal @args
}

function unpack_inno($path, $to, $removal) {
Expand All @@ -310,3 +350,150 @@ function extract_zip($path, $to, $removal) {
Show-DeprecatedWarning $MyInvocation 'Expand-ZipArchive'
Expand-ZipArchive -Path $path -DestinationPath $to -Removal:$removal
}

function Expand-NsisInstaller {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[String]
$Architecture,
[Switch]
$Removal
)
Expand-7ZipArchive -Path $Path -DestinationPath $DestinationPath -Removal:$Removal
if (Test-Path "$DestinationPath\`$PLUGINSDIR\app-64.7z") {
if ($Architecture -eq "64bit") {
Expand-7ZipArchive -Path "$DestinationPath\`$PLUGINSDIR\app-64.7z" -DestinationPath $DestinationPath
} else {
abort "Software doesn't support $Architecture architecture!"
}
} elseif (Test-Path "$DestinationPath\`$PLUGINSDIR\app-32.7z") {
Expand-7ZipArchive -Path "$DestinationPath\`$PLUGINSDIR\app-32.7z" -DestinationPath $DestinationPath
}
@("*uninst*", "`$*") | ForEach-Object { Get-Item "$DestinationPath\$_" | Remove-Item -Recurse -Force }
}

function Expand-WixInstaller {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[String[]]
$Exclude,
[Switch]
$Removal
)
Expand-DarkArchive -Path $Path -DestinationPath (ensure "$DestinationPath\_tmp") -Removal:$Removal
niheaven marked this conversation as resolved.
Show resolved Hide resolved
if ($Exclude) {
Remove-Item "$DestinationPath\_tmp\AttachedContainer\*.msi" -Include $Exclude -Force
}
Get-ChildItem "$DestinationPath\_tmp\AttachedContainer\*.msi" | ForEach-Object { Expand-MsiArchive $_ $DestinationPath }
Remove-Directory -Path "$DestinationPath\_tmp"
}

function ConvertFrom-Inno {
[CmdletBinding()]
[OutputType([Hashtable])]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[System.Array]
$InputObject,
[String[]]
$Include,
[String[]]
$Exclude
)

$FileList = New-Object System.Collections.Generic.List[System.Object]
$Files = $InputObject -match '^Source:'
foreach ($File in $Files) {
if ($File -match 'Source: "(?<source>(?<srcdir>[^\\]*).*?)"; DestDir: "(?<destdir>.*?)"; (?:DestName: "(?<destname>.*?)"; )?(?:Components: (?<components>.*?);)?') {
$FileList.Add([PSCustomObject]@{source = $Matches.source; srcdir = $Matches.srcdir; destdir = $Matches.destdir; destname = $Matches.destname; components = $Matches.components })
}
}
if ($FileList.components) {
$Comps = $FileList.components | Select-Object -Unique
$IncludeComps = @()
$ExcludeComps = @()
if ($Include) {
$Include = $Include -split '\\' | Select-Object -Unique
foreach ($IncFile in $Include) {
$IncFile = '\b' + [Regex]::Escape($IncFile) + '\b'
$IncludeComps += $Comps | Where-Object {
($_ -match "$IncFile") -and ($_ -notmatch "not[^(]*?\(?[^(]*?$IncFile")
}
$ExcludeComps += $Comps | Where-Object { $_ -match "not[^(]*?\(?[^(]*?$IncFile" }
}
}
if ($Exclude) {
foreach ($ExcFile in $Exclude) {
$ExcFile = '\b' + [Regex]::Escape($ExcFile) + '\b'
$ExcludeComps += $Comps | Where-Object { ($_ -match "$ExcFile") -and ($_ -notmatch "not[^(]*?\(?[^(]*?$ExcFile") -and ($_ -notmatch "or[^(]*?$ExcFile") -and ($_ -notmatch "$ExcFile[^(]*?or") }
}
$IncludeComps = $IncludeComps | Where-Object { $_ -notin $ExcludeComps }
}
$Included = $FileList | Where-Object { $_.components -in $IncludeComps }
$Excluded = $FileList | Where-Object { $_.components -in $ExcludeComps }
}

return @{
FileList = $FileList;
Excluded = $Excluded;
Included = $Included;
Extracted = @($FileList.srcdir | Select-Object -Unique) -ne '{tmp}'
}
}

function Expand-InnoInstaller {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[String]
$Path,
[Parameter(Position = 1)]
[String]
$DestinationPath = (Split-Path $Path),
[String]
$ExtractDir,
[String[]]
$Include,
[String[]]
$Exclude,
[Switch]
$Removal
)
if ($ExtractDir) {
Expand-InnoArchive -Path $Path -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Removal:$Removal
} else {
Expand-InnoArchive -Path $Path -DestinationPath $DestinationPath -ExtractDir '.' -Switches 'install_script.iss' # Just extract install script
$InstallScript = Get-Content -Path "$DestinationPath\install_script.iss"
$InnoFiles = ConvertFrom-Inno -InputObject $InstallScript -Include $Include -Exclude ($Exclude -notlike '{*}')
$InnoFiles.Extracted | Where-Object { $_ -notin ($Exclude -like '{*}') } | ForEach-Object {
Expand-InnoArchive -Path $Path -DestinationPath $DestinationPath -ExtractDir $_ -Switches '-a'
}
if ($InnoFiles.Excluded) {
($InnoFiles.Excluded.source -replace "{.*?}", "$DestinationPath") | Remove-Item -Force -ErrorAction Ignore
}
if ($InnoFiles.Included) {
$InnoFiles.Included | Where-Object { $_.source -match ',' } | Rename-Item -Path { $_.source -replace "{.*?}", "$DestinationPath" } -NewName { $_.destname } -Force -ErrorAction Ignore
}
Get-ChildItem -Path $DestinationPath -Filter '*,*' -Recurse | Rename-Item -NewName { $_.name -Replace ',\d', '' } -Force -ErrorAction Ignore
Get-ChildItem -Path $DestinationPath -Filter '*,*' -Recurse | Remove-Item -Force -ErrorAction Ignore
Remove-Directory -Path $DestinationPath -OnlyEmpty
Remove-Item -Path "$DestinationPath\install_script.iss" -Force

if ($Removal) {
# Remove original archive file
Remove-Item -Path $Path -Force
}
}
}
10 changes: 6 additions & 4 deletions lib/depends.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,18 @@ function script_deps($script) {
function install_deps($manifest, $arch) {
$deps = @()

if (!(Test-HelperInstalled -Helper 7zip) -and (Test-7zipRequirement -URL (url $manifest $arch))) {
if (!(Test-HelperInstalled -Helper 7zip) -and (Test-7zipRequirement -Manifest $manifest -Architecture $arch)) {
$deps += '7zip'
}
if (!(Test-HelperInstalled -Helper Lessmsi) -and (Test-LessmsiRequirement -URL (url $manifest $arch))) {
if (!(Test-HelperInstalled -Helper Lessmsi) -and (Test-LessmsiRequirement -Manifest $manifest -Architecture $arch)) {
$deps += 'lessmsi'
}
if (!(Test-HelperInstalled -Helper Innounp) -and $manifest.innosetup) {
if (!(Test-HelperInstalled -Helper Innounp) -and (Test-InnounpRequirement -Manifest $manifest -Architecture $arch)) {
$deps += 'innounp'
}

if (!(Test-HelperInstalled -Helper Dark) -and (Test-DarkRequirement -Manifest $manifest -Architecture $arch)) {
$deps += 'dark'
}
$pre_install = arch_specific 'pre_install' $manifest $arch
$installer = arch_specific 'installer' $manifest $arch
$post_install = arch_specific 'post_install' $manifest $arch
Expand Down
Loading