diff --git a/Cargo.lock b/Cargo.lock index 0817e017..5c8c05fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -726,7 +726,7 @@ dependencies = [ [[package]] name = "cargo-playdate" -version = "0.5.0-beta.6" +version = "0.5.0-pre.1" dependencies = [ "anstyle", "anyhow", @@ -4147,7 +4147,7 @@ dependencies = [ [[package]] name = "playdate-build" -version = "0.4.0-pre3" +version = "0.4.0" dependencies = [ "dirs", "fs_extra", diff --git a/Cargo.toml b/Cargo.toml index 27a1330c..d372b816 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ system = { version = "0.3", path = "api/system", package = "playdate-system", de sys = { version = "0.4", path = "api/sys", package = "playdate-sys", default-features = false } tool = { version = "0.1", path = "support/tool", package = "playdate-tool" } -build = { version = "=0.4.0-pre3", path = "support/build", package = "playdate-build", default-features = false } +build = { version = "0.4", path = "support/build", package = "playdate-build", default-features = false } utils = { version = "0.3", path = "support/utils", package = "playdate-build-utils", default-features = false } device = { version = "0.2", path = "support/device", package = "playdate-device" } simulator = { version = "0.1", path = "support/sim-ctrl", package = "playdate-simulator-utils", default-features = false } diff --git a/cargo/Cargo.toml b/cargo/Cargo.toml index 3e82a11b..280209d4 100644 --- a/cargo/Cargo.toml +++ b/cargo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-playdate" -version = "0.5.0-beta.6" +version = "0.5.0-pre.1" readme = "README.md" description = "Build tool for neat yellow console." keywords = ["playdate", "build", "cargo", "plugin", "cargo-subcommand"] diff --git a/cargo/README.md b/cargo/README.md index c3137775..c69c0ddf 100644 --- a/cargo/README.md +++ b/cargo/README.md @@ -6,7 +6,7 @@ It can build programs written in Rust, manage assets, build package for Playdate Usually it builds static or dynamic libraries for sim and hardware, but also it can build executable binaries for hardware and this method produces highly optimized output with dramatically minimized size (thanks to DCE & LTO)\*. -\* _For executable binaries use `--no-gcc` argument._ +\* _For executable binaries use `--no-gcc` argument needed to set up alternative linking final binary._ ### Platform specific pre-req install instructions @@ -57,10 +57,7 @@ cargo +nightly playdate --version Or install to use bleeding edge bits from a local git clone: ```bash -mkdir ~/code -cd ~/code -git clone https://github.com/boozook/playdate.git -cargo +nightly install --path="$HOME/code/playdate/cargo" cargo-playdate +cargo +nightly install cargo-playdate --git=https://github.com/boozook/playdate.git ``` ## Hello World @@ -109,22 +106,19 @@ Execute `cargo playdate -h` for more details, or with `--help` for further more. ### Limitations -1. Global crate-level attributes like `crate_type` and `crate_name` doesn't supported, e.g: -```rust -#![crate_name = "Game"] -#![crate_type = "lib"] -``` - -2. Cargo-targets such as `bin` and `example` should be in the cargo manifest. Autodetect isn't yet tested and may not work. Example: -```toml -[[example]] -name = "demo" -crate-type = ["dylib", "staticlib"] -path = "examples/demo.rs" -``` +* The `cargo-playdate` supports [cargo's auto-targets][target-auto-discovery] such as `bin` and `example`, but only for binary executable targets ignoring `#![crate_type = "lib"]` attribute. So if you want to build `example`-target as `lib`, that needed for run in simulator, you could declare it in the package manifest like this: + ```toml + [[example]] + name = "demo" + crate-type = ["dylib", "staticlib"] + path = "examples/demo.rs" + ``` + Otherwise `example` will be built as `bin` and runnable on device only. + In future versions it may be fixed with adding support of `rustc` command like it does `cargo rustc` to set `--crate-type`. +[target-auto-discovery]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#target-auto-discovery -3. Assets especially for `example` cargo-targets inherits from package assets. Currently there's no way to set assets for single cargo-target, but only for entire package __or for dev-targets__ - [there is `dev-assets` extra table][dev-assets-doc] inherited by main. +* Assets especially for `example` cargo-targets inherits from package assets. Currently there's no way to set assets for single cargo-target, but only for entire package __and for dev-targets__ - [there is `dev-assets` extra table][dev-assets-doc] inherited by package assets. [dev-assets-doc]: https://github.com/boozook/playdate/tree/main/support/build#dev-assets @@ -132,7 +126,7 @@ path = "examples/demo.rs" ## Troubleshooting -* On windows in some cases hardware cannot be ejected because of no permissions. Try to give rights and/or build `cargo-playdate` with feature `eject`. +* On any OS in case of a restricted environment hardware cannot be ejected because of no permissions. Try to give rights and/or build `cargo-playdate` with feature `eject`. * Welcome to [discussions](https://github.com/boozook/playdate/discussions) and [issues](https://github.com/boozook/playdate/issues). diff --git a/cargo/src/config.rs b/cargo/src/config.rs index 9b54103b..8345693e 100644 --- a/cargo/src/config.rs +++ b/cargo/src/config.rs @@ -61,7 +61,6 @@ pub struct Config<'cfg> { sdk: Lazy, gcc: Lazy, rustflags: Lazy, - build_plan: Lazy, unit_graph: Lazy, ws_metadata: Lazy, target_infos: Lazy>>, @@ -130,7 +129,6 @@ impl<'cfg> Config<'cfg> { sdk: Lazy::new(), gcc: Lazy::new(), rustflags: Lazy::new(), - build_plan: Lazy::new(), unit_graph: Lazy::new(), ws_metadata: Lazy::new(), target_infos: Lazy::new(), @@ -166,11 +164,6 @@ impl<'cfg> Config<'cfg> { }) } - #[deprecated = "corrupts cargo build cache"] - pub fn build_plan(&self) -> CargoResult<&crate::utils::cargo::build_plan::format::BuildPlan> { - self.build_plan - .try_get_or_create(|| crate::utils::cargo::build_plan::build_plan(self)) - } pub fn unit_graph(&self) -> CargoResult<&crate::utils::cargo::unit_graph::format::UnitGraph> { self.unit_graph diff --git a/cargo/src/package/mod.rs b/cargo/src/package/mod.rs index 939bff8c..f2e71e91 100644 --- a/cargo/src/package/mod.rs +++ b/cargo/src/package/mod.rs @@ -9,7 +9,6 @@ use anyhow::anyhow; use anyhow::bail; use cargo::core::PackageId; use cargo::CargoResult; -use cargo::core::Package; use cargo::core::compiler::CompileKind; use cargo::core::compiler::CrateType; use cargo::core::profiles::DebugInfo; diff --git a/cargo/src/proc/reader.rs b/cargo/src/proc/reader.rs index 9f3d8bae..2c80d298 100644 --- a/cargo/src/proc/reader.rs +++ b/cargo/src/proc/reader.rs @@ -126,7 +126,7 @@ pub mod format { use serde::Serialize; use serde::Deserialize; use cargo::core::PackageId; - use crate::utils::cargo::build_plan::format::de_crate_types; + use crate::utils::cargo::format::de_crate_types; use crate::utils::cargo::format::de_package_id_or_spec; pub use crate::utils::cargo::format::TargetKind; diff --git a/cargo/src/utils/cargo/format.rs b/cargo/src/utils/cargo/format.rs index 676d16be..cbefc218 100644 --- a/cargo/src/utils/cargo/format.rs +++ b/cargo/src/utils/cargo/format.rs @@ -89,6 +89,32 @@ impl Serialize for TargetKind { } +#[derive(Debug, Clone, Copy)] +pub enum TargetKindWild { + Lib, + Bin, + Test, + Bench, + ExampleLib, + ExampleBin, + CustomBuild, +} + +impl PartialEq for TargetKindWild { + fn eq(&self, other: &TargetKind) -> bool { + match self { + TargetKindWild::Lib => matches!(other, TargetKind::Lib(_)), + TargetKindWild::Bin => matches!(other, TargetKind::Bin), + TargetKindWild::Test => matches!(other, TargetKind::Test), + TargetKindWild::Bench => matches!(other, TargetKind::Bench), + TargetKindWild::ExampleLib => matches!(other, TargetKind::Example), + TargetKindWild::ExampleBin => matches!(other, TargetKind::Example), + TargetKindWild::CustomBuild => matches!(other, TargetKind::CustomBuild), + } + } +} + + pub fn de_package_id_or_specs<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de> { let items = Vec::::deserialize(deserializer)?; diff --git a/cargo/src/utils/cargo/meta_deps.rs b/cargo/src/utils/cargo/meta_deps.rs index 855c90a6..695ac4a5 100644 --- a/cargo/src/utils/cargo/meta_deps.rs +++ b/cargo/src/utils/cargo/meta_deps.rs @@ -16,8 +16,8 @@ use serde::de::IntoDeserializer; use crate::config::Config; use crate::logger::LogErr; -use super::build_plan::format::TargetKind; -use super::build_plan::TargetKindWild; +use super::format::TargetKind; +use super::format::TargetKindWild; use super::metadata::format::{Package, CrateMetadata}; use super::metadata::CargoMetadataPd; use super::unit_graph::format::{Unit, UnitTarget}; diff --git a/cargo/src/utils/cargo/mod.rs b/cargo/src/utils/cargo/mod.rs index 120de93a..f12deccf 100644 --- a/cargo/src/utils/cargo/mod.rs +++ b/cargo/src/utils/cargo/mod.rs @@ -5,7 +5,6 @@ use playdate::consts::DEVICE_TARGET; /// Shared format pub(crate) mod format; -pub mod build_plan; pub mod unit_graph; pub mod meta_deps; pub mod metadata; diff --git a/cargo/src/utils/cargo/unit_graph.rs b/cargo/src/utils/cargo/unit_graph.rs index 9a1f0f53..6dfab6fd 100644 --- a/cargo/src/utils/cargo/unit_graph.rs +++ b/cargo/src/utils/cargo/unit_graph.rs @@ -4,10 +4,9 @@ use crate::cli::cmd::Cmd; use crate::config::Config; use crate::proc::cargo_proxy_cmd; use crate::proc::read_cargo_json; +use super::format::TargetKindWild; use self::format::UnitGraph; -use super::build_plan::TargetKindWild; - pub fn unit_graph(cfg: &Config) -> CargoResult { let mut cargo = cargo_proxy_cmd(cfg, &Cmd::Build)?; diff --git a/cargo/tests/build.rs b/cargo/tests/build.rs index 2dc3f2c3..1ee86832 100644 --- a/cargo/tests/build.rs +++ b/cargo/tests/build.rs @@ -2,4 +2,5 @@ mod common; pub mod build { pub mod simple; + pub mod auto_target; } diff --git a/cargo/tests/build/auto_target.rs b/cargo/tests/build/auto_target.rs new file mode 100644 index 00000000..9a10fcfe --- /dev/null +++ b/cargo/tests/build/auto_target.rs @@ -0,0 +1,91 @@ +use std::ffi::OsStr; +use std::ffi::OsString; +use std::path::Path; +use std::path::PathBuf; +use std::process::Output; +use anyhow::Result; + +use ::build::consts::DEVICE_TARGET; +use crate::common::*; + + +fn run_build(crate_path: &Path, + args: impl IntoIterator>) + -> Result<(Output, &'static Path)> { + println!("crate: {}", crate_path.display()); + + let target_dir = target_dir(); + let target_dir_arg = format!("--target-dir={}", target_dir.display()); + let args = args.into_iter() + .map(Into::into) + .chain([OsString::from(target_dir_arg)]); + let output = Tool::build(crate_path, args)?; + assert!( + output.status.success(), + "Tool failed with stderr:\n{}", + std::str::from_utf8(&output.stderr).unwrap() + ); + Ok((output, target_dir)) +} + +fn test_artifact_dev(path: &Path, _debug: bool) { + println!("validating: {}", path.display()); + assert!(path.exists(), "path does not exist: {}", path.display()); +} + + +fn export_dir(target_dir: &Path, target: &str, profile: &str) -> PathBuf { target_dir.join(target).join(profile) } + + +#[test] +fn bins_examples() -> Result<()> { + let target = DEVICE_TARGET; + let args = ["--device", "--bins", "--examples"].into_iter().map(OsStr::new); + + let path = auto_target()?; + let (_, target_dir) = run_build(path, args.clone())?; + let export_dir = export_dir(target_dir, target, "debug"); + + // check expectations: + let package_name = "test-auto-target"; + let cargo_package_name = to_cargo_package_crate_name(Path::new(package_name)).expect("package_crate_name"); + for trg in ["test-auto-target", "auto-bin", "example-bin"] { + let cargo_target_fullname = format!("{cargo_package_name}-{trg}"); + let artifact = export_dir.join("playdate") + .join(cargo_target_fullname) + .join(PathBuf::from("build/pdex.elf")); + println!("should be there: {artifact:?}"); + test_artifact_dev(&artifact, false); + } + + Ok(()) +} + + +#[test] +#[cfg_attr(windows, ignore = "Off until paths on Windows fixed.")] +// Error on Windows: +// failed to parse value from --config argument `target.thumbv7em-none-eabihf.rustflags=["-Ctarget-cpu=cortex-m7", "-Clink-args=--emit-relocs", "-Crelocation-model=pic", "-Csoft-float=no", "-Clink-arg=--cref", "-Clink-arg=--gc-sections", "-Clink-arg=--entry=eventHandlerShim", "-Clink-arg=-T\\?\\D:\\a\playdate\\playdate\\target\\tmp\\pd.x"]` as a dotted key expression +fn bins_examples_no_gcc() -> Result<()> { + let target = DEVICE_TARGET; + let args = ["--device", "--bins", "--examples", "--no-gcc"].into_iter() + .map(OsStr::new); + + let path = auto_target()?; + let (_, target_dir) = run_build(path, args.clone())?; + let export_dir = export_dir(target_dir, target, "debug"); + + // check expectations: + let package_name = "test-auto-target"; + let cargo_package_name = to_cargo_package_crate_name(Path::new(package_name)).expect("package_crate_name"); + for trg in ["test-auto-target", "auto-bin", "example-bin"] { + let cargo_target_fullname = format!("{cargo_package_name}-{trg}"); + let artifact = export_dir.join("playdate") + .join(cargo_target_fullname) + .join(PathBuf::from("build/pdex.elf")); + println!("should be there: {artifact:?}"); + test_artifact_dev(&artifact, false); + } + + Ok(()) +} diff --git a/cargo/tests/build/simple.rs b/cargo/tests/build/simple.rs index 35cbc060..aa96aba4 100644 --- a/cargo/tests/build/simple.rs +++ b/cargo/tests/build/simple.rs @@ -59,7 +59,6 @@ const EXAMPLE_PREFIX: &str = "example"; fn dev_lib_release() -> Result<()> { let target = DEVICE_TARGET; let args = ["--device", "--lib", "--release"].into_iter().map(OsStr::new); - // let args = ["--device", "--no-sdk", "--no-gcc", "--release"].into_iter().map(OsStr::new); for path in simple_crates()? { let (_, target_dir) = run_build(&path, args.clone())?; @@ -200,12 +199,6 @@ fn dev_sim_release_exp() -> Result<()> { } -// (issue: #315) Convert dir-name to package-name, then to crate_name -fn to_cargo_package_crate_name(path: &Path) -> Option { - Some(path.file_name()?.to_str()?.replace('-', "_")) -} - - mod examples { use super::*; use std::ffi::OsStr; diff --git a/cargo/tests/common.rs b/cargo/tests/common.rs index 3abd0893..ca2f7c1b 100644 --- a/cargo/tests/common.rs +++ b/cargo/tests/common.rs @@ -98,6 +98,12 @@ pub fn simple_crates() -> Result> { Ok(crates) } +pub fn auto_target() -> Result<&'static Path> { + let root = Path::new("tests/crates/auto-target"); + assert!(root.exists()); + Ok(root) +} + pub fn workspace() -> Result<&'static Path> { let root = Path::new("tests/crates/workspace"); assert!(root.exists()); @@ -154,3 +160,9 @@ pub fn target_triple() -> String { ) } } + + +// (issue: #315) Convert dir-name to package-name, then to crate_name +pub fn to_cargo_package_crate_name(path: &Path) -> Option { + Some(path.file_name()?.to_str()?.replace('-', "_")) +} diff --git a/cargo/tests/crates/auto-target/Cargo.toml b/cargo/tests/crates/auto-target/Cargo.toml new file mode 100644 index 00000000..c7300ed3 --- /dev/null +++ b/cargo/tests/crates/auto-target/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] + +[package] +name = "test-auto-target" +version = "0.1.0" +edition = "2021" +publish = false + +autotests = false +autobenches = false + + +[dependencies.pd] +package = "playdate-sys" +path = "../../../../api/sys" +features = ["lang-items"] + + +[profile] +dev.panic = "abort" +release.panic = "abort" diff --git a/cargo/tests/crates/auto-target/bin.inc.rs b/cargo/tests/crates/auto-target/bin.inc.rs new file mode 100644 index 00000000..af89f876 --- /dev/null +++ b/cargo/tests/crates/auto-target/bin.inc.rs @@ -0,0 +1,65 @@ +use core::ffi::*; + +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; + +#[macro_use] +extern crate pd; +use pd::ffi::*; + +#[path = "../../shared.rs"] +mod shared; + +pd::ll_symbols!(); + + +#[no_mangle] +pub extern "C" fn eventHandlerShim(api: *const PlaydateAPI, event: PDSystemEvent, _arg: u32) -> c_int { + match event { + PDSystemEvent::kEventInit => unsafe { + pd::API = api; + let f = (*(*api).system).setUpdateCallback.unwrap(); + f(Some(on_update), core::ptr::null_mut()); + + println!("Init OK"); + }, + + PDSystemEvent::kEventLock => println!("Lock"), + PDSystemEvent::kEventUnlock => println!("Unlock"), + PDSystemEvent::kEventPause => println!("Pause"), + PDSystemEvent::kEventResume => println!("Resume"), + PDSystemEvent::kEventKeyPressed => println!("KeyPressed"), + PDSystemEvent::kEventKeyReleased => println!("KeyReleased"), + PDSystemEvent::kEventLowPower => println!("LowPower"), + PDSystemEvent::kEventInitLua => println!("InitLua"), + PDSystemEvent::kEventTerminate => println!("Terminate"), + } + + 0 +} + + +unsafe extern "C" fn on_update(_: *mut c_void) -> i32 { + // This is used for execution tests: + if let Some(s) = shared::CARGO_PLAYDATE_TEST_VALUE { + println!("{}{s}", shared::CARGO_PLAYDATE_TEST_VALUE_PREFIX); + } + + check_crank_docked(); + 1 +} + +#[inline(never)] +pub fn check_crank_docked() { + unsafe { + let b = (*(*pd::API).system).isCrankDocked.as_ref().unwrap()() != 0; + if b { + let f = (*(*pd::API).system).drawFPS.as_ref().unwrap(); + f(40, 40); + } else { + let f = (*(*pd::API).graphics).clear.as_ref().unwrap(); + f(0); + } + } +} diff --git a/cargo/tests/crates/auto-target/examples/example-bin.rs b/cargo/tests/crates/auto-target/examples/example-bin.rs new file mode 100644 index 00000000..1d654a77 --- /dev/null +++ b/cargo/tests/crates/auto-target/examples/example-bin.rs @@ -0,0 +1,4 @@ +#![crate_type = "bin"] +#![no_std] +#![no_main] +core::include!("../bin.inc.rs"); diff --git a/cargo/tests/crates/auto-target/src/bin/auto-bin.rs b/cargo/tests/crates/auto-target/src/bin/auto-bin.rs new file mode 100644 index 00000000..a7e5d249 --- /dev/null +++ b/cargo/tests/crates/auto-target/src/bin/auto-bin.rs @@ -0,0 +1,4 @@ +#![crate_type = "bin"] +#![no_std] +#![no_main] +core::include!("../../bin.inc.rs"); diff --git a/cargo/tests/crates/auto-target/src/main.rs b/cargo/tests/crates/auto-target/src/main.rs new file mode 100644 index 00000000..1d654a77 --- /dev/null +++ b/cargo/tests/crates/auto-target/src/main.rs @@ -0,0 +1,4 @@ +#![crate_type = "bin"] +#![no_std] +#![no_main] +core::include!("../bin.inc.rs"); diff --git a/cargo/tests/crates/simple/lib.rs b/cargo/tests/crates/simple/lib.rs index 12c4fbe2..10e328a3 100644 --- a/cargo/tests/crates/simple/lib.rs +++ b/cargo/tests/crates/simple/lib.rs @@ -34,7 +34,7 @@ pub extern "C" fn eventHandlerShim(api: *const PlaydateAPI, event: PDSystemEvent PDSystemEvent::kEventKeyReleased => println!("KeyReleased"), PDSystemEvent::kEventLowPower => println!("LowPower"), PDSystemEvent::kEventInitLua => println!("InitLua"), - PDSystemEvent::kEventTerminate => panic!("It finally works!!!"), + PDSystemEvent::kEventTerminate => println!("Terminate"), } 0 diff --git a/cargo/tests/init/init.rs b/cargo/tests/init/init.rs index 1ad1c399..4969d1b4 100644 --- a/cargo/tests/init/init.rs +++ b/cargo/tests/init/init.rs @@ -1,3 +1,4 @@ +#![allow(unexpected_cfgs)] use std::ffi::OsStr; use std::ffi::OsString; use std::path::PathBuf; diff --git a/cargo/tests/init/new.rs b/cargo/tests/init/new.rs index 4db3904d..4a342916 100644 --- a/cargo/tests/init/new.rs +++ b/cargo/tests/init/new.rs @@ -1,3 +1,4 @@ +#![allow(unexpected_cfgs)] use std::ffi::OsStr; use std::ffi::OsString; use std::path::PathBuf; diff --git a/support/build/Cargo.toml b/support/build/Cargo.toml index cb31db59..105462dc 100644 --- a/support/build/Cargo.toml +++ b/support/build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-build" -version = "0.4.0-pre3" +version = "0.4.0" readme = "README.md" description = "Utils that help to build package for Playdate" keywords = ["playdate", "package", "encoding", "manifest", "assets"] diff --git a/support/build/src/assets/plan.rs b/support/build/src/assets/plan.rs index 28090dd4..df500340 100644 --- a/support/build/src/assets/plan.rs +++ b/support/build/src/assets/plan.rs @@ -993,7 +993,7 @@ mod tests { // left hand of rule: let targets = ["trg", "/trg", "//trg"]; // right hand of rule: - let tests: HashSet<_> = vec!["Cargo.toml", "src/lib.rs"].into_iter().collect(); + let tests = vec!["Cargo.toml", "src/lib.rs"]; // latest because there is no to files into one target, so "into" will be used for trg in targets { @@ -1014,7 +1014,7 @@ mod tests { ) = pair { assert_eq!(left, stripped_trg); - assert!(tests.contains(right.as_str())); + assert!(tests.contains(&right.as_str())); assert_eq!(source, Path::new(right)); assert_eq!(target, Path::new(stripped_trg)); } else { @@ -1023,6 +1023,38 @@ mod tests { } } } + + #[test] + fn local_exact_exclude() { + let env = Env::try_default().unwrap(); + let opts = AssetsOptions::default(); + + let root = crate_root(); + let root = Some(root.as_path().into()); + + // left hand of rule: + let tests = vec!["Cargo.toml", "src/lib.rs"]; + + let exprs = tests.iter() + .map(|s| (*s, RuleValue::Boolean(true))) + .chain([("*.toml", RuleValue::Boolean(false))]) + .collect(); + + let assets = AssetsRules::Map(exprs); + + let plan = build_plan(&env, &assets, &opts, root.clone()).unwrap(); + + let pairs = plan.as_inner(); + assert_eq!(1, pairs.len()); + + let pair = pairs.first().unwrap(); + + if let Mapping::AsIs(_, (Expr::Original(left), _)) = pair { + assert_eq!(tests[1], left); + } else { + panic!("pair is not matching: {pair:#?}"); + } + } } @@ -1088,7 +1120,7 @@ mod tests { let targets = ["/trg/", "//trg/", "/trg", "trg"]; let targets_rel = ["trg/", "trg"]; // non-abs targets // right hand of rule: - let tests: HashSet<_> = vec!["Cargo.tom*", "src/lib.*"].into_iter().collect(); + let tests = vec!["Cargo.tom*", "src/lib.*"]; // latest because there is no to files into one target, so "into" will be used for trg in targets { @@ -1111,7 +1143,7 @@ mod tests { assert_eq!(&target.to_string_lossy(), left); assert_eq!(1, sources.len()); - assert!(tests.contains(right.as_str())); + assert!(tests.contains(&right.as_str())); #[cfg(feature = "assets-report")] assert_eq!(0, excluded.len()); @@ -1121,6 +1153,51 @@ mod tests { } } } + + + #[test] + #[cfg_attr(windows, should_panic)] + fn glob_local_exclude() { + let env = Env::try_default().unwrap(); + let opts = AssetsOptions::default(); + + let root = crate_root(); + let root = Some(root.as_path().into()); + + // exclude: + let exclude = "src/*"; + // left hand of rule: + let trg = "/trg"; + // right hand of rule: + let tests: HashMap<_, _> = vec![("Cargo.tom*", 1), ("src/lib.*", 0)].into_iter().collect(); + // left + right: + let exprs = tests.iter() + .enumerate() + .map(|(i, (s, _))| (trg.to_string() + &"/".repeat(i), RuleValue::String(s.to_string()))) + .chain([(exclude.to_string(), RuleValue::Boolean(false))]) + .collect(); + + let assets = AssetsRules::Map(exprs); + let plan = build_plan(&env, &assets, &opts, root.clone()).unwrap(); + + let pairs = plan.as_inner(); + assert_eq!(2, pairs.len()); + + for pair in pairs.iter() { + if let Mapping::ManyInto { sources, + target, + exprs: (Expr::Original(left), Expr::Original(right)), + .. } = pair + { + assert_eq!(&target.to_string_lossy(), left); + + let sources_expected = tests[right.as_str()]; + assert_eq!(sources_expected, sources.len()); + } else { + panic!("pair is not matching: {pair:#?}"); + } + } + } } } }