-
Notifications
You must be signed in to change notification settings - Fork 13
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
Update shell detection #3466
Update shell detection #3466
Conversation
MDrakos
commented
Aug 27, 2024
•
edited by github-actions
bot
Loading
edited by github-actions
bot
DX-3006 Improve SHELL detection; base on parent process |
@Naatan I'm looking for feedback on how I addressed the integration test failures. I think the comment explain it but if there are any questions let me know. With this approach or a different one I will have to go through all of the integration tests and update them. Of course feel free to review everything. I'm just asking for a review early before I address the remaining tests. |
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.
This looks ok to me, but I don't think we need to make such sweeping changes. The only place this ought to matter is where we specifically test shell detection, which I imagine should be only one test.
I imagine what you're running into is that other tests have started to break because we shifted shell detection to be process based? If that's the case I think a more general purpose solution is appropriate, eg. add an env var that will trump shell detection that we can set on CI (ACTIVESTATE_OVERRIDE_SHELL
?).
I'd prefer that over updating all these tests and the e2e code, as that feels less maintainable.
internal/subshell/subshell.go
Outdated
if os.Getenv(constants.OverrideShellEnvVarName) != "" { | ||
binary = os.Getenv(constants.OverrideShellEnvVarName) | ||
} | ||
|
||
if binary == "" { | ||
binary = detectShellParent() | ||
} | ||
|
||
if binary == "" { | ||
binary = configured | ||
} | ||
|
||
if binary == "" { | ||
if runtime.GOOS == "windows" { | ||
binary = "cmd.exe" | ||
} else { | ||
binary = "bash" | ||
} | ||
binary = os.Getenv(SHELL_ENV_VAR) | ||
} | ||
|
||
if binary == "" { | ||
binary = OS_DEFULAT | ||
} |
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.
Can we change this into a switch case? We don't need to assert binary == nil
, instead assert whether we have something to populate it with.
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 can however this leads to us calling functions like Getenv
or detectShellParent()
twice. We could also move the function calls outside of the switch but then there will be cases where we are calling them needlessly.
I'm not sure how much of a performance impact detectShellParent()
has but we would be adding inefficiency for a marginal gain in readability. I'm fine with whatever direction we want to go but I wanted to flag this before I make the change.
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.
Hmm I see. Annoying Go doesn't let you assign in a switch case like it does in a regular conditional. I guess there isn't really a decent pattern for us to use here :\
internal/subshell/subshell.go
Outdated
p, err := process.NewProcess(int32(os.Getppid())) | ||
if err != nil && !errors.As(err, ptr.To(&os.PathError{})) { | ||
panic(err) | ||
logging.Error("Failed to get parent process: %v", err) |
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.
Not sure why this was a panic, but we went from panicking to essentially ignoring it. Please return the error up the chain instead.
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.
This was originally a windows only function which may be a reason for the panic?
No other functions in this package return errors either as DetectShell
has fallbacks so it always returns a shell name. This function is also used but subshell.New
. So even if we get a fallback shell from either the SHELL
env var or the system default we would error out because we couldn't detect the parent.
Again, I just want to check before making this change.
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.
ok, let's go with this for now, but please make it a multilog error so we can track this on rollbar. If this is happening a lot we'll want to know about it.
@@ -74,7 +74,7 @@ func (s *SpawnedCmd) ExpectInput(opts ...termtest.SetExpectOpt) error { | |||
expect := `expect'input from posix shell` | |||
if cmdName != "bash" && shellName != "bash" && runtime.GOOS == "windows" { | |||
if strings.Contains(cmdName, "powershell") || strings.Contains(shellName, "powershell") { | |||
send = "echo \"`<expect input from powershell`>\"" |
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.
Are you sure this works? IIRC the backtick is an escape on powershell.
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.
You were right, I was running into a failure with this because it was defaulting back to cmd.exe
and not powershell.
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.
Never mind, I was right. Here's the output on powershell
[ActiveState-CLI/small-python] C:\Users\runneradmin\AppData\Local\Temp\2179854665\work\small-python>echo "`<expect input from powershell`>"
"`<expect input from powershell`>"
And the expect
'Expected: "<expect input from powershell>": after 40s: timeout':
'after 40s: timeout': timeout
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.
My guess is it depends on which shell you started from. So your new tests may want this variant but older tests will want the escaping? Worth perhaps looking for other places where we run ExpectInput and running those tests on Windows before merging your PR.
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.
All of the integration tests that start powershell are also critical. Only one of them expects input which is the one that flagged this change.
Handle case insensitivitiy
and clear config
internal/subshell/subshell.go
Outdated
if os.Getenv(constants.OverrideShellEnvVarName) != "" { | ||
binary = os.Getenv(constants.OverrideShellEnvVarName) | ||
} | ||
|
||
if binary == "" { | ||
binary = detectShellParent() | ||
} | ||
|
||
if binary == "" { | ||
binary = configured | ||
} | ||
|
||
if binary == "" { | ||
if runtime.GOOS == "windows" { | ||
binary = "cmd.exe" | ||
} else { | ||
binary = "bash" | ||
} | ||
binary = os.Getenv(SHELL_ENV_VAR) | ||
} | ||
|
||
if binary == "" { | ||
binary = OS_DEFULAT | ||
} |
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.
Hmm I see. Annoying Go doesn't let you assign in a switch case like it does in a regular conditional. I guess there isn't really a decent pattern for us to use here :\
internal/subshell/subshell.go
Outdated
p, err := process.NewProcess(int32(os.Getppid())) | ||
if err != nil && !errors.As(err, ptr.To(&os.PathError{})) { | ||
panic(err) | ||
logging.Error("Failed to get parent process: %v", err) |
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.
ok, let's go with this for now, but please make it a multilog error so we can track this on rollbar. If this is happening a lot we'll want to know about it.
internal/subshell/subshell.go
Outdated
@@ -188,19 +189,19 @@ func DetectShell(cfg sscommon.Configurable) (string, string) { | |||
} | |||
|
|||
if binary == "" { | |||
binary = detectShellParent() | |||
binary = configured |
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.
Sorry I realized upon reading the changes that configured had a different connotation than I remembered. In my mind this was "what the user configured", but actually this is just a fallback we ourselves set when we detect the shell.
This is awkward and should probably be revisited, but given the current behaviour I this should probably be a fallback after shell parent and environment.
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, but please read the comment on ExpectInput.
@@ -74,7 +74,7 @@ func (s *SpawnedCmd) ExpectInput(opts ...termtest.SetExpectOpt) error { | |||
expect := `expect'input from posix shell` | |||
if cmdName != "bash" && shellName != "bash" && runtime.GOOS == "windows" { | |||
if strings.Contains(cmdName, "powershell") || strings.Contains(shellName, "powershell") { | |||
send = "echo \"`<expect input from powershell`>\"" |
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.
My guess is it depends on which shell you started from. So your new tests may want this variant but older tests will want the escaping? Worth perhaps looking for other places where we run ExpectInput and running those tests on Windows before merging your PR.