Types/OpenPackage.Source/Tar.ps1

<#
.SYNOPSIS
    Gets a tarfile as a package
.DESCRIPTION
    Gets a tarfile as an open package.
#>

param(
# The path to a tarfile.
[Parameter(Mandatory,ValueFromPipelineByPropertyName)]
[string]
$TarFile,

# A list of file wildcards to include.
[Parameter(ValueFromPipelineByPropertyName)]
[SupportsWildcards()]
[string[]]
$Include,

# A list of file wildcards to exclude.
[Parameter(ValueFromPipelineByPropertyName)]
[SupportsWildcards()]
[string[]]
$Exclude,

# The base path within the package.
# Content should be added beneath this base path.
[string]
$BasePath = '/',

# A content type map.
# This maps extensions and URIs to a content type.
[Collections.IDictionary]
$TypeMap = $(
    ([PSCustomObject]@{PSTypeName='OpenPackage.ContentTypeMap'}).TypeMap
),

# The compression option.
[IO.Packaging.CompressionOption]
[Alias('CompressionLevel')]
$CompressionOption = 'Superfast',
        
# If set, will force the redownload of various resources and remove existing files or directories
[switch]
$Force,

# If set, will include hidden files and folders, except for files beneath `.git`
[Alias('IncludeDotFiles')]
[switch]
$IncludeHidden,

# If set, will include the `.git` directory contents if found.
[switch]
$IncludeGit,

# If set, will include any content found in `/node_modules`.
[Alias('IncludeNodeModules')]
[switch]
$IncludeNodeModule
)

$namedParameters = [Ordered]@{}
foreach ($key in $MyInvocation.MyCommand.Parameters.Keys) {
    $var = $ExecutionContext.SessionState.PSVariable.Get($key)
    if ($var) {
        $namedParameters[$key] = $var.value
    }
}
$namedParameters.Remove('TarFile')

# Put tar files into their own subdirectory
foreach ($resolvedItem in Get-Item -Path $TarFile) {    
    # First lets peek at the magic bytes that might give us a clue
    $peekMagicBytes = Get-Content -AsByteStream -LiteralPath $resolvedItem.FullName -First 5
    $myAppData = if ($env:OpenPackagePath) {
        # Get our first OpenPackage package path
        @($env:OpenPackagePath -split $(
            if ($IsLinux -or $IsMacOS) {
                ':'
            } else {
                ';'
            }
        ))[0]
    } else {
        $pwd
    }
    $tarDestination = Join-Path $myAppData 'tar'
    if (-not (Test-Path $tarDestination)) {
        $newDir = New-Item -ItemType Directory -Path $tarDestination -Force
        if (-not $newDir) { return }
    }

    # and each destination in its own subdirectory
    $thisTarDestination = Join-Path $tarDestination ($resolvedItem.Name -replace '\.gz$' -replace '\.tar$')
    if (-not (Test-Path $thisTarDestination)) {
        $newDir = New-Item -ItemType Directory -Path $thisTarDestination -Force
        if (-not $newDir) { return }
    }

    $tarFormat = 
    if (
        $peekMagicBytes[0] -as [char] -eq '.' -and
        $peekMagicBytes[1] -as [char] -eq '/' 
    ) {
        # classic tarfile without gzipping
        'tar'
    } elseif ($peekMagicBytes -and 
        $peekMagicBytes[0] -eq 31 -and 
        $peekMagicBytes[1] -eq 139 -and 
        $peekMagicBytes[2] -eq 8
    ) {
        # gzipped tarball
        'tar.gz'
    } else {
        Write-Error "$($resolvedItem.Name) does not appear to be a .tar or .tar.gz file"
        continue
    }    
    
    # If the engine supports tarfiles
    if ('Formats.Tar.TarFile' -as [Type]) {
        # read the file as a stream
        $openFile = [IO.File]::OpenRead($resolvedItem.FullName)
        if ($tarFormat -eq 'tar.gz') {
            # and read that as a decompressed gzip stream
            $gzipStream = [IO.Compression.GZipStream]::new($openFile, [IO.Compression.CompressionMode]'Decompress')
            if (-not $gzipStream) {
                $openFile.Close()
            }
            [Formats.Tar.TarFile]::ExtractToDirectory($gzipStream, $thisTarDestination, $true)
            # Track if it worked
            $worked = $?
            # and close up
            $gzipStream.Close()
            $null = $gzipStream.DisposeAsync()
            $openFile.Close()
            $null = $openFile.DisposeAsync()
        } else {            
            [Formats.Tar.TarFile]::ExtractToDirectory($openFile, $thisTarDestination, $true)
            $worked = $?
            $openFile.Close()            
            $null = $openFile.DisposeAsync()
        }
        
        # If it worked
        if ($worked) {
            # pack that directory
            Get-Item -LiteralPath "$thisTarDestination" | Get-OpenPackage @namedParameters
        }                                                
    } elseif ($(
        $tarApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand('tar', 'Application')
        $tarApp
    )) {
        # Alternatively, if the tar application installed, we can use that
        $null = & $tarApp -xvf $resolvedItem.FullName -C "$thisTarDestination"
        if ($?) {
            # and then pack the directory
            Get-Item -LiteralPath "$thisTarDestination" | Get-OpenPackage @namedParameters
        }
    } else {
        # If neither of those paths work, write a warning.
        Write-Warning "$($resolvedItem.FullName) is a tar gz, but Formats.Tar.TarFile is not loaded and `tar` app does not exist"
    }
}