Skip to content

Commit

Permalink
feat(getopt): Support option terminator (--) (#5121)
Browse files Browse the repository at this point in the history
Co-authored-by: Hsiao-nan Cheung <[email protected]>
  • Loading branch information
L. Yeung and niheaven authored Aug 25, 2022
1 parent 1985a05 commit e06c7f0
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Features

- **getopt:** Support option terminator (`--`) ([#5121](https://github.com/ScoopInstaller/Scoop/issues/5121))
- **scoop-(un)hold:** Support `scoop (un)hold scoop` ([#5089](https://github.com/ScoopInstaller/Scoop/issues/5089))
- **scoop-config:** Allow 'hold_update_until' be set manually ([#5100](https://github.com/ScoopInstaller/Scoop/issues/5100))
- **scoop-update:** Stash uncommitted changes before update ([#5091](https://github.com/ScoopInstaller/Scoop/issues/5091))
Expand Down
47 changes: 29 additions & 18 deletions lib/getopt.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
# array of strings that are long-form options. options that take
# a parameter should end with '='
# returns @(opts hash, remaining_args array, error string)
# NOTES:
# The first "--" in $argv, if any, will terminate all options; any
# following arguments are treated as non-option arguments, even if
# they begin with a hyphen. The "--" itself will not be included in
# the returned $opts. (POSIX-compatible)
function getopt($argv, $shortopts, $longopts) {
$opts = @{}; $rem = @()

Expand All @@ -16,29 +21,35 @@ function getopt($argv, $shortopts, $longopts) {
}

function regex_escape($str) {
return [regex]::escape($str)
return [Regex]::Escape($str)
}

# ensure these are arrays
$argv = @($argv)
$longopts = @($longopts)

for($i = 0; $i -lt $argv.length; $i++) {
for ($i = 0; $i -lt $argv.Length; $i++) {
$arg = $argv[$i]
if($null -eq $arg) { continue }
if ($null -eq $arg) { continue }
# don't try to parse array arguments
if($arg -is [array]) { $rem += ,$arg; continue }
if($arg -is [int]) { $rem += $arg; continue }
if($arg -is [decimal]) { $rem += $arg; continue }
if ($arg -is [Array]) { $rem += , $arg; continue }
if ($arg -is [Int]) { $rem += $arg; continue }
if ($arg -is [Decimal]) { $rem += $arg; continue }

if($arg.startswith('--')) {
$name = $arg.substring(2)
if ($arg -eq '--') {
if ($i -lt $argv.Length - 1) {
$rem += $argv[($i + 1)..($argv.Length - 1)]
}
break
} elseif ($arg.StartsWith('--')) {
$name = $arg.Substring(2)

$longopt = $longopts | Where-Object { $_ -match "^$name=?$" }

if($longopt) {
if($longopt.endswith('=')) { # requires arg
if($i -eq $argv.length - 1) {
if ($longopt) {
if ($longopt.EndsWith('=')) {
# requires arg
if ($i -eq $argv.Length - 1) {
return err "Option --$name requires an argument."
}
$opts.$name = $argv[++$i]
Expand All @@ -48,14 +59,14 @@ function getopt($argv, $shortopts, $longopts) {
} else {
return err "Option --$name not recognized."
}
} elseif($arg.startswith('-') -and $arg -ne '-') {
for($j = 1; $j -lt $arg.length; $j++) {
$letter = $arg[$j].tostring()
} elseif ($arg.StartsWith('-') -and $arg -ne '-') {
for ($j = 1; $j -lt $arg.Length; $j++) {
$letter = $arg[$j].ToString()

if($shortopts -match "$(regex_escape $letter)`:?") {
$shortopt = $matches[0]
if($shortopt[1] -eq ':') {
if($j -ne $arg.length -1 -or $i -eq $argv.length - 1) {
if ($shortopts -match "$(regex_escape $letter)`:?") {
$shortopt = $Matches[0]
if ($shortopt[1] -eq ':') {
if ($j -ne $arg.Length - 1 -or $i -eq $argv.Length - 1) {
return err "Option -$letter requires an argument."
}
$opts.$letter = $argv[++$i]
Expand Down
14 changes: 14 additions & 0 deletions test/Scoop-GetOpts.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,18 @@ Describe 'getopt' -Tag 'Scoop' {
$err | Should -BeNullOrEmpty
$opt.'long-arg' | Should -Be 'test'
}

It 'handles the option terminator' {
$opt, $rem, $err = getopt '--long-arg', '--' '' 'long-arg'
$err | Should -BeNullOrEmpty
$opt.'long-arg' | Should -BeTrue
$rem[0] | Should -BeNullOrEmpty
$opt, $rem, $err = getopt '--long-arg', '--', '-x', '-y' 'xy' 'long-arg'
$err | Should -BeNullOrEmpty
$opt.'long-arg' | Should -BeTrue
$opt.'x' | Should -BeNullOrEmpty
$opt.'y' | Should -BeNullOrEmpty
$rem[0] | Should -Be '-x'
$rem[1] | Should -Be '-y'
}
}

0 comments on commit e06c7f0

Please sign in to comment.