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 #[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: String,
62
63 expected: String,
65
66 found: String,
68 },
69
70 #[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 #[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}