From 927c926884332a9b53c599867a12f4413c692178 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Wed, 26 Jul 2023 04:41:54 -0700 Subject: [PATCH 1/2] exit-once: Clarify that `run()` ins't prescriptive Clarify that the example of using `run()` and `log.Fatal` isn't intended to be prescriptive. Provide samples of using `os.Exit` directly, using different exit codes, and clarify that there's flexibility here on how everything is set up. Refs #189 --- src/exit-once.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/exit-once.md b/src/exit-once.md index 5f31c636..812fa14f 100644 --- a/src/exit-once.md +++ b/src/exit-once.md @@ -75,3 +75,43 @@ func run() error { + +The example above uses `log.Fatal`, but the guidance also applies to +`os.Exit` or any library code that calls `os.Exit`. + +```go +func main() { + if err := run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +``` + +You may alter the signature of `run()` to fit your needs. +For example, if your program must exit with specific exit codes for failures, +`run()` may return the exit code instead of an error. +This allows unit tests to verify this behavior directly as well. + +```go +func main() { + os.Exit(run(args)) +} + +func run() (exitCode int) { + // ... +} +``` + +More generally, note that the `run()` function used in these examples +is not intended to be prescriptive. +There's flexibility in the name, signature, and setup of the `run()` function. +Among other things, you may: + +- accept unparsed command line arguments (e.g., `run(os.Args[1:])`) +- parse command line arguments in `main()` and pass them onto `run` +- use a custom error type to carry the exit code back to `main()` +- put business logic in a different layer of abstraction from `package main` + +This guidance only requires that there's a single place in your `main()` +responsible for actually exiting the process. From b4c8af3a1c4ff778a512c0bb1a78a31f6b3af00f Mon Sep 17 00:00:00 2001 From: abhinav Date: Wed, 26 Jul 2023 11:47:24 +0000 Subject: [PATCH 2/2] Auto-update style.md --- style.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/style.md b/style.md index a8777d21..42ce98ba 100644 --- a/style.md +++ b/style.md @@ -1865,6 +1865,46 @@ func run() error { +The example above uses `log.Fatal`, but the guidance also applies to +`os.Exit` or any library code that calls `os.Exit`. + +```go +func main() { + if err := run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +``` + +You may alter the signature of `run()` to fit your needs. +For example, if your program must exit with specific exit codes for failures, +`run()` may return the exit code instead of an error. +This allows unit tests to verify this behavior directly as well. + +```go +func main() { + os.Exit(run(args)) +} + +func run() (exitCode int) { + // ... +} +``` + +More generally, note that the `run()` function used in these examples +is not intended to be prescriptive. +There's flexibility in the name, signature, and setup of the `run()` function. +Among other things, you may: + +- accept unparsed command line arguments (e.g., `run(os.Args[1:])`) +- parse command line arguments in `main()` and pass them onto `run` +- use a custom error type to carry the exit code back to `main()` +- put business logic in a different layer of abstraction from `package main` + +This guidance only requires that there's a single place in your `main()` +responsible for actually exiting the process. + ### Use field tags in marshaled structs Any struct field that is marshaled into JSON, YAML,