-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Fix problems with application path and installation directory resolution #951
Conversation
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.
Looks good!
I just left a bit of feedback that is hopefully helpful and constructive.
b = Path.GetFullPath(b); | ||
|
||
// Note: we do not resolve or handle symlinks on Windows | ||
// because they require administrator permissions to even create! |
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.
That's not true on Windows 10 in Developer Mode, though.
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.
But until there's enough of the world on a version of Windows where you don't need admin to create a symlink, then it's not worth our time supporting symlinks at all in Windows, IMO.
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.
We do not have any reliable indicator in Git for Windows as to how many users run in Developer Mode and use symlinks, but there have been enough complaints that we had to implement patches to support that (git-for-windows/git@9086edc, git-for-windows/build-extra@e6085cb, just to name two).
So I do not believe that the fraction of symlink/Developer Mode users is actually small.
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.
But how many people are going to be installing and configuring standalone GCM via a symlink? :-)
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.
Thanks for the context however on symlink usage for G4W 👍
// (how we were launched), so let's now try to extract the | ||
// fully resolved executable path from /proc/self/exe. | ||
// Note that this means we may miss if we've been invoked | ||
// via a symlink, but it's better than nothing at this point! |
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'll play devil's advocate here for a moment: why do we need the absolute path? Is the purpose of this functionality not to determine whether the program was called via the git-credential-manager-core
symlink?
If that is the case, using /proc/self/exe
won't give us what we need because it already points to the resolved path of the actual executable, not to the symlink.
And if that is the case, we actually do not need the absolute path at all, right? If we see that argv[0]
is git-credential-manager-core
(without any slash, i.e. not an absolute nor a relative path), we know that we want to warn, right?
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'll play devil's advocate here for a moment: why do we need the absolute path? Is the purpose of this functionality not to determine whether the program was called via the git-credential-manager-core symlink?
The path here is used for two things.. one is indeed the -core
rename warning, but the other, more important one is for the git-credential-manager configure
command.
We want to use the invoked name (absolute) for the credential.helper
value.
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.
Okay, that makes sense. I do suspect, though, that we need to look at argv[0]
instead of /proc/self/exe
for that -core
rename warning.
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.
Indeed we will. But since this is just a warning, and there may be some cases where argv[0]
is missing/empty, we can fall-back on /proc/self/exe
to get a valid(*) path to the real executable for the more important (un)configure
command usage.
(*) unless someone deletes us before we read this link of course 🤡
Replace netstandard2.0 where possible with net6.0, or dual target net6.0 and net472 for projects that are included on Windows.
fac3f47
to
b375ff6
Compare
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.
Great work! ⭐ This was really nice to review - the code is very clean and easy to follow.
There is a systematic bug in all the IFileSystem implementations in that we were incorrectly calling `Path.GetFileName` rather than `Path.GetFullPath`, meaning we're only comparing the file _names_ of two paths for equality! Fix this. For Mac and Linux we also handle symlinks (or firmlinks) by now using the .NET APIs to resolve links. On .NET Framework we don't do anything.
Introduce a new property on the ICommandContext that represents the GCM installation directory, separate from the application executable path. The app executable is not always found in the installation directory if the app exe path is a symlink (or we're a .NET tool where the AppHost is outside of the tool store).
Our previous implementation of getting the native argv[0] was flawed on Linux and Mac. The Mac `_NSArgv` and Linux `/proc/self/cmdline` function/proc-file return the raw argv[0] which may not be an absolute or rooted path, but we expected this to be the same. Additionally, the logic of appending the CWD to the argv[0] value when the latter wasn't rooted was also just wrong! Update to now use `_NSExecutablePath` on macOS, which always returns the full absolute path, and add correct handling of unrooted argv[0] on Linux. Furthermore, on Linux, if we are unable to handle the value from /proc/self/cmdline, we fall back to resolving the /proc/self/exe symlink instead.
Moving to target .NET 6 directly with the core library has unearthed a bug/warning in the secret service implementation. IntPtr is a value type, so it can never be null.. we should have been comparing this pointer to `IntPtr.Zero`.
b375ff6
to
322ef98
Compare
When we introduced the rename warning in #551, there was broken logic for resolving the actual invoked program name on Mac and Linux.
Windows
We continue to use
CommandLineToArgvW(GetCommandLine(), ..)
to return the absolute, full path to the entry executable.macOS
Switch from
_NSGetArgv()
to_NSGetExecutablePath(..)
which, like the Windows APIs above, returns the full path to the entry executable (or symlink).Linux
As there is no equivalent to
CommandLineToArgvW
or_NSGetExecutablePath
here, we instead do some path computation based on the form ofargv[0]
that we get from/proc/self/cmdline
../name
) then combine this with the current directory.dir/name
) then also resolve this from the current directory.argv[0]
value must have been a file name (name
) resolved from the$PATH
.If we still don't manage to resolve from the
$PATH
, try and resolve the symlink/proc/self/exe
that points to the executable image that was loaded from disk. Note that we may miss any intermediate link names here, but it's better than nothing.In addition, we also never tested the .NET Tool scenario after updating the
ICommandContext.ApplicationPath
to use the entry executable name, whereas previously this was computed from the .NET assembly path.Introduce a separate concept, the
InstallationDirectory
that always points to the home of the core assemblies. This is used for resolving things like in-box UI helpers.