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
Implemented feedback.Fatal and FatalError
These functions outputs the error (also in machine-encoded if user
choose to do so) and at the same time exits with os.Exit().

This API is much more readable and provides a better meaning to the CLI
commands implementation.
  • Loading branch information
cmaglie committed Jan 3, 2023
commit 017258ca9429dabfbd83c13d93a27463db0dc866
12 changes: 6 additions & 6 deletions cli/arguments/arguments.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package arguments

import (
"os"
"strings"

"github.com/arduino/arduino-cli/cli/errorcodes"
Expand All @@ -34,18 +33,19 @@ func CheckFlagsConflicts(command *cobra.Command, flagNames ...string) {
return
}
}
feedback.Errorf(tr("Can't use %s flags at the same time.", "--"+strings.Join(flagNames, " "+tr("and")+" --")))
os.Exit(errorcodes.ErrBadArgument)
flags := "--" + strings.Join(flagNames, ", --")
msg := tr("Can't use the following flags together: %s", flags)
feedback.Fatal(msg, errorcodes.ErrBadArgument)
}

// CheckFlagsMandatory is a helper function useful to report errors when at least one flag is not used in a group of "required" flags
func CheckFlagsMandatory(command *cobra.Command, flagNames ...string) {
for _, flagName := range flagNames {
if command.Flag(flagName).Changed {
continue
} else {
feedback.Errorf(tr("Flag %[1]s is mandatory when used in conjunction with flag %[2]s.", "--"+flagName, "--"+strings.Join(flagNames, " "+tr("and")+" --")))
os.Exit(errorcodes.ErrBadArgument)
}
flags := "--" + strings.Join(flagNames, ", --")
msg := tr("Flag %[1]s is mandatory when used in conjunction with: %[2]s", "--"+flagName, flags)
feedback.Fatal(msg, errorcodes.ErrBadArgument)
}
}
10 changes: 3 additions & 7 deletions cli/arguments/fqbn.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package arguments

import (
"os"
"strings"

"github.com/arduino/arduino-cli/arduino"
Expand Down Expand Up @@ -81,21 +80,18 @@ func CalculateFQBNAndPort(portArgs *Port, fqbnArg *Fqbn, instance *rpc.Instance,
}
if fqbn == "" {
if portArgs == nil || portArgs.address == "" {
feedback.Error(&arduino.MissingFQBNError{})
os.Exit(errorcodes.ErrGeneric)
feedback.FatalError(&arduino.MissingFQBNError{}, errorcodes.ErrGeneric)
}
fqbn, port := portArgs.DetectFQBN(instance)
if fqbn == "" {
feedback.Error(&arduino.MissingFQBNError{})
os.Exit(errorcodes.ErrGeneric)
feedback.FatalError(&arduino.MissingFQBNError{}, errorcodes.ErrGeneric)
}
return fqbn, port
}

port, err := portArgs.GetPort(instance, sk)
if err != nil {
feedback.Errorf(tr("Error getting port metadata: %v", err))
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error getting port metadata: %v", err), errorcodes.ErrGeneric)
}
return fqbn, port.ToRPC()
}
10 changes: 3 additions & 7 deletions cli/arguments/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package arguments

import (
"fmt"
"os"
"time"

"github.com/arduino/arduino-cli/arduino"
Expand Down Expand Up @@ -147,8 +146,7 @@ func (p *Port) DetectFQBN(inst *rpc.Instance) (string, *rpc.Port) {
Timeout: p.timeout.Get().Milliseconds(),
})
if err != nil {
feedback.Errorf(tr("Error during FQBN detection: %v", err))
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error during FQBN detection: %v", err), errorcodes.ErrGeneric)
}
for _, detectedPort := range detectedPorts {
port := detectedPort.GetPort()
Expand All @@ -159,12 +157,10 @@ func (p *Port) DetectFQBN(inst *rpc.Instance) (string, *rpc.Port) {
continue
}
if len(detectedPort.MatchingBoards) > 1 {
feedback.Error(&arduino.MultipleBoardsDetectedError{Port: port})
os.Exit(errorcodes.ErrBadArgument)
feedback.FatalError(&arduino.MultipleBoardsDetectedError{Port: port}, errorcodes.ErrBadArgument)
}
if len(detectedPort.MatchingBoards) == 0 {
feedback.Error(&arduino.NoBoardsDetectedError{Port: port})
os.Exit(errorcodes.ErrBadArgument)
feedback.FatalError(&arduino.NoBoardsDetectedError{Port: port}, errorcodes.ErrBadArgument)
}
return detectedPort.MatchingBoards[0].Fqbn, port
}
Expand Down
8 changes: 2 additions & 6 deletions cli/arguments/sketch.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
package arguments

import (
"os"

"github.com/arduino/arduino-cli/arduino/sketch"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
Expand All @@ -34,8 +32,7 @@ func InitSketchPath(path string) (sketchPath *paths.Path) {
} else {
wd, err := paths.Getwd()
if err != nil {
feedback.Errorf(tr("Couldn't get current working directory: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Couldn't get current working directory: %v", err), errorcodes.ErrGeneric)
}
logrus.Infof("Reading sketch from dir: %s", wd)
sketchPath = wd
Expand All @@ -48,8 +45,7 @@ func InitSketchPath(path string) (sketchPath *paths.Path) {
func NewSketch(sketchPath *paths.Path) *sketch.Sketch {
sketch, err := sketch.New(sketchPath)
if err != nil {
feedback.Errorf(tr("Error opening sketch: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error opening sketch: %v", err), errorcodes.ErrGeneric)
}
return sketch
}
Expand Down
6 changes: 2 additions & 4 deletions cli/board/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ func runAttachCommand(path string, port *arguments.Port, fqbn string) {
address, protocol, _ := port.GetPortAddressAndProtocol(nil, sk)
if address != "" {
if err := sk.SetDefaultPort(address, protocol); err != nil {
feedback.Errorf("%s: %s", tr("Error saving sketch metadata"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(fmt.Sprintf("%s: %s", tr("Error saving sketch metadata"), err), errorcodes.ErrGeneric)
}
current.Port = &boardAttachPortResult{
Address: address,
Expand All @@ -77,8 +76,7 @@ func runAttachCommand(path string, port *arguments.Port, fqbn string) {
}
if fqbn != "" {
if err := sk.SetDefaultFQBN(fqbn); err != nil {
feedback.Errorf("%s: %s", tr("Error saving sketch metadata"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(fmt.Sprintf("%s: %s", tr("Error saving sketch metadata"), err), errorcodes.ErrGeneric)
}
current.Fqbn = fqbn
}
Expand Down
3 changes: 1 addition & 2 deletions cli/board/details.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ func runDetailsCommand(cmd *cobra.Command, args []string) {
})

if err != nil {
feedback.Errorf(tr("Error getting board details: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error getting board details: %v", err), errorcodes.ErrGeneric)
}

feedback.PrintResult(detailsResult{details: res})
Expand Down
3 changes: 1 addition & 2 deletions cli/board/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ func runListCommand(cmd *cobra.Command, args []string) {
func watchList(cmd *cobra.Command, inst *rpc.Instance) {
eventsChan, closeCB, err := board.Watch(&rpc.BoardListWatchRequest{Instance: inst})
if err != nil {
feedback.Errorf(tr("Error detecting boards: %v"), err)
os.Exit(errorcodes.ErrNetwork)
feedback.Fatal(tr("Error detecting boards: %v", err), errorcodes.ErrNetwork)
}
defer closeCB()

Expand Down
3 changes: 1 addition & 2 deletions cli/board/listall.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ func runListAllCommand(cmd *cobra.Command, args []string) {
IncludeHiddenBoards: showHiddenBoard,
})
if err != nil {
feedback.Errorf(tr("Error listing boards: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error listing boards: %v", err), errorcodes.ErrGeneric)
}

feedback.PrintResult(resultAll{list})
Expand Down
3 changes: 1 addition & 2 deletions cli/board/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ func runSearchCommand(cmd *cobra.Command, args []string) {
IncludeHiddenBoards: showHiddenBoard,
})
if err != nil {
feedback.Errorf(tr("Error searching boards: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error searching boards: %v", err), errorcodes.ErrGeneric)
}

feedback.PrintResult(searchResults{res.Boards})
Expand Down
6 changes: 2 additions & 4 deletions cli/burnbootloader/burnbootloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ func runBootloaderCommand(command *cobra.Command, args []string) {
// We don't need a Sketch to upload a board's bootloader
discoveryPort, err := port.GetPort(instance, nil)
if err != nil {
feedback.Errorf(tr("Error during Upload: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error during Upload: %v", err), errorcodes.ErrGeneric)
}

if _, err := upload.BurnBootloader(context.Background(), &rpc.BurnBootloaderRequest{
Expand All @@ -83,8 +82,7 @@ func runBootloaderCommand(command *cobra.Command, args []string) {
Programmer: programmer.String(),
DryRun: dryRun,
}, os.Stdout, os.Stderr); err != nil {
feedback.Errorf(tr("Error during Upload: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error during Upload: %v", err), errorcodes.ErrGeneric)
}
os.Exit(0)
}
3 changes: 1 addition & 2 deletions cli/cache/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ func runCleanCommand(cmd *cobra.Command, args []string) {
cachePath := configuration.DownloadsDir(configuration.Settings)
err := cachePath.RemoveAll()
if err != nil {
feedback.Errorf(tr("Error cleaning caches: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error cleaning caches: %v", err), errorcodes.ErrGeneric)
}
}
15 changes: 5 additions & 10 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ func preRun(cmd *cobra.Command, args []string) {
// initialize inventory
err := inventory.Init(configuration.DataDir(configuration.Settings).String())
if err != nil {
feedback.Errorf("Error: %v", err)
os.Exit(errorcodes.ErrBadArgument)
feedback.Fatal(fmt.Sprintf("Error: %v", err), errorcodes.ErrBadArgument)
}

// https://no-color.org/
Expand Down Expand Up @@ -201,8 +200,7 @@ func preRun(cmd *cobra.Command, args []string) {
if logFile != "" {
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
feedback.Errorf(tr("Unable to open file for logging: %s", logFile))
os.Exit(errorcodes.ErrBadCall)
feedback.Fatal(tr("Unable to open file for logging: %s", logFile), errorcodes.ErrBadCall)
}

// we use a hook so we don't get color codes in the log file
Expand All @@ -215,8 +213,7 @@ func preRun(cmd *cobra.Command, args []string) {

// configure logging filter
if lvl, found := toLogLevel(configuration.Settings.GetString("logging.level")); !found {
feedback.Errorf(tr("Invalid option for --log-level: %s"), configuration.Settings.GetString("logging.level"))
os.Exit(errorcodes.ErrBadArgument)
feedback.Fatal(tr("Invalid option for --log-level: %s", configuration.Settings.GetString("logging.level")), errorcodes.ErrBadArgument)
} else {
logrus.SetLevel(lvl)
}
Expand All @@ -228,8 +225,7 @@ func preRun(cmd *cobra.Command, args []string) {
// check the right output format was passed
format, found := feedback.ParseOutputFormat(outputFormat)
if !found {
feedback.Errorf(tr("Invalid output format: %s"), outputFormat)
os.Exit(errorcodes.ErrBadCall)
feedback.Fatal(tr("Invalid output format: %s", outputFormat), errorcodes.ErrBadCall)
}

// use the output format to configure the Feedback
Expand All @@ -250,8 +246,7 @@ func preRun(cmd *cobra.Command, args []string) {
if outputFormat != "text" {
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
logrus.Warn("Calling help on JSON format")
feedback.Error(tr("Invalid Call : should show Help, but it is available only in TEXT mode."))
os.Exit(errorcodes.ErrBadCall)
feedback.Fatal(tr("Invalid Call : should show Help, but it is available only in TEXT mode."), errorcodes.ErrBadCall)
})
}
}
Expand Down
34 changes: 14 additions & 20 deletions cli/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,14 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
logrus.Info("Executing `arduino-cli compile`")

if dumpProfile && feedback.GetFormat() != feedback.Text {
feedback.Errorf(tr("You cannot use the %[1]s flag together with %[2]s.", "--dump-profile", "--format json"))
os.Exit(errorcodes.ErrBadArgument)
feedback.Fatal(tr("You cannot use the %[1]s flag together with %[2]s.", "--dump-profile", "--format json"), errorcodes.ErrBadArgument)
}
if profileArg.Get() != "" {
if len(libraries) > 0 {
feedback.Errorf(tr("You cannot use the %s flag while compiling with a profile.", "--libraries"))
os.Exit(errorcodes.ErrBadArgument)
feedback.Fatal(tr("You cannot use the %s flag while compiling with a profile.", "--libraries"), errorcodes.ErrBadArgument)
}
if len(library) > 0 {
feedback.Errorf(tr("You cannot use the %s flag while compiling with a profile.", "--library"))
os.Exit(errorcodes.ErrBadArgument)
feedback.Fatal(tr("You cannot use the %s flag while compiling with a profile.", "--library"), errorcodes.ErrBadArgument)
}
}

Expand All @@ -185,15 +182,13 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
if sourceOverrides != "" {
data, err := paths.New(sourceOverrides).ReadFile()
if err != nil {
feedback.Errorf(tr("Error opening source code overrides data file: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error opening source code overrides data file: %v", err), errorcodes.ErrGeneric)
}
var o struct {
Overrides map[string]string `json:"overrides"`
}
if err := json.Unmarshal(data, &o); err != nil {
feedback.Errorf(tr("Error: invalid source code overrides data file: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error: invalid source code overrides data file: %v", err), errorcodes.ErrGeneric)
}
overrides = o.Overrides
}
Expand Down Expand Up @@ -241,16 +236,14 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
Protocol: port.Protocol,
})
if err != nil {
feedback.Errorf(tr("Error during Upload: %v", err))
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error during Upload: %v", err), errorcodes.ErrGeneric)
}

fields := map[string]string{}
if len(userFieldRes.UserFields) > 0 {
feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.Protocol))
if f, err := arguments.AskForUserFields(userFieldRes.UserFields); err != nil {
feedback.Error(err)
os.Exit(errorcodes.ErrBadArgument)
feedback.FatalError(err, errorcodes.ErrBadArgument)
} else {
fields = f
}
Expand Down Expand Up @@ -278,8 +271,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
uploadError = upload.Upload(context.Background(), uploadRequest, os.Stdout, os.Stderr)
}
if uploadError != nil {
feedback.Errorf(tr("Error during Upload: %v"), uploadError)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error during Upload: %v", uploadError), errorcodes.ErrGeneric)
}
}

Expand Down Expand Up @@ -338,7 +330,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
Success: compileError == nil,
})
if compileError != nil {
feedback.Errorf(tr("Error during build: %v"), compileError)
msg := tr("Error during build: %v", compileError)

// Check the error type to give the user better feedback on how
// to resolve it
Expand All @@ -358,14 +350,16 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
release()

if profileArg.String() == "" {
msg += "\n"
if platform != nil {
feedback.Errorf(tr("Try running %s", fmt.Sprintf("`%s core install %s`", globals.VersionInfo.Application, platformErr.Platform)))
suggestion := fmt.Sprintf("`%s core install %s`", globals.VersionInfo.Application, platformErr.Platform)
msg += tr("Try running %s", suggestion)
} else {
feedback.Errorf(tr("Platform %s is not found in any known index\nMaybe you need to add a 3rd party URL?", platformErr.Platform))
msg += tr("Platform %s is not found in any known index\nMaybe you need to add a 3rd party URL?", platformErr.Platform)
}
}
}
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(msg, errorcodes.ErrGeneric)
}
}

Expand Down
3 changes: 1 addition & 2 deletions cli/completion/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ func NewCommand() *cobra.Command {
func runCompletionCommand(cmd *cobra.Command, args []string) {
logrus.Info("Executing `arduino-cli completion`")
if completionNoDesc && (args[0] == "powershell") {
feedback.Errorf(tr("Error: command description is not supported by %v"), args[0])
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Error: command description is not supported by %v", args[0]), errorcodes.ErrGeneric)
}
switch args[0] {
case "bash":
Expand Down
7 changes: 3 additions & 4 deletions cli/config/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ func runAddCommand(cmd *cobra.Command, args []string) {
kind := validateKey(key)

if kind != reflect.Slice {
feedback.Errorf(tr("The key '%[1]v' is not a list of items, can't add to it.\nMaybe use '%[2]s'?"), key, "config set")
os.Exit(errorcodes.ErrGeneric)
msg := tr("The key '%[1]v' is not a list of items, can't add to it.\nMaybe use '%[2]s'?", key, "config set")
feedback.Fatal(msg, errorcodes.ErrGeneric)
}

v := configuration.Settings.GetStringSlice(key)
Expand All @@ -101,7 +101,6 @@ func runAddCommand(cmd *cobra.Command, args []string) {
configuration.Settings.Set(key, v)

if err := configuration.Settings.WriteConfig(); err != nil {
feedback.Errorf(tr("Can't write config file: %v"), err)
os.Exit(errorcodes.ErrGeneric)
feedback.Fatal(tr("Can't write config file: %v", err), errorcodes.ErrGeneric)
}
}
Loading