-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Join multiple paths in one call to Join-Path #2014
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Hi @dlwyatt, I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution! The agreement was validated by Microsoft and real humans are currently evaluating your PR. TTYL, MSBOT; |
| [AllowEmptyString] | ||
| public string ChildPath { get; set; } = String.Empty; | ||
| [AllowEmptyCollection] | ||
| public string[] ChildPath { get; set; } = new string[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To help GC a little, we use Utils.EmptyArray<string>() so we can share empty arrays.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that changing the type on a public API is normally considered a breaking change.
That said, cmdlets are too hard to use as an API, so it's unlikely to break anybody.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured that PowerShell will happily bind a string to a string[] parameter anyway, so no harm done. :) (Unless someone's using the cmdlet directly in C#,but that seems unlikely.)
On Aug 22, 2016, at 11:16 AM, Jason Shirk notifications@github.com wrote:
In src/Microsoft.PowerShell.Commands.Management/commands/management/CombinePathCommand.cs:
[AllowNull] [AllowEmptyString]
public string ChildPath { get; set; } = String.Empty;[AllowEmptyCollection] Note that changing the type on a public API is normally considered a breaking change.public string[] ChildPath { get; set; } = new string[0];That said, cmdlets are too hard to use as an API, so it's unlikely to break anybody.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Unless someone's using the cmdlet directly in C#,but that seems unlikely
Yeah, unlikely for this cmdlet, given it would be easier to use Path.Combine() from C#. PS. Nice enhancement!
|
We have a tool to update the workflow activity files that we run periodically so that you don't need to worry about it every time you add a new parameter to a cmdlet. |
|
Travis CI build blew up, not sure why. |
|
We've discussed this PR some internally, here is a summary - just points for discussion at this point.
|
True. The output from
Not sure I understand this one. Did you mean Personally, I like having Join-Path one two three,four,five
# versus
Join-Path one two three four fiveI think the second syntax looks much nicer (and less error prone), but even if I had to go with the first option, it would still be useful. |
|
No, I meant what I wrote - try it: #57 PS> & {
>> param(
>> [string[]]
>> [Parameter(Position=0)]
>> $Path,
>>
>> [string[]]
>> [Parameter(Position=1, ValueFromRemainingArguments)]
>> $Extra)
>> $Extra.Count;
>> $Extra | % { "arg: $_"}
>> } root aa,bb
1
arg: aa bbI do think your example is fine w/ no commas, but folks do learn to use commas, and sometimes it's surprising. This isn't specific to your usage, it applies to |
|
That doesn't make any sense. Seems like a bug in the parameter binder to me. It shouldn't matter whether you pass remaining arguments or an explicit array, both should wind up with identical values in the command.
|
|
Interestingly, this problem doesn't affect cmdlets, just PowerShell functions: & {
param(
[string[]]
[Parameter(Position=0)]
$Path,
[string[]]
[Parameter(Position=1, ValueFromRemainingArguments)]
$Extra)
$Extra.Count;
for ($i = 0; $i -lt $Extra.Count; $i++)
{
"${i}: $($Extra[$i])"
}
} root aa,bb
<#
1
0: aa bb
#>
Add-Type -OutputAssembly $env:temp\testBinding.dll -TypeDefinition @'
using System;
using System.Management.Automation;
[Cmdlet("Test", "Binding")]
public class TestBindingCommand : PSCmdlet
{
[Parameter(Position = 0)]
public string Root { get; set; }
[Parameter(Position = 1, ValueFromRemainingArguments = true)]
public string[] Extra { get; set; }
protected override void ProcessRecord()
{
WriteObject(Extra.Length);
for (int i = 0; i < Extra.Length; i++)
{
WriteObject(String.Format("{0}: {1}", i, Extra[i]));
}
}
}
'@
Import-Module $env:temp\testBinding.dll
Test-Binding root aa,bb
<#
2
0: aa
1: bb
#> |
|
Logged issue #2035 for the different binding behavior between cmdlets and functions. |
|
Binding bug should be fixed in #2038 . |
|
Now that the binder thing is sorted out (even if the other PR isn't accepted due to being classified as a breaking change, it doesn't affect the Join-Path cmdlet anyway), looking back at this one. Would you prefer to change If so, what's your preference for behavior if someone passes arguments to the new parameter, but
Come to think of it, the same question applies if someone passes empty strings at any point in the new parameter. Ignore them, or have some doubled separators in the output? |
|
👍 I really like this @dlwyatt! This style is similar to ruby's |
|
Regarding $null entries - it seems like it should be an a terminating error. Note that PS> 'a','b' | Join-Path -ChildPath c
a\c
b\cAnd $null results in a non-terminating error. That said, if there are any |
|
For whatever reason, I'm leaning toward ignoring empty values unless they're at the end of the list, in which case we'll go ahead and tack on a trailing separator to keep behavior consistent with today. |
|
Well, I can't say I like it, but it's at least consistent with string.Join: |
|
True, but the benefit of Join-Path is that you don't have dumb logic like that. It looks to see if either of the strings have leading / trailing separators already so it doesn't double them up. :) |
|
In fact, that's how |
|
As discussed, moved new code to a new parameter. Didn't bother putting a default value back on ChildPath since it's mandatory anyway. |
|
Closed via 22aac12 - I deleted a blank line between the comments and a property. |
Now that we've got cross-platform PowerShell, this is a quality of life improvement for script authors who want to make code compatible across Windows and Linux. In the current implementation (on Windows), if you want to join paths multiple levels deep, you'd do this:
Since you knew what the entire child path needed to be, there was no need for "join" logic there. Now, we'd prefer to see a path completely built up with the proper directory separator character for the platform. That would have looked something like this mess:
With this PR, it becomes much more pleasant:
Question for the team: do I need to update JoinPathActivity.cs in this PR to reflect the new
string[]parameter type as well, or do those workflow activity files get automatically regenerated later?