diff --git a/CHANGELOG.md b/CHANGELOG.md index 844dc5b8cd3..63a525f5c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ + +### v2.29.3 (2018-02-05) + + +#### Improvements + +* **Overrides:** clap now supports arguments which override with themselves ([6c7a0010](https://github.com/kbknapp/clap-rs/commit/6c7a001023ca1eac1cc6ffe6c936b4c4a2aa3c45), closes [#976](https://github.com/kbknapp/clap-rs/issues/976)) + +#### Bug Fixes + +* **Requirements:** fixes an issue where conflicting args would still show up as required ([e06cefac](https://github.com/kbknapp/clap-rs/commit/e06cefac97083838c0a4e1444dcad02a5c3f911e), closes [#1158](https://github.com/kbknapp/clap-rs/issues/1158)) +* Fixes a bug which disallows proper nesting of `--` ([73993fe](https://github.com/kbknapp/clap-rs/commit/73993fe30d135f682e763ec93dcb0814ed518011), closes [#1161](https://github.com/kbknapp/clap-rs/issues/1161)) + +#### New Settings + +* **AllArgsOverrideSelf:** adds a new convenience setting to allow all args to override themselves ([4670325d](https://github.com/kbknapp/clap-rs/commit/4670325d1bf0369addec2ae2bcb56f1be054c924)) + + + ### v2.29.2 (2018-01-16) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 8899cd36e96..50e7235d790 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,85 +1,89 @@ the following is a list of contributors: -[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[little-dude](https://github.com/little-dude) |[sru](https://github.com/sru) | +[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[willmurphyscode](https://github.com/willmurphyscode) |[little-dude](https://github.com/little-dude) | :---: |:---: |:---: |:---: |:---: |:---: | -[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[little-dude](https://github.com/little-dude) |[sru](https://github.com/sru) | +[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[willmurphyscode](https://github.com/willmurphyscode) |[little-dude](https://github.com/little-dude) | -[willmurphyscode](https://github.com/willmurphyscode) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) | +[sru](https://github.com/sru) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) | :---: |:---: |:---: |:---: |:---: |:---: | -[willmurphyscode](https://github.com/willmurphyscode) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) | +[sru](https://github.com/sru) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) | [segevfiner](https://github.com/segevfiner) |[ignatenkobrain](https://github.com/ignatenkobrain) |[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) | :---: |:---: |:---: |:---: |:---: |:---: | [segevfiner](https://github.com/segevfiner) |[ignatenkobrain](https://github.com/ignatenkobrain) |[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) | -[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) |[crazymerlyn](https://github.com/crazymerlyn) | +[discosultan](https://github.com/discosultan) |[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) | :---: |:---: |:---: |:---: |:---: |:---: | -[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) |[crazymerlyn](https://github.com/crazymerlyn) | +[discosultan](https://github.com/discosultan) |[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) | -[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) |[jimmycuadra](https://github.com/jimmycuadra) | +[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) | :---: |:---: |:---: |:---: |:---: |:---: | -[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) |[jimmycuadra](https://github.com/jimmycuadra) | +[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) | -[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) |[frewsxcv](https://github.com/frewsxcv) | +[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) | :---: |:---: |:---: |:---: |:---: |:---: | -[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) |[frewsxcv](https://github.com/frewsxcv) | +[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) | -[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) |[porglezomp](https://github.com/porglezomp) | +[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) | :---: |:---: |:---: |:---: |:---: |:---: | -[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) |[porglezomp](https://github.com/porglezomp) | +[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) | -[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) |[vmchale](https://github.com/vmchale) | +[porglezomp](https://github.com/porglezomp) |[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) | :---: |:---: |:---: |:---: |:---: |:---: | -[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) |[vmchale](https://github.com/vmchale) | +[porglezomp](https://github.com/porglezomp) |[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) | -[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) |[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) | +[vmchale](https://github.com/vmchale) |[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) |[alex-gulyas](https://github.com/alex-gulyas) | :---: |:---: |:---: |:---: |:---: |:---: | -[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) |[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) | +[vmchale](https://github.com/vmchale) |[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) |[alex-gulyas](https://github.com/alex-gulyas) | -[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) |[brennie](https://github.com/brennie) | +[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) | :---: |:---: |:---: |:---: |:---: |:---: | -[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) |[brennie](https://github.com/brennie) | +[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) | -[pixelistik](https://github.com/pixelistik) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) |[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) | +[brennie](https://github.com/brennie) |[pixelistik](https://github.com/pixelistik) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) |[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) | :---: |:---: |:---: |:---: |:---: |:---: | -[pixelistik](https://github.com/pixelistik) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) |[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) | +[brennie](https://github.com/brennie) |[pixelistik](https://github.com/pixelistik) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) |[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) | -[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) |[daboross](https://github.com/daboross) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) | +[brianp](https://github.com/brianp) |[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) |[daboross](https://github.com/daboross) |[da-x](https://github.com/da-x) | :---: |:---: |:---: |:---: |:---: |:---: | -[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) |[daboross](https://github.com/daboross) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) | +[brianp](https://github.com/brianp) |[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) |[daboross](https://github.com/daboross) |[da-x](https://github.com/da-x) | -[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) |[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) | +[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) |[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) | :---: |:---: |:---: |:---: |:---: |:---: | -[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) |[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) | +[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) |[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) | -[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) |[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[discosultan](https://github.com/discosultan) | +[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) |[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) | :---: |:---: |:---: |:---: |:---: |:---: | -[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) |[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[discosultan](https://github.com/discosultan) | +[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) |[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) | -[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) |[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) | +[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) |[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) | :---: |:---: |:---: |:---: |:---: |:---: | -[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) |[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) | +[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) |[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) | -[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) |[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) | +[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) |[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) | :---: |:---: |:---: |:---: |:---: |:---: | -[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) |[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) | +[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) |[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) | -[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) |[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) | +[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) |[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) | :---: |:---: |:---: |:---: |:---: |:---: | -[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) |[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) | +[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) |[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) | -[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) |[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) |[rnelson](https://github.com/rnelson) | +[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) |[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) | :---: |:---: |:---: |:---: |:---: |:---: | -[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) |[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) |[rnelson](https://github.com/rnelson) | +[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) |[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) | -[swatteau](https://github.com/swatteau) |[tspiteri](https://github.com/tspiteri) |[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) | +[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tchajed](https://github.com/tchajed) |[tspiteri](https://github.com/tspiteri) |[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) | :---: |:---: |:---: |:---: |:---: |:---: | -[swatteau](https://github.com/swatteau) |[tspiteri](https://github.com/tspiteri) |[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) | +[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tchajed](https://github.com/tchajed) |[tspiteri](https://github.com/tspiteri) |[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) | -[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) |[kennytm](https://github.com/kennytm) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[ogham](https://github.com/ogham) | +[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) |[kennytm](https://github.com/kennytm) |[mvaude](https://github.com/mvaude) | :---: |:---: |:---: |:---: |:---: |:---: | -[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) |[kennytm](https://github.com/kennytm) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[ogham](https://github.com/ogham) | +[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) |[kennytm](https://github.com/kennytm) |[mvaude](https://github.com/mvaude) | + +[panicbit](https://github.com/panicbit) |[ogham](https://github.com/ogham) | +:---: |:---: | +[panicbit](https://github.com/panicbit) |[ogham](https://github.com/ogham) | diff --git a/Cargo.toml b/Cargo.toml index e2b252115c6..f659c47121b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clap" -version = "2.29.2" +version = "2.29.3" authors = ["Kevin K. "] exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"] repository = "https://github.com/kbknapp/clap-rs" diff --git a/README.md b/README.md index 9601aaf3317..de44e2bb766 100644 --- a/README.md +++ b/README.md @@ -42,25 +42,32 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) ## What's New +Here's whats new in 2.29.3: + +* **Self Overrides:** now supports arguments which override themselves (Allows true shell aliases, config files, etc!) +* **Requirements:** fixes an issue where conflicting args would still show up as required and missing +* Fixes a bug which disallows proper nesting of `--` for args that capture all values after the first `--` +* **AppSettings::AllArgsOverrideSelf:** adds a new convenience setting to allow all args to override themselves + Here's whats new in 2.29.2: * **Many ZSH Completions Improvements** (Thanks to @segevfiner) * Positional arguments will default to file completion when not using specific values! - * Implement postional argument possible values completion - * Removes redundant code from output - * Don't pass `-S` to `_arguments` if Zsh is too old - * Fix completions with mixed positionals and subcommands - * String escape possible values for options + * Implement postional argument possible values completion + * Removes redundant code from output + * Don't pass `-S` to `_arguments` if Zsh is too old + * Fix completions with mixed positionals and subcommands + * String escape possible values for options Here's whats new in 2.29.1: * Debloats clap by deduplicating logic and refactors for a ~57% decrease in code size! This is with zero functinoality lost, and a slight perf increase! -* Change the bash completion script code generation to support hyphens. +* Change the bash completion script code generation to support hyphens. * Fix completion of long option values in ZSH completions * Fixes broken links in docs * Updates contributors list -* Fixes the ripgrep benchmark by adding a value to a flag that expects it +* Fixes the ripgrep benchmark by adding a value to a flag that expects it Here's whats new in 2.29.0: diff --git a/src/app/parser.rs b/src/app/parser.rs index 96d4493e959..29c624d4595 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -251,6 +251,7 @@ where fn add_reqs(&mut self, a: &Arg<'a, 'b>) { if a.is_set(ArgSettings::Required) { // If the arg is required, add all it's requirements to master required list + self.required.push(a.b.name); if let Some(ref areqs) = a.b.requires { for name in areqs .iter() @@ -260,7 +261,6 @@ where self.required.push(name); } } - self.required.push(a.b.name); } } @@ -909,9 +909,15 @@ where } if starts_new_arg { + let check_all = self.is_set(AS::AllArgsOverrideSelf); { let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); - matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all + ); } if arg_os.starts_with(b"--") { @@ -1039,9 +1045,15 @@ where self.settings.set(AS::TrailingValues); } if self.cache.map_or(true, |name| name != p.b.name) { + let check_all = self.is_set(AS::AllArgsOverrideSelf); { let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); - matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all + ); } self.cache = Some(p.b.name); } @@ -1157,9 +1169,15 @@ where } // In case the last arg was new, we need to process it's overrides + let check_all = self.is_set(AS::AllArgsOverrideSelf); { let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); - matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all + ); } self.remove_overrides(matcher); diff --git a/src/app/settings.rs b/src/app/settings.rs index 1b304225ab3..840d77585c5 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -46,6 +46,7 @@ bitflags! { const VALID_ARG_FOUND = 1 << 37; const INFER_SUBCOMMANDS = 1 << 38; const CONTAINS_LAST = 1 << 39; + const ARGS_OVERRIDE_SELF = 1 << 40; } } @@ -75,6 +76,7 @@ impl AppFlags { impl_settings! { AppSettings, ArgRequiredElseHelp => Flags::A_REQUIRED_ELSE_HELP, ArgsNegateSubcommands => Flags::ARGS_NEGATE_SCS, + AllArgsOverrideSelf => Flags::ARGS_OVERRIDE_SELF, AllowExternalSubcommands => Flags::ALLOW_UNK_SC, AllowInvalidUtf8 => Flags::UTF8_NONE, AllowLeadingHyphen => Flags::LEADING_HYPHEN, @@ -165,6 +167,13 @@ pub enum AppSettings { /// [`ArgMatches::lossy_values_of`]: ./struct.ArgMatches.html#method.lossy_values_of AllowInvalidUtf8, + /// Essentially sets [`Arg::overrides_with("itself")`] for all arguments. + /// + /// **WARNING:** Positional arguments cannot override themselves (or we would never be able + /// to advance to the next positional). This setting ignores positional arguments. + /// [`Arg::overrides_with("itself")`]: ./struct.Arg.html#method.overrides_with + AllArgsOverrideSelf, + /// Specifies that leading hyphens are allowed in argument *values*, such as negative numbers /// like `-10`. (which would otherwise be parsed as another flag or option) /// diff --git a/src/app/validator.rs b/src/app/validator.rs index 9751321a149..448a8fc7edb 100644 --- a/src/app/validator.rs +++ b/src/app/validator.rs @@ -36,11 +36,14 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { self.0.add_defaults(matcher)?; if let ParseResult::Opt(a) = needs_val_of { debugln!("Validator::validate: needs_val_of={:?}", a); - let o = self.0 + let o = { + self.0 .opts .iter() .find(|o| o.b.name == a) - .expect(INTERNAL_ERROR_MSG); + .expect(INTERNAL_ERROR_MSG) + .clone() + }; self.validate_required(matcher)?; reqs_validated = true; let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) { @@ -50,7 +53,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { }; if should_err { return Err(Error::empty_value( - o, + &o, &*usage::create_error_usage(self.0, matcher, None), self.0.color(), )); @@ -336,7 +339,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { where A: AnyArg<'a, 'b> + Display, { - debugln!("Validator::validate_arg_num_vals;"); + debugln!("Validator::validate_arg_num_vals:{}", a.name()); if let Some(num) = a.num_vals() { debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num); let should_err = if a.is_set(ArgSettings::Multiple) { @@ -438,20 +441,46 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { Ok(()) } - fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> { + fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> { debugln!( "Validator::validate_required: required={:?};", self.0.required ); - 'outer: for name in &self.0.required { + let mut should_err = false; + let mut to_rem = Vec::new(); + for name in &self.0.required { debugln!("Validator::validate_required:iter:{}:", name); if matcher.contains(name) { - continue 'outer; + continue; } - if let Some(a) = find_any_by_name!(self.0, *name) { + if to_rem.contains(name) { + continue; + } else if let Some(a) = find_any_by_name!(self.0, *name) { if self.is_missing_required_ok(a, matcher) { - continue 'outer; + to_rem.push(a.name()); + if let Some(reqs) = a.requires() { + for r in reqs + .iter() + .filter(|&&(val, _)| val.is_none()) + .map(|&(_, name)| name) + { + to_rem.push(r); + } + } + continue; + } + } + should_err = true; + break; + } + if should_err { + for r in &to_rem { + 'inner: for i in (0 .. self.0.required.len()).rev() { + if &self.0.required[i] == r { + self.0.required.swap_remove(i); + break 'inner; + } } } return self.missing_required_error(matcher, None); diff --git a/src/args/arg.rs b/src/args/arg.rs index bdcd63a5ec4..6cbf3a76612 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -1203,6 +1203,10 @@ impl<'a, 'b> Arg<'a, 'b> { /// **NOTE:** When an argument is overridden it is essentially as if it never was used, any /// conflicts, requirements, etc. are evaluated **after** all "overrides" have been removed /// + /// **WARNING:** Positional arguments cannot override themselves (or we would never be able + /// to advance to the next positional). If a positional agument lists itself as an override, + /// it is simply ignored. + /// /// # Examples /// /// ```rust @@ -1222,6 +1226,74 @@ impl<'a, 'b> Arg<'a, 'b> { /// // was never used because it was overridden with color /// assert!(!m.is_present("flag")); /// ``` + /// Care must be taken when using this setting, and having an arg override with itself. This + /// is common practice when supporting things like shell aliases, config files, etc. + /// However, when combined with multiple values, it can get dicy. + /// Here is how clap handles such situations: + /// + /// When a flag overrides itself, it's as if the flag was only ever used once (essentially + /// preventing a "Unexpected multiple usage" error): + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--flag 'some flag'").overrides_with("flag")) + /// .get_matches_from(vec!["posix", "--flag", "--flag"]); + /// assert!(m.is_present("flag")); + /// assert_eq!(m.occurrences_of("flag"), 1); + /// ``` + /// Making a flag `multiple(true)` and override itself is essentially meaningless. Therefore + /// clap ignores an override of self if it's a flag and it already accepts multiple occurrences. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--flag... 'some flag'").overrides_with("flag")) + /// .get_matches_from(vec!["", "--flag", "--flag", "--flag", "--flag"]); + /// assert!(m.is_present("flag")); + /// assert_eq!(m.occurrences_of("flag"), 4); + /// ``` + /// Now notice with options, it's as if only the last occurrence mattered + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("opt")) + /// .get_matches_from(vec!["", "--opt=some", "--opt=other"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// assert_eq!(m.value_of("opt"), Some("other")); + /// ``` + /// + /// Here is where it gets interesting. If an option is declared as `multiple(true)` and it also + /// overrides with itself, only the last *set* of values will be saved. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val]... 'some option'") + /// .overrides_with("opt")) + /// .get_matches_from(vec!["", "--opt", "first", "over", "--opt", "other", "val"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// assert_eq!(m.values_of("opt").unwrap().collect::>(), &["other", "val"]); + /// ``` + /// + /// A safe thing to do, to ensure there is no confusion is to require an argument delimiter and + /// and only one "value set" per instance of the option. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val]... 'some option'") + /// .overrides_with("opt") + /// .number_of_values(1) + /// .require_delimiter(true)) + /// .get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// assert_eq!(m.values_of("opt").unwrap().collect::>(), &["one", "two"]); + /// ``` pub fn overrides_with(mut self, name: &'a str) -> Self { if let Some(ref mut vec) = self.b.overrides { vec.push(name.as_ref()); diff --git a/src/args/arg_matcher.rs b/src/args/arg_matcher.rs index 25f3fc5d749..16ea79b1312 100644 --- a/src/args/arg_matcher.rs +++ b/src/args/arg_matcher.rs @@ -21,13 +21,17 @@ impl<'a> Default for ArgMatcher<'a> { impl<'a> ArgMatcher<'a> { pub fn new() -> Self { ArgMatcher::default() } - pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>) { + pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>, check_all: bool) { debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name()))); if let Some(aa) = a { + let mut self_done = false; if let Some(a_overrides) = aa.overrides() { for overr in a_overrides { debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr); - if self.is_present(overr) { + if overr == &aa.name() { + self_done = true; + self.handle_self_overrides(a); + } else if self.is_present(overr) { debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing from matches;", overr); self.remove(overr); for i in (0 .. required.len()).rev() { @@ -37,11 +41,38 @@ impl<'a> ArgMatcher<'a> { break; } } + overrides.push((overr, aa.name())); } else { overrides.push((overr, aa.name())); } } } + if check_all && !self_done { + self.handle_self_overrides(a); + } + } + } + + pub fn handle_self_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>) { + debugln!("ArgMatcher::handle_self_overrides:{:?};", a.map_or(None, |a| Some(a.name()))); + if let Some(aa) = a { + if !aa.has_switch() || (!aa.takes_value() && aa.is_set(ArgSettings::Multiple)) { + // positional args can't override self or else we would never advance to the next + + // Also flags with --multiple set are ignored otherwise we could never have more + // than one + return; + } + if let Some(ma) = self.get_mut(aa.name()) { + if ma.vals.len() > 1 { + // swap_remove(0) would be O(1) but does not preserve order, which + // we need + ma.vals.remove(0); + ma.occurs = 1; + } else if !aa.takes_value() && ma.occurs > 1 { + ma.occurs = 1; + } + } } } @@ -143,7 +174,6 @@ impl<'a> ArgMatcher<'a> { occurs: 0, vals: Vec::with_capacity(1), }); - // let len = ma.vals.len() + 1; ma.vals.push(val.to_owned()); } diff --git a/src/lib.rs b/src/lib.rs index 128bd443231..3651344ec4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -513,7 +513,7 @@ //! this repository for more information. #![crate_type = "lib"] -#![doc(html_root_url = "https://docs.rs/clap/2.29.2")] +#![doc(html_root_url = "https://docs.rs/clap/2.29.3")] #![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts, unused_import_braces, unused_allocation)] // Lints we'd like to deny but are currently failing for upstream crates diff --git a/tests/app_settings.rs b/tests/app_settings.rs index 258ebd7025a..cbba0f060ba 100644 --- a/tests/app_settings.rs +++ b/tests/app_settings.rs @@ -668,4 +668,150 @@ fn issue_1093_allow_ext_sc() { .version("v1.4.8") .setting(AppSettings::AllowExternalSubcommands); assert!(test::compare_output(app, "clap-test --help", ALLOW_EXT_SC, false)); +} + +#[test] +fn aaos_flags() { + // flags + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--flag 'some flag'")) + .get_matches_from_safe(vec!["", "--flag", "--flag"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 1); +} + +#[test] +fn aaos_flags_mult() { + // flags with multiple + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--flag... 'some flag'")) + .get_matches_from_safe(vec!["", "--flag", "--flag", "--flag", "--flag"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 4); +} + +#[test] +fn aaos_opts() { + // opts + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'")) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.value_of("opt"), Some("other")); +} + +#[test] +fn aaos_opts_w_other_overrides() { + // opts with other overrides + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'")) + .arg(Arg::from_usage("--other [val] 'some other option'").overrides_with("opt")) + .get_matches_from_safe(vec!["", "--opt=some", "--other=test", "--opt=other"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert!(!m.is_present("other")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.value_of("opt"), Some("other")); +} + +#[test] +fn aaos_opts_w_other_overrides_rev() { + // opts with other overrides, rev + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'")) + .arg(Arg::from_usage("--other [val] 'some other option'").overrides_with("opt")) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--other=val"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(!m.is_present("opt")); + assert!(m.is_present("other")); + assert_eq!(m.value_of("other"), Some("val")); +} + +#[test] +fn aaos_opts_w_other_overrides_2() { + // opts with other overrides + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("other")) + .arg(Arg::from_usage("--other [val] 'some other option'")) + .get_matches_from_safe(vec!["", "--opt=some", "--other=test", "--opt=other"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert!(!m.is_present("other")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.value_of("opt"), Some("other")); +} + +#[test] +fn aaos_opts_w_other_overrides_rev_2() { + // opts with other overrides, rev + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("other")) + .arg(Arg::from_usage("--other [val] 'some other option'")) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--other=val"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(!m.is_present("opt")); + assert!(m.is_present("other")); + assert_eq!(m.value_of("other"), Some("val")); +} + +#[test] +fn aaos_opts_mult() { + // opts with multiple + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val]... 'some option'") + .number_of_values(1) + .require_delimiter(true)) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.values_of("opt").unwrap().collect::>(), &["one", "two"]); +} + +#[test] +fn aaos_opts_mult_req_delims() { + // opts with multiple and require delims + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val]... 'some option'")) + .get_matches_from_safe(vec!["", "--opt", "first", "overides", "--opt", "some", "other", "val"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.values_of("opt").unwrap().collect::>(), &["some", "other", "val"]); +} + +#[test] +fn aaos_pos_mult() { + // opts with multiple + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("[val]... 'some pos'")) + .get_matches_from_safe(vec!["", "some", "other", "value"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("val")); + assert_eq!(m.occurrences_of("val"), 3); + assert_eq!(m.values_of("val").unwrap().collect::>(), &["some", "other", "value"]); } \ No newline at end of file diff --git a/tests/posix_compatible.rs b/tests/posix_compatible.rs index 83f14481239..0a790c2cb87 100644 --- a/tests/posix_compatible.rs +++ b/tests/posix_compatible.rs @@ -2,6 +2,81 @@ extern crate clap; use clap::{App, Arg, ErrorKind}; +#[test] +fn flag_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--flag 'some flag'").overrides_with("flag")) + .get_matches_from_safe(vec!["", "--flag", "--flag"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 1); +} + +#[test] +fn mult_flag_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--flag... 'some flag'").overrides_with("flag")) + .get_matches_from_safe(vec!["", "--flag", "--flag", "--flag", "--flag"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 4); +} + +#[test] +fn option_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("opt")) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.value_of("opt"), Some("other")); +} + +#[test] +fn mult_option_require_delim_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--opt [val]... 'some option'") + .overrides_with("opt") + .number_of_values(1) + .require_delimiter(true)) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.values_of("opt").unwrap().collect::>(), &["one", "two"]); +} + +#[test] +fn mult_option_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--opt [val]... 'some option'") + .overrides_with("opt")) + .get_matches_from_safe(vec!["", "--opt", "first", "overides", "--opt", "some", "other", "val"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.values_of("opt").unwrap().collect::>(), &["some", "other", "val"]); +} + +#[test] +fn aaos_pos_mult() { + // opts with multiple + let res = App::new("posix") + .arg(Arg::from_usage("[val]... 'some pos'").overrides_with("val")) + .get_matches_from_safe(vec!["", "some", "other", "value"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("val")); + assert_eq!(m.occurrences_of("val"), 3); + assert_eq!(m.values_of("val").unwrap().collect::>(), &["some", "other", "value"]); +} + #[test] fn posix_compatible_flags_long() { let m = App::new("posix") diff --git a/tests/require.rs b/tests/require.rs index 5dbf2dc17ed..a0a658eaa57 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -30,6 +30,51 @@ USAGE: For more information try --help"; +static ISSUE_1158: &'static str = "error: The following required arguments were not provided: + -x + -y + -z + +USAGE: + example [OPTIONS] -x -y -z + +For more information try --help"; + +#[test] +fn issue_1158_conflicting_requirements() { + let app = App::new("example") + .arg(Arg::from_usage("-c, --config [FILE] 'Custom config file.'") + .required_unless("ID") + .conflicts_with("ID")) + .arg(Arg::from_usage("[ID] 'ID'") + .required_unless("config") + .conflicts_with("config") + .requires_all(&["x", "y", "z"])) + .arg(Arg::from_usage("-x [X] 'X'")) + .arg(Arg::from_usage("-y [Y] 'Y'")) + .arg(Arg::from_usage("-z [Z] 'Z'")); + + assert!(test::compare_output(app, "example id", ISSUE_1158, true)); +} + +#[test] +fn issue_1158_conflicting_requirements_rev() { + let res = App::new("example") + .arg(Arg::from_usage("-c, --config [FILE] 'Custom config file.'") + .required_unless("ID") + .conflicts_with("ID")) + .arg(Arg::from_usage("[ID] 'ID'") + .required_unless("config") + .conflicts_with("config") + .requires_all(&["x", "y", "z"])) + .arg(Arg::from_usage("-x [X] 'X'")) + .arg(Arg::from_usage("-y [Y] 'Y'")) + .arg(Arg::from_usage("-z [Z] 'Z'")) + .get_matches_from_safe(vec!["example", "--config", "some"]); + + assert!(res.is_ok()); +} + #[test] fn flag_required() { let result = App::new("flag_required")