Skip to content
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

Merged
merged 16 commits into from
Nov 21, 2023

Conversation

anpep
Copy link
Collaborator

@anpep anpep commented Jun 14, 2023

  • Implements the concept of personality, two variables that contain 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.

 * 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.
@anpep anpep self-assigned this Jun 14, 2023
@@ -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")

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?

Copy link
Contributor

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}}.

internals/cli/cmd_exec.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
If the client panics due to the Pebble daemon stopping early,
include the program name from personality so it's unambiguous.
@anpep anpep requested review from atesburak and benhoyt June 19, 2023 07:45
Copy link
Contributor

@flotter flotter left a 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.

internals/cli/cli.go Show resolved Hide resolved
internals/cli/cli.go Outdated Show resolved Hide resolved
internals/cli/cli.go Outdated Show resolved Hide resolved
internals/cli/cmd_enter.go Outdated Show resolved Hide resolved
internals/cli/cmd_enter.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Show resolved Hide resolved
internals/cli/cmd_run.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cli.go Show resolved Hide resolved
internals/cli/cli.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_run.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Show resolved Hide resolved
Copy link

@atesburak atesburak left a 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

@anpep
Copy link
Collaborator Author

anpep commented Jul 11, 2023 via email

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.
@anpep anpep requested a review from niemeyer July 24, 2023 08:03
@anpep
Copy link
Collaborator Author

anpep commented Jul 24, 2023

This PR is ready for review now, but changes will be required when #232 is merged.

anpep added a commit to anpep/pebble that referenced this pull request Jul 31, 2023
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()`.
@anpep anpep mentioned this pull request Jul 31, 2023
Copy link
Contributor

@flotter flotter left a 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)

internals/cli/cmd_run.go Outdated Show resolved Hide resolved
@anpep anpep changed the title cli: make CLI name-agnostic feat(cli): implement personality for application name-agnostic help manuals Aug 23, 2023
Copy link
Contributor

@paul-rodriguez paul-rodriguez left a comment

Choose a reason for hiding this comment

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

Seems ok

Copy link
Contributor

@niemeyer niemeyer left a 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:

internals/cli/cmd_help.go Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cli.go Outdated Show resolved Hide resolved
internals/cli/cmd_exec.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_help.go Outdated Show resolved Hide resolved
internals/cli/cmd_run.go Outdated Show resolved Hide resolved
internals/cli/cmd_warnings.go Outdated Show resolved Hide resolved
cmd/version.go Outdated Show resolved Hide resolved
 * `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.
@anpep anpep requested a review from niemeyer September 11, 2023 13:03
@anpep
Copy link
Collaborator Author

anpep commented Nov 15, 2023

@benhoyt What's the state of this? Do you think it's merge ready?

@anpep anpep added the Reviewed label Nov 15, 2023
Copy link
Contributor

@benhoyt benhoyt left a 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]
...

cmd/version.go Outdated Show resolved Hide resolved
internals/cli/cli.go Show resolved Hide resolved
internals/cli/cli.go Outdated Show resolved Hide resolved
internals/cli/cmd_enter.go Outdated Show resolved Hide resolved
}

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 + " "
Copy link
Contributor

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?

Copy link
Collaborator Author

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)

Copy link
Collaborator Author

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).

Copy link
Contributor

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_help.go Outdated Show resolved Hide resolved
@@ -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.
Copy link
Contributor

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}}.

Copy link
Contributor

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_run.go Outdated Show resolved Hide resolved
@@ -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
Copy link
Contributor

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?

Copy link
Collaborator Author

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.

Copy link
Contributor

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-

@anpep
Copy link
Collaborator Author

anpep commented Nov 20, 2023

Note also that the usage help still says "Usage: pebble ...". Can we change that?

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.

@benhoyt
Copy link
Contributor

benhoyt commented Nov 20, 2023

Note also that the usage help still says "Usage: pebble ...". Can we change that?

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)

Copy link
Contributor

@benhoyt benhoyt left a 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.

@@ -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
Copy link
Contributor

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-

run-checks Outdated Show resolved Hide resolved
}

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 + " "
Copy link
Contributor

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.

@@ -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.
Copy link
Contributor

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")
Copy link
Contributor

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}}.

@benhoyt
Copy link
Contributor

benhoyt commented Nov 20, 2023

One more thing. Now that the pebble notices command is merged, we need to update that to use {{.ProgramName}} too. I've changed ProgramName and DisplayName locally to something other than "pebble" / "Pebble", and get this (the run one I've already noted above):

$ go run ./cmd/pebble help --man >manpage 
$ grep -i pebble manpage
may then be acknowledged by running 'pebble okay'. When a notice repeats, it
The \fIrun\fP command starts pebble and runs the configured environment.

Copy link
Contributor

@paul-rodriguez paul-rodriguez left a 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".

Copy link
Contributor

@benhoyt benhoyt left a 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!

@benhoyt benhoyt merged commit 4593177 into canonical:master Nov 21, 2023
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants