From a407749f331af45910b57888a953ebe80b8f355b Mon Sep 17 00:00:00 2001 From: N3xed Date: Thu, 9 Dec 2021 20:04:35 +0100 Subject: [PATCH 1/7] Add cargo-idf sub-crate, fix licenses --- Cargo.toml | 2 +- LICENSE-MIT | 2 +- cargo-idf/Cargo.toml | 16 ++++ cargo-idf/LICENSE-APACHE | 201 +++++++++++++++++++++++++++++++++++++++ cargo-idf/LICENSE-MIT | 25 +++++ cargo-idf/README.md | 32 +++++++ cargo-idf/src/main.rs | 1 + cargo-pio/LICENSE-MIT | 2 +- ldproxy/LICENSE-MIT | 2 +- 9 files changed, 279 insertions(+), 4 deletions(-) create mode 100644 cargo-idf/Cargo.toml create mode 100644 cargo-idf/LICENSE-APACHE create mode 100644 cargo-idf/LICENSE-MIT create mode 100644 cargo-idf/README.md create mode 100644 cargo-idf/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index e298aa6..bea7fb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["cargo-pio", "ldproxy"] +members = ["cargo-pio", "ldproxy", "cargo-idf"] [package] name = "embuild" diff --git a/LICENSE-MIT b/LICENSE-MIT index b03fd3c..1601ac8 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright 2019-2020 Contributors to xtensa-lx6-rt +Copyright 2019-2021 Contributors to embuild Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/cargo-idf/Cargo.toml b/cargo-idf/Cargo.toml new file mode 100644 index 0000000..924d936 --- /dev/null +++ b/cargo-idf/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "cargo-idf" +version = "0.1.0" +edition = "2021" +authors = ["Dominik Gschwind "] +categories = ["embedded", "development-tools::cargo-plugins"] +keywords = ["idf", "esp-idf", "esp32", "tool"] + +[dependencies] +embuild = { version = "0.27", path = "..", features = [] } +anyhow = {version = "1", features = ["backtrace"]} +log = "0.4" +env_logger = "0.8" +cargo_metadata = "0.14" +clap = "3.0.0-rc.0" +escargot = "0.5" diff --git a/cargo-idf/LICENSE-APACHE b/cargo-idf/LICENSE-APACHE new file mode 100644 index 0000000..f8e5e5e --- /dev/null +++ b/cargo-idf/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/cargo-idf/LICENSE-MIT b/cargo-idf/LICENSE-MIT new file mode 100644 index 0000000..59d584d --- /dev/null +++ b/cargo-idf/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright 2019-2021 Contributors to cargo-idf + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/cargo-idf/README.md b/cargo-idf/README.md new file mode 100644 index 0000000..4d4e369 --- /dev/null +++ b/cargo-idf/README.md @@ -0,0 +1,32 @@ +# cargo-idf + - `esp-idf` dir + - `out-dir` + - `esp-idf build` dir + - esp-idf `python` + + +## `cargo idf menuconfig` + +- `python esp-idf/tools/kconfig_new/prepare_kconfig_files.py --env-file + /build/config.env` (implement in rust) + +python esp-idf/tools/kconfig_new/confgen.py --kconfig esp-idf/Kconfig --sdkconfig-rename +esp-idf/sdkconfig.rename --config /sdkconfig --defaults ... --env-file /build/config.env +--env IDF_TARGET=esp32c3 --env IDF_ENV_FPGA= --dont-write-deprecated --output config /sdkconfig + +python esp-idf/tools/check_term.py + +- COMPONENT_KCONFIGS_SOURCE_FILE=/build/kconfigs.in +- COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE=/build/kconfigs_projbuild.in +- IDF_CMAKE=y +- KCONFIG_CONFIG=/sdkconfig +- IDF_TARGET=esp32c3 IDF_ENV_FPGA= +python -m menuconfig esp-idf/Kconfig + +python esp-idf/tools/kconfig_new/confgen.py --kconfig esp-idf/Kconfig --sdkconfig-rename esp-idf/sdkconfig.rename --config /sdkconfig --defaults ... --env-file /build/config.env --env IDF_TARGET=esp32c3 --env IDF_ENV_FPGA= --output config + ``` + +## `cargo idf flash` +## `cargo idf monitor` +## `cargo idf erase-flash` +## `cargo idf size` \ No newline at end of file diff --git a/cargo-idf/src/main.rs b/cargo-idf/src/main.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/cargo-idf/src/main.rs @@ -0,0 +1 @@ + diff --git a/cargo-pio/LICENSE-MIT b/cargo-pio/LICENSE-MIT index b03fd3c..dc15567 100644 --- a/cargo-pio/LICENSE-MIT +++ b/cargo-pio/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright 2019-2020 Contributors to xtensa-lx6-rt +Copyright 2019-2021 Contributors to cargo-pio Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/ldproxy/LICENSE-MIT b/ldproxy/LICENSE-MIT index b03fd3c..9e9b167 100644 --- a/ldproxy/LICENSE-MIT +++ b/ldproxy/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright 2019-2020 Contributors to xtensa-lx6-rt +Copyright 2019-2021 Contributors to ldproxy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated From 0341ff3ef4dfc172e2b95cbc7dcb0fdd59b5b454 Mon Sep 17 00:00:00 2001 From: N3xed Date: Wed, 29 Dec 2021 15:42:12 +0100 Subject: [PATCH 2/7] Implement menuconfig subcommand --- cargo-idf/Cargo.toml | 9 ++- cargo-idf/README.md | 44 ++++++++---- cargo-idf/src/build.rs | 135 ++++++++++++++++++++++++++++++++++++ cargo-idf/src/main.rs | 48 +++++++++++++ cargo-idf/src/menuconfig.rs | 99 ++++++++++++++++++++++++++ 5 files changed, 319 insertions(+), 16 deletions(-) create mode 100644 cargo-idf/src/build.rs create mode 100644 cargo-idf/src/menuconfig.rs diff --git a/cargo-idf/Cargo.toml b/cargo-idf/Cargo.toml index 924d936..eeda403 100644 --- a/cargo-idf/Cargo.toml +++ b/cargo-idf/Cargo.toml @@ -7,10 +7,13 @@ categories = ["embedded", "development-tools::cargo-plugins"] keywords = ["idf", "esp-idf", "esp32", "tool"] [dependencies] -embuild = { version = "0.27", path = "..", features = [] } -anyhow = {version = "1", features = ["backtrace"]} +embuild = { version = "0.27", path = "..", features = ["espidf"] } log = "0.4" env_logger = "0.8" cargo_metadata = "0.14" -clap = "3.0.0-rc.0" +structopt = "0.3" +clap-cargo = { version = "0.7", features = ["cargo_metadata"] } escargot = "0.5" +serde_json = "1" +thiserror = "1" +anyhow = "1" \ No newline at end of file diff --git a/cargo-idf/README.md b/cargo-idf/README.md index 4d4e369..a80a5a6 100644 --- a/cargo-idf/README.md +++ b/cargo-idf/README.md @@ -7,25 +7,43 @@ ## `cargo idf menuconfig` -- `python esp-idf/tools/kconfig_new/prepare_kconfig_files.py --env-file - /build/config.env` (implement in rust) +Opens the menuconfig tool to configure the project configuration interactively. -python esp-idf/tools/kconfig_new/confgen.py --kconfig esp-idf/Kconfig --sdkconfig-rename -esp-idf/sdkconfig.rename --config /sdkconfig --defaults ... --env-file /build/config.env ---env IDF_TARGET=esp32c3 --env IDF_ENV_FPGA= --dont-write-deprecated --output config /sdkconfig +If the option `--idf-build-info ` is *not* specified, a `cargo build` will be +performed in the current directory. The needed `esp-idf-build.json` will then be taken +from `/esp-idf-build.json`. If this option is specified *its* json +file will be used instead and no build will be performed. -python esp-idf/tools/check_term.py +All other options are applied only to the build. -- COMPONENT_KCONFIGS_SOURCE_FILE=/build/kconfigs.in -- COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE=/build/kconfigs_projbuild.in -- IDF_CMAKE=y -- KCONFIG_CONFIG=/sdkconfig -- IDF_TARGET=esp32c3 IDF_ENV_FPGA= -python -m menuconfig esp-idf/Kconfig +TODO: Add caution about setting optimization options in sdkconfig. + +
+ +Commands used + + +```console +python esp-idf/tools/kconfig_new/prepare_kconfig_files.py + --env-file /build/config.env -python esp-idf/tools/kconfig_new/confgen.py --kconfig esp-idf/Kconfig --sdkconfig-rename esp-idf/sdkconfig.rename --config /sdkconfig --defaults ... --env-file /build/config.env --env IDF_TARGET=esp32c3 --env IDF_ENV_FPGA= --output config +python esp-idf/tools/kconfig_new/confgen.py + --kconfig esp-idf/Kconfig + --sdkconfig-rename esp-idf/sdkconfig.rename + --config /sdkconfig + --defaults ... + --env-file /build/config.env + --dont-write-deprecated + --output config /sdkconfig + +python -m menuconfig esp-idf/Kconfig + Env variables: + - KCONFIG_CONFIG=/sdkconfig + - /config.env ``` +
+ ## `cargo idf flash` ## `cargo idf monitor` ## `cargo idf erase-flash` diff --git a/cargo-idf/src/build.rs b/cargo-idf/src/build.rs new file mode 100644 index 0000000..a7f2a1c --- /dev/null +++ b/cargo-idf/src/build.rs @@ -0,0 +1,135 @@ +use std::env; +use std::ffi::{OsStr, OsString}; +use std::io::BufReader; +use std::path::PathBuf; +use std::process::{Command, Stdio}; + +use anyhow::anyhow; +use cargo_metadata::Message; +use embuild::utils::CmdError; +use structopt::StructOpt; + +#[derive(Debug, thiserror::Error)] +pub enum BuildError { + #[error("failed to get metadata of the crate")] + NoMetadata(#[source] cargo_metadata::Error), + + #[error("could not determine the root crate")] + NoRootCrate, + + #[error("dependency `esp-idf-sys` not found")] + EspIdfSysNotFound(#[source] Option), + + #[error("`cargo build` failed")] + CargoBuildFailed(#[source] embuild::utils::CmdError), + + #[error("communication with cargo failed")] + CargoMsgError(#[source] std::io::Error), +} + +#[derive(Debug, StructOpt)] +pub struct BuildOpts { + #[structopt(flatten)] + manifest: clap_cargo::Manifest, + #[structopt(flatten)] + features: clap_cargo::Features, +} + +pub struct BuildInfo { + /// The path of the built executable + pub bin_path: Option, + pub esp_idf_build_info_json: PathBuf, +} + +/// Run `cargo build` in the current directory. +/// +/// And get the path to the built binary and the path to the `esp-idf-build.json` +/// generated by the `esp-idf-sys` build script. +pub fn run(opts: BuildOpts) -> Result { + // Get metadata to determine package-ids of the root package and esp-idf-sys. + let meta = opts + .features + .forward_metadata(&mut opts.manifest.metadata()) + .exec() + .map_err(BuildError::NoMetadata)?; + + let root = meta.root_package().ok_or(BuildError::NoRootCrate)?.clone(); + + let esp_idf_sys = meta + .packages + .iter() + .find(|p| p.name == "esp-idf-sys") + .ok_or(BuildError::EspIdfSysNotFound(None))? + .clone(); + drop(meta); + + // Build the crate + let mut cmd = Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))); + cmd.args(&["build", "--message-format=json-diagnostic-rendered-ansi"]) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()); + if let Some(ref manifest) = opts.manifest.manifest_path { + cmd.args(&[OsStr::new("--manifest-path"), manifest.as_os_str()]); + } + if opts.features.all_features { + cmd.arg("--all-features"); + } + if opts.features.no_default_features { + cmd.arg("--no-default-features"); + } + if !opts.features.features.is_empty() { + cmd.args(&["--features", &opts.features.features.join(",")]); + } + log::debug!("Running {:?}", cmd); + let mut process = match cmd.spawn() { + Err(e) => return Err(BuildError::CargoBuildFailed(CmdError::no_run(&cmd, e))), + Ok(p) => p, + }; + + let reader = BufReader::new(process.stdout.take().unwrap()); + + let mut esp_idf_sys_out_dir = None; + let mut bin_path = None; + + for message in Message::parse_stream(reader) { + let message = message.map_err(BuildError::CargoMsgError)?; + log::trace!("{:?}", message); + match message { + Message::CompilerMessage(msg) => { + println!("{}", msg); + } + Message::CompilerArtifact(artifact) => { + // Get the path to the final binary + if bin_path.is_none() && artifact.package_id == root.id { + bin_path = artifact.filenames.into_iter().next(); + } + } + Message::BuildScriptExecuted(script) => { + // Get the out dir for esp-idf-sys + if esp_idf_sys_out_dir.is_none() && script.package_id == esp_idf_sys.id { + esp_idf_sys_out_dir = Some(script.out_dir); + } + } + Message::BuildFinished(_) => (), + _ => (), + } + } + CmdError::status_into_result( + process + .wait() + .map_err(|err| BuildError::CargoBuildFailed(CmdError::no_run(&cmd, err)))?, + &cmd, + || None, + ) + .map_err(BuildError::CargoBuildFailed)?; + + let esp_idf_build_info_json = esp_idf_sys_out_dir + .ok_or_else(|| BuildError::EspIdfSysNotFound(Some(anyhow!("Failed to get out dir"))))? + .join("esp-idf-build.json") + .into_std_path_buf(); + + Ok(BuildInfo { + bin_path: bin_path.map(Into::into), + esp_idf_build_info_json, + }) +} diff --git a/cargo-idf/src/main.rs b/cargo-idf/src/main.rs index 8b13789..f77c3f7 100644 --- a/cargo-idf/src/main.rs +++ b/cargo-idf/src/main.rs @@ -1 +1,49 @@ +use log::LevelFilter; +use structopt::clap::AppSettings; +use structopt::StructOpt; +mod build; +mod menuconfig; + +#[derive(StructOpt)] +#[structopt(global_setting = AppSettings::GlobalVersion)] +#[structopt(bin_name = "cargo")] +struct Opts { + #[structopt(subcommand)] + sub_cmd: CargoSubCommand, +} + +#[derive(StructOpt)] +enum CargoSubCommand { + Idf(CargoIdfOpts), +} + +#[derive(StructOpt)] +enum CargoIdfOpts { + Menuconfig(menuconfig::MenuconfigOpts), + Flash, + EraseFlash, + Monitor, + Size, +} + +fn main() -> anyhow::Result<()> { + env_logger::Builder::from_env( + env_logger::Env::new() + .write_style_or("CARGO_IDF_LOG_STYLE", "Auto") + .filter_or("CARGO_IDF_LOG", LevelFilter::Info.to_string()), + ) + .target(env_logger::Target::Stderr) + .format_indent(None) + .format_module_path(false) + .format_timestamp(None) + .init(); + + let CargoSubCommand::Idf(opts) = Opts::from_args().sub_cmd; + match opts { + CargoIdfOpts::Menuconfig(opts) => menuconfig::run(opts)?, + _ => unimplemented!(), + }; + + Ok(()) +} diff --git a/cargo-idf/src/menuconfig.rs b/cargo-idf/src/menuconfig.rs new file mode 100644 index 0000000..ed00be3 --- /dev/null +++ b/cargo-idf/src/menuconfig.rs @@ -0,0 +1,99 @@ +use std::collections::HashMap; +use std::ffi::OsStr; +use std::fs; +use std::path::PathBuf; + +use anyhow::{anyhow, Context}; +use embuild::espidf::EspIdfBuildInfo; +use embuild::utils::CmdError; +use embuild::{cmd, path_buf}; +use structopt::StructOpt; + +use crate::build::{self, BuildError}; + +#[derive(Debug, thiserror::Error)] +#[error("Could not open menuconfig")] +pub enum MenuconfigError { + Build(#[from] BuildError), + Cmd(#[from] CmdError), + Anyhow(#[from] anyhow::Error), + Io(#[from] std::io::Error), + Serde(#[from] serde_json::Error), +} + +#[derive(StructOpt)] +pub struct MenuconfigOpts { + #[structopt(flatten)] + build_opts: build::BuildOpts, + /// Path to the esp-idf build info json file. + /// + /// If this option is not specified cargo-idf will perform a `cargo build` in the + /// current directory. + #[structopt(long)] + idf_build_info: Option, +} + +pub fn run(opts: MenuconfigOpts) -> Result<(), MenuconfigError> { + let build_info_json = if let Some(path) = opts.idf_build_info { + path + } else { + build::run(opts.build_opts)?.esp_idf_build_info_json + }; + + let EspIdfBuildInfo { + venv_python, + esp_idf_dir, + build_dir, + project_dir, + sdkconfig_defaults, + .. + } = embuild::espidf::EspIdfBuildInfo::from_json(&build_info_json).with_context(|| { + anyhow!( + "Failed to get esp-idf build info from '{}'", + build_info_json.display() + ) + })?; + let sdkconfig_defaults = sdkconfig_defaults.unwrap_or_default(); + + std::env::set_var("IDF_PATH", &esp_idf_dir); + + let prepare_kconfig_py = path_buf![ + &esp_idf_dir, + "tools", + "kconfig_new", + "prepare_kconfig_files.py" + ]; + let confgen_py = path_buf![&esp_idf_dir, "tools", "kconfig_new", "confgen.py"]; + + let kconfig = path_buf![&esp_idf_dir, "Kconfig"]; + let sdkconfig_rename = path_buf![&esp_idf_dir, "sdkconfig.rename"]; + let build_sdkconfig = path_buf![&project_dir, "sdkconfig"]; + let config_env = path_buf![&build_dir, "config.env"]; + + cmd!(&venv_python, &prepare_kconfig_py, "--env-file", &config_env)?; + + let defaults = sdkconfig_defaults + .iter() + .map(|d| [OsStr::new("--defaults"), d.as_os_str()]) + .flatten(); + + cmd!( + &venv_python, &confgen_py, + "--kconfig", &kconfig, + "--sdkconfig-rename", &sdkconfig_rename, + "--config", &build_sdkconfig, + @defaults, + "--env-file", &config_env, + "--dont-write-deprecated", + "--output", "config", &build_sdkconfig + )?; + + let env: HashMap = serde_json::from_reader(fs::File::open(&config_env)?)?; + cmd!( + &venv_python, "-m", "menuconfig", &kconfig; + envs=(env), + env=("KCONFIG_CONFIG", &build_sdkconfig) + )?; + + Ok(()) +} From 2450d113a07fcaa7fdd75b8b80136bcb35922bd9 Mon Sep 17 00:00:00 2001 From: N3xed Date: Wed, 29 Dec 2021 19:35:16 +0100 Subject: [PATCH 3/7] Improve README --- README.md | 1 + cargo-idf/README.md | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1a185fc..17d3428 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,4 @@ - [`cargo-pio`](cargo-pio) - [`ldproxy`](ldproxy) +- [`cargo-idf`](cargo-idf) \ No newline at end of file diff --git a/cargo-idf/README.md b/cargo-idf/README.md index a80a5a6..1787445 100644 --- a/cargo-idf/README.md +++ b/cargo-idf/README.md @@ -1,9 +1,7 @@ # cargo-idf - - `esp-idf` dir - - `out-dir` - - `esp-idf build` dir - - esp-idf `python` - + + A cargo subcommand for the `esp32` platform in conjunction with + [`esp-idf-sys`](https://crates.io/crates/esp-idf-sys). ## `cargo idf menuconfig` From 36ae5be76dd611b94dd0c758e8bd36ddaf7cfe90 Mon Sep 17 00:00:00 2001 From: N3xed Date: Sat, 1 Jan 2022 20:09:15 +0100 Subject: [PATCH 4/7] Add minimum esp-idf-sys version requirement --- cargo-idf/src/build.rs | 11 ++++++----- cargo-idf/src/menuconfig.rs | 27 +++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/cargo-idf/src/build.rs b/cargo-idf/src/build.rs index a7f2a1c..2e666f1 100644 --- a/cargo-idf/src/build.rs +++ b/cargo-idf/src/build.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use std::process::{Command, Stdio}; use anyhow::anyhow; -use cargo_metadata::Message; +use cargo_metadata::{Message, Version}; use embuild::utils::CmdError; use structopt::StructOpt; @@ -38,7 +38,8 @@ pub struct BuildOpts { pub struct BuildInfo { /// The path of the built executable pub bin_path: Option, - pub esp_idf_build_info_json: PathBuf, + pub esp_idf_sys_out_dir: PathBuf, + pub esp_idf_sys_version: Version, } /// Run `cargo build` in the current directory. @@ -123,13 +124,13 @@ pub fn run(opts: BuildOpts) -> Result { ) .map_err(BuildError::CargoBuildFailed)?; - let esp_idf_build_info_json = esp_idf_sys_out_dir + let esp_idf_sys_out_dir = esp_idf_sys_out_dir .ok_or_else(|| BuildError::EspIdfSysNotFound(Some(anyhow!("Failed to get out dir"))))? - .join("esp-idf-build.json") .into_std_path_buf(); Ok(BuildInfo { bin_path: bin_path.map(Into::into), - esp_idf_build_info_json, + esp_idf_sys_out_dir, + esp_idf_sys_version: esp_idf_sys.version, }) } diff --git a/cargo-idf/src/menuconfig.rs b/cargo-idf/src/menuconfig.rs index ed00be3..532fd9a 100644 --- a/cargo-idf/src/menuconfig.rs +++ b/cargo-idf/src/menuconfig.rs @@ -4,21 +4,30 @@ use std::fs; use std::path::PathBuf; use anyhow::{anyhow, Context}; -use embuild::espidf::EspIdfBuildInfo; +use cargo_metadata::Version; +use embuild::espidf::{self, EspIdfBuildInfo}; use embuild::utils::CmdError; use embuild::{cmd, path_buf}; use structopt::StructOpt; -use crate::build::{self, BuildError}; +use crate::build::{self, BuildError, BuildInfo}; + +const MIN_ESP_IDF_SYS_VERSION: Version = Version::new(0, 28, 3); #[derive(Debug, thiserror::Error)] -#[error("Could not open menuconfig")] +#[error(transparent)] pub enum MenuconfigError { + #[error("Build failed")] Build(#[from] BuildError), Cmd(#[from] CmdError), Anyhow(#[from] anyhow::Error), Io(#[from] std::io::Error), Serde(#[from] serde_json::Error), + #[error( + "esp-idf-sys version ({0}) too old, version must be >= {}", + MIN_ESP_IDF_SYS_VERSION + )] + EspIdfSysTooOld(Version), } #[derive(StructOpt)] @@ -37,7 +46,17 @@ pub fn run(opts: MenuconfigOpts) -> Result<(), MenuconfigError> { let build_info_json = if let Some(path) = opts.idf_build_info { path } else { - build::run(opts.build_opts)?.esp_idf_build_info_json + let BuildInfo { + esp_idf_sys_out_dir, + esp_idf_sys_version, + .. + } = build::run(opts.build_opts)?; + + if esp_idf_sys_version < MIN_ESP_IDF_SYS_VERSION { + return Err(MenuconfigError::EspIdfSysTooOld(esp_idf_sys_version)); + } + + esp_idf_sys_out_dir.join(espidf::BUILD_INFO_FILENAME) }; let EspIdfBuildInfo { From 1572c8c1253f10c114552b23b68ddce193553bbf Mon Sep 17 00:00:00 2001 From: N3xed Date: Tue, 4 Jan 2022 15:38:01 +0100 Subject: [PATCH 5/7] Upgrade to clap 3 --- cargo-idf/Cargo.toml | 7 ++-- cargo-idf/README.md | 30 ++++++++++++++-- cargo-idf/src/build.rs | 21 +++++++---- cargo-idf/src/flash.rs | 71 +++++++++++++++++++++++++++++++++++++ cargo-idf/src/main.rs | 28 +++++++++------ cargo-idf/src/menuconfig.rs | 15 ++++---- 6 files changed, 141 insertions(+), 31 deletions(-) create mode 100644 cargo-idf/src/flash.rs diff --git a/cargo-idf/Cargo.toml b/cargo-idf/Cargo.toml index eeda403..75c7f57 100644 --- a/cargo-idf/Cargo.toml +++ b/cargo-idf/Cargo.toml @@ -11,9 +11,10 @@ embuild = { version = "0.27", path = "..", features = ["espidf"] } log = "0.4" env_logger = "0.8" cargo_metadata = "0.14" -structopt = "0.3" -clap-cargo = { version = "0.7", features = ["cargo_metadata"] } +clap = { version = "3", features = ["derive"] } +clap-cargo = { version = "0.8", features = ["cargo_metadata"] } escargot = "0.5" serde_json = "1" thiserror = "1" -anyhow = "1" \ No newline at end of file +anyhow = "1" +strum = { version = "0.23", features = ["derive"] } \ No newline at end of file diff --git a/cargo-idf/README.md b/cargo-idf/README.md index 1787445..ce8e2d5 100644 --- a/cargo-idf/README.md +++ b/cargo-idf/README.md @@ -17,9 +17,7 @@ All other options are applied only to the build. TODO: Add caution about setting optimization options in sdkconfig.
- -Commands used - +Commands used ```console python esp-idf/tools/kconfig_new/prepare_kconfig_files.py @@ -43,6 +41,32 @@ python -m menuconfig esp-idf/Kconfig
## `cargo idf flash` + + +
+Commands used + +```console +cmake.exe + -D IDF_PATH="..." + -D SERIAL_TOOL="python esp-idf-v4.3.1/components/esptool_py/esptool/esptool.py --chip esp32c3" + -D SERIAL_TOOL_ARGS="--before=default_reset --after=hard_reset write_flash @flash_args" + -D WORKING_DIRECTORY=/build + -P esp-idf-v4.3.1/components/esptool_py/run_serial_tool.cmake +``` + +
+ ## `cargo idf monitor` ## `cargo idf erase-flash` + +
+Commands used + +```console + COMMAND = cmd.exe /C "cd /D C:\Users\n3xed\.espressif\esp-idf-v4.3.1\components\esptool_py && C:\Users\n3xed\.espressif\tools\cmake\3.20.3\bin\cmake.exe -D IDF_PATH="C:/Users/n3xed/.espressif/esp-idf-v4.3.1" -D SERIAL_TOOL="python C:/Users/n3xed/.espressif/esp-idf-v4.3.1/components/esptool_py/esptool/esptool.py --chip esp32c3" -D SERIAL_TOOL_ARGS="erase_flash" -P run_serial_tool.cmake" +``` + +
+ ## `cargo idf size` \ No newline at end of file diff --git a/cargo-idf/src/build.rs b/cargo-idf/src/build.rs index 2e666f1..d861dda 100644 --- a/cargo-idf/src/build.rs +++ b/cargo-idf/src/build.rs @@ -1,13 +1,13 @@ use std::env; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsStr; use std::io::BufReader; use std::path::PathBuf; use std::process::{Command, Stdio}; use anyhow::anyhow; use cargo_metadata::{Message, Version}; +use clap::Args; use embuild::utils::CmdError; -use structopt::StructOpt; #[derive(Debug, thiserror::Error)] pub enum BuildError { @@ -27,12 +27,16 @@ pub enum BuildError { CargoMsgError(#[source] std::io::Error), } -#[derive(Debug, StructOpt)] +#[derive(Debug, Args)] +#[clap(help_heading = "BUILD OPTIONS")] pub struct BuildOpts { - #[structopt(flatten)] + #[clap(flatten)] manifest: clap_cargo::Manifest, - #[structopt(flatten)] + #[clap(flatten)] features: clap_cargo::Features, + /// Build with release profile + #[clap(long)] + release: bool, } pub struct BuildInfo { @@ -65,12 +69,12 @@ pub fn run(opts: BuildOpts) -> Result { drop(meta); // Build the crate - let mut cmd = Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))); + let mut cmd = Command::new(env::var_os("CARGO").unwrap_or_else(|| "cargo".into())); cmd.args(&["build", "--message-format=json-diagnostic-rendered-ansi"]) .stdout(Stdio::piped()) .stderr(Stdio::inherit()); if let Some(ref manifest) = opts.manifest.manifest_path { - cmd.args(&[OsStr::new("--manifest-path"), manifest.as_os_str()]); + cmd.args([OsStr::new("--manifest-path"), manifest.as_os_str()]); } if opts.features.all_features { cmd.arg("--all-features"); @@ -78,6 +82,9 @@ pub fn run(opts: BuildOpts) -> Result { if opts.features.no_default_features { cmd.arg("--no-default-features"); } + if opts.release { + cmd.arg("--release"); + } if !opts.features.features.is_empty() { cmd.args(&["--features", &opts.features.features.join(",")]); } diff --git a/cargo-idf/src/flash.rs b/cargo-idf/src/flash.rs new file mode 100644 index 0000000..60ca2cd --- /dev/null +++ b/cargo-idf/src/flash.rs @@ -0,0 +1,71 @@ +use std::ffi::OsStr; +use std::path::PathBuf; +use std::str::FromStr; + +use anyhow::bail; +use clap::{AppSettings, ArgEnum, Args}; +use strum::{Display, EnumString}; + +use crate::build; + +#[derive(Args)] +#[clap(global_setting = AppSettings::DisableVersionFlag)] +pub struct FlashOpts { + /// Which bootloader to flash [possible values: esp-idf, none, ] + /// + /// - `esp-idf` will flash the bootloader compiled locally from the esp-idf. + /// - `none` prevents flashing a bootloader. + /// - `` will flash the user provided binary file if it exists. + #[clap( + long, + default_value_t = Bootloader::EspIdf, + parse(try_from_os_str = Bootloader::try_from_os_str), + verbatim_doc_comment + )] + bootloader: Bootloader, + + /// How to flash the binary + #[clap(long, arg_enum, default_value_t = Mode::Esptool)] + mode: Mode, + + #[clap(flatten)] + build_opts: build::BuildOpts, +} + +#[derive(Debug, ArgEnum, Clone, Copy)] +pub enum Mode { + Esptool, + Dfu, + Uf2, +} + +#[derive(Debug, Clone, EnumString, Display)] +#[strum(serialize_all = "kebab-case")] +pub enum Bootloader { + EspIdf, + None, + #[strum(default)] + #[strum(to_string = "")] + File(PathBuf), +} + +impl Bootloader { + pub fn try_from_os_str(arg: &OsStr) -> Result { + let val = if let Some(arg) = arg.to_str() { + Bootloader::from_str(arg).unwrap() + } else { + Bootloader::File(arg.into()) + }; + + if let Bootloader::File(ref path) = val { + if !path.is_file() { + bail!("'{}' is not a file", path.display()) + } + } + Ok(val) + } +} + +pub fn run(opts: FlashOpts) -> anyhow::Result<()> { + Ok(()) +} diff --git a/cargo-idf/src/main.rs b/cargo-idf/src/main.rs index f77c3f7..9dfc1d6 100644 --- a/cargo-idf/src/main.rs +++ b/cargo-idf/src/main.rs @@ -1,30 +1,35 @@ +use clap::Subcommand; use log::LevelFilter; -use structopt::clap::AppSettings; -use structopt::StructOpt; +use clap::AppSettings; +use clap::Parser; mod build; mod menuconfig; +mod flash; -#[derive(StructOpt)] -#[structopt(global_setting = AppSettings::GlobalVersion)] -#[structopt(bin_name = "cargo")] +#[derive(Parser)] +#[clap(global_setting = AppSettings::PropagateVersion)] +#[clap(global_setting = AppSettings::DeriveDisplayOrder)] +#[clap(version)] +#[clap(bin_name = "cargo")] struct Opts { - #[structopt(subcommand)] + #[clap(subcommand)] sub_cmd: CargoSubCommand, } -#[derive(StructOpt)] +#[derive(Subcommand)] enum CargoSubCommand { + #[clap(subcommand)] Idf(CargoIdfOpts), } -#[derive(StructOpt)] +#[derive(Subcommand)] enum CargoIdfOpts { Menuconfig(menuconfig::MenuconfigOpts), - Flash, - EraseFlash, + Flash(flash::FlashOpts), Monitor, Size, + EraseFlash, } fn main() -> anyhow::Result<()> { @@ -39,9 +44,10 @@ fn main() -> anyhow::Result<()> { .format_timestamp(None) .init(); - let CargoSubCommand::Idf(opts) = Opts::from_args().sub_cmd; + let CargoSubCommand::Idf(opts) = Opts::parse().sub_cmd; match opts { CargoIdfOpts::Menuconfig(opts) => menuconfig::run(opts)?, + CargoIdfOpts::Flash(opts) => flash::run(opts)?, _ => unimplemented!(), }; diff --git a/cargo-idf/src/menuconfig.rs b/cargo-idf/src/menuconfig.rs index 532fd9a..6f9a24f 100644 --- a/cargo-idf/src/menuconfig.rs +++ b/cargo-idf/src/menuconfig.rs @@ -8,7 +8,7 @@ use cargo_metadata::Version; use embuild::espidf::{self, EspIdfBuildInfo}; use embuild::utils::CmdError; use embuild::{cmd, path_buf}; -use structopt::StructOpt; +use clap::{Args, AppSettings}; use crate::build::{self, BuildError, BuildInfo}; @@ -30,16 +30,17 @@ pub enum MenuconfigError { EspIdfSysTooOld(Version), } -#[derive(StructOpt)] +#[derive(Args)] +#[clap(global_setting = AppSettings::DeriveDisplayOrder)] +#[clap(global_setting = AppSettings::DisableVersionFlag)] pub struct MenuconfigOpts { - #[structopt(flatten)] - build_opts: build::BuildOpts, - /// Path to the esp-idf build info json file. + /// Optional path to the esp-idf build info json file. /// - /// If this option is not specified cargo-idf will perform a `cargo build` in the + /// If this argument is not specified cargo-idf will perform a `cargo build` in the /// current directory. - #[structopt(long)] idf_build_info: Option, + #[clap(flatten)] + build_opts: build::BuildOpts, } pub fn run(opts: MenuconfigOpts) -> Result<(), MenuconfigError> { From 5f154321f21bb29230fbc30f558c5472c9b378c1 Mon Sep 17 00:00:00 2001 From: N3xed Date: Wed, 5 Jan 2022 22:34:13 +0100 Subject: [PATCH 6/7] Flash args --- cargo-idf/src/flash.rs | 73 ++-------------------- cargo-idf/src/flash/opts.rs | 119 ++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 69 deletions(-) create mode 100644 cargo-idf/src/flash/opts.rs diff --git a/cargo-idf/src/flash.rs b/cargo-idf/src/flash.rs index 60ca2cd..8d03bbc 100644 --- a/cargo-idf/src/flash.rs +++ b/cargo-idf/src/flash.rs @@ -1,71 +1,6 @@ -use std::ffi::OsStr; -use std::path::PathBuf; -use std::str::FromStr; +pub mod opts; +pub use opts::FlashOpts; -use anyhow::bail; -use clap::{AppSettings, ArgEnum, Args}; -use strum::{Display, EnumString}; - -use crate::build; - -#[derive(Args)] -#[clap(global_setting = AppSettings::DisableVersionFlag)] -pub struct FlashOpts { - /// Which bootloader to flash [possible values: esp-idf, none, ] - /// - /// - `esp-idf` will flash the bootloader compiled locally from the esp-idf. - /// - `none` prevents flashing a bootloader. - /// - `` will flash the user provided binary file if it exists. - #[clap( - long, - default_value_t = Bootloader::EspIdf, - parse(try_from_os_str = Bootloader::try_from_os_str), - verbatim_doc_comment - )] - bootloader: Bootloader, - - /// How to flash the binary - #[clap(long, arg_enum, default_value_t = Mode::Esptool)] - mode: Mode, - - #[clap(flatten)] - build_opts: build::BuildOpts, -} - -#[derive(Debug, ArgEnum, Clone, Copy)] -pub enum Mode { - Esptool, - Dfu, - Uf2, -} - -#[derive(Debug, Clone, EnumString, Display)] -#[strum(serialize_all = "kebab-case")] -pub enum Bootloader { - EspIdf, - None, - #[strum(default)] - #[strum(to_string = "")] - File(PathBuf), -} - -impl Bootloader { - pub fn try_from_os_str(arg: &OsStr) -> Result { - let val = if let Some(arg) = arg.to_str() { - Bootloader::from_str(arg).unwrap() - } else { - Bootloader::File(arg.into()) - }; - - if let Bootloader::File(ref path) = val { - if !path.is_file() { - bail!("'{}' is not a file", path.display()) - } - } - Ok(val) - } -} - -pub fn run(opts: FlashOpts) -> anyhow::Result<()> { - Ok(()) +pub fn run(_opts: FlashOpts) -> anyhow::Result<()> { + unimplemented!() } diff --git a/cargo-idf/src/flash/opts.rs b/cargo-idf/src/flash/opts.rs new file mode 100644 index 0000000..7e47dbc --- /dev/null +++ b/cargo-idf/src/flash/opts.rs @@ -0,0 +1,119 @@ +use std::ffi::{OsStr, OsString}; +use std::path::PathBuf; +use std::str::FromStr; + +use anyhow::bail; +use clap::{AppSettings, ArgEnum, Args}; +use embuild::utils::OsStrExt; +use strum::{Display, EnumDiscriminants, EnumString}; + +use crate::build; + +#[derive(Args)] +#[clap(global_setting = AppSettings::DisableVersionFlag)] +pub struct FlashOpts { + /// One or more images to flash [possible values: all, bootloader, partition-table, + /// app, ,
] + /// + /// - `all`: flash the whole project (bootloader, partition-table, app) + /// - `bootloader`: flash bootloader (see `--bootloader` option) + /// - `partition-table`: flash the partition table (see `--partition-table` option) + /// - `app`: flash the app + /// - ` `: flash at the address of + /// - `
`: flash at
+ #[clap( + parse(from_os_str = ImageArg::from_os_str), + validator_os = ImageArg::parse_validator(), + verbatim_doc_comment, + default_value = "all" + )] + images: Vec, + + /// The bootloader binary file to use instead of the default + #[clap(long, parse(from_os_str), value_name = "file")] + bootloader: Option, + + /// The partition table `.csv` file to use instead of the default + #[clap(long, parse(from_os_str), value_name = "file")] + partition_table: Option, + + #[clap(flatten)] + build_opts: build::BuildOpts, +} + +#[derive(Debug, ArgEnum, Clone, Copy)] +pub enum Mode { + Esptool, + Dfu, + Uf2, +} + +#[derive(Debug, Clone, Display, EnumDiscriminants)] +#[strum_discriminants(name(ImageArgKind))] +pub enum ImageArg { + #[strum(to_string = "")] + Name(ImageName), + #[strum(to_string = "
")] + Address(usize), + #[strum(to_string = "")] + PartitionOrFile(OsString), + Partition(String), + File(PathBuf), +} + +impl Default for ImageArgKind { + fn default() -> Self { + ImageArgKind::Name + } +} + +#[derive(Debug, EnumString, Display, Clone, Copy)] +#[strum(serialize_all = "kebab-case")] +pub enum ImageName { + All, + Bootloader, + PartitionTable, + App, +} + +impl ImageArg { + fn from_os_str(arg: &OsStr) -> ImageArg { + if let Some(arg) = arg.to_str() { + if let Ok(name) = ImageName::from_str(arg) { + return ImageArg::Name(name); + } else if let Ok(address) = arg.parse::() { + return ImageArg::Address(address); + } + } + ImageArg::PartitionOrFile(arg.to_owned()) + } + + fn parse_validator() -> impl FnMut(&OsStr) -> Result<(), anyhow::Error> { + let mut previous = ImageArgKind::default(); + move |arg| { + let next = Self::from_os_str(arg); + previous = Self::parse(previous, next)?.into(); + Ok(()) + } + } + + /// Parses image arg with a given previous arg kind. + /// + /// Never returns [`ImageArg::PartitionOrFile`]. + pub fn parse(last: ImageArgKind, next: ImageArg) -> Result { + use ImageArgKind::*; + let result = match (last, next) { + (Name | File, ImageArg::PartitionOrFile(file)) => { + ImageArg::Partition(file.try_to_str()?.into()) + } + (Partition | Address, ImageArg::PartitionOrFile(file)) => ImageArg::File(file.into()), + (Name | File, val @ ImageArg::Name(_) | val @ ImageArg::Address(_)) => val, + (Partition | Address, _) => bail!("expected "), + + (_, ImageArg::File(_) | ImageArg::Partition(_)) | (PartitionOrFile, _) => { + unreachable!("invalid state") + } + }; + Ok(result) + } +} From dcebd216ef6cd91970cf0aa8320f7acb547f5390 Mon Sep 17 00:00:00 2001 From: N3xed Date: Sun, 6 Mar 2022 11:53:23 +0100 Subject: [PATCH 7/7] Update embuild to 0.28 --- cargo-idf/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-idf/Cargo.toml b/cargo-idf/Cargo.toml index 75c7f57..48a47ec 100644 --- a/cargo-idf/Cargo.toml +++ b/cargo-idf/Cargo.toml @@ -7,7 +7,7 @@ categories = ["embedded", "development-tools::cargo-plugins"] keywords = ["idf", "esp-idf", "esp32", "tool"] [dependencies] -embuild = { version = "0.27", path = "..", features = ["espidf"] } +embuild = { version = "0.28", path = "..", features = ["espidf"] } log = "0.4" env_logger = "0.8" cargo_metadata = "0.14"