-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Parameter Space Tooling (#1)
* implement `mionps`/`mionparamspace` this pr completely re-implements `mionps`, and `mionparamspace` in sprig tooling. there probably isn't too many uses for `mionps`, and `mionparamspace` directly, they're mostly just blockers for re-implementing `cafe.bat`/`cafex.bat`/`mochiato`. They also seemed like a much easier thing to "bite off" rather than taking a stab at `FSEmul.exe` even though FSEmul will be the most useful part because it seems like it's the actual PCFS implementation. this took me way too long to do because frankly paramspace while small, it's CLI tools are a pretty gigantic mess, and i just was NOT feeling it with all the other personal stuff going on. * add get-parameters/set-parameters to bridgectl this ports over the equivalents of `mionps`/`mionparamspace` to `bridgectl`. users can now get/set many parameters at once as opposed to needing to call the CLI multiple times. it also supports actually using parameter names rather than just indexes, and setting values to hex values which is what dump, and others show you anyway. * add `dump-parameters` command this adds in the last command bridgectl needs for the parameters port part of the cat-dev, this is a shortcut for grabbing all the parameters at once.
- Loading branch information
Showing
38 changed files
with
4,292 additions
and
467 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ members = [ | |
"cmd/bridgectl", | ||
"cmd/findbridge", | ||
"cmd/getbridgeconfig", | ||
"cmd/mionps", | ||
"cmd/mionparamspace", | ||
"cmd/setbridgeconfig", | ||
"pkg/cat-dev", | ||
"pkg/log", | ||
|
@@ -15,17 +17,18 @@ fnv = "^1.0.7" | |
mac_address = "^1.1.5" | ||
miette = { version = "^5.10.0", features = ["fancy"] } | ||
network-interface = "^1.1.1" | ||
once_cell = "^1.18.0" | ||
once_cell = "^1.19.0" | ||
time = "^0.3.31" | ||
tracing = { version = "^0.1.40", features = ["valuable"] } | ||
tokio = { version = "^1.34.0", features = ["full", "tracing"] } | ||
tokio = { version = "^1.35.1", features = ["full", "tracing"] } | ||
valuable = { version = "^0.1.0", features = ["derive"] } | ||
|
||
[workspace.package] | ||
authors = ["Cynthia <[email protected]>"] | ||
edition = "2021" | ||
license = "MIT" | ||
repository = "https://github.com/rem-verse/sprig" | ||
version = "0.0.1" | ||
version = "0.0.2" | ||
|
||
[profile.release] | ||
codegen-units = 1 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
//! Common helpers for dealing with bridge arguments. | ||
use crate::{ | ||
exit_codes::{ | ||
ARGV_COULD_NOT_GET_DEFAULT_BRIDGE, GET_DEFAULT_CONFLICTING_FILTERS, | ||
GET_DEFAULT_WITH_FILTERS, | ||
}, | ||
utils::{add_context_to, bridge_state_from_path, get_bridge_state_path}, | ||
}; | ||
use mac_address::MacAddress; | ||
use miette::miette; | ||
use std::{net::Ipv4Addr, path::PathBuf}; | ||
use tracing::{error, field::valuable}; | ||
|
||
/// Attempt to get the filters to use to "find" a bridge from all of the | ||
/// arguments. | ||
/// | ||
/// This will return `None` if you should just find the default bridge. | ||
/// This will return `Some` if you need to execute some sort of broadcast | ||
/// to find the bridge. | ||
/// | ||
/// - `use_json`: if we're outputting json logs. | ||
/// - `just_fetch_default`: if the user specified the equivalent of a | ||
/// `--default` flag. | ||
/// - `flag_arguments`: The three flag filtering arguments ip/mac/name. | ||
/// - `positional_argument`: The positional argument that could be the bridge | ||
/// name. | ||
/// - `positional_specified_is_bridge_name`: Some commands may have argv1 be | ||
/// a bridge name, but ALTERNATIVELY it could be param 2, and they just used | ||
/// flags to filter the bridge. This boolean lets you denote whether they | ||
/// actually specified it as a name. | ||
/// | ||
/// ## Panics | ||
/// | ||
/// This function will exit/panic the program if the user specified conflicting | ||
/// arguments (e.g. flag + positional of the same field). | ||
pub fn coalesce_bridge_arguments( | ||
use_json: bool, | ||
just_fetch_default: bool, | ||
flag_arguments: (Option<Ipv4Addr>, Option<String>, Option<String>), | ||
positional_argument: Option<String>, | ||
positional_specified_is_bridge_name: bool, | ||
) -> Option<(Option<Ipv4Addr>, Option<MacAddress>, Option<String>)> { | ||
if just_fetch_default { | ||
if flag_arguments.0.is_some() | ||
|| flag_arguments.1.is_some() | ||
|| flag_arguments.2.is_some() | ||
|| positional_specified_is_bridge_name | ||
{ | ||
if use_json { | ||
error!( | ||
id = "bridgectl::argv::no_filters_allowed_on_default", | ||
flags.ip = ?flag_arguments.0, | ||
flags.mac = ?flag_arguments.1, | ||
flags.name = ?flag_arguments.2, | ||
args.positional = ?positional_argument, | ||
suggestions = valuable(&[ | ||
"If you want to fetch the default bridge all you need to do is run: `bridgectl get-parameters <parameters> --default`", | ||
"If you want to apply extra filtering you can do something like outputting JSON, and using `jq` to filter", | ||
]), | ||
); | ||
} else { | ||
error!( | ||
"\n{:?}", | ||
add_context_to( | ||
miette!("Cannot specify filters when fetching the default bridge!"), | ||
[ | ||
miette!("If you want to fetch the default bridge all you need to do is run: `bridgectl get-parameters <parameters> --default`."), | ||
miette!( | ||
help = format!( | ||
"Flags: (--ip: `{:?}`, --mac: `{:?}`, --name: `{:?}`) / Positional Argument: `{:?}`", | ||
flag_arguments.0, | ||
flag_arguments.1, | ||
flag_arguments.2, | ||
positional_argument, | ||
), | ||
"If you want to apply extra filtering you can do something like outputting JSON, and using `jq` to filter.", | ||
), | ||
].into_iter(), | ||
), | ||
); | ||
} | ||
|
||
std::process::exit(GET_DEFAULT_WITH_FILTERS); | ||
} | ||
|
||
None | ||
} else { | ||
Some(coalesce_bridge_search_arguments( | ||
use_json, | ||
flag_arguments, | ||
positional_argument, | ||
)) | ||
} | ||
} | ||
|
||
/// Get the default bridge, or exit out if there is no default bridge | ||
/// configured. | ||
/// | ||
/// ## Panics | ||
/// | ||
/// Will panic if there is no default bridge that has been configured. | ||
pub async fn get_default_bridge( | ||
use_json: bool, | ||
host_state_path: Option<PathBuf>, | ||
) -> (String, Option<Ipv4Addr>) { | ||
let bridge_state = | ||
bridge_state_from_path(get_bridge_state_path(&host_state_path, use_json), use_json).await; | ||
|
||
if let Some(default_bridge) = bridge_state.get_default_bridge() { | ||
default_bridge | ||
} else if use_json { | ||
error!( | ||
id = "bridgectl::argv::no_default_bridge", | ||
host_state_path = %bridge_state.get_path().display(), | ||
suggestions = valuable(&[ | ||
"Please double check the configuration file located at the path specified, and ensure `BRIDGE_DEFAULT_NAME` is set to a real bridge name.", | ||
"If the bridge isn't set as the default you can use `bridge add --default <name> <ip>`, or `bridge set-default <'name' or 'ip'>`.", | ||
]), | ||
"No default bridge present in configuration file.", | ||
); | ||
std::process::exit(ARGV_COULD_NOT_GET_DEFAULT_BRIDGE); | ||
} else { | ||
error!( | ||
"\n{:?}", | ||
add_context_to( | ||
miette!("No default bridge present in the configuration file."), | ||
[ | ||
miette!("Please double check the configuration file located at the path specified, and ensure `BRIDGE_DEFAULT_NAME` is set to a real bridge name."), | ||
miette!( | ||
help = format!("The bridge configuration file was located at: {}", bridge_state.get_path().display()), | ||
"If the bridge isn't set as the default you can use `bridge add --default <name> <ip>`, or `bridge set-default <'name' or 'ip'>`.", | ||
), | ||
].into_iter(), | ||
), | ||
); | ||
std::process::exit(ARGV_COULD_NOT_GET_DEFAULT_BRIDGE); | ||
} | ||
} | ||
|
||
fn coalesce_bridge_search_arguments( | ||
use_json: bool, | ||
flag_arguments: (Option<Ipv4Addr>, Option<String>, Option<String>), | ||
cli_arguments: Option<String>, | ||
) -> (Option<Ipv4Addr>, Option<MacAddress>, Option<String>) { | ||
let mac_flag = flag_arguments | ||
.1 | ||
.and_then(|mac| MacAddress::try_from(mac.as_str()).ok()); | ||
let Some(cli_arg) = cli_arguments else { | ||
return (flag_arguments.0, mac_flag, flag_arguments.2); | ||
}; | ||
|
||
if let Ok(arg_as_ip) = cli_arg.parse::<Ipv4Addr>() { | ||
if flag_arguments.0.is_none() { | ||
return (Some(arg_as_ip), mac_flag, flag_arguments.2); | ||
} | ||
} | ||
if let Ok(arg_as_mac) = cli_arg.parse::<MacAddress>() { | ||
if mac_flag.is_none() { | ||
return (flag_arguments.0, Some(arg_as_mac), flag_arguments.2); | ||
} | ||
} | ||
if flag_arguments.2.is_none() { | ||
return (flag_arguments.0, mac_flag, Some(cli_arg)); | ||
} | ||
|
||
if use_json { | ||
error!( | ||
id = "bridgectl::argv::conflicting_filters_on_get", | ||
flags.ip = ?flag_arguments.0, | ||
flags.mac = ?mac_flag, | ||
flags.name = ?flag_arguments.2, | ||
args.positional = cli_arg, | ||
suggestions = valuable(&[ | ||
"If the positional argument is a name, it may be trying to be parsed as something like an IP/Mac.", | ||
"Get bridge can only filter down to one bridge, if you're trying to apply multiple ip filters/name filters/mac filters either use multiple `bridgectl get` calls, or use something like `bridgectl list`.", | ||
]), | ||
); | ||
} else { | ||
error!( | ||
"\n{:?}", | ||
add_context_to( | ||
miette!("Positional argument conflicts with flag arguments!"), | ||
[ | ||
miette!("If the positional argument is a name, it may be trying to be parsed as something like an IP/Mac."), | ||
miette!( | ||
help = format!( | ||
"Flags: (--ip: `{:?}`, --mac: `{:?}`, --name: `{:?}`) / Positional Argument: `{:?}`", | ||
flag_arguments.0, | ||
mac_flag, | ||
flag_arguments.2, | ||
cli_arg, | ||
), | ||
"Get bridge can only filter down to one bridge, if you're trying to apply multiple ip filters/name filters/mac filters either use multiple `bridgectl get` calls, or use something like `bridgectl list`.", | ||
), | ||
].into_iter(), | ||
), | ||
); | ||
} | ||
|
||
std::process::exit(GET_DEFAULT_CONFLICTING_FILTERS); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
//! Argument helpers for commands that take a lot of the exact same arguments. | ||
mod bridge; | ||
mod strings; | ||
|
||
pub use bridge::*; | ||
pub use strings::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
//! String utility helpers | ||
use std::{fmt::Display, num::ParseIntError}; | ||
|
||
/// Get a string potentially padded with spaces, or cut off with '...'. | ||
pub fn get_padded_string(ty: impl Display, max_length: usize) -> String { | ||
let mut to_return = String::with_capacity(max_length); | ||
let as_display = format!("{ty}"); | ||
if as_display.len() > max_length { | ||
to_return.push_str(&as_display[..(max_length - 3)]); | ||
to_return.push_str("..."); | ||
} else { | ||
to_return = as_display; | ||
while to_return.len() < max_length { | ||
to_return.push(' '); | ||
} | ||
} | ||
to_return | ||
} | ||
|
||
/// Get a byte value which could potentially be a hex value. | ||
pub fn get_byte_value(value: &str) -> Result<u8, ParseIntError> { | ||
if let Some(hex_value) = value.strip_prefix("0x") { | ||
u8::from_str_radix(hex_value, 16) | ||
} else if value | ||
.to_lowercase() | ||
.chars() | ||
.any(|character| matches!(character, 'a'..='f')) | ||
{ | ||
u8::from_str_radix(value, 16) | ||
} else { | ||
value.parse::<u8>() | ||
} | ||
} |
Oops, something went wrong.