Utils/realpath.ps1
|
Register-GnuUtil @{ Name = 'realpath' Category = 'File info and disk usage' Synopsis = 'Print the resolved path.' Usage = @('realpath [OPTION]... FILE...') Description = @('Print the resolved absolute file name;', 'all but the last component must exist') FileOperands = $true Options = @( @{ Short = 'e'; Long = 'canonicalize-existing'; Key = 'require'; Value = 'all'; Help = 'all components of the path must exist' } @{ Short = 'm'; Long = 'canonicalize-missing'; Key = 'require'; Value = 'none'; Help = 'no path components need exist or be a directory' } @{ Short = 'L'; Long = 'logical'; Key = 'resolve'; Value = 'logical'; Help = 'resolve ''..'' components before symlinks' } @{ Short = 'P'; Long = 'physical'; Key = 'resolve'; Value = 'physical'; Help = 'resolve symlinks as encountered (default)' } @{ Short = 'q'; Long = 'quiet'; Help = 'suppress most error messages' } @{ Long = 'relative-to'; Arg = 'DIR'; Help = 'print the resolved path relative to DIR' } @{ Long = 'relative-base'; Arg = 'DIR'; Help = 'print absolute paths unless paths below DIR' } @{ Short = 's'; Long = 'strip'; Key = 'no-symlinks'; Help = 'don''t expand symlinks' } @{ Long = 'no-symlinks'; Help = 'don''t expand symlinks' } @{ Short = 'z'; Long = 'zero'; Help = 'end each output line with NUL, not newline' } ) Notes = @('PowerShell note: ''..'' is always resolved textually before links, so -L and -P give the same result.') } function script:Invoke-GnuRealpathResolve { <# .SYNOPSIS Implementation of realpath. #> param([Parameter(Mandatory)][hashtable]$Context) $operands = @($Context.Operands) if ($operands.Count -eq 0) { Write-GnuUsageError -Context $Context -Message 'missing operand' return } $require = [string](Get-GnuOptionValue -Context $Context -Key 'require' -Default 'parent') $noSymlinks = Test-GnuOption -Context $Context -Key 'no-symlinks' $quiet = Test-GnuOption -Context $Context -Key 'quiet' $bases = @{} foreach ($key in @('relative-to', 'relative-base')) { if (-not (Test-GnuOption -Context $Context -Key $key)) { continue } $directory = [string](Get-GnuOptionValue -Context $Context -Key $key) $resolved = Get-GnuCanonicalPath -Path $directory -Require $require -NoSymlinks:$noSymlinks if (-not $resolved.ContainsKey('Path')) { Write-GnuError -Context $Context -Message "$($directory): $($resolved.Error)" return } $bases[$key] = $resolved.Path } if ($bases.ContainsKey('relative-base') -and -not $bases.ContainsKey('relative-to')) { $bases['relative-to'] = $bases['relative-base'] } $results = foreach ($name in $operands) { $resolved = Get-GnuCanonicalPath -Path $name -Require $require -NoSymlinks:$noSymlinks if (-not $resolved.ContainsKey('Path')) { if ($quiet) { $Context.ExitCode = 1 } else { Write-GnuError -Context $Context -Message "$($name): $($resolved.Error)" } continue } $path = $resolved.Path if ($bases.ContainsKey('relative-to')) { $useRelative = $true if ($bases.ContainsKey('relative-base')) { $useRelative = Test-GnuInsidePath -Path $path -Ancestor $bases['relative-base'] if ($useRelative) { $useRelative = Test-GnuInsidePath -Path $bases['relative-to'] -Ancestor $bases['relative-base'] } } if ($useRelative) { $path = (Get-GnuRelativePath -From $bases['relative-to'] -To $path).Replace('/', [string][System.IO.Path]::DirectorySeparatorChar) } } $path } ConvertTo-GnuRecordOutput -Record @($results) -Zero:(Test-GnuOption -Context $Context -Key 'zero') } |