Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ecec676
Added source code static-check to enforce `--format` output.
cmaglie Dec 1, 2022
3604efa
Slightly improved naming/docs of OutputFormat enumeration
cmaglie Dec 1, 2022
922a3eb
Removed `feedback.Feedback` since only the global instance is used
cmaglie Dec 1, 2022
4d593ad
Moved `cli/output` package into `cli/feedback`
cmaglie Dec 1, 2022
93c2d62
Print progress bar and task progess only on interactive terminals
cmaglie Dec 1, 2022
766da7f
Use feedback functions to output task progress
cmaglie Dec 1, 2022
344669e
User-input functions are now moved into `feedback` package
cmaglie Dec 4, 2022
c850c16
Fix user-input function
cmaglie Dec 4, 2022
53c80b0
Added cmd to test feedback functions
cmaglie Dec 4, 2022
94cb4b5
Better error message
cmaglie Dec 4, 2022
5c41e74
Removed unprotected print
cmaglie Dec 4, 2022
07f4bd0
Removed useless response from Upload and UploadWithProgrammer
cmaglie Dec 5, 2022
36817e7
VersionInfo now implements feedback.Result interface
cmaglie Dec 5, 2022
8d6b33d
Added `feedback` support for direct streaming
cmaglie Dec 6, 2022
5d1fef1
Replace direct use of os.Stdout/Stderr in Upload command
cmaglie Dec 6, 2022
017258c
Implemented feedback.Fatal and FatalError
cmaglie Dec 6, 2022
ad48671
Added output buffers in error messages (if used)
cmaglie Dec 6, 2022
0563574
Removed direct access to stdio streams in monitor command
cmaglie Dec 6, 2022
206370a
Removed direct access to stdio streams in debug command
cmaglie Dec 6, 2022
43d3889
Removed direct access to stdio streams in daemon command
cmaglie Dec 6, 2022
a8c0121
Removed direct access to stdio streams in burn-bootlodaer command
cmaglie Dec 6, 2022
94faeab
Removed direct access to stdio streams in compile command
cmaglie Dec 6, 2022
c2fb4b0
Removed direct access to stdio streams in completion command
cmaglie Dec 6, 2022
9ae0d39
compile: print platforms stats only if present
cmaglie Dec 6, 2022
f64b08b
Removed direct access to stdio streams in --dump-profile command
cmaglie Dec 7, 2022
bbc2a50
Added feedback functions to report warnings
cmaglie Dec 7, 2022
2d0d667
Moved `errorcodes` into `feedback`
cmaglie Dec 9, 2022
61fb1c8
Remove direct os.Stdin access from daemon command
cmaglie Dec 9, 2022
bb0c707
Removed redundant `cli/globals` package
cmaglie Dec 12, 2022
744093a
Made `cli` package internal
cmaglie Dec 12, 2022
6310e1e
updated docs
cmaglie Dec 12, 2022
8e70a61
Removed redundant logic in getter for stdio streams
cmaglie Jan 3, 2023
68be5fa
Internationalize more strings
cmaglie Jan 3, 2023
08fb7e6
Spellcheck internal/cli/feedback/stdio.go
cmaglie Jan 3, 2023
8586cde
Spellcheck internal/cli/feedback/feedback_cmd.go
cmaglie Jan 3, 2023
6a4a1dc
feedback: remove stray '\r' on Windows on interactive input
cmaglie Jan 4, 2023
722138d
Ban use of os.Exit from cli package
cmaglie Jan 4, 2023
ca2451b
Removed unused parameter in compile.Compile
cmaglie Jan 4, 2023
d2db935
Non-interactive stream are always buffered
cmaglie Jan 12, 2023
3ef55a6
Use direct streams where appropiate
cmaglie Jan 12, 2023
3b20b8d
Compile outputs profile dump as part of the result
cmaglie Jan 12, 2023
ab8a756
Report saved warnings also when erroring out
cmaglie Jan 12, 2023
4e05142
Print compile error and suggestions as part of the result
cmaglie Jan 12, 2023
5735f8a
Add trailing newline only if compiler has produced output
cmaglie Jan 12, 2023
3d5ea52
FatalResult now outputs the error on stderr
cmaglie Jan 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added feedback functions to report warnings
  • Loading branch information
cmaglie committed Jan 3, 2023
commit bbc2a50b091335504220b4b9d03f2cf5477ff99d
7 changes: 5 additions & 2 deletions cli/arguments/sketch.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package arguments

import (
"fmt"

"github.com/arduino/arduino-cli/arduino/sketch"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
Expand Down Expand Up @@ -54,9 +56,10 @@ func NewSketch(sketchPath *paths.Path) *sketch.Sketch {
func WarnDeprecatedFiles(sketchPath *paths.Path) {
// .pde files are still supported but deprecated, this warning urges the user to rename them
if files := sketch.CheckForPdeFiles(sketchPath); len(files) > 0 {
feedback.Error(tr("Sketches with .pde extension are deprecated, please rename the following files to .ino:"))
msg := tr("Sketches with .pde extension are deprecated, please rename the following files to .ino:")
for _, f := range files {
feedback.Error(f)
msg += fmt.Sprintf("\n - %s", f)
}
feedback.Warning(msg)
}
}
4 changes: 2 additions & 2 deletions cli/board/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ func runListCommand(cmd *cobra.Command, args []string) {
Timeout: timeoutArg.Get().Milliseconds(),
})
if err != nil {
feedback.Errorf(tr("Error detecting boards: %v"), err)
feedback.Warning(tr("Error detecting boards: %v", err))
}
for _, err := range discvoeryErrors {
feedback.Errorf(tr("Error starting discovery: %v"), err)
feedback.Warning(tr("Error starting discovery: %v", err))
}
feedback.PrintResult(result{ports})
}
Expand Down
7 changes: 4 additions & 3 deletions cli/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,10 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
libs += fmt.Sprintln(" - " + lib.GetName() + " (" + lib.GetVersion() + ")")
}
if hasVendoredLibs {
fmt.Println()
fmt.Println(tr("WARNING: The sketch is compiled using one or more custom libraries."))
fmt.Println(tr("Currently, Build Profiles only support libraries available through Arduino Library Manager."))
msg := "\n"
msg += tr("WARNING: The sketch is compiled using one or more custom libraries.") + "\n"
msg += tr("Currently, Build Profiles only support libraries available through Arduino Library Manager.")
feedback.Warning(msg)
}

newProfileName := "my_profile_name"
Expand Down
11 changes: 5 additions & 6 deletions cli/core/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,16 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool) {
}

// proceed upgrading, if anything is upgradable
exitErr := false
platformsRefs, err := arguments.ParseReferences(args)
if err != nil {
feedback.Fatal(tr("Invalid argument passed: %v", err), errorcodes.ErrBadArgument)
}

hasBadArguments := false
for i, platformRef := range platformsRefs {
if platformRef.Version != "" {
feedback.Errorf(tr("Invalid item %s"), args[i])
exitErr = true
feedback.Warning(tr("Invalid item %s", args[i]))
hasBadArguments = true
continue
}

Expand All @@ -99,7 +99,6 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool) {
Architecture: platformRef.Architecture,
SkipPostInstall: skipPostInstall,
}

if _, err := core.PlatformUpgrade(context.Background(), r, feedback.ProgressBar(), feedback.TaskProgress()); err != nil {
if errors.Is(err, &arduino.PlatformAlreadyAtTheLatestVersionError{}) {
feedback.Print(err.Error())
Expand All @@ -110,7 +109,7 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool) {
}
}

if exitErr {
os.Exit(errorcodes.ErrBadArgument)
if hasBadArguments {
feedback.Fatal(tr("Some upgrades failed, please check the output for details."), errorcodes.ErrBadArgument)
}
}
56 changes: 31 additions & 25 deletions cli/feedback/feedback.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ package feedback
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"os"

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/i18n"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/status"
"gopkg.in/yaml.v2"
)

Expand Down Expand Up @@ -76,6 +74,7 @@ var (
feedbackErr io.Writer
bufferOut *bytes.Buffer
bufferErr *bytes.Buffer
bufferWarnings []string
format OutputFormat
formatSelected bool
)
Expand All @@ -92,6 +91,7 @@ func reset() {
feedbackErr = os.Stderr
bufferOut = &bytes.Buffer{}
bufferErr = &bytes.Buffer{}
bufferWarnings = nil
format = Text
formatSelected = false
}
Expand Down Expand Up @@ -135,6 +135,7 @@ func SetFormat(f OutputFormat) {
} else {
feedbackOut = bufferOut
feedbackErr = bufferErr
bufferWarnings = nil
}
}

Expand All @@ -153,27 +154,14 @@ func Print(v string) {
fmt.Fprintln(feedbackOut, v)
}

// Errorf behaves like fmt.Printf but writes on the error writer and adds a
// newline. It also logs the error.
func Errorf(format string, v ...interface{}) {
// Unbox grpc status errors
for i := range v {
if s, isStatus := v[i].(*status.Status); isStatus {
v[i] = errors.New(s.Message())
} else if err, isErr := v[i].(error); isErr {
if s, isStatus := status.FromError(err); isStatus {
v[i] = errors.New(s.Message())
}
}
// Warning outputs a warning message.
func Warning(msg string) {
if format == Text {
fmt.Fprintln(feedbackErr, msg)
} else {
bufferWarnings = append(bufferWarnings, msg)
}
Error(fmt.Sprintf(format, v...))
}

// Error behaves like fmt.Print but writes on the error writer and adds a
// newline. It also logs the error.
func Error(v ...interface{}) {
fmt.Fprintln(stdErr, v...)
logrus.Error(fmt.Sprint(v...))
logrus.Warning(msg)
}

// FatalError outputs the error and exits with status exitCode.
Expand Down Expand Up @@ -213,26 +201,44 @@ func Fatal(errorMsg string, exitCode int) {
os.Exit(exitCode)
}

func augment(data interface{}) interface{} {
if len(bufferWarnings) == 0 {
return data
}
d, err := json.Marshal(data)
if err != nil {
return data
}
var res interface{}
if err := json.Unmarshal(d, &res); err != nil {
return data
}
if m, ok := res.(map[string]interface{}); ok {
m["warnings"] = bufferWarnings
}
return res
}

// PrintResult is a convenient wrapper to provide feedback for complex data,
// where the contents can't be just serialized to JSON but requires more
// structure.
func PrintResult(res Result) {
var data string
switch format {
case JSON:
d, err := json.MarshalIndent(res.Data(), "", " ")
d, err := json.MarshalIndent(augment(res.Data()), "", " ")
if err != nil {
Fatal(fmt.Sprintf("Error during JSON encoding of the output: %v", err), errorcodes.ErrGeneric)
}
data = string(d)
case MinifiedJSON:
d, err := json.Marshal(res.Data())
d, err := json.Marshal(augment(res.Data()))
if err != nil {
Fatal(fmt.Sprintf("Error during JSON encoding of the output: %v", err), errorcodes.ErrGeneric)
}
data = string(d)
case YAML:
d, err := yaml.Marshal(res.Data())
d, err := yaml.Marshal(augment(res.Data()))
if err != nil {
Fatal(fmt.Sprintf("Error during YAML encoding of the output: %v", err), errorcodes.ErrGeneric)
}
Expand Down
6 changes: 3 additions & 3 deletions cli/instance/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func Init(instance *rpc.Instance) {
func InitWithProfile(instance *rpc.Instance, profileName string, sketchPath *paths.Path) *rpc.Profile {
// In case the CLI is executed for the first time
if err := FirstUpdate(instance); err != nil {
feedback.Errorf(tr("Error initializing instance: %v"), err)
feedback.Warning(tr("Error initializing instance: %v", err))
return nil
}

Expand All @@ -89,7 +89,7 @@ func InitWithProfile(instance *rpc.Instance, profileName string, sketchPath *pat
var profile *rpc.Profile
err := commands.Init(initReq, func(res *rpc.InitResponse) {
if st := res.GetError(); st != nil {
feedback.Errorf(tr("Error initializing instance: %v"), st.Message)
feedback.Warning(tr("Error initializing instance: %v", st.Message))
}

if progress := res.GetInitProgress(); progress != nil {
Expand All @@ -106,7 +106,7 @@ func InitWithProfile(instance *rpc.Instance, profileName string, sketchPath *pat
}
})
if err != nil {
feedback.Errorf(tr("Error initializing instance: %v"), err)
feedback.Warning(tr("Error initializing instance: %v", err))
}

return profile
Expand Down
8 changes: 6 additions & 2 deletions cli/monitor/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,18 @@ func runMonitorCmd(cmd *cobra.Command, args []string) {
go func() {
_, err := io.Copy(tty, portProxy)
if err != nil && !errors.Is(err, io.EOF) {
feedback.Error(tr("Port closed:"), err)
if !quiet {
feedback.Print(tr("Port closed: %v", err))
}
}
cancel()
}()
go func() {
_, err := io.Copy(portProxy, tty)
if err != nil && !errors.Is(err, io.EOF) {
feedback.Error(tr("Port closed:"), err)
if !quiet {
feedback.Print(tr("Port closed: %v", err))
}
}
cancel()
}()
Expand Down
4 changes: 3 additions & 1 deletion cli/updater/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package updater

import (
"fmt"
"os"
"strings"
"time"
Expand Down Expand Up @@ -66,11 +67,12 @@ func ForceCheckForUpdate(currentVersion *semver.Version) *semver.Version {

// NotifyNewVersionIsAvailable prints information about the new latestVersion
func NotifyNewVersionIsAvailable(latestVersion string) {
feedback.Errorf("\n\n%s %s → %s\n%s",
msg := fmt.Sprintf("\n\n%s %s → %s\n%s",
color.YellowString(tr("A new release of Arduino CLI is available:")),
color.CyanString(globals.VersionInfo.VersionString),
color.CyanString(latestVersion),
color.YellowString("https://arduino.github.io/arduino-cli/latest/installation/#latest-packages"))
feedback.Warning(msg)
}

// shouldCheckForUpdate return true if it actually makes sense to check for new updates,
Expand Down
10 changes: 5 additions & 5 deletions configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func Init(configFile string) *viper.Viper {
// ConfigFileNotFoundError is acceptable, anything else
// should be reported to the user
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
feedback.Errorf(tr("Error reading config file: %v"), err)
feedback.Warning(tr("Error reading config file: %v", err))
}
}

Expand All @@ -85,7 +85,7 @@ func BindFlags(cmd *cobra.Command, settings *viper.Viper) {
func getDefaultArduinoDataDir() string {
userHomeDir, err := os.UserHomeDir()
if err != nil {
feedback.Errorf(tr("Unable to get user home dir: %v"), err)
feedback.Warning(tr("Unable to get user home dir: %v", err))
return "."
}

Expand All @@ -97,7 +97,7 @@ func getDefaultArduinoDataDir() string {
case "windows":
localAppDataPath, err := win32.GetLocalAppDataFolder()
if err != nil {
feedback.Errorf(tr("Unable to get Local App Data Folder: %v"), err)
feedback.Warning(tr("Unable to get Local App Data Folder: %v", err))
return "."
}
return filepath.Join(localAppDataPath, "Arduino15")
Expand All @@ -110,7 +110,7 @@ func getDefaultArduinoDataDir() string {
func getDefaultUserDir() string {
userHomeDir, err := os.UserHomeDir()
if err != nil {
feedback.Errorf(tr("Unable to get user home dir: %v"), err)
feedback.Warning(tr("Unable to get user home dir: %v", err))
return "."
}

Expand All @@ -122,7 +122,7 @@ func getDefaultUserDir() string {
case "windows":
documentsPath, err := win32.GetDocumentsFolder()
if err != nil {
feedback.Errorf(tr("Unable to get Documents Folder: %v"), err)
feedback.Warning(tr("Unable to get Documents Folder: %v", err))
return "."
}
return filepath.Join(documentsPath, "Arduino")
Expand Down