From 2df4c33974769c39f618bd25a352588b51143959 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Sat, 16 Jul 2022 03:26:36 +0800 Subject: [PATCH 1/2] Try to use the "cargo metadata" command when automatically discovering the target dir --- Cargo.lock | 1 + crates/fj-host/Cargo.toml | 1 + crates/fj-host/src/lib.rs | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e33938e921..4cb7bf1501 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -870,6 +870,7 @@ dependencies = [ name = "fj-host" version = "0.8.0" dependencies = [ + "cargo_metadata", "fj", "libloading", "notify", diff --git a/crates/fj-host/Cargo.toml b/crates/fj-host/Cargo.toml index 395486a0b6..4fcd24d4b3 100644 --- a/crates/fj-host/Cargo.toml +++ b/crates/fj-host/Cargo.toml @@ -16,6 +16,7 @@ categories = ["encoding", "mathematics", "rendering"] libloading = "0.7.2" notify = "5.0.0-pre.15" thiserror = "1.0.31" +cargo_metadata = "0.15.0" [dependencies.fj] version = "0.8.0" diff --git a/crates/fj-host/src/lib.rs b/crates/fj-host/src/lib.rs index c8ddc6463c..f71ad9d42e 100644 --- a/crates/fj-host/src/lib.rs +++ b/crates/fj-host/src/lib.rs @@ -21,12 +21,13 @@ use std::{ collections::{HashMap, HashSet}, ffi::OsStr, io, - path::PathBuf, + path::{Path, PathBuf}, process::Command, sync::mpsc, thread, }; +use cargo_metadata::Metadata; use notify::Watcher as _; use thiserror::Error; @@ -64,7 +65,9 @@ impl Model { let lib_path = { let file = HostPlatform::lib_file_name(&name); - let target_dir = target_dir.unwrap_or_else(|| path.join("target")); + let target_dir = target_dir + .or_else(|| cargo_metadata_target_dir(&path)) + .unwrap_or_else(|| path.join("target")); target_dir.join("debug").join(file) }; @@ -285,3 +288,14 @@ pub enum Error { } type ModelFn = unsafe extern "C" fn(args: &Parameters) -> fj::Shape; + +fn cargo_metadata_target_dir(model: &Path) -> Option { + let Metadata { + target_directory, .. + } = cargo_metadata::MetadataCommand::new() + .current_dir(model) + .exec() + .ok()?; + + Some(target_directory.into()) +} From 9baa869e4e86040acd11c5ea1589e299a87f8104 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Sat, 16 Jul 2022 16:03:24 +0800 Subject: [PATCH 2/2] Use cargo to get the package associated with a directory --- crates/fj-host/src/lib.rs | 69 +++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/crates/fj-host/src/lib.rs b/crates/fj-host/src/lib.rs index f71ad9d42e..f94b234590 100644 --- a/crates/fj-host/src/lib.rs +++ b/crates/fj-host/src/lib.rs @@ -27,7 +27,6 @@ use std::{ thread, }; -use cargo_metadata::Metadata; use notify::Watcher as _; use thiserror::Error; @@ -41,7 +40,8 @@ pub struct Model { } impl Model { - /// Initialize the model from a path + /// Initialize the model using the path to its crate (i.e. the folder + /// containing `Cargo.toml`). /// /// Optionally, the target directory where plugin files are compiled to can /// be provided. If it is not provided, the target directory is assumed to @@ -50,33 +50,28 @@ impl Model { path: PathBuf, target_dir: Option, ) -> io::Result { - let name = { - // Can't panic. It only would, if the path ends with "..", and we - // are canonicalizing it here to prevent that. - let canonical = path.canonicalize()?; - let file_name = canonical - .file_name() - .expect("Expected path to be canonical"); - - file_name.to_string_lossy().replace('-', "_") - }; + let crate_dir = path.canonicalize()?; + + let metadata = cargo_metadata::MetadataCommand::new() + .current_dir(&crate_dir) + .exec() + .map_err(metadata_error_to_io)?; - let src_path = path.join("src"); + let pkg = package_associated_with_directory(&metadata, &crate_dir)?; + let src_path = crate_dir.join("src"); let lib_path = { + let name = pkg.name.replace('-', "_"); let file = HostPlatform::lib_file_name(&name); let target_dir = target_dir - .or_else(|| cargo_metadata_target_dir(&path)) - .unwrap_or_else(|| path.join("target")); + .unwrap_or_else(|| metadata.target_directory.clone().into()); target_dir.join("debug").join(file) }; - let manifest_path = path.join("Cargo.toml"); - Ok(Self { src_path, lib_path, - manifest_path, + manifest_path: pkg.manifest_path.as_std_path().to_path_buf(), }) } @@ -211,6 +206,33 @@ impl Model { } } +fn metadata_error_to_io(e: cargo_metadata::Error) -> std::io::Error { + match e { + cargo_metadata::Error::Io(io) => io, + _ => std::io::Error::new(io::ErrorKind::Other, e), + } +} + +fn package_associated_with_directory<'m>( + metadata: &'m cargo_metadata::Metadata, + dir: &Path, +) -> Result<&'m cargo_metadata::Package, io::Error> { + for pkg in metadata.workspace_packages() { + let crate_dir = pkg + .manifest_path + .parent() + .and_then(|p| p.canonicalize().ok()); + + if crate_dir.as_deref() == Some(dir) { + return Ok(pkg); + } + } + + let msg = format!("\"{}\" doesn't point to a crate", dir.display()); + + Err(io::Error::new(io::ErrorKind::Other, msg)) +} + /// Watches a model for changes, reloading it continually pub struct Watcher { _watcher: Box, @@ -288,14 +310,3 @@ pub enum Error { } type ModelFn = unsafe extern "C" fn(args: &Parameters) -> fj::Shape; - -fn cargo_metadata_target_dir(model: &Path) -> Option { - let Metadata { - target_directory, .. - } = cargo_metadata::MetadataCommand::new() - .current_dir(model) - .exec() - .ok()?; - - Some(target_directory.into()) -}