Skip to content

Enable path globbing for native commands - #2325

Closed
Andy Jordan (andyleejordan) wants to merge 2 commits into
PowerShell:masterfrom
andyleejordan:globbing
Closed

Andy Jordan (andyleejordan) wants to merge 2 commits into
PowerShell:masterfrom
andyleejordan:globbing

Conversation

@andyleejordan

@andyleejordan Andy Jordan (andyleejordan) commented Sep 20, 2016 •

Copy link
Copy Markdown
Member
  • Resolves Implement shell globbing #954
  • Still need tests
  • Need to update known issues
  • Need to fix globbing to have unix semantics:
    • expand hidden (.dotfile) directories
    • return relative (not absolute) paths
  • Need to file issue about escape characters

Enable path globbing for native commands.

E.g. ls *.md expands to ls /path/to/README.md /path/to/CHANGELOG.md

If expansion fails, the argument is sent literally, so ls foo* results in /usr/bin/ls: cannot access foo*: No such file or directory.

Don't glob expand if the verbatim marker was used. So ls --% * fails with /bin/ls: cannot access '*': No such file or directory

Same caveats as #1639; but the code is enabled only on *nix platforms, and the failing test is fixed.

@msftclas

Hi Andy Jordan (@andschwa), I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution!


It looks like you're a Microsoft contributor (Andy Schwartzmeyer). If you're full-time, we DON'T require a Contribution License Agreement. If you are a vendor, please DO sign the electronic Contribution License Agreement. It will take 2 minutes and there's no faxing! https://cla.microsoft.com.

TTYL, MSBOT;

@andyleejordan

Copy link
Copy Markdown
Member Author

Jeffery's great. The problem with ls .git* and other .dotfiles is that the globbing semantics by default ignore hidden directories. This isn't a problem with Get-ChildItem because it can be passed -Hidden; but for globbing on *nix, I'll add a set of semantics to the globber to include hidden files (and return relative instead of absolute paths).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can avoid a memory allocation that is thrown away in a common case by initializing with null instead.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is worth some discussion - I think we'll actually want to add escaping to globbing instead of this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I agree escaping is the better way to go, I think that not only can it be done separately, it really needs to be done separately as it's a much much larger change (and would affect many more systems, as this is the same globbing system used by cmdlets).

@vors sergei (vors) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should talk about the overall approach in more details

@vors sergei (vors) Sep 21, 2016 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that we should provide some way to control it and not tide it to the platform. We can have different defaults on different platforms.

But the problem come with cross-platform tools (i.e. git). It would be pretty unfun to get inconsistent behavior on different platforms.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jason Shirk (@lzybkr) wanted it tied to the platform in #1639. Do you want something in addition to --% to disable globbing?

I agree, inconsistent behavior isn't fun. But this is what I'm operating off:

At a minimum, I think we can't do globbing on Windows at all - Windows tools implement globbing themselves, so even if we did something, it might work differently than the tool we're calling.

So Windows versus Linux tools are already introducing inconsistent behavior regardless of us.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said, the motivation example are tools that exists on both platforms, like git, gcc and so on.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and they appear to already operate differently. Investigating:

Git

PS C:\Users\andrew\src\test> ls


    Directory: C:\Users\andrew\src\test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        9/22/2016  10:42 AM              0 foo
-a----        9/22/2016  10:42 AM              0 foobar
-a----        9/22/2016  10:42 AM              0 foobaz
-a----        9/22/2016  10:42 AM              0 foobil
-a----        9/22/2016  10:42 AM              0 foocod


PS C:\Users\andrew\src\test> git add foo*
PS C:\Users\andrew\src\test> git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   foo
        new file:   foobar
        new file:   foobaz
        new file:   foobil
        new file:   foocod

It did the same with PowerShell on Linux without these changes; so it globs itself on both platforms. That said, Bash definitely glob expands and it works just fine.

GCC

On Linux without these changes:

~/test |-/ ls                                                                                                                                             
foobar.c  foobaz.c  foobil.c  foo.c  foocod.c
~/test |-/ gcc *.c                                                                                                                                        
gcc: error: *.c: No such file or directory
gcc: fatal error: no input files
compilation terminated.

But with GCC through MinGW (i.e. not Cygwin) on Windows, GCC globs:

PS C:\Users\andrew\src\test> ls


    Directory: C:\Users\andrew\src\test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        9/22/2016  11:07 AM              0 foo.c
-a----        9/22/2016  11:07 AM              0 foobar.c
-a----        9/22/2016  11:07 AM              0 foobaz.c
-a----        9/22/2016  11:07 AM              0 foobil.c
-a----        9/22/2016  11:07 AM              0 foocod.c


PS C:\Users\andrew\src\test> C:\MinGW\bin\gcc.exe *.c
PS C:\Users\andrew\src\test>
PS C:\Users\andrew\src\test> C:\MinGW\bin\gcc.exe *.blah
gcc.exe: error: *.blah: Invalid argument
gcc.exe: fatal error: no input files
compilation terminated.

We can't test everything, but so far Jason Shirk (@lzybkr) appears right, and tools built for Windows (even cross-platform ones like Git and GCC) don't expect globbing to be done for them, and so do it themselves.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the detailed info!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't get why globbing place any role here. There is no *, so it should not alternate the arguments that are passed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ is also a wildcard character.

@andyleejordan Andy Jordan (andyleejordan) Sep 22, 2016 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And was previously discovered by Jason Shirk (@lzybkr), the :: is being interpreted as a filesystem provider separator.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The meaning of :: as file path separator should not anyhow trigger globbing resolving. The [ makes more sense, I think the explanation comment above needs correction.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I agree; but it's what's happening:

> & $powershell 2>&1 -noprofile -command '[Console]::Error.Write(\"foo`n`nbar`n`nbaz\");' 
Cannot find a provider with the name '[Console]'.
At line:1 char:1
+ & $powershell 2>&1 -noprofile -command '[Console]::Error.Write(\"foo` ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: ([Console]:String) [], ProviderNotFoundException
    + FullyQualifiedErrorId : ProviderNotFound

@andyleejordan Andy Jordan (andyleejordan) Sep 22, 2016 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where I could really use some help, is there a better globber to use inside of PowerShell than this:

context.LocationGlobber.GetGlobbedProviderPathsFromMonadPath

It sure seemed correct; but I have minimal context.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(By the way, if you do the non-sensical test of:

~ |-/ dir '[Console]::Error.Write(\"foo`n`nbar`n`nbaz\");'                                                                                                
dir : Cannot find a provider with the name '[Console]'.
At line:1 char:1
+ dir '[Console]::Error.Write(\"foo`n`nbar`n`nbaz\");'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: ([Console]:String) [Get-ChildItem], ProviderNotFoundException
    + FullyQualifiedErrorId : ProviderNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

the same problem happens due to globbing. This is just a weird scenario because we're passing non-path data to a native command, but now glob arguments to native commands; and in this case we don't want to do that, so use verbatim.)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If expansion fails, the argument is sent literally, so ls foo* results in /usr/bin/ls: cannot access foo*: No such file or directory.

Same should be applied here: if expansion failed due to provider error, the argument should be passed literally.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, yes I agree. Will fix.

@andyleejordan

Copy link
Copy Markdown
Member Author

I think we should talk about the overall approach in more details

sergei (@vors) Sure, please do. What ideas do you have? My approach was to plumb PowerShell's existing globbing logic into the native command parameter parser; minimum work and reuses logic to be consistent.

@vors

sergei (vors) commented Sep 22, 2016 •

Copy link
Copy Markdown
Collaborator

Andy Jordan (@andschwa) I was mostly referring to UX and scripts portability, not the implementation. My concerns are in the single-line comments above.

@vors

Copy link
Copy Markdown
Collaborator

Hm, still getting used to GitHub reviews. I tried to remove my "change needed" mark, but the only way I found was to turn it into "approved". Now I don't see a way to recall it.

E.g. `ls *.md` expands to `ls /path/to/README.md /path/to/CHANGELOG.md`

If expansion fails, the argument is sent literally, so `ls foo*` results
in `/usr/bin/ls: cannot access foo*: No such file or directory`.

Don't glob expand if the verbatim marker was used.
@vors

Copy link
Copy Markdown
Collaborator

Per commitie decision we should revisit this work item.

Jason Shirk (@lzybkr) proposed an implementation that would just call glob(3) lib function. From glancing at the current version of the code, it seems that it could modified to this with minimal changes. All changes would be localized in native command binder.

@andyleejordan

Copy link
Copy Markdown
Member Author

sergei (@vors) just read through the decision, it looks like a solid plan to me. I think we can close this PR, but feel free to reuse any portions of course.

@iSazonov Ilya (iSazonov) removed the Review - Needed The PR is being reviewed label Mar 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement shell globbing

7 participants