Skip to main content

cargo_v5/
errors.rs

1use std::path::PathBuf;
2
3use humansize::{BINARY, format_size};
4use image::ImageError;
5use inquire::InquireError;
6use miette::Diagnostic;
7use thiserror::Error;
8use vex_v5_serial::protocol::{FixedStringSizeError, cdc2::Cdc2Ack};
9
10use crate::commands::migrate::MigrateError;
11
12#[non_exhaustive]
13#[derive(Error, Diagnostic, Debug)]
14pub enum CliError {
15    #[error(transparent)]
16    #[diagnostic(code(cargo_v5::io_error))]
17    IoError(#[from] std::io::Error),
18
19    #[error(transparent)]
20    #[diagnostic(code(cargo_v5::serial_error))]
21    SerialError(#[from] vex_v5_serial::serial::SerialError),
22
23    #[error(transparent)]
24    #[diagnostic(code(cargo_v5::cdc2_nack))]
25    Nack(#[from] Cdc2Ack),
26
27    #[error(transparent)]
28    #[diagnostic(transparent)]
29    MigrateError(#[from] MigrateError),
30
31    #[cfg(feature = "fetch-template")]
32    #[error(transparent)]
33    #[diagnostic(code(cargo_v5::bad_response))]
34    ReqwestError(#[from] reqwest::Error),
35
36    #[cfg(feature = "fetch-template")]
37    #[error("Received a malformed HTTP response")]
38    #[diagnostic(code(cargo_v5::malformed_response))]
39    MalformedResponse,
40
41    #[error(transparent)]
42    #[diagnostic(code(cargo_v5::image_error))]
43    ImageError(#[from] ImageError),
44
45    #[error(transparent)]
46    #[diagnostic(code(cargo_v5::inquire))]
47    Inquire(#[from] InquireError),
48
49    #[error(transparent)]
50    #[diagnostic(code(cargo_v5::fixed_string_size_error))]
51    FixedStringSizeError(#[from] FixedStringSizeError),
52
53    // TODO: Add source spans.
54    #[error("Incorrect type for field `{field}` (expected {expected}, found {found}).")]
55    #[diagnostic(
56        code(cargo_v5::bad_field_type),
57        help("The `{field}` field should be of type {expected}.")
58    )]
59    BadFieldType {
60        /// Field name
61        field: String,
62
63        /// Expected type
64        expected: String,
65
66        /// Actual type
67        found: String,
68    },
69
70    // TODO: Add optional source spans.
71    #[error("The provided slot should be in the range [1, 8] inclusive.")]
72    #[diagnostic(
73        code(cargo_v5::slot_out_of_range),
74        help(
75            "The V5 Brain only has eight program slots. Adjust the `slot` field or argument to be a number from 1-8."
76        )
77    )]
78    SlotOutOfRange,
79
80    // TODO: Add source spans.
81    #[error("{0} is not a valid icon.")]
82    #[diagnostic(
83        code(cargo_v5::invalid_icon),
84        help("See `cargo v5 upload --help` for a list of valid icon identifiers.")
85    )]
86    InvalidIcon(String),
87
88    #[error("{0} is not a valid upload strategy.")]
89    #[diagnostic(
90        code(cargo_v5::invalid_upload_strategy),
91        help("See `cargo v5 upload --help` for a list of valid upload strategies.")
92    )]
93    InvalidUploadStrategy(String),
94
95    #[error("No slot number was provided.")]
96    #[diagnostic(
97        code(cargo_v5::no_slot),
98        help(
99            "A slot number is required to upload programs. Try passing in a slot using the `--slot` argument, or setting the `package.v5.metadata.slot` field in your Cargo.toml."
100        )
101    )]
102    NoSlot,
103
104    #[error("ELF build artifact not found. Is this a binary crate?")]
105    #[diagnostic(
106        code(cargo_v5::no_artifact),
107        help(
108            "`cargo v5 build` should generate an ELF file in your project's `target` folder unless this is a library crate. You can explicitly supply a file to upload with the `--file` (`-f`) argument."
109        )
110    )]
111    NoArtifact,
112
113    #[error("No V5 devices found.")]
114    #[diagnostic(
115        code(cargo_v5::no_device),
116        help(
117            "Ensure that a V5 Brain or controller is plugged in and powered on with a stable USB connection, then try again."
118        )
119    )]
120    NoDevice,
121
122    #[error("cargo-v5 requires Nightly Rust features, but you're using stable.")]
123    #[diagnostic(
124        code(cargo_v5::unsupported_release_channel),
125        help("Try switching to a nightly release channel with `rustup override set nightly`.")
126    )]
127    UnsupportedReleaseChannel,
128
129    #[error("Output ELF file could not be parsed.")]
130    #[diagnostic(code(cargo_v5::elf_parse_error))]
131    ElfParseError(#[from] object::Error),
132
133    #[error("Controller is stuck in radio channel 9.")]
134    #[diagnostic(
135        code(cargo_v5::radio_channel_stuck),
136        help(
137            "This is a bug in the controller's firmware. Please power cycle the controller to fix this."
138        )
139    )]
140    RadioChannelStuck,
141
142    #[error("Controller never switched radio channels.")]
143    #[diagnostic(
144        code(cargo_v5::radio_channel_disconnect_timeout),
145        help(
146            "Try running `cargo v5 upload` again. If the problem persists, power cycle your controller and Brain."
147        )
148    )]
149    RadioChannelDisconnectTimeout,
150
151    #[error("Controller never reconnected after switching radio channels.")]
152    #[diagnostic(
153        code(cargo_v5::radio_channel_reconnect_timeout),
154        help(
155            "Try running `cargo v5 upload` again. If the problem persists, power cycle your controller and Brain."
156        )
157    )]
158    RadioChannelReconnectTimeout,
159
160    #[cfg(feature = "field-control")]
161    #[error("No V5 controllers found.")]
162    #[diagnostic(
163        code(cargo_v5::no_controller),
164        help(
165            "`cargo v5 fc` can only be ran over a controller connection. Make sure you have a controller plugged into USB, then try again."
166        )
167    )]
168    NoController,
169
170    #[cfg(feature = "field-control")]
171    #[error("Attempted to change the match mode over a direct Brain connection.")]
172    #[diagnostic(
173        code(cargo_v5::brain_connection_set_match_mode),
174        help(
175            "This state should not be reachable and is a bug if encountered. Please report it to https://github.com/vexide/cargo-v5"
176        )
177    )]
178    BrainConnectionSetMatchMode,
179
180    #[error("Attempted to create a new project at {0}, but the directory is not empty.")]
181    #[diagnostic(
182        code(cargo_v5::project_dir_full),
183        help("Try creating the project in a different directory or with a different name.")
184    )]
185    ProjectDirFull(PathBuf),
186
187    #[error("Program exceeded the maximum differential upload size of 2MiB (program was {}).", format_size(*.0, BINARY))]
188    #[diagnostic(
189        code(cargo_v5::program_too_large),
190        help(
191            "This size limitation may change in the future. To upload larger binaries, switch to a monolith upload by specifying `--upload-strategy=monolith`."
192        )
193    )]
194    ProgramTooLarge(usize),
195
196    #[error("Patch exceeded the maximum size of 2MiB (patch was {}).", format_size(*.0, BINARY))]
197    #[diagnostic(
198        code(cargo_v5::patch_too_large),
199        help("Try running a cold upload using `cargo v5 upload --cold`.")
200    )]
201    PatchTooLarge(usize),
202}