Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

27 running examples via cli #32

Merged
merged 3 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ crate-type = ["rlib"]

[dependencies]
bevy = "0.11"
dexterous_developer = "0.0.12-pre.0"
dexterous_developer = "0.0.11"
serde = "1" # If you want the serialization capacities
```

Expand Down Expand Up @@ -83,3 +83,7 @@ fn reloadable(app: &mut ReloadableAppContents) {
}

```

## Bevy Main

If you want to use the current bevy main, you should use the `main` branch of the github repository. Otherwise, all published versions of `dexterous_developer` currently only support bevy `0.11`.
1 change: 1 addition & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- add support for hot re-loading states
- add support for hot re-loading events
- add support for running examples with the `dylib` crate type.

## Version 0.0.11

Expand Down
23 changes: 20 additions & 3 deletions dexterous_developer_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ enum Commands {
#[arg(short, long)]
package: Option<String>,

/// Example to build
#[arg(short, long)]
example: Option<String>,

/// Features to include
#[arg(short, long)]
features: Vec<String>,
Expand All @@ -44,6 +48,10 @@ enum Commands {
#[arg(short, long)]
package: Option<String>,

/// Example to build
#[arg(short, long)]
example: Option<String>,

/// Features to include
#[arg(short, long)]
features: Vec<String>,
Expand Down Expand Up @@ -92,6 +100,10 @@ enum Commands {
#[arg(short, long)]
package: Option<String>,

/// Example to build
#[arg(short, long)]
example: Option<String>,

/// Features to include
#[arg(short, long)]
features: Vec<String>,
Expand All @@ -110,6 +122,7 @@ impl Default for Commands {
fn default() -> Self {
Self::Run {
package: None,
example: None,
features: vec![],
watch: vec![],
}
Expand All @@ -135,17 +148,19 @@ async fn main() {
match command {
Commands::Run {
package,
example,
features,
watch,
} => {
println!("Running {package:?} with {features:?}");

let temporary = setup_temporary_manifest(&dir, package.as_deref())
let temporary = setup_temporary_manifest(&dir, package.as_deref(), example.as_deref())
.expect("Couldn't set up temporary manifest");

let options = HotReloadOptions {
features,
package,
example,
watch_folders: watch,
..Default::default()
};
Expand All @@ -160,13 +175,14 @@ async fn main() {
}
Commands::Serve {
package,
example,
features,
watch,
port,
} => {
println!("Serving {package:?} on port {port}");

let temporary = setup_temporary_manifest(&dir, package.as_deref())
let temporary = setup_temporary_manifest(&dir, package.as_deref(), example.as_deref())
.expect("Couldn't set up temporary manifest");
run_server(port, package, features, watch)
.await
Expand Down Expand Up @@ -198,11 +214,12 @@ async fn main() {
}
Commands::CompileLibs {
package,
example,
features,
libs,
target,
} => {
let temporary = setup_temporary_manifest(&dir, package.as_deref())
let temporary = setup_temporary_manifest(&dir, package.as_deref(), example.as_deref())
.expect("Couldn't set up temporary manifest");
let CliPaths { cross_config, .. } = paths::get_paths().expect("Couldn't get cli paths");
if cross_config.exists() {
Expand Down
5 changes: 5 additions & 0 deletions dexterous_developer_cli/src/temporary_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ use toml::{Table, Value};
pub fn setup_temporary_manifest(
dir: &Path,
package: Option<&str>,
example: Option<&str>,
) -> anyhow::Result<Option<TemporaryManifest>> {
if example.is_some() {
return Ok(None);
}
let mut get_metadata = cargo_metadata::MetadataCommand::new();
get_metadata.no_deps();
get_metadata.current_dir(dir);
Expand All @@ -27,6 +31,7 @@ pub fn setup_temporary_manifest(
}
pkg.targets
.iter()
.filter(|p| !(p.is_example() || p.is_bench() || p.is_test()))
.find(|p| {
p.crate_types
.iter()
Expand Down
28 changes: 25 additions & 3 deletions dexterous_developer_internal/src/hot/build_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub(crate) struct BuildSettings {
pub watch_folders: Vec<PathBuf>,
pub manifest: Option<PathBuf>,
pub lib_path: PathBuf,
pub package: String,
pub package: PackageOrExample,
pub features: String,
pub target_folder: Option<PathBuf>,
pub out_target: PathBuf,
Expand All @@ -22,13 +22,25 @@ pub(crate) struct BuildSettings {
pub watch_folders: Vec<PathBuf>,
pub manifest: Option<PathBuf>,
pub lib_path: PathBuf,
pub package: String,
pub package: PackageOrExample,
pub features: String,
pub target_folder: Option<PathBuf>,
pub out_target: PathBuf,
pub build_target: Option<crate::Target>,
}

#[derive(Clone, Debug)]
pub enum PackageOrExample {
Package(String),
Example(String),
}

impl Default for PackageOrExample {
fn default() -> Self {
Self::Package(String::default())
}
}

impl ToString for BuildSettings {
fn to_string(&self) -> String {
let BuildSettings {
Expand Down Expand Up @@ -57,6 +69,10 @@ impl ToString for BuildSettings {
.map(|v| v.to_string_lossy())
.unwrap_or_default();
let lib_path: std::borrow::Cow<'_, str> = lib_path.to_string_lossy();
let package = match package {
PackageOrExample::Package(v) => v.clone(),
PackageOrExample::Example(v) => format!("example:{v}"),
};

format!("{lib_path}:!:{watch_folder}:!:{manifest}:!:{package}:!:{features}:!:{out_target}:!:{target}")
}
Expand All @@ -79,7 +95,13 @@ impl TryFrom<&str> for BuildSettings {
let manifest = split.next().filter(|v| !v.is_empty()).map(PathBuf::from);
let package = split
.next()
.map(|v| v.to_string())
.map(|v| {
if v.starts_with("example:") {
PackageOrExample::Example(v.replace("example:", "").to_string())
} else {
PackageOrExample::Package(v.to_string())
}
})
.ok_or(Error::msg("no package"))?;
let features = split
.next()
Expand Down
97 changes: 70 additions & 27 deletions dexterous_developer_internal/src/hot/command.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
collections::BTreeSet,
collections::{BTreeSet, HashSet},
path::PathBuf,
process::{Command, Stdio},
sync::mpsc,
Expand All @@ -14,7 +14,10 @@ use log::{debug, error, info, trace};
use notify::{RecursiveMode, Watcher};

use crate::{
hot::singleton::{BUILD_SETTINGS, WATCHER},
hot::{
build_settings::PackageOrExample,
singleton::{BUILD_SETTINGS, WATCHER},
},
internal_shared::cargo_path_utils,
internal_shared::LibPathSet,
HotReloadOptions,
Expand All @@ -33,6 +36,7 @@ pub(crate) fn setup_build_settings(
let HotReloadOptions {
manifest_path,
package,
example,
lib_name,
watch_folders,
target_folder,
Expand Down Expand Up @@ -100,15 +104,29 @@ pub(crate) fn setup_build_settings(
return None;
}
}
pkg.targets
.iter()
.find(|p| {
p.crate_types
.iter()
.map(|v| v.as_str())
.any(|v| v == "dylib")
})
.map(|p| (pkg, p))
if let Some(example) = example.as_ref() {
pkg.targets
.iter()
.filter(|p| p.is_example() && p.name == example.as_str())
.find(|p| {
p.crate_types
.iter()
.map(|v| v.as_str())
.any(|v| v == "dylib")
})
.map(|p| (PackageOrExample::Example(p.name.clone()), p, pkg))
} else {
pkg.targets
.iter()
.filter(|p| !(p.is_example() || p.is_bench() || p.is_test()))
.find(|p| {
p.crate_types
.iter()
.map(|v| v.as_str())
.any(|v| v == "dylib")
})
.map(|p| (PackageOrExample::Package(pkg.name.clone()), p, pkg))
}
});

let libs: Vec<_> = if let Some(library) = lib_name.as_ref() {
Expand All @@ -121,7 +139,7 @@ pub(crate) fn setup_build_settings(
bail!("Workspace contains multiple libraries - please set the one you want with the --package option");
}

let Some((pkg, lib)) = libs.first() else {
let Some((pkg_or_example, lib, pkg)) = libs.first() else {
bail!("Workspace contains no matching libraries");
};

Expand Down Expand Up @@ -198,18 +216,30 @@ pub(crate) fn setup_build_settings(
let settings = BuildSettings {
lib_path: lib_path.clone(),
watch_folders: if watch_folders.is_empty() {
vec![lib
.src_path
.clone()
.into_std_path_buf()
.parent()
.map(|v| v.to_path_buf())
.ok_or(Error::msg("Couldn't find source directory to watch"))?]
let set: HashSet<PathBuf> = [
lib.src_path
.clone()
.into_std_path_buf()
.parent()
.map(|v| v.to_path_buf())
.ok_or(Error::msg("Couldn't find source directory to watch"))?,
pkg.manifest_path
.clone()
.into_std_path_buf()
.parent()
.ok_or(Error::msg("Couldn't find source directory to watch"))?
.join("src"),
]
.iter()
.map(|v| v.to_owned())
.collect();

set.into_iter().collect()
} else {
watch_folders.clone()
},
manifest: manifest_path.clone(),
package: pkg.name.clone().clone(),
package: pkg_or_example.clone(),
features: features.into_iter().collect::<Vec<_>>().join(","),
target_folder: target_folder.as_ref().cloned().map(|mut v| {
if v.ends_with("debug") {
Expand Down Expand Up @@ -373,12 +403,18 @@ fn rebuild_internal(settings: &BuildSettings) -> anyhow::Result<()> {

let mut command = Command::new(cargo);
let build_command = super::env::set_envs(&mut command, build_target.as_ref())?;
command.args(build_command).arg("--profile").arg("dev");

match package {
crate::hot::build_settings::PackageOrExample::Package(package) => {
command.arg("-p").arg(package.as_str());
}
crate::hot::build_settings::PackageOrExample::Example(example) => {
command.arg("--example").arg(example.as_str());
}
}

command
.args(build_command)
.arg("--profile")
.arg("dev")
.arg("-p")
.arg(package.as_str())
.arg("--lib")
.arg("--features")
.arg(features)
Expand Down Expand Up @@ -482,8 +518,15 @@ fn rebuild_internal(settings: &BuildSettings) -> anyhow::Result<()> {
let extension = extension.to_string_lossy().to_string();
trace!("file has stem {stem} and extension {extension}");

if parent.to_string_lossy() != "deps" {
let deps = parent.join("deps");
let parent_str = parent.to_string_lossy();
trace!("File parent is: {parent_str}");

if !parent_str.contains("deps") {
let deps = if parent_str.ends_with("examples") {
parent.to_path_buf()
} else {
parent.join("deps")
};
let deps_path = deps.join(filename);
if deps_path.exists() {
trace!("{deps_path:?} exists - using it instead of {path:?}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,6 @@ impl LibraryHolderInner {

await_file(3, &new_path);

let _folder = new_path.parent();

crate::logger::debug!("Search Paths: ");
for path in cargo_path_utils::dylib_path() {
crate::logger::debug!("{path:?}");
if let Ok(dir) = std::fs::read_dir(&path) {
for entry in dir.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if name.contains("libbevy_dylib") {
crate::logger::debug!("Found bevy dylib at {:?}", entry.path());
}
}
} else {
crate::logger::error!("THIS PATH DOES NOT EXIST - {path:?}");
}
}

// SAFETY: Here we are relying on libloading's safety processes for ensuring the Library we receive is properly set up. We expect that library to respect rust ownership semantics because we control it's compilation and know that it is built in rust as well, but the wrappers are unaware so they rely on unsafe.
match unsafe { libloading::Library::new(&new_path) } {
Ok(lib) => {
Expand Down Expand Up @@ -98,8 +81,8 @@ fn await_file(iterations: usize, path: &PathBuf) {
}
if iterations > 0 {
crate::logger::debug!("{path:?} doesn't exist yet...");
await_file(iterations.saturating_sub(1), path);
std::thread::sleep(Duration::from_secs_f32(0.5));
await_file(iterations.saturating_sub(1), path);
}
}

Expand Down
1 change: 1 addition & 0 deletions dexterous_developer_internal/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use anyhow::bail;
pub struct HotReloadOptions {
pub manifest_path: Option<PathBuf>,
pub package: Option<String>,
pub example: Option<String>,
pub lib_name: Option<String>,
pub watch_folders: Vec<PathBuf>,
pub target_folder: Option<PathBuf>,
Expand Down
Loading
Loading