-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Implement User/Group from_name?/from_id? like Ruby #10182
Conversation
Thank you for your recent contributions! It's very appreciated. FYI: If you write |
Note that your commit isn't attributed to your GitHub account. If you set locally a Git mail, which is also linked to your GH account, it will be. |
@j8r, I added my second email address to my github account. Hopefully, this does the job. |
src/crystal/system/unix/user.cr
Outdated
buf = Bytes.new(buf.size * 2) | ||
else | ||
raise RuntimeError.from_errno("getpwuid_r") | ||
end |
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.
The code for all four methods looks very similar now, except for a few differences like what's the function to call and the name to use for from_errno
. Could we extract them to a separate method that yields? That way all that logic will be in a single place. Or maybe not a method that yields, I'm sure there's a more DRY way to do this.
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 created a macro to wrap the functions.
I also tried putting it in a method that yields. But that was too complicated.
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.
Please refactor to avoid duplicate code.
I would suggest a yielding method similar to def from_username?(username : String)
username.check_no_null_byte
pwd = uninitialized LibC::Passwd
pwd_pointer = pointerof(pwd)
retry_with_buffer("getpwnam_r", GETPW_R_SIZE_MAX) do |buf|
LibC.getpwnam_r(username, pwd_pointer, buf, buf.size, pointerof(pwd_pointer))
end
from_struct(pwd) if pwd_pointer
end
def retry_with_buffer(function_name, max_buffer)
initial_buf = uninitialized UInt8[1024]
buf = initial_buf
while (ret = yield buf.to_slice) != 0
case ret
when LibC::ENOENT, LibC::ESRCH, LibC::EBADF, LibC::EPERM
return nil
when LibC::ERANGE
raise RuntimeError.from_errno(function_name) if buf.size >= max_buffer
buf = Bytes.new(buf.size * 2)
else
raise RuntimeError.from_errno(function_name)
end
end
end |
Yes, a yielding method is better. Macros should be avoided unless absolutely necessary. |
Thanks for the hint. I implemented it now like suggested by @straight-shoota |
Ruby handles
ENOENT
,ESRCH
,EBADF
andEPERM
as not found when callinggetgrgid_r
,getgrnam_r
,getpwnam_r
orgetpwuid_r
.I implemented the same behavior for crystal. Unfortunately, it's not possible to write unit tests for this.
Fixes #8069.