Skip to content
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

(#310) Uninstall-ChocolateyPath #1019

Closed
wants to merge 1 commit into from
Closed

(#310) Uninstall-ChocolateyPath #1019

wants to merge 1 commit into from

Conversation

DarwinJS
Copy link
Contributor

@DarwinJS DarwinJS commented Oct 15, 2016

I would like feedback on whether to incorporate any of these features:

  • DONE: Awarn that the path also exists in the opposite scope (User or Machine) - but don't process the removal from the non-requested scope
  • DONE: allow a special scope option 'All' which removes the path from both scopes (User and Machine) in one pass

Closes #310

@@ -0,0 +1,117 @@
# Copyright 2011 - Present RealDimensions Software, LLC & original authors/contributors from https://github.com/chocolatey/chocolatey
Copy link
Member

Choose a reason for hiding this comment

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

Not that you would have known this, but this won't carry the second part of the copyright as this didn't come from the old code base.

Write-Output "Only evaluating and updating path scope `"$pathType`", path will not be assessed nor removed for other scope, so path may exist in other scope as well."
$originalPathToUninstall = $PathToUninstall
#First half on handling trailing slash properly - remove it from requested path:
$PathToUninstall = $PathToUninstall.trimend('\')
Copy link
Member

Choose a reason for hiding this comment

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

What is trimend and is it available in PowerShell v2+ (and thus .NET Framework 2.0+)?

[parameter(ValueFromRemainingArguments = $true)][Object[]] $ignoredArguments
)
Write-Debug "Running 'Uninstall-ChocolateyPath' with PathToUninstall:`'$PathToUninstall`'";
Write-Output "Only evaluating and updating path scope `"$pathType`", path will not be assessed nor removed for other scope, so path may exist in other scope as well."
Copy link
Member

@ferventcoder ferventcoder Oct 15, 2016

Choose a reason for hiding this comment

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

I know it is widely believed that Write-Host is wrong, and it is under most circumstances. When it comes to logging, we prefer Write-Host in the Chocolatey installer module. It doesn't cause issues when you want to return actual things (Write-Output will return things to the pipeline). So please convert these to Write-Host.

Yes, I am familiar with http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/:

  • The blog post appears to be about scripts (or modules) that could be used by other tools. This module is used for Chocolatey, so it is the end consumer of its own module.
  • Write-Output ends up in the pipeline (aka is part of the return value from the function). This can have (and has had) disastrous results, so we prefer Write-Host. I prefer real life examples to rhetoric, so 44306ef
  • We control the hosts this runs under.
  • We simply want logging messages.

Consider Write-Output == Log.Info() and Write-Host == Log.Info() for the Chocolatey framework.
Yes, I realize this means we should have probably set up a logging utility. We could go on all day long about how we should have brought in an actual logging facility like log4net, but honestly all of that work to provide what Write-Host already provides seems non-beneficial.

@ferventcoder
Copy link
Member

allow a special scope option 'All' which removes the path from both scopes (User and Machine) in one pass

I like it!

@ferventcoder
Copy link
Member

warn that the path also exists in the opposite scope (User or Machine) - but don't process the removal from the non-requested scope

Also like it. And you could also provide that there is an "ALL" option as part of the warning.

@ferventcoder ferventcoder changed the title Issue310 (GH-310) Uninstall-ChocolateyPath Oct 15, 2016
@DarwinJS
Copy link
Contributor Author

DarwinJS commented Oct 17, 2016

OK - the combination of: [1] Always logging which scopes the path appears in (even if not the one being changed) and [2] Supporting the recursion of the function to switch to admin rights if possible and [3] allow use of -pathToUninstall 'All' - resulted in a very different code structure.

}
Else
{
Throw "Something is wrong as I did not get admin rights on the recursive call and was about to go into a recursive loop. (Recursive loops make the Chocolatey gods dizzy.)"
Copy link
Member

Choose a reason for hiding this comment

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

Leave Chocolatey gods references out. It sends the wrong message to some folks. And I should remove the one that is in there about pushing to non-secure urls from Chocolatey. I know it is fun, but some folks take offense to this.

Also, no messages in the first person.

`-PathType 'Machine'`.

This is used when the application/tool is not being linked by Chocolatey
(not in the lib folder).
Copy link
Member

Choose a reason for hiding this comment

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

I will also need to update this to indicate first supported version of Chocolatey this is in.

Modified to Check for -pathToUninstall in all scopes and to support scope option 'All'

Handles multiple occurances of path, promiscuous handling of trailing slash (just does the right thing whether or not pathToUninstall or embedded path do or do not have trailing slash)
@DarwinJS
Copy link
Contributor Author

Ok - choco gods reference removed and corrected error in first person.

I am having a hard time discovering whether .trimend is available in PSH 2 via research.

I have temporarily lost access to my Windows 7 VMs because they were in Hyper-V and after Windows 10 Anniversary update I cannot have both Virtual Box AND Hyper-V INSTALLED at the same time. Before Anniversary Update both could be installed, but not active at once. I don't have any VMs with PSH 2 on Virtual Box yet and it would be a bit of fusing to reinstall hyper-V and then deinstall when done.

@DarwinJS
Copy link
Contributor Author

I was able to test to be sure that ".trimend" is available as a string method on PSH 2.0

@jberezanski
Copy link

FWIW, System.String.TrimEnd(char[]) is available at least since .NET 1.1 (that's as far back as MSDN docs go).

@DarwinJS
Copy link
Contributor Author

@jberezanski - thanks for the research on that!

@dragon788
Copy link
Contributor

Looking forward to this, was just taking a whack at implementing this within an individual package similar to one on the linked issues that DarwinJS had mentioned. Nothing drives me nuts more than clutter in the PATH that leads to aberrant behavior.

@dragon788
Copy link
Contributor

Since I needed to remove multiple entries from the PATH and I didn't want to loop over the list multiple times, I improved a little bit on your workaround on ec2clitools.

@DarwinJS perhaps a similar "optimization" could be useful here? Since multiple foreach loops is rough, I opted to use the regex array comparison outlined http://masteringposh.com/powershell-script-multiple-array-comparisons-using-regular-expressions/ and ended up with the code below.

[regex] $PathsToRemove = "^(%NVM_HOME%|%NVM_SYMLINK%)"
$environmentPath = [Environment]::GetEnvironmentVariable("PATH","Machine")
[string[]]$newpath = ''
foreach ($path in $environmentPath.split(';'))
{
  If (($path) -and ($path -notmatch $PathsToRemove))
    {
        [string[]]$newpath += "$path"
        "$path added to `$newpath"
    } else {
        "Bad path found: $path"
    }
}
$AssembledNewPath = ($newpath -join(';')).trimend(';')

[Environment]::SetEnvironmentVariable("PATH",$AssembledNewPath,"Machine")

@DarwinJS
Copy link
Contributor Author

DarwinJS commented Nov 1, 2016

@dragon788 -

  • I believe multiple path removal would be an edge case.
  • Not sure what would be rough about it as it's likely milliseconds of time among a much longer wait - you could just call the function twice.
  • the above does not seem to handle the trailing slash?

If multiple paths is deemed as a requirement, I would probably just make the function capable of receiving pipelined input then you could do this:
@('%NVM_HOME%','%NVM_SYMLINK%') | Uninstall-ChocolateyPath

Here is a brief article on why taking the pipeline approach can be very powerful: http://csi-windows.com/blog/all/74-powershell/438-paradigm-shift-the-power-of-functions-that-take-pipelined-input

I definitely wouldn't want have end consumers of the function have to remember that they are using a regex when it seems they won't need that most of the time.

@ferventcoder - what do you think about multiple path support with a pipeline capable function?

@dragon788
Copy link
Contributor

That's pretty awesome, and I definitely agree that multiple values in the path are unlikely. Hopefully most packages are following the single responsibility principle and keeping things grouped together, I just tend to hit corner cases (Nvm for Windows that manages node versions via symlinks in Program Files but also needs awareness of itself and it's location).

@DarwinJS
Copy link
Contributor Author

DarwinJS commented Nov 1, 2016

Another really cool thing is that the user of the function never needs to even know that the function can take pipelined input when using it with a single value. So the predominant use case is natural and the advanced use case requires a little more discovery if you're willing to do it.

@ferventcoder
Copy link
Member

multiple path support with a pipeline capable function?

Could be interesting. For first pass implementation, it doesn't cost much to loop over path information multiple times. So perhaps a new enhancement issue for this one?

$PathToUninstall = $PathToUninstall.trimend('\')
#array drops blanks (one of which is always created by final semi-colon)
$actualPathArrayUser = (Get-EnvironmentVariable -Name 'Path' -Scope 'user' -PreserveVariables).split(';',[System.StringSplitOptions]::RemoveEmptyEntries)
$actualPathArrayMachine = (Get-EnvironmentVariable -Name 'Path' -Scope 'machine' -PreserveVariables).split(';',[System.StringSplitOptions]::RemoveEmptyEntries)
Copy link

Choose a reason for hiding this comment

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

We're going to have to do something a little smarter since apparently semicolons can be escaped using quotes. Too bad there isn't a Windows API for this.

Reassembling the path will have to follow the same procedure in reverse.

Copy link

@jnm2 jnm2 Jan 27, 2018

Choose a reason for hiding this comment

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

Confirmed using Windows' environment variable list editor: a tl;dr entry causes ;"tl;dr"; to be added to the path. (Luckily a path can't contain ".)

Copy link

Choose a reason for hiding this comment

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

Also, the path needs to be recognized and removed even if it is quoted in the PATH variable. I assume the input path would never be quoted.

Copy link
Member

Choose a reason for hiding this comment

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

So luckily PATH doesn't have " and it doesn't have escaped ; - if you make it have ", it doesn't like you anymore IIRC.

Copy link
Member

Choose a reason for hiding this comment

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

Am I understanding that a semi-colon is allowed in a folder name???!!!

Copy link
Member

Choose a reason for hiding this comment

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

I just died a little inside. 👎

@jnm2
Copy link

jnm2 commented Jan 27, 2018

@DarwinJS @ferventcoder I would really like to see this in Chocolatey. Can I do anything to help? I might start on a proof of concept for both Install- and Uninstall-ChocolateyPath which properly understands quoted paths when looking for existing paths or inserting a new path just to unblock my own package. Would be happier getting them in Chocolatey sooner though!

@DarwinJS
Copy link
Contributor Author

@jnm2 - feel free to take this over. Handling quotes seems like a very rare case - maybe consider getting this merged and then do that as a new PR?

@jnm2
Copy link

jnm2 commented Feb 8, 2018

@DarwinJS Thank you.

This was the direction I was hoping we might go towards. It tries to make the uninstall work as symmetrically as possible with the install and leave a minimal footprint.

Can we do this? What would the next step be? /cc @ferventcoder

@jnm2
Copy link

jnm2 commented Feb 9, 2018

Here's the branch with the Un/install-ChocolateyPath pair which respect semicolons: master...jnm2:env_path_uninstall
I put in comments explaining why it is done that way. What do you guys think of this approach?

@jnm2
Copy link

jnm2 commented Jun 29, 2018

Hey @gep13, Rob said I should tag you for the two comments above. I'd like to help out and I have a proof of concept that deals with all the edge cases I know of, but I'm not sure if I should start a new PR?

@FranklinYu
Copy link
Contributor

Any news? Shall we start reviewing @jnm2’s branch?

@jnm2
Copy link

jnm2 commented Oct 17, 2018

@FranklinYu I haven't heard anything from anyone about this, so I went ahead: #1663

@CLAassistant
Copy link

CLAassistant commented Jun 8, 2020

CLA assistant check
All committers have signed the CLA.

@ferventcoder
Copy link
Member

This may be superseded with @jnm2 's changes.

@gep13 gep13 changed the title (GH-310) Uninstall-ChocolateyPath (#310) Uninstall-ChocolateyPath Oct 15, 2021
@vexx32
Copy link
Member

vexx32 commented Apr 19, 2024

Apologies for the long wait on this PR. This is being added as part of a larger scope of work involving some rewrites that will be submitted soon, so for now we'll close this PR.

Thank you very much for the contribution! 💜

@vexx32 vexx32 closed this Apr 19, 2024
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.

Add Uninstall-ChocolateyPath function to manage removing entries from PATH
8 participants