Skip to content

Conversation

@jorpilo
Copy link

@jorpilo jorpilo commented Mar 9, 2023

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew style with your changes locally?
  • Have you successfully run brew typecheck with your changes locally?
  • Have you successfully run brew tests with your changes locall

Added service.nice to allow to define default nice levels in plist and systemd units.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

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

Thanks for the PR. Looking good so far!

@run&.map(&:to_s)
end

sig { params(value: T.nilable(Integer)).returns(T.nilable(Integer)) }
Copy link
Member

Choose a reason for hiding this comment

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

Why/when would you want to pass in a value: nil?

Suggested change
sig { params(value: T.nilable(Integer)).returns(T.nilable(Integer)) }
sig { params(value: Integer).returns(T.nilable(Integer)) }

may make more sense if not

Copy link
Author

@jorpilo jorpilo Mar 9, 2023

Choose a reason for hiding this comment

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

Correct, we can remove nil but I was following the format of the rest of parameters like restart_delay which is also defined nilable

sig { params(value: T.nilable(Integer)).returns(T.nilable(Integer)) }

Copy link
Member

Choose a reason for hiding this comment

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

CC @SMillerDev for thoughts here, I think it'd probably make sense to make none of these nilable.

Copy link
Member

Choose a reason for hiding this comment

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

Most of these methods simply return the current value when nil (i.e. no argument) is passed. We don't seem to be calling any of these without an argument though.

Copy link
Author

Choose a reason for hiding this comment

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

I will remove the nil to also resolve the typecheck issue but we might want to also change the rest of parameters. Please verify that the change is correct.

Also if we remove the nilable, the TypeError is unrechable as it expects an integer. Should I remove the it?

Copy link
Member

Choose a reason for hiding this comment

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

@dduugg @reitermarkus Also would welcome your thoughts on how, in a future PR, we could refactor this type handling to lean more on Sorbet (bearing in mind that e.g. formulae will almost never be evaluated at runtime to use Sorbet and are currently never type checked by Sorbet)

Copy link
Member

Choose a reason for hiding this comment

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

I don't think i have any especially creative suggestions. You can try to bump these files to typed: strict to catch more edge cases. I believe we do runtime typechecking in tests, so covering every service DSL in tests could do the trick. A rubocop that flags unacceptablenice values could help too (it's tricky if you're allowing vars to be passed to nice, but it could enforce that nice is followed by a literal Integer in the required range).

Copy link
Member

Choose a reason for hiding this comment

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

Thanks @dduugg!

Copy link
Member

Choose a reason for hiding this comment

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

CC @SMillerDev for thoughts here, I think it'd probably make sense to make none of these nilable.

Not a clue, pretty sure I just copied this from livecheck

jorpilo and others added 3 commits March 10, 2023 03:31
revert table header

Co-authored-by: Mike McQuaid <mike@mikemcquaid.com>
@MikeMcQuaid
Copy link
Member

Thanks @jorpilo! Run brew typecheck locally and fix the error: https://github.com/Homebrew/brew/actions/runs/4379299101/jobs/7665097153#step:7:12

Essentially it's saying the Integer check here is no longer needed. If you're willing: would be good to clean up the rest of the file in this way, too, after this PR is merged!

end

sig { params(value: Integer).returns(T.nilable(Integer)) }
def nice(value)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
def nice(value)
def nice(value = nil)

Sorry, this bit is still needed and then then when nil below will also be needed.

We want users to be able to call nice() or nice(5) but not nice("5") or nice(nil).

Does that make sense?

Sorry for all the back and forth!

Copy link
Author

Choose a reason for hiding this comment

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

Sorry it was my bad as I don't get the objective of calling nice() without a value?
calling nice() without value shouldn't add anything to the plist or unit.

Copy link
Author

Choose a reason for hiding this comment

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

Also if we want to preserve the nil default value we need to make the argument nilable or typecheck fails.

I have reverted back to be nilable. typecheck and style pass locally. Please let me know if there is any further modification needed

Thanks

Copy link
Member

@reitermarkus reitermarkus Mar 11, 2023

Choose a reason for hiding this comment

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

When would we want to call nice without arguments though?

Copy link
Member

Choose a reason for hiding this comment

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

I don't really see a reason why any of these methods would need to behave like a getter.

Copy link
Author

Choose a reason for hiding this comment

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

As I mentioned, you don't really want to call nice without arguments. Is there any other better way to get the value? if not, then I do not see the issue in keep it

Copy link
Author

Choose a reason for hiding this comment

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

Also, if you try to use it as a getter like the following example, it will return nil instead of 5

f = stub_formula do
        service do
          run opt_bin/"beanstalkd"
          nice(5)
        end
end
expect(f.service.nice).to eq(5)
# This fails as it returns nil instead of 5

if I do an instance_eval in the nice case, then it does return the correct value

when nil
        instance_eval(&@service_block)
        @nice

jorpilo added 2 commits March 10, 2023 21:18
Signed-off-by: Jorge Pinilla López <jorpilo@gmail.com>
Signed-off-by: Jorge Pinilla López <jorpilo@gmail.com>
jorpilo added 2 commits March 10, 2023 22:04
Signed-off-by: Jorge Pinilla López <jorpilo@gmail.com>
Signed-off-by: Jorge Pinilla López <jorpilo@gmail.com>
@MikeMcQuaid MikeMcQuaid requested a review from SMillerDev March 10, 2023 12:36
when nil
@nice
when Integer
if (T.must(value) < -20) || (T.must(value) > 19)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (T.must(value) < -20) || (T.must(value) > 19)
unless (-20..19).cover?(nice)

This is concise, and also lets you avoid the T.musts. (You could even extract the magic numbers into a const, e.g. NICE_RANGE = -20..19)

Copy link
Author

Choose a reason for hiding this comment

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

Changed to use cover and NICE_RANGE. Thank you for the suggestion.

Any way I can use NICE_RANGE in the tests?

Copy link
Member

Choose a reason for hiding this comment

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

Could you elaborate on the issue in using NICE_RANGE in tests?

when nil
@nice
when Integer
if (T.must(value) < -20) || (T.must(value) > 19)
Copy link
Member

Choose a reason for hiding this comment

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

Do you need sudo for negative nice?

Copy link
Author

Choose a reason for hiding this comment

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

You are correct, thank you for noticing. you do need root to run negative nice levels. If you try to run without root it will just run with nice level of 0 (no error will trigger).
You can run positive nice levels as user.

I can add a check for requires_root if the nice level is negative. Not sure if we should throw an error or just a warning. Also where would it best to set the check? at the nice function or when generating plist/units?

Copy link
Member

Choose a reason for hiding this comment

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

I guess a warning when you call brew services without sudo suffices here. But CC @SMillerDev and @MikeMcQuaid for thoughts here.

Copy link
Member

Choose a reason for hiding this comment

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

Since this is not something that should happen I think throwing an error is the best course of action.

Copy link
Member

Choose a reason for hiding this comment

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

It seems reasonable to truncate the nice level if you don't want to run brew services with sudo (which is what will happen automatically), though, so throwing an error seems a bit much here.

Copy link
Member

Choose a reason for hiding this comment

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

I believe requires_root still allows you to run as a user, it'll just warn against doing so. So if we require that with the nice level you can still opt to have it truncated, brew will just suggest the fully functional option.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds like we should just have nice < 0 imply requires_root then, regardless of whether the service block includes it. Not sure what the value of forcing its inclusion by throwing an error is.

Copy link
Member

Choose a reason for hiding this comment

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

It would make it clear to developers and maintainers why it requires root. Instead of only telling users that they need to use root.

Copy link
Member

Choose a reason for hiding this comment

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

I don't think an extra line that says require_root true is going to make the reason more transparent.

jorpilo added 2 commits March 11, 2023 16:17
Signed-off-by: Jorge Pinilla López <jorpilo@gmail.com>
Signed-off-by: Jorge Pinilla López <jorpilo@gmail.com>
@run&.map(&:to_s)
end

sig { params(value: T.nilable(Integer)).returns(T.nilable(Integer)) }
Copy link
Author

Choose a reason for hiding this comment

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

I will remove the nil to also resolve the typecheck issue but we might want to also change the rest of parameters. Please verify that the change is correct.

Also if we remove the nilable, the TypeError is unrechable as it expects an integer. Should I remove the it?

options << "ExecStart=#{cmd}"

options << "Restart=always" if @keep_alive.present? && @keep_alive[:always].present?
options << "RestartSec=#{restart_delay}" if @restart_delay.present?
Copy link
Author

Choose a reason for hiding this comment

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

Is this correct or should it be the following:

Suggested change
options << "RestartSec=#{restart_delay}" if @restart_delay.present?
options << "RestartSec=#{@restart_delay}" if @restart_delay.present?

Copy link
Member

Choose a reason for hiding this comment

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

@SMillerDev can confirm

Copy link
Member

Choose a reason for hiding this comment

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

@ seems more consistent

end

sig { params(value: Integer).returns(T.nilable(Integer)) }
def nice(value)
Copy link
Author

Choose a reason for hiding this comment

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

Sorry it was my bad as I don't get the objective of calling nice() without a value?
calling nice() without value shouldn't add anything to the plist or unit.

end

sig { params(value: Integer).returns(T.nilable(Integer)) }
def nice(value)
Copy link
Author

Choose a reason for hiding this comment

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

Also if we want to preserve the nil default value we need to make the argument nilable or typecheck fails.

I have reverted back to be nilable. typecheck and style pass locally. Please let me know if there is any further modification needed

Thanks

when nil
@nice
when Integer
if (T.must(value) < -20) || (T.must(value) > 19)
Copy link
Author

Choose a reason for hiding this comment

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

You are correct, thank you for noticing. you do need root to run negative nice levels. If you try to run without root it will just run with nice level of 0 (no error will trigger).
You can run positive nice levels as user.

I can add a check for requires_root if the nice level is negative. Not sure if we should throw an error or just a warning. Also where would it best to set the check? at the nice function or when generating plist/units?

when nil
@nice
when Integer
if (T.must(value) < -20) || (T.must(value) > 19)
Copy link
Author

Choose a reason for hiding this comment

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

Changed to use cover and NICE_RANGE. Thank you for the suggestion.

Any way I can use NICE_RANGE in the tests?

end

sig { params(value: Integer).returns(T.nilable(Integer)) }
def nice(value)
Copy link
Author

Choose a reason for hiding this comment

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

As I mentioned, you don't really want to call nice without arguments. Is there any other better way to get the value? if not, then I do not see the issue in keep it

end

sig { params(value: Integer).returns(T.nilable(Integer)) }
def nice(value)
Copy link
Author

Choose a reason for hiding this comment

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

Also, if you try to use it as a getter like the following example, it will return nil instead of 5

f = stub_formula do
        service do
          run opt_bin/"beanstalkd"
          nice(5)
        end
end
expect(f.service.nice).to eq(5)
# This fails as it returns nil instead of 5

if I do an instance_eval in the nice case, then it does return the correct value

when nil
        instance_eval(&@service_block)
        @nice

@jorpilo
Copy link
Author

jorpilo commented Mar 12, 2023

Also sorry for the late reply. I had all my comments as "pending" and I didn't realised I do need to accept the comments for them to be visible....

Co-authored-by: Douglas Eichelberger <dduugg@users.noreply.github.com>
end
end

describe "#nice" do
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a bool check or something still?

f = stub_formula do
service do
run opt_bin/"beanstalkd"
nice(-21)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
nice(-21)
nice -21

Or does RuboCop complain about this?

Copy link
Author

Choose a reason for hiding this comment

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

yeah... syntax

@github-actions
Copy link

github-actions bot commented Apr 6, 2023

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@github-actions github-actions bot added the stale No recent activity label Apr 6, 2023
@github-actions github-actions bot closed this Apr 13, 2023
@github-actions github-actions bot added the outdated PR was locked due to age label May 14, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

outdated PR was locked due to age stale No recent activity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants