diff --git a/plotly_static/README.md b/plotly_static/README.md index c2c20feb..46a78ae5 100644 --- a/plotly_static/README.md +++ b/plotly_static/README.md @@ -63,6 +63,7 @@ serde_json = "1.0" ### Feature Flags +- To use static export, enable exactly one of the driver features below. - `chromedriver`: Use Chromedriver and Chrome/Chromium browser for rendering and export - `geckodriver`: Use Geckodriver Firefox browser for rendering for rendering and export - `webdriver_download`: Auto-download the chosen WebDriver binary diff --git a/plotly_static/build.rs b/plotly_static/build.rs index 49f18a50..a574fa8b 100644 --- a/plotly_static/build.rs +++ b/plotly_static/build.rs @@ -1,3 +1,8 @@ +#![cfg_attr( + not(any(feature = "geckodriver", feature = "chromedriver")), + allow(unused) +)] + use std::env; use std::fs; use std::path::{Path, PathBuf}; @@ -12,10 +17,6 @@ use webdriver_downloader::prelude::*; #[cfg(all(feature = "geckodriver", feature = "chromedriver"))] compile_error!("Only one of 'geckodriver' or 'chromedriver' features can be enabled at a time."); -// Enforce that at least one driver feature is enabled -#[cfg(not(any(feature = "geckodriver", feature = "chromedriver")))] -compile_error!("At least one of 'geckodriver' or 'chromedriver' features must be enabled."); - #[cfg(target_os = "windows")] const DRIVER_EXT: &str = ".exe"; #[cfg(not(target_os = "windows"))] @@ -199,7 +200,7 @@ fn setup_driver(config: &WebdriverDownloadConfig) -> Result<()> { Ok(()) } -#[cfg(feature = "chromedriver")] +#[cfg(all(feature = "chromedriver", not(feature = "geckodriver")))] fn get_chrome_path() -> Result { if let Ok(chrome_path) = env::var(BROWSER_BIN_PATH_ENV) { let path = PathBuf::from(&chrome_path); diff --git a/plotly_static/src/lib.rs b/plotly_static/src/lib.rs index 42f23b86..cf9fdbcd 100644 --- a/plotly_static/src/lib.rs +++ b/plotly_static/src/lib.rs @@ -59,9 +59,9 @@ //! //! ## Features and Dependencies //! -//! ### Required Features +//! ### Driver Features //! -//! You must enable one of the following features: +//! To use static export, enable one of the following features: //! //! - `chromedriver`: Use Chrome/Chromium for rendering //! - `geckodriver`: Use Firefox for rendering @@ -294,6 +294,7 @@ use fantoccini::{wd::Capabilities, Client, ClientBuilder}; #[cfg(not(any(test, feature = "debug")))] use log::{debug, error, warn}; use serde::Serialize; +#[cfg(any(feature = "chromedriver", feature = "geckodriver"))] use serde_json::map::Map as JsonMap; use urlencoding::encode; use webdriver::WebDriver; @@ -927,6 +928,10 @@ pub struct AsyncStaticExporter { pdf_export_timeout: u32, /// Browser command-line flags (e.g., "--headless", "--no-sandbox") + #[cfg_attr( + not(any(feature = "chromedriver", feature = "geckodriver")), + allow(dead_code) + )] webdriver_browser_caps: Vec, /// Cached WebDriver client for session reuse @@ -1121,46 +1126,55 @@ impl AsyncStaticExporter { } fn build_webdriver_caps(&self) -> Result { - // Define browser capabilities (copied to avoid reordering existing code) - let mut caps = JsonMap::new(); - let mut browser_opts = JsonMap::new(); - let browser_args = self.webdriver_browser_caps.clone(); - - browser_opts.insert("args".to_string(), serde_json::json!(browser_args)); - - // Add Chrome binary capability if BROWSER_PATH is set - #[cfg(feature = "chromedriver")] - if let Ok(chrome_path) = std::env::var("BROWSER_PATH") { - browser_opts.insert("binary".to_string(), serde_json::json!(chrome_path)); - debug!("Added Chrome binary capability: {chrome_path}"); - } - // Add Firefox binary capability if BROWSER_PATH is set - #[cfg(feature = "geckodriver")] - if let Ok(firefox_path) = std::env::var("BROWSER_PATH") { - browser_opts.insert("binary".to_string(), serde_json::json!(firefox_path)); - debug!("Added Firefox binary capability: {firefox_path}"); - } - - // Add Firefox-specific preferences for CI environments - #[cfg(feature = "geckodriver")] + #[cfg(not(any(feature = "chromedriver", feature = "geckodriver")))] { - let prefs = common::get_firefox_ci_preferences(); - browser_opts.insert("prefs".to_string(), serde_json::json!(prefs)); - debug!("Added Firefox preferences for CI compatibility"); + Err(anyhow!( + "Static image export requires enabling either the 'chromedriver' or 'geckodriver' feature." + )) } + #[cfg(any(feature = "chromedriver", feature = "geckodriver"))] + { + // Define browser capabilities (copied to avoid reordering existing code) + let mut caps = JsonMap::new(); + let mut browser_opts = JsonMap::new(); + let browser_args = self.webdriver_browser_caps.clone(); + + browser_opts.insert("args".to_string(), serde_json::json!(browser_args)); + + // Add Chrome binary capability if BROWSER_PATH is set + #[cfg(feature = "chromedriver")] + if let Ok(chrome_path) = std::env::var("BROWSER_PATH") { + browser_opts.insert("binary".to_string(), serde_json::json!(chrome_path)); + debug!("Added Chrome binary capability: {chrome_path}"); + } + // Add Firefox binary capability if BROWSER_PATH is set + #[cfg(feature = "geckodriver")] + if let Ok(firefox_path) = std::env::var("BROWSER_PATH") { + browser_opts.insert("binary".to_string(), serde_json::json!(firefox_path)); + debug!("Added Firefox binary capability: {firefox_path}"); + } - caps.insert( - "browserName".to_string(), - serde_json::json!(get_browser_name()), - ); - caps.insert( - get_options_key().to_string(), - serde_json::json!(browser_opts), - ); + // Add Firefox-specific preferences for CI environments + #[cfg(feature = "geckodriver")] + { + let prefs = common::get_firefox_ci_preferences(); + browser_opts.insert("prefs".to_string(), serde_json::json!(prefs)); + debug!("Added Firefox preferences for CI compatibility"); + } + + caps.insert( + "browserName".to_string(), + serde_json::json!(get_browser_name()), + ); + caps.insert( + get_options_key().to_string(), + serde_json::json!(browser_opts), + ); - debug!("WebDriver capabilities: {caps:?}"); + debug!("WebDriver capabilities: {caps:?}"); - Ok(caps) + Ok(caps) + } } #[cfg(target_os = "windows")] diff --git a/plotly_static/src/webdriver.rs b/plotly_static/src/webdriver.rs index fa6f2e1c..20b016eb 100644 --- a/plotly_static/src/webdriver.rs +++ b/plotly_static/src/webdriver.rs @@ -29,6 +29,9 @@ const WEBDRIVER_BIN: &str = "geckodriver"; #[cfg(feature = "chromedriver")] const WEBDRIVER_BIN: &str = "chromedriver"; +#[cfg(not(any(feature = "chromedriver", feature = "geckodriver")))] +const WEBDRIVER_BIN: &str = "webdriver"; + /// Default WebDriver port pub(crate) const WEBDRIVER_PORT: u32 = 4444; /// Default WebDriver URL