-
Notifications
You must be signed in to change notification settings - Fork 56
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
feat(cli): implement personality for application name-agnostic help manuals #238
Conversation
* Implements the concept of personality, a struct that contains information about the application identity, such as the program binary name and the application display name. This enables the implementation of Pebble-based software that does not necessarily have the same name as Pebble. * Help strings throughout the application have been slightly modified so self-references to pebble/Pebble are removed without changing the semantics of the help manual.
@@ -160,7 +160,7 @@ func (cmd *cmdEnter) Execute(args []string) error { | |||
case runStop = <-runReadyCh: | |||
case runPanic := <-runResultCh: | |||
if runPanic == nil { | |||
panic("internal error: pebble daemon stopped early") | |||
panic("internal error: daemon stopped early") |
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.
In case of multiple services wouldn't the program name be useful in a panic?
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.
That's fine -- I'd be happy to reinstate it as {{.DisplayName}}
.
If the client panics due to the Pebble daemon stopping early, include the program name from personality so it's unambiguous.
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 close! Few ideas to simplify mostly.
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 on par up to last week's discussion
Actually, this is missing the logic for replacing <pebble> with something
else from personality; however I think it would be a great starting point
to merge this along with the CLI API and then implement the replacement
logic, because it has to be done in the parser code which has been
rewritten in the CLI API PR.
…On Tue, Jul 11, 2023 at 16:38 burak ***@***.***> wrote:
***@***.**** approved this pull request.
Looks on par with last week's discussion
—
Reply to this email directly, view it on GitHub
<#238 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ANEOQKP3V6DJTC3NW7YUNLLXPVQNBANCNFSM6AAAAAAZGDWF3I>
.
You are receiving this because you were assigned.Message ID:
***@***.***>
|
Argument, option and command descriptions can now utilize the `<display name>` and `<program name>` notation that will be substituted with the corresponding values depending on the current binary personality.
This PR is ready for review now, but changes will be required when #232 is merged. |
This patch, similar in spirit to canonical#238, introduces a new public API for extending the Pebble client. The basic idea behind this patch is the client mixin struct embedded in commands' structs no longer holds an instance of the Pebble-specific `client.Client` struct, but instead take a `ClientGetter` interface that implements a `Client()` method. `ClientGetter.Client()` always returns a Pebble-specific `client.Client` struct. For applications that indent to extend Pebble, this means that either the Pebble client or a new, application-specific client can be used. In the latter case, the application-specific client must implement the `ClientGetter` interface so that a Pebble-specific `client.Client` struct can always be derived by the facilities consuming the `ClientGetter` interface. The easiest way to implement this is to embed the Pebble client: type PebbleClient = client.Client type MyClient struct { *PebbleClient } Since the Pebble-specific `client.Client` is embedded, and the `ClientGetter` interface requires `Client()` to be implemented with a pointer receiver, the snippet above suffices to implement a client based off the Pebble-supplied one without much hassle, and that provides lower-level facilities for communicating with the daemon, such as `DoSync()`, `DoAsync()` and `DoAsyncFull()`.
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 to me. (Just the one typo to fix)
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.
Seems ok
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! Quite a few comments, but pretty simple stuff mostly:
* `PersonalityInfo` has been removed in favour of independent variables. * Change `<personality var>` syntax to `{{.PersonalityVar}}`. (e.g. `{{.ProgramName}}` instead of `<program name>`) * Fixed `manfixer` logic in the help command. * Restored variables in help command instead of inline strings.
@benhoyt What's the state of this? Do you think it's merge ready? |
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.
Some changes requested. Note also that the usage help still says "Usage: pebble ...". Can we change that? For example, I've changed ProgramName
to elbbep
locally, and get this:
$ go run ./cmd/pebble run -h
Usage:
pebble run [run-OPTIONS]
...
} | ||
|
||
func (w *manfixer) Write(buf []byte) (int, error) { | ||
if !w.done { | ||
w.done = true | ||
if bytes.HasPrefix(buf, []byte(".TH pebble 1 ")) { | ||
prefix := ".TH " + w.programName + " " |
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 probably had this discussion already ages ago, but can you please explain again why this changes from ".TH pebble 1 "
to ".TH pebble "
, and why the slicing lengths change below?
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 fact that I don't recall the details about this issue validates your point even further (: I'll look at it, fail again to find a better way to do this, and really document it this time.
(Also: see canonical/go-flags#5)
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.
So, apparently this is not changing from .TH pebble 1
to .TH pebble
. What it's doing is identify the .TH <program name>
prefix, find it, and replace the man section number afterwards by an 8
(instead of the default 1
).
The slicing lengths change from fixed magic numbers to the actual lengths of the prefix so that the code appears to be less magic than it was before.
The w.programName
bit comes from the actual go-flags understanding of what is the program name (cmd.parser.Name
).
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. If you could add an updated comment about what's going on here, that would be great.
internals/cli/cmd_run.go
Outdated
@@ -31,16 +31,16 @@ import ( | |||
"github.com/canonical/pebble/internals/systemd" | |||
) | |||
|
|||
const cmdRunSummary = "Run the pebble environment" | |||
const cmdRunSummary = "Run the {{.DisplayName}} environment" | |||
const cmdRunDescription = ` | |||
The run command starts pebble and runs the configured 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.
Need to override this instance too? Probably with {{.DisplayName}}
.
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 like this comment was resolved but not done? The cmdRunDescription
still says "The run command starts pebble..."
internals/cli/cmd_signal.go
Outdated
@@ -28,7 +28,7 @@ const cmdSignalDescription = ` | |||
The signal command sends a signal to one or more running services. The signal | |||
name must be uppercase, for example: | |||
|
|||
pebble signal HUP mysql nginx | |||
{{.ProgramName}} signal HUP mysql nginx |
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.
Any reason this should be indented?
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's indented everywhere else (: Also, the pattern is to even include the shell caret ($
) which I'm not sure if I should include here as well for consistency.
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 other example (in cmd_exec.go
) doesn't use indentation or the $
prefix. How about we drop them here and in cmd_run.go
for consistency?
$ rg '^\s*pebble ' -C2
cmd_signal.go
29-name must be uppercase, for example:
30-
31:pebble signal HUP mysql nginx
32-`
33-
cmd_exec.go
40-arguments using "--", for example:
41-
42:pebble exec --timeout 10s -- echo -n foo bar
43-`
44-
I'll have to look if go-flags allows for such a change. Otherwise I'm afraid we might be stuck with it taking the binary name from argv0. |
Looks like we could change it with this tweak: diff --git a/internals/cli/cli.go b/internals/cli/cli.go
index 4de25ac..86c46e8 100644
--- a/internals/cli/cli.go
+++ b/internals/cli/cli.go
@@ -166,6 +166,7 @@ func Parser(cli *client.Client) *flags.Parser {
flagOpts := flags.Options(flags.PassDoubleDash)
parser := flags.NewParser(&defaultOpts, flagOpts)
+ parser.Command.Name = cmd.ProgramName
parser.ShortDescription = "System and service manager"
parser.LongDescription = applyPersonality(longPebbleDescription) |
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.
Few more minor comments. See note about modifying the "Usage:" thing above.
internals/cli/cmd_signal.go
Outdated
@@ -28,7 +28,7 @@ const cmdSignalDescription = ` | |||
The signal command sends a signal to one or more running services. The signal | |||
name must be uppercase, for example: | |||
|
|||
pebble signal HUP mysql nginx | |||
{{.ProgramName}} signal HUP mysql nginx |
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 other example (in cmd_exec.go
) doesn't use indentation or the $
prefix. How about we drop them here and in cmd_run.go
for consistency?
$ rg '^\s*pebble ' -C2
cmd_signal.go
29-name must be uppercase, for example:
30-
31:pebble signal HUP mysql nginx
32-`
33-
cmd_exec.go
40-arguments using "--", for example:
41-
42:pebble exec --timeout 10s -- echo -n foo bar
43-`
44-
} | ||
|
||
func (w *manfixer) Write(buf []byte) (int, error) { | ||
if !w.done { | ||
w.done = true | ||
if bytes.HasPrefix(buf, []byte(".TH pebble 1 ")) { | ||
prefix := ".TH " + w.programName + " " |
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. If you could add an updated comment about what's going on here, that would be great.
internals/cli/cmd_run.go
Outdated
@@ -31,16 +31,16 @@ import ( | |||
"github.com/canonical/pebble/internals/systemd" | |||
) | |||
|
|||
const cmdRunSummary = "Run the pebble environment" | |||
const cmdRunSummary = "Run the {{.DisplayName}} environment" | |||
const cmdRunDescription = ` | |||
The run command starts pebble and runs the configured 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 like this comment was resolved but not done? The cmdRunDescription
still says "The run command starts pebble..."
@@ -160,7 +160,7 @@ func (cmd *cmdEnter) Execute(args []string) error { | |||
case runStop = <-runReadyCh: | |||
case runPanic := <-runResultCh: | |||
if runPanic == nil { | |||
panic("internal error: pebble daemon stopped early") | |||
panic("internal error: daemon stopped early") |
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.
That's fine -- I'd be happy to reinstate it as {{.DisplayName}}
.
One more thing. Now that the
|
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.
run-checks should be removed. I was confused by one of the changes putting back an explicit "pebble".
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 to me now, thanks!
pebble
/Pebble are removed without changing the semantics of the help manual.