Skip to content

Use the CLI's error codes to detect when the primary package index, library index, hardware platform is missing on IDE2 startup #1925

Open
@kittaakos

Description

@kittaakos
Contributor

Describe the request

The CLI can programmatically indicate when the InitRequest has failed: arduino/arduino-cli#2076

IDE2 should eliminate the error-prone message parsing and use error codes to be more robust.

Describe the current behavior

IDE2 parsers the English error message and try to detect the error. This can be problematic when the user's default CLI language is other than English.

Arduino IDE version

2.0.4

Operating system

macOS

Operating system version

12.6.3

Additional context

No response

Issue checklist

  • I searched for previous requests in the issue tracker
    I verified the feature was still missing when using the latest nightly build
    My request contains all necessary details

Activity

self-assigned this
on Feb 28, 2023
kittaakos

kittaakos commented on Feb 28, 2023

@kittaakos
ContributorAuthor

IDE2 cannot yet adapt the changes: arduino/arduino-cli#2076

On IDE2's side, we have to figure out how to convert such messages to objects in a generic way assuming the client does not know what the type is:

[
    {
        "code": 9,
        "message": "Error loading hardware platform: discovery builtin:serial-discovery not found",
        "detailsList": [
            {
                "typeUrl": "type.googleapis.com/cc.arduino.cli.commands.v1.PlatformLoadingError",
                "value": ""
            }
        ]
    },
    {
        "code": 9,
        "message": "Loading index file: loading json index file /Users/a.kitta/Library/Arduino15/package_index.json: open /Users/a.kitta/Library/Arduino15/package_index.json: no such file or directory",
        "detailsList": [
            {
                "typeUrl": "type.googleapis.com/cc.arduino.cli.commands.v1.FailedInstanceInitError",
                "value": "CAIStAFMb2FkaW5nIGluZGV4IGZpbGU6IGxvYWRpbmcganNvbiBpbmRleCBmaWxlIC9Vc2Vycy9hLmtpdHRhL0xpYnJhcnkvQXJkdWlubzE1L3BhY2thZ2VfaW5kZXguanNvbjogb3BlbiAvVXNlcnMvYS5raXR0YS9MaWJyYXJ5L0FyZHVpbm8xNS9wYWNrYWdlX2luZGV4Lmpzb246IG5vIHN1Y2ggZmlsZSBvciBkaXJlY3Rvcnk="
            }
        ]
    }
]

Something like this works, but the error types are unknown upfront

let unpacked: unknown = undefined;
const typeName = any.getTypeName();
switch (typeName) {
  case 'cc.arduino.cli.commands.v1.FailedInstanceInitError': {
    unpacked = any.unpack(
      FailedInstanceInitError.deserializeBinary,
      typeName
    );
    break;
  }
  case 'cc.arduino.cli.commands.v1.PlatformLoadingError': {
    unpacked = any.unpack(
      PlatformLoadingError.deserializeBinary,
      typeName
    );
    break;
  }
}

protocolbuffers/protobuf-javascript#68 (comment)

cmaglie

cmaglie commented on Feb 28, 2023

@cmaglie
Member

In golang, we call the UnmarshalNew() method from one of the details elements (that is of actual type *anypb.Any) to get a concrete object and, after that, we do a type assertion to get the actual error.

Here the go snippet:

// res is the response from the Init call
if status := res.GetError(); status != nil {
	// GetCode() returns the gRPC error code, it's usually useless
	fmt.Println()
	fmt.Printf("Init error code: %v\n", status.GetCode())

	// from the status we get the details
	details := status.GetDetails()
	if len(details) > 0 {
		// if there are details let's examine the first one, and call UnmarshalNew on that one
		detail, unmarshalError := status.GetDetails()[0].UnmarshalNew()

		// detail is a "protoreflect.ProtoMessage" (basically a super interface of all protobuf objects)
		fmt.Printf("  detail type: %T\n", detail) // this prints the actual type of details

		// with the following type-switch we typecast it to a concrete type
		switch err := detail.(type) {
		case *rpc.FailedInstanceInitError:
			fmt.Println("       reason:", err.GetReason()) // GetReason returns a grpc enum FailedInstanceInitReason
			fmt.Println("          msg:", err.GetMessage())
		case *rpc.PlatformLoadingError:
			fmt.Println("  no more details")
		}
	}
}

this outputs:

Init error code: 9
  detail type: *commands.FailedInstanceInitError
       reason: FAILED_INSTANCE_INIT_REASON_INDEX_LOAD_ERROR
          msg: Sto caricando il file dell'indice: caricamento del file indice json /tmp/arduino-rpc-client3282699494/package_index.json: open /tmp/arduino-rpc-client3282699494/package_index.json: no such file or directory

Init error code: 9
  detail type: *commands.FailedInstanceInitError
       reason: FAILED_INSTANCE_INIT_REASON_INDEX_LOAD_ERROR
          msg: Sto caricando il file dell'indice: caricamento del file indice json /tmp/arduino-rpc-client3282699494: read /tmp/arduino-rpc-client3282699494: is a directory

Init error code: 9
  detail type: *commands.PlatformLoadingError
  no more details

Init error code: 9
  detail type: *commands.PlatformLoadingError
  no more details

I'm not familiar with the JS binding, Is there a similar method in JS?
Maybe we could have a call to figure this out?

kittaakos

kittaakos commented on Feb 28, 2023

@kittaakos
ContributorAuthor

Thanks for the snippet. I have not yet found the JS equivalent of:

// with the following type-switch we typecast it to a concrete type
switch err := detail.(type) {
case *rpc.FailedInstanceInitError:
	fmt.Println("       reason:", err.GetReason()) // GetReason returns a grpc enum FailedInstanceInitReason
	fmt.Println("          msg:", err.GetMessage())
case *rpc.PlatformLoadingError:
	fmt.Println("  no more details")
}

At least, JS can switch on the typeUrl string, but as I wrote in #1925 (comment), it's suboptimal because the client should know the possible errors. If you check the gRPC API changes from arduino/arduino-cli#2076, you can see that there are two new messages types, FailedInstanceInitError and PlatformLoadingError , but they are not referenced. So from the sole proto API, clients do not know what can be an error.

removed their assignment
on Feb 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: CLIRelated to Arduino CLItopic: codeRelated to content of the project itselftype: enhancementProposed improvement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @cmaglie@kittaakos

        Issue actions

          Use the CLI's error codes to detect when the primary package index, library index, hardware platform is missing on IDE2 startup · Issue #1925 · arduino/arduino-ide