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

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

Open
3 tasks done
kittaakos opened this issue Feb 28, 2023 · 4 comments
Labels
topic: CLI Related to Arduino CLI topic: code Related to content of the project itself type: enhancement Proposed improvement

Comments

@kittaakos
Copy link
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
@kittaakos kittaakos added type: enhancement Proposed improvement topic: code Related to content of the project itself topic: CLI Related to Arduino CLI labels Feb 28, 2023
@kittaakos kittaakos self-assigned this Feb 28, 2023
@kittaakos
Copy link
Contributor Author

kittaakos commented Feb 28, 2023

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
Copy link
Member

cmaglie commented Feb 28, 2023

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
Copy link
Contributor Author

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.

@kittaakos
Copy link
Contributor Author

kittaakos pushed a commit that referenced this issue Feb 28, 2023
kittaakos pushed a commit that referenced this issue Mar 21, 2023
@kittaakos kittaakos removed their assignment Feb 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: CLI Related to Arduino CLI topic: code Related to content of the project itself type: enhancement Proposed improvement
Projects
None yet
Development

No branches or pull requests

2 participants