dinitctl: show the service path in the "status" command output#550
dinitctl: show the service path in the "status" command output#550mobin-2008 wants to merge 2 commits into
Conversation
|
Someone was already working on this (#511). It does look like that effort stalled, but could you confirm with them please before we proceed with this new PR, out of politeness. It would be good if you could communicate what you are intending to work on before you start doing it, that will help avoid this sort of situation. |
I asked him and I'm waiting for his response.
Yes. I should did more than assigning issue (#508) to myself. |
|
Let's give it 3 days to wait for an answer. In the meantime, can you please close this PR and re-open after that time (I assume you have properly self-reviewed, if not please do that before re-opening). |
|
I forgot to reopen this PR before force pushing my branch :( |
|
Create a new branch from your current one ( |
4a646c5 to
d03c4d5
Compare
|
As per the contribution guide, you should specify what testing has been done when opening a PR. Can you do that now please? Can you also confirm that you're otherwise following the process, and have self-reviewed? |
d03c4d5 to
c4be545
Compare
Changes tested against these cases:
Yes. |
It seems like you just pushed changes after opening the PR - that's not the process, and we've talked about that before! - and yet you are now saying, just a few minutes later, that you are following the process. Please read the CONTRIBUTING and PR-PROCESS guides, in full. This is the last time I will allow you grace for this.. |
|
|
||
| // Issue STATUS request | ||
| { | ||
| // Prepare to show the service path in the output later down |
There was a problem hiding this comment.
- "Service path" isn't a thing. You're talking about a service description file path. Don't make up terminology please.
Two questions:
- "Prepare to show" is not clear. What is this code actually doing?
- Why do you feel the output "later down" is significant enough that it needs to be mentioned here?
There was a problem hiding this comment.
- "Service path" isn't a thing. You're talking about a service description file path. Don't make up terminology please.
OK. Will be fixed.
Two questions:
* "Prepare to show" is not clear. What is this code actually doing?
It's preparing a variable (service_path) to be used for showing the service path in the output later down. The code shows how this preparation works.
* Why do you feel the output "later down" is significant enough that it needs to be mentioned here?
Because it feels weird to me that there is a random get_service_description_dir before issuing STATUS. This is here to mention it's going to be used for showing the service path in the output later down the code and you need to keep looking for its usage.
There was a problem hiding this comment.
It's preparing a variable (
service_path) to be used for showing the service path in the output later down.
What does "preparing" mean in this case? (Also, can you explain it without referring to a variable? Variables are everywhere and I can see the variables in the code).
The code shows how this preparation works.
It shouldn't be necessary to read the code to understand what a comment means. The comment is supposed to explain the code, not the other way around.
What is the specific purpose of the comment here? Eg Is it explaining something that you think is difficult to understand, or is it just summarising what the following section of code does to help navigating the code, or something else?
This is here to mention it's going to be used for showing the service path in the output later down the code and you need to keep looking for its usage
Isn't that normal though? There are heaps of places where some value is determined so that it can be used later - that's basically every variable assignment! - so does it really need to be explained in the comment? Do you see any other comments that do that?
Because it feels weird to me that there is a random get_service_description_dir before issuing STATUS
The comment doesn't explain why get_service_description_dir is called at all, though.
There was a problem hiding this comment.
Sorry, that's a bit of an overload of questions. Can we focus on these for now:
What does "preparing" mean in this case?
("Preparing a variable" means nothing to me. What do you mean exactly?)
and
What is the specific purpose of the comment here? Eg Is it explaining something that you think is difficult to understand, or is it just summarising what the following section of code does to help navigating the code, or something else?
There was a problem hiding this comment.
("Preparing a variable" means nothing to me. What do you mean exactly?)
The original comment was this:
// Get the service description directory to show the service path in the output later down
I thought it is a bad idea to repeat what the code does in this comment, so I replaced it with "prepare" which is also bad, because everything up to the issuing the STATUS request is just preparation.
What is the specific purpose of the comment here? Eg Is it explaining something that you think is difficult to understand, or is it just summarising what the following section of code does to help navigating the code, or something else?
To be faithful to the style of this function, I thought it needs a comment explaining the section below. I mean it does
just summarising what the following section of code does to help navigating the code
but now I think it doesn't need to a comment explaining it, I just misunderstood the style.
There was a problem hiding this comment.
I thought it is a bad idea to repeat what the code does in this comment
It is fine to explain what a block of code does (at a slightly higher level than the code itself) with a comment.
If the comment is summarising the section of code though, then it should focus on what this section of code does, not non-specific things such as that it is "preparing" something "to be output later down". Those words (quoted) don't give any useful information to someone reading the comment.
but now I think it doesn't need to a comment explaining it
It is fine and good to have a comment here, that summarises what the code is doing. That is why I asked: what does this code actually do? (I know what it does - but I want you to explain it, in a way that would be useful as a comment).
So again: what does this code actually do?
There was a problem hiding this comment.
So again: what does this code actually do?
It constructs resolves the service description path.
There was a problem hiding this comment.
Yes. This would make a reasonable comment; "constructs" is ok (but a little ambiguous because constructing an object is a thing, and that's not really what is meant). "resolves" is also ok, but also has ambiguity because "resolve" has a special meaning with file paths (see https://stackoverflow.com/questions/67187401/what-exactly-does-it-mean-to-resolve-a-path). I would personally use "determines".
| } | ||
|
|
||
| cout << "Service: " << service_name << "\n" | ||
| cout << "Service: " << service_name << " (" << service_path << ")" << "\n" |
There was a problem hiding this comment.
Don't output it here. Output it with an appropriate heading (maybe 'File:') as with other status elements.
Feature design should really be discussed before working on it - that's also part of the documented process.
There was a problem hiding this comment.
I think adding File is good.
There was a problem hiding this comment.
It would also have been a good idea to check whether the file is up-to-date and report if not, much like dinitctl start now does.
There was a problem hiding this comment.
It would also have been a good idea to check whether the file is up-to-date and report if not, much like
dinitctl startnow does.
How to display it? Using the same message like in start? On top of status output or after writing entries?
Also something funny happened when testing it. I setup a minimal dinit.d:
$ ls /tmp/dinit.d/
boot srv
$ cat /tmp/dinit.d/*
type = internal
waits-for: srv
type = process
command = /usr/bin/sleep infinity
#ldaskd kasThen I tried to hit the message for modified service but I didn't. I straced the dinitctl call and saw something funny:
$ strace dinitctl -p /tmp/dinit.sock start srv
...
socket(AF_UNIX, SOCK_STREAM, 0) = 3
connect(3, {sa_family=AF_UNIX, sun_path="/tmp/dinit.sock"}, 18) = 0
write(3, "\0", 1) = 1
read(3, ":\1\0\6\0", 1024) = 5
write(3, "\2\3\0srv", 6) = 6
read(3, ";\2\0\0\0\0\2", 1019) = 7
write(3, "\26\0\0\0\0\0", 6) = 6
read(3, "M\10\0\0\0dinit.d/", 1012) = 13
newfstatat(AT_FDCWD, "dinit.d//srv", 0x7fff483c41c0, 0) = -1 ENOENT (No such file or directory)
write(3, "\3\0\0\0\0\0", 6) = 6
read(3, "=", 999) = 1
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
write(1, "Service (already) started.\n", 27Service (already) started.
) = 27
exit_group(0) = ?
+++ exited with 0 +++
I ran Dinit as dinit -d dinit.d/ -p dinit.sock. I shouldn't specify a relative path as services directory with trailing slash or this is a bug that needs to be fixed?
There was a problem hiding this comment.
I shouldn't specify directory with trailing slash or this is a bug that needs to be fixed?
A little of both. Can you open an issue please.
Sorry, I misunderstood you. No, this is not an error. The problem is not that you specified a trailing slash (multiple slashes are allowed between path components), it is that you used a relative path. Perhaps that should be made to work, let me think on it.
There was a problem hiding this comment.
(But, it is not something you need to consider for this PR. Please proceed and process in the same way that dinitctl start does).
How to display it? Using the same message like in start?
In start it's a warning specifically because the user may have forgotten to reload the service and as a result the original version of the service description will be used instead to start the service. That doesn't apply here so I don't understand why we would use the same message.
On top of status output
What do you mean by that?
or after writing entries?
I think it makes sense to keep the information with the filename, either on the same line or just after.
There was a problem hiding this comment.
What do you mean by that?
I mean something like this:
Note: service description may have changed; use 'dinitctl reload srv' to apply changes.
Service: srv
File: /tmp/dinit.d//srv
State: STARTED
Activation: start due to dependent(s)
Process ID: 25183
I think it makes sense to keep the information with the filename, either on the same line or just after.
So something like this?
Service: srv
File: /tmp/dinit.d//srv
Note: service description may have changed; use 'dinitctl reload srv' to apply changes.
State: STARTED
Activation: start due to dependent(s)
Process ID: 25183
There was a problem hiding this comment.
So something like this?
No, as I said earlier:
In start it's a warning specifically because the user may have forgotten to reload the service and as a result the original version of the service description will be used instead to start the service. That doesn't apply here so I don't understand why we would use the same message.
What you posted above isn't substantially different from the warning that dinitctl start prints.
The modification status is part of the status. So display it as part of the status. " (modified since loaded)" after the filename would do it, for example. Or suitable information on the next line, as part of the status, not as some "note".
|
Please answer questions above and then I will complete the review. |
Now I see how half-baked this PR is, I try my best to fix it. I answered your questions and also asked a question for better understanding the current design. If the feedback is still negative, I would mark this PR as draft until it gets to the point of being up to the standard. |
There's still a question pending - see above. Once that's resolved I'll complete the review. Thanks. |
| const char *at_ptr = strchr(service_name, '@'); | ||
| if (at_ptr != nullptr) { | ||
| service_base_name = string_view(service_name, static_cast<size_t>(at_ptr - service_name)); | ||
| } |
There was a problem hiding this comment.
The strip_service_arg function already exists; use it instead of replicating the functionality.
| } | ||
|
|
||
| cout << "Service: " << service_name << "\n" | ||
| cout << "Service: " << service_name << " (" << service_path << ")" << "\n" |
There was a problem hiding this comment.
It would also have been a good idea to check whether the file is up-to-date and report if not, much like dinitctl start now does.
| { | ||
| using std::cout; | ||
| using std::cerr; | ||
| using std::string; |
There was a problem hiding this comment.
I wouldn't normally add using for a class that's only used a handful of times.
|
Ok, I've completed the review, please make changes and push once ready (after self-review). |
c4be545 to
6964af8
Compare
|
|
6964af8 to
e1598a0
Compare
There was a problem because of how I reviewed commits ( I applied all the suggested fixes, added a check for modified service descriptions (see the new commit) and self-reviewed the changes. Changes are tested against these cases: |
davmac314
left a comment
There was a problem hiding this comment.
Commit messages:
Also use the newer "SERVICESTATUS6" protocol request if daemon supports
it
- Don't drop articles (in "if daemon").
- This isn't the point of the change. If you're explaining an implementation detail that was necessary for the change, then make that clear with appropriate language.
Add a "File" field to service status showing the path of the service
description file for the currently loaded service.
- Don't drop articles (in "to service status").
- Remove redundant/implicit/obvious information ("for the currently loaded service")
| // Check the service description file hasn't changed. We already located said file, so stat | ||
| // it to find the modification time, then compare that with the modification time according | ||
| // to dinit. |
There was a problem hiding this comment.
Nit: You've basically copied the comment from start_stop_service, but this is a different context.
In that context a few things need to be done to do the modification check: locate the service file (get the service directory and append the service name), issue a SERVICESTATUS6 request, and then check the file time. That's why the comment is more than just a single line.
In this context, the code block is nice and short and doesn't need the same level of explanation.
You don't have to change this, but in future please don't blindly take comments from elsewhere. It's much better if you try to come up with a reasonable comment yourself, I think practicing that would be worthwhile.
There was a problem hiding this comment.
I don't change this and I will try to come up with a reasonable comment myself next time.
| if (dinit_sdf_time.tv_sec != file_time.tv_sec | ||
| || dinit_sdf_time.tv_nsec != file_time.tv_nsec) { | ||
| sdf_has_changed = true; |
There was a problem hiding this comment.
sdf_has_changed = dinit_sdf_time.tv_sec != ...(etc)
you don't need if here.
| unsigned status_buf_size = proto_version < 5 ? STATUS_BUFFER_SIZE : STATUS_BUFFER5_SIZE; | ||
| // Determine the service description path | ||
| std::string sdf_path; | ||
| if (proto_version >= 3) { |
There was a problem hiding this comment.
There's no need to deal with protocol versions before 3, that's ridiculously old now.
| char status_req_id; | ||
| unsigned status_buf_size; | ||
| switch (proto_version) { | ||
| case 6: | ||
| status_req_id = (char)cp_cmd::SERVICESTATUS6; | ||
| status_buf_size = STATUS_BUFFER6_SIZE; | ||
| break; | ||
| case 5: | ||
| status_req_id = (char)cp_cmd::SERVICESTATUS5; | ||
| status_buf_size = STATUS_BUFFER5_SIZE; | ||
| break; | ||
| default: | ||
| status_req_id = (char)cp_cmd::SERVICESTATUS; | ||
| status_buf_size = STATUS_BUFFER_SIZE; | ||
| break; | ||
| } |
There was a problem hiding this comment.
You don't need 16 lines of code for this. It was 2 previously, it shouldn't be much more than that.
This doesn't correctly handle future protocol versions (7+), it's going to fall back to pre-5 status in those cases. (That corresponds to dinit-0.18.0, which we don't really need to support any more anyway, though there is support elsewhere in the code so it's good to be consistent for now).
| std::string sdf_path; | ||
| if (proto_version >= 3) { | ||
| std::string sd_dir = get_service_description_dir(socknum, rbuffer, handle); | ||
| std::string service_base_name = string_view(service_name, |
There was a problem hiding this comment.
Don't allocate a string unnecessarily
| if (proto_version >= 3) { | ||
| std::string sd_dir = get_service_description_dir(socknum, rbuffer, handle); | ||
| std::string service_base_name = string_view(service_name, | ||
| static_cast<size_t>(strip_service_arg(service_name) - service_name)); |
There was a problem hiding this comment.
Surely this cast isn't needed?
There was a problem hiding this comment.
I don't think so but regardless, I removed the additional strings and by using the std::string::append(const char *__first, const char *__last) the whole subtraction can be removed.
| if (sdf_has_changed) { | ||
| cout << " (modified since loaded)"; | ||
| } |
Add a "File" field to the service status showing the path of the service description file. Addresses davmac314#508
e1598a0 to
57afa42
Compare
|
Fixed the commit messages, applied the requested changes and self-reviewed the changes. Changes are tested against these cases: |
You don't have to say this each time, especially when you are just repeating what you said before. The testing details are supposed to be in the PR summary. |
There was a problem hiding this comment.
Also use the newer "SERVICESTATUS6" protocol request if daemon supports it
- Don't drop articles (in "if daemon").
- This isn't the point of the change. If you're explaining an implementation detail that was necessary for the change, then make that clear with appropriate language.
The 2nd point wasn't addressed. It still says exactly what I quoted above (except that the "the" article has been added as per first point, thanks).
This change wasn't "also". It was fundamental to the main change.
| char status_req_id = (proto_version >= 6) ? (char)cp_cmd::SERVICESTATUS6 | ||
| : (proto_version == 5) ? (char)cp_cmd::SERVICESTATUS5 | ||
| : (char)cp_cmd::SERVICESTATUS; |
There was a problem hiding this comment.
Use extra parentheses (/) to make the expression more clear. Same below.
| cout << "\n"; | ||
| cout << " State: "; |
There was a problem hiding this comment.
Combine into one line, there's no need to output two literal strings one after the other, just output a single literal string.
Show "(modified since loaded)" at the end of the "File" field when the service description file has changed since it was loaded. Use the newer "SERVICESTATUS6" protocol request to implement this feature. This is required to get the modification time of the service description file when dinit loaded the service. Fallback to the older protocol requests when the daemon doesn't support the newer.
57afa42 to
79e39e3
Compare
I think this new push does address your point. I removed the "also" and made it clear that it's used for implementing this feature. |
davmac314
left a comment
There was a problem hiding this comment.
Commit comment:
Fallback to the older protocol requests when the daemon doesn't support the newer.
newer one.
Given that the commit message is supposed to be focusing on the functional change, this talk of fallback to older protocol should really have some sort of explanation of what the functional effect of this fallback actually is.
| char status_req_id = ((proto_version >= 6) ? (char)cp_cmd::SERVICESTATUS6 | ||
| : (proto_version == 5) ? (char)cp_cmd::SERVICESTATUS5 | ||
| : (char)cp_cmd::SERVICESTATUS); | ||
| unsigned status_buf_size = ((proto_version >= 6) ? STATUS_BUFFER6_SIZE | ||
| : (proto_version == 5) ? STATUS_BUFFER5_SIZE : STATUS_BUFFER_SIZE); |
There was a problem hiding this comment.
This is not what I meant. I'm struggling to understand why you put the parentheses where you did.
Adding parentheses around the whole expression doesn't make it easier to understand - just adding '(' at the beginning of a complicated expression, and ')' at the end of it, doesn't make it clearer, it just adds noise.
The parentheses around the conditions aren't really useful either. They're not complicated conditions.
The original expression was:
unsigned status_buf_size = (proto_version >= 6) ? STATUS_BUFFER6_SIZE
: (proto_version == 5) ? STATUS_BUFFER5_SIZE : STATUS_BUFFER_SIZE;
That's a double ? : operator combination and you need to make clear which parts are which and how the operands bind (i.e. the associativity). The expression is particularly unclear to anyone who is uncertain of the precedence/associativity of the '? :' operator.
Use parentheses to make the precedence/binding clear. That means, in this case, put them around the second '? :' subexpression, i.e. the 2nd alternative to the first '? :'. Then you're removing the syntactic ambiguity, and allowing to easily identify the two alternatives for the first operator without having to mentally parse the expression.
If you didn't understand this, then ask (as you should've asked if you didn't understand in the first place).
Use the existing functionality to show the service path of currently loaded service.
Fixes #508