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

[BREAKING] feat: added details to all init errors #2097

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 5 additions & 3 deletions arduino/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,11 @@ func (e *PlatformLoadingError) Error() string {

// ToRPCStatus converts the error into a *status.Status
func (e *PlatformLoadingError) ToRPCStatus() *status.Status {
s, _ := status.New(codes.FailedPrecondition, e.Error()).
WithDetails(&rpc.PlatformLoadingError{})
return s
return (&InitFailedError{
Code: codes.FailedPrecondition,
Cause: e.Cause,
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_PLATFORM_LOAD_ERROR,
}).ToRPCStatus()
}

func (e *PlatformLoadingError) Unwrap() error {
Expand Down
87 changes: 45 additions & 42 deletions commands/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ func Create(req *rpc.CreateRequest, extraUserAgent ...string) (*rpc.CreateRespon
}, nil
}

type rpcStatusConverter interface {
ToRPCStatus() *status.Status
}

// Init loads installed libraries and Platforms in CoreInstance with specified ID,
// a gRPC status error is returned if the CoreInstance doesn't exist.
// All responses are sent through responseCallback, can be nil to ignore all responses.
Expand All @@ -214,10 +218,11 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
if responseCallback == nil {
responseCallback = func(r *rpc.InitResponse) {}
}
responseError := func(st *status.Status) {

responseError := func(e rpcStatusConverter) {
responseCallback(&rpc.InitResponse{
Message: &rpc.InitResponse_Error{
Error: st.Proto(),
Error: e.ToRPCStatus().Proto(),
},
})
}
Expand Down Expand Up @@ -278,17 +283,19 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
// Load Platforms
if profile == nil {
for _, err := range pmb.LoadHardware() {
s := &arduino.PlatformLoadingError{Cause: err}
responseError(s.ToRPCStatus())
responseError(&arduino.InitFailedError{
Code: codes.Internal,
Cause: err,
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_TOOL_LOAD_ERROR,
})
}
} else {
// Load platforms from profile
errs := pmb.LoadHardwareForProfile(
profile, true, downloadCallback, taskCallback,
)
for _, err := range errs {
s := &arduino.PlatformLoadingError{Cause: err}
responseError(s.ToRPCStatus())
responseError(&arduino.PlatformLoadingError{Cause: err})
}

// Load "builtin" tools
Expand All @@ -303,35 +310,28 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
for _, u := range urls {
URL, err := utils.URLParse(u)
if err != nil {
e := &arduino.InitFailedError{
responseError(&arduino.InitFailedError{
Code: codes.InvalidArgument,
Cause: fmt.Errorf(tr("Invalid additional URL: %v", err)),
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_INVALID_INDEX_URL,
}
responseError(e.ToRPCStatus())
})
continue
}

var loadFunc func(*url.URL) error = pmb.LoadPackageIndex
if URL.Scheme == "file" {
_, err := pmb.LoadPackageIndexFromFile(paths.New(URL.Path))
if err != nil {
e := &arduino.InitFailedError{
Code: codes.FailedPrecondition,
Cause: fmt.Errorf(tr("Loading index file: %v", err)),
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_INDEX_LOAD_ERROR,
}
responseError(e.ToRPCStatus())
loadFunc = func(u *url.URL) error {
_, err := pmb.LoadPackageIndexFromFile(paths.New(URL.Path))
return err
}
continue
}

if err := pmb.LoadPackageIndex(URL); err != nil {
e := &arduino.InitFailedError{
if err := loadFunc(URL); err != nil {
responseError(&arduino.InitFailedError{
Code: codes.FailedPrecondition,
Cause: fmt.Errorf(tr("Loading index file: %v", err)),
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_INDEX_LOAD_ERROR,
}
responseError(e.ToRPCStatus())
})
}
}

Expand All @@ -343,12 +343,11 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
for name, tool := range pmb.GetOrCreatePackage("builtin").Tools {
latest := tool.LatestRelease()
if latest == nil {
e := &arduino.InitFailedError{
responseError(&arduino.InitFailedError{
Code: codes.Internal,
Cause: fmt.Errorf(tr("can't find latest release of tool %s", name)),
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_TOOL_LOAD_ERROR,
}
responseError(e.ToRPCStatus())
})
} else if !latest.IsInstalled() {
builtinToolsToInstall = append(builtinToolsToInstall, latest)
}
Expand All @@ -358,20 +357,22 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
if len(builtinToolsToInstall) > 0 {
for _, toolRelease := range builtinToolsToInstall {
if err := installTool(pmb.Build(), toolRelease, downloadCallback, taskCallback); err != nil {
e := &arduino.InitFailedError{
responseError(&arduino.InitFailedError{
Code: codes.Internal,
Cause: err,
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_TOOL_LOAD_ERROR,
}
responseError(e.ToRPCStatus())
})
}
}

// We installed at least one builtin tool after loading hardware
// so we must reload again otherwise we would never found them.
for _, err := range loadBuiltinTools() {
s := &arduino.PlatformLoadingError{Cause: err}
responseError(s.ToRPCStatus())
responseError(&arduino.InitFailedError{
Code: codes.Internal,
Cause: err,
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_TOOL_LOAD_ERROR,
})
}
}

Expand All @@ -382,8 +383,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
defer release()

for _, err := range pme.LoadDiscoveries() {
s := &arduino.PlatformLoadingError{Cause: err}
responseError(s.ToRPCStatus())
responseError(&arduino.PlatformLoadingError{Cause: err})
}

// Create library manager and add libraries directories
Expand All @@ -403,8 +403,11 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
}

if err := lm.LoadIndex(); err != nil {
s := status.Newf(codes.FailedPrecondition, tr("Loading index file: %v"), err)
responseError(s)
responseError(&arduino.InitFailedError{
Code: codes.FailedPrecondition,
Cause: fmt.Errorf(tr("Loading index file: %v", err)),
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_LIBRARY_LOAD_ERROR,
})
}

if profile == nil {
Expand All @@ -431,14 +434,12 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
})
if libRelease == nil {
taskCallback(&rpc.TaskProgress{Name: tr("Library %s not found", libraryRef)})
err := &arduino.LibraryNotFoundError{Library: libraryRef.Library}
responseError(err.ToRPCStatus())
responseError(&arduino.LibraryNotFoundError{Library: libraryRef.Library})
continue
}
if err := libRelease.Resource.Download(lm.DownloadsDir, nil, libRelease.String(), downloadCallback, ""); err != nil {
taskCallback(&rpc.TaskProgress{Name: tr("Error downloading library %s", libraryRef)})
e := &arduino.FailedLibraryInstallError{Cause: err}
responseError(e.ToRPCStatus())
responseError(&arduino.FailedLibraryInstallError{Cause: err})
continue
}
taskCallback(&rpc.TaskProgress{Completed: true})
Expand All @@ -447,8 +448,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
taskCallback(&rpc.TaskProgress{Name: tr("Installing library %s", libraryRef)})
if err := libRelease.Resource.Install(lm.DownloadsDir, libRoot, libDir); err != nil {
taskCallback(&rpc.TaskProgress{Name: tr("Error installing library %s", libraryRef)})
e := &arduino.FailedLibraryInstallError{Cause: err}
responseError(e.ToRPCStatus())
responseError(&arduino.FailedLibraryInstallError{Cause: err})
continue
}
taskCallback(&rpc.TaskProgress{Completed: true})
Expand All @@ -459,8 +459,11 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
}

for _, err := range lm.RescanLibraries() {
s := status.Newf(codes.FailedPrecondition, tr("Loading libraries: %v"), err)
responseError(s)
responseError(&arduino.InitFailedError{
Code: codes.FailedPrecondition,
Cause: fmt.Errorf(tr("Loading libraries: %v"), err),
Reason: rpc.FailedInstanceInitReason_FAILED_INSTANCE_INIT_REASON_LIBRARY_LOAD_ERROR,
})
}

// Refreshes the locale used, this will change the
Expand Down
5 changes: 5 additions & 0 deletions docs/UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Here you can find a list of migration guides to handle breaking changes between

## 0.32.0

### PlatformLoadingError error reshaped

In the gRPC API the type `PlatformLoadingError` is dropped. Now a `FailedInstanceInitError` is returned as error details
instead of it with the reason field set to `FAILED_INSTANCE_INIT_REASON_PLATFORM_LOAD_ERROR`.

### `arduino-cli` doesn't lookup anymore in the current directory for configuration file.

Configuration file lookup in current working directory and its parents is dropped. The command line flag `--config-file`
Expand Down
Loading