-
Notifications
You must be signed in to change notification settings - Fork 143
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
Detect Elan self update disabled (e.g. installed from distro repos) #998
Conversation
Is there any way we can know this? If so, we can automatically skip this rather than hardcoding it? Does |
It prints an error message with the reason, but returns with error code 1, just like any other error. |
Great, then we can use it! Just like what we did here: https://github.com/topgrade-rs/topgrade/pull/971/files |
There is no error when I reused the code for Helm, which checks if the error message contains this specific error, and in such a case just keeps going with the rest of the update. It still prints the error, which may or may not be desired behaviour. |
src/steps/generic.rs
Outdated
let disabled = "self-update is disabled"; | ||
let mut exec = ctx.run_type().execute(&elan); | ||
let mut success = true; | ||
if let Err(e) = exec.arg("self").arg("update").status_checked() { |
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.
It still prints the error, which may or may not be desired behaviour.
If you use output_checked()
directly, then the error won't be printed.
Can you just do, I guess this would work
let result = ctx
.run_type()
.execute(&uv_exec)
.args(["self", "update"])
.output_checked();
if result.is_ok() {
ctx.run_type()
.execute(&uv_exec)
.args(["self", "update"])
.status_checked()?;
}
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 would do self-update twice, if the first one succeeds, right?
Is that better than comparing the output of the "self update" call to a saved error message?
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 would do self-update twice, if the first one succeeds, right?
Right, thanks for catching this. I was probably dizzy at that time 🤦♂️
Is that better than comparing the output of the "self update" call to a saved error message?
I think we do need to compare the output with the saved message, what about:
- Do
elan self update
, capture the output- If 1 succeeds, the self-update feature is available and it just successfully performed the update, we
print!()
the capturedstdout
andeprint!()
the capturedstderr
- If 1 fails, there are possibly 2 cases why this failure happened:
- The self-update feature is unavailable (stdout or stderr contains the saved error message), nothing further needs to be done
- The self-update feature is available, but the operation just failed, error out
- If 1 succeeds, the self-update feature is available and it just successfully performed the update, we
- Do
elan update
// If elan is externally managed, then running `elan self update` will give an
// error message that contains `disabled_error_msg`, in this case, Topgrade
// tries to hide that `elan self update` has just been executed.
let disabled_error_msg = "self-update is disabled";
let executor_output = ctx.run_type().execute(&elan).args(["self", "update"]).output()?;
match executor_output{
ExecutorOutput::Wet(command_output) => {
if command_output.status.success() {
// Flush the captured output
std::io::stdout().lock().write(&command_output.stdout).unwrap();
std::io::stderr().lock().write(&command_output.stderr).unwrap();
} else {
let stderr_as_str = std::str::from_utf8(&command_output.stderr).unwrap();
if stderr_as_str.contains(disabled_error_msg) {
// `elan` is externally managed, we cannot do the update. Users
// won't see any error message because Topgrade captures them
// all.
} else {
// `elan` is NOT externally managed, `elan self update` can
// be performed, but the invocation failed, so we report the
// error to the user and error out.
std::io::stdout().lock().write(&command_output.stdout).unwrap();
std::io::stderr().lock().write(&command_output.stderr).unwrap();
return Err(StepFailed.into());
}
}
}
ExecutorOutput::Dry => {/* nothing needed because in a dry run */}
}
The latest commit hides the output if the "self update" command fails because it is disabled, otherwise returns the error of that command. This, to me, seems better than running "self update" twice. Let me know if you disagree. |
Looks like we are doing the same thing, check out my last comment, it provides an implementation with slightly better UX |
Though my patch needs this #1002 to work |
Sorry, I missed that one. Yes, we are doing the same thing, and I agree yours do look better code-wise. Let's wait for #1002, and fix this once that is merged. The "filtering error messages" methodology might be common enough to create a function |
If it becomes commonly used, yeah, we should make it a utility |
I took your code and adjusted it with clippy's suggestions. It should be ready now :) |
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
What does this PR do
Adds a config option to disable elan self-update (for people like me, who installed elan from distro repos).
Standards checklist
CONTRIBUTING.md
For new steps
--dry-run
option works with this step--yes
option works with this step if it is supported bythe underlying command
If you developed a feature or a bug fix for someone else and you do not have the
means to test it, please tag this person here.