From 3760c2d5079f9bd0254663ae170a1c2ad20212e1 Mon Sep 17 00:00:00 2001 From: Simone Basso Date: Thu, 1 Feb 2024 21:07:28 +0100 Subject: [PATCH] chore(buildtool): support go1.18+ (#1483) See https://github.com/ooni/probe/issues/2664 --- internal/logmodel/logmodel.go | 41 ++++++++++++++++++++++++++++++++++ internal/logx/operation.go | 8 +++---- internal/logx/prefix.go | 6 ++--- internal/logx/scrubber.go | 6 ++--- internal/model/logger.go | 32 +++++--------------------- internal/must/must.go | 8 +++---- internal/shellx/shellx.go | 29 ++++++++++++------------ internal/shellx/shellx_test.go | 6 ++--- script/nocopyreadall.bash | 14 ++++++++++++ 9 files changed, 90 insertions(+), 60 deletions(-) create mode 100644 internal/logmodel/logmodel.go diff --git a/internal/logmodel/logmodel.go b/internal/logmodel/logmodel.go new file mode 100644 index 0000000000..5fcbdb1655 --- /dev/null +++ b/internal/logmodel/logmodel.go @@ -0,0 +1,41 @@ +// Package logmodel contains the core log model. +// +// This package has been separated from the ./internal/model package +// so that ./internal/cmd/buildtool can support go1.18+. +// +// See https://github.com/ooni/probe/issues/2664 for context. +package logmodel + +// DebugLogger is a logger emitting only debug messages. +type DebugLogger interface { + // Debug emits a debug message. + Debug(msg string) + + // Debugf formats and emits a debug message. + Debugf(format string, v ...interface{}) +} + +// InfoLogger is a logger emitting debug and infor messages. +type InfoLogger interface { + // An InfoLogger is also a DebugLogger. + DebugLogger + + // Info emits an informational message. + Info(msg string) + + // Infof formats and emits an informational message. + Infof(format string, v ...interface{}) +} + +// Logger defines the common interface that a logger should have. It is +// out of the box compatible with `log.Log` in `apex/log`. +type Logger interface { + // A Logger is also an InfoLogger. + InfoLogger + + // Warn emits a warning message. + Warn(msg string) + + // Warnf formats and emits a warning message. + Warnf(format string, v ...interface{}) +} diff --git a/internal/logx/operation.go b/internal/logx/operation.go index 58a1ab439a..642e176f2b 100644 --- a/internal/logx/operation.go +++ b/internal/logx/operation.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/logmodel" ) // NewOperationLogger creates a new logger that logs @@ -13,11 +13,11 @@ import ( // time to emit the result of the operation, the code // will emit an interim log message mentioning that the // operation is currently in progress. -func NewOperationLogger(logger model.Logger, format string, v ...any) *OperationLogger { +func NewOperationLogger(logger logmodel.Logger, format string, v ...any) *OperationLogger { return newOperationLogger(500*time.Millisecond, logger, format, v...) } -func newOperationLogger(maxwait time.Duration, logger model.Logger, format string, v ...any) *OperationLogger { +func newOperationLogger(maxwait time.Duration, logger logmodel.Logger, format string, v ...any) *OperationLogger { ol := &OperationLogger{ logger: logger, maxwait: maxwait, @@ -35,7 +35,7 @@ func newOperationLogger(maxwait time.Duration, logger model.Logger, format strin // OperationLogger keeps state required to log about an in-progress // operation as documented by [NewOperationLogger]. type OperationLogger struct { - logger model.Logger + logger logmodel.Logger maxwait time.Duration message string once *sync.Once diff --git a/internal/logx/prefix.go b/internal/logx/prefix.go index 42189e4e83..d02dbdc4e1 100644 --- a/internal/logx/prefix.go +++ b/internal/logx/prefix.go @@ -1,14 +1,14 @@ package logx -import "github.com/ooni/probe-cli/v3/internal/model" +import "github.com/ooni/probe-cli/v3/internal/logmodel" // PrefixLogger is a logger with a prefix. type PrefixLogger struct { Prefix string - Logger model.Logger + Logger logmodel.Logger } -var _ model.Logger = &PrefixLogger{} +var _ logmodel.Logger = &PrefixLogger{} // Debug implements DebugLogger.Debug func (p *PrefixLogger) Debug(msg string) { diff --git a/internal/logx/scrubber.go b/internal/logx/scrubber.go index 2ba139730f..fc2498a7d2 100644 --- a/internal/logx/scrubber.go +++ b/internal/logx/scrubber.go @@ -3,17 +3,17 @@ package logx import ( "fmt" - "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/logmodel" "github.com/ooni/probe-cli/v3/internal/scrubber" ) -// ScrubberLogger is a [model.Logger] with scrubbing. All messages are scrubbed including the ones +// ScrubberLogger is a [logmodel.Logger] with scrubbing. All messages are scrubbed including the ones // that won't be emitted. As such, this logger is less efficient than a logger without scrubbing. // // The zero value is invalid; please init all MANDATORY fields. type ScrubberLogger struct { // Logger is the MANDATORY underlying logger to use. - Logger model.Logger + Logger logmodel.Logger } // Debug scrubs and emits a debug message. diff --git a/internal/model/logger.go b/internal/model/logger.go index 78fbc99198..507e6fa6f9 100644 --- a/internal/model/logger.go +++ b/internal/model/logger.go @@ -1,42 +1,20 @@ package model +import "github.com/ooni/probe-cli/v3/internal/logmodel" + // // Logger // // DebugLogger is a logger emitting only debug messages. -type DebugLogger interface { - // Debug emits a debug message. - Debug(msg string) - - // Debugf formats and emits a debug message. - Debugf(format string, v ...interface{}) -} +type DebugLogger = logmodel.DebugLogger // InfoLogger is a logger emitting debug and infor messages. -type InfoLogger interface { - // An InfoLogger is also a DebugLogger. - DebugLogger - - // Info emits an informational message. - Info(msg string) - - // Infof formats and emits an informational message. - Infof(format string, v ...interface{}) -} +type InfoLogger = logmodel.InfoLogger // Logger defines the common interface that a logger should have. It is // out of the box compatible with `log.Log` in `apex/log`. -type Logger interface { - // A Logger is also an InfoLogger. - InfoLogger - - // Warn emits a warning message. - Warn(msg string) - - // Warnf formats and emits a warning message. - Warnf(format string, v ...interface{}) -} +type Logger = logmodel.Logger // DiscardLogger is the default logger that discards its input var DiscardLogger Logger = logDiscarder{} diff --git a/internal/must/must.go b/internal/must/must.go index f0ffb66ee2..1ba0e9ff73 100644 --- a/internal/must/must.go +++ b/internal/must/must.go @@ -12,7 +12,7 @@ import ( "net/url" "os" - "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/logmodel" "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/shellx" ) @@ -108,7 +108,7 @@ func SplitHostPort(hostport string) (host string, port string) { } // Run is like [shellx.Run] but calls [runtimex.PanicOnError] on failure. -func Run(logger model.Logger, command string, args ...string) { +func Run(logger logmodel.Logger, command string, args ...string) { err := shellx.Run(logger, command, args...) runtimex.PanicOnError(err, "shellx.Run failed") } @@ -121,7 +121,7 @@ func RunQuiet(command string, args ...string) { // RunCommandLine is like [shellx.RunCommandLine] but calls // [runtimex.PanicOnError] on failure. -func RunCommandLine(logger model.Logger, cmdline string) { +func RunCommandLine(logger logmodel.Logger, cmdline string) { err := shellx.RunCommandLine(logger, cmdline) runtimex.PanicOnError(err, "shellx.RunCommandLine failed") } @@ -159,7 +159,7 @@ func FirstLineBytes(data []byte) []byte { // RunOutput is like [shellx.Output] but calls // [runtimex.PanicOnError] on failure. -func RunOutput(logger model.Logger, command string, args ...string) []byte { +func RunOutput(logger logmodel.Logger, command string, args ...string) []byte { out, err := shellx.Output(logger, command, args...) runtimex.PanicOnError(err, "shellx.Output failed") return out diff --git a/internal/shellx/shellx.go b/internal/shellx/shellx.go index e47ad4c7fe..d9a26cd4fb 100644 --- a/internal/shellx/shellx.go +++ b/internal/shellx/shellx.go @@ -2,17 +2,16 @@ package shellx import ( - "context" "errors" "fmt" + "io" "io/fs" "os" "strings" "github.com/google/shlex" "github.com/ooni/probe-cli/v3/internal/fsx" - "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/netxlite" + "github.com/ooni/probe-cli/v3/internal/logmodel" "golang.org/x/sys/execabs" ) @@ -109,7 +108,7 @@ const ( // Config contains config for executing programs. type Config struct { // Logger is the OPTIONAL logger to use. - Logger model.Logger + Logger logmodel.Logger // Flags contains OPTIONAL binary flags to configure the program. Flags int64 @@ -155,7 +154,7 @@ func OutputEx(config *Config, argv *Argv, envp *Envp) ([]byte, error) { } // output is the common implementation of [Output] and [OutputQuiet]. -func output(logger model.Logger, flags int64, command string, args ...string) ([]byte, error) { +func output(logger logmodel.Logger, flags int64, command string, args ...string) ([]byte, error) { argv, err := NewArgv(command, args...) if err != nil { return nil, err @@ -176,7 +175,7 @@ func OutputQuiet(command string, args ...string) ([]byte, error) { // Output is like [OutputQuiet] except that it logs the command to be executed // and the environment variables specific to this command. -func Output(logger model.Logger, command string, args ...string) ([]byte, error) { +func Output(logger logmodel.Logger, command string, args ...string) ([]byte, error) { return output(logger, FlagShowStdoutStderr, command, args...) } @@ -191,7 +190,7 @@ func RunEx(config *Config, argv *Argv, envp *Envp) error { } // run is the common implementation of [Run] and [RunQuiet]. -func run(logger model.Logger, flags int64, command string, args ...string) error { +func run(logger logmodel.Logger, flags int64, command string, args ...string) error { argv, err := NewArgv(command, args...) if err != nil { return err @@ -212,13 +211,13 @@ func RunQuiet(command string, args ...string) error { // Run is like [RunQuiet] except that it also logs the command to // exec, the environment variables specific to this command, the text // logged to stdout and stderr. -func Run(logger model.Logger, command string, args ...string) error { +func Run(logger logmodel.Logger, command string, args ...string) error { return run(logger, FlagShowStdoutStderr, command, args...) } // runCommandLine is the common implementation of // [RunCommandLineQuiet] and [RunCommandLine]. -func runCommandLine(logger model.Logger, flags int64, cmdline string) error { +func runCommandLine(logger logmodel.Logger, flags int64, cmdline string) error { argv, err := ParseCommandLine(cmdline) if err != nil { return err @@ -238,13 +237,13 @@ func RunCommandLineQuiet(cmdline string) error { // RunCommandLine is like [RunCommandLineQuiet] but logs the command to // execute as well as the command-specific environment variables. -func RunCommandLine(logger model.Logger, cmdline string) error { +func RunCommandLine(logger logmodel.Logger, cmdline string) error { return runCommandLine(logger, FlagShowStdoutStderr, cmdline) } // outputCommandLine is the common implementation // of [OutputCommandLineQuiet] and [OutputCommandLine]. -func outputCommandLine(logger model.Logger, flags int64, cmdline string) ([]byte, error) { +func outputCommandLine(logger logmodel.Logger, flags int64, cmdline string) ([]byte, error) { argv, err := ParseCommandLine(cmdline) if err != nil { return nil, err @@ -264,7 +263,7 @@ func OutputCommandLineQuiet(cmdline string) ([]byte, error) { // OutputCommandLine is like OutputCommandLineQuiet but logs the command to // execute as well as the command-specific environment variables. -func OutputCommandLine(logger model.Logger, cmdline string) ([]byte, error) { +func OutputCommandLine(logger logmodel.Logger, cmdline string) ([]byte, error) { return outputCommandLine(logger, FlagShowStdoutStderr, cmdline) } @@ -300,8 +299,8 @@ var fsxOpenFile = fsx.OpenFile // osOpenFile is the generic function to open a file. var osOpenFile = os.OpenFile -// netxliteCopyContext is the generic function to copy content. -var netxliteCopyContext = netxlite.CopyContext +// ioCopy is the generic function to copy content. +var ioCopy = io.Copy // CopyFile copies [source] to [dest]. func CopyFile(source, dest string, perms fs.FileMode) error { @@ -314,7 +313,7 @@ func CopyFile(source, dest string, perms fs.FileMode) error { if err != nil { return err } - if _, err := netxliteCopyContext(context.Background(), destfp, sourcefp); err != nil { + if _, err := ioCopy(destfp, sourcefp); err != nil { destfp.Close() return err } diff --git a/internal/shellx/shellx_test.go b/internal/shellx/shellx_test.go index 241b53659e..3fa753135b 100644 --- a/internal/shellx/shellx_test.go +++ b/internal/shellx/shellx_test.go @@ -1,7 +1,6 @@ package shellx import ( - "context" "errors" "io" "io/fs" @@ -16,7 +15,6 @@ import ( "github.com/ooni/probe-cli/v3/internal/fsx" "github.com/ooni/probe-cli/v3/internal/mocks" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/netxlite" ) // testGolangExe is the golang exe to use in this test suite @@ -479,11 +477,11 @@ func TestCopyFile(t *testing.T) { dest := filepath.Join("testdata", "copy.txt") defer os.Remove(dest) expected := errors.New("mocked error") - netxliteCopyContext = func(ctx context.Context, dst io.Writer, src io.Reader) (int64, error) { + ioCopy = func(dst io.Writer, src io.Reader) (int64, error) { return 0, expected } defer func() { - netxliteCopyContext = netxlite.CopyContext + ioCopy = io.Copy }() if err := CopyFile(source, dest, 0600); !errors.Is(err, expected) { t.Fatal("unexpected error", err) diff --git a/script/nocopyreadall.bash b/script/nocopyreadall.bash index 78a36fe549..15299fca4f 100755 --- a/script/nocopyreadall.bash +++ b/script/nocopyreadall.bash @@ -21,6 +21,20 @@ for file in $(find . -type f -name \*.go); do continue fi + if [ "$file" = "./internal/shellx/shellx.go" ]; then + # We're allowed to use ReadAll and Copy in this file to + # avoid depending on netxlite, given that netxlite's does + # not compile with go1.18 due to the quic dependency. + continue + fi + + if [ "$file" = "./internal/shellx/shellx_test.go" ]; then + # We're allowed to use ReadAll and Copy in this file to + # avoid depending on netxlite, given that netxlite's does + # not compile with go1.18 due to the quic dependency. + continue + fi + if [ "$file" = "./internal/testingsocks5/request.go" ]; then # We're allowed to use ReadAll and Copy in this file because # it's code that we only use for testing purposes.