Skip to content

Commit 03629c0

Browse files
committed
add setup for windows ci for plotly_static
Signed-off-by: Andrei Gherghescu <[email protected]>
1 parent 21d696c commit 03629c0

File tree

8 files changed

+461
-133
lines changed

8 files changed

+461
-133
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Windows environment setup for plotly static export tests
2+
# This script sets up Chrome, chromedriver, and environment variables for Windows CI
3+
4+
param(
5+
[string]$ChromeVersion,
6+
[string]$ChromePath,
7+
[string]$ChromeDriverPath
8+
)
9+
10+
Write-Host "=== Setting up Windows environment for static export ==="
11+
12+
# Find chromedriver path
13+
$chromedriverPath = $ChromeDriverPath
14+
if (-not (Test-Path $chromedriverPath)) {
15+
Write-Host "Action output chromedriver path not found, searching for alternatives..."
16+
17+
$commonPaths = @(
18+
"C:\Program Files\Google\Chrome\Application\chromedriver.exe",
19+
"C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe",
20+
"$env:USERPROFILE\AppData\Local\Google\Chrome\Application\chromedriver.exe",
21+
"$env:PROGRAMFILES\Google\Chrome\Application\chromedriver.exe",
22+
"$env:PROGRAMFILES(X86)\Google\Chrome\Application\chromedriver.exe"
23+
)
24+
25+
foreach ($path in $commonPaths) {
26+
if (Test-Path $path) {
27+
Write-Host "Using chromedriver from: $path"
28+
$chromedriverPath = $path
29+
break
30+
}
31+
}
32+
}
33+
34+
# Find Chrome path
35+
$chromePath = $ChromePath
36+
if (-not (Test-Path $chromePath)) {
37+
# Try the tool cache path first
38+
$toolCachePath = "C:\hostedtoolcache\windows\setup-chrome\chromium\$ChromeVersion\x64\chrome.exe"
39+
if (Test-Path $toolCachePath) {
40+
$chromePath = $toolCachePath
41+
Write-Host "Using Chrome from setup-chrome installation: $chromePath"
42+
} else {
43+
# Fallback: search for Chrome in the tool cache
44+
$toolCacheDir = "C:\hostedtoolcache\windows\setup-chrome\chromium"
45+
if (Test-Path $toolCacheDir) {
46+
$chromeExe = Get-ChildItem -Path $toolCacheDir -Recurse -Name "chrome.exe" | Select-Object -First 1
47+
if ($chromeExe) {
48+
$chromePath = Join-Path $toolCacheDir $chromeExe
49+
Write-Host "Using Chrome from tool cache search: $chromePath"
50+
} else {
51+
$chromePath = "C:\Program Files\Google\Chrome\Application\chrome.exe"
52+
Write-Host "Using system Chrome: $chromePath"
53+
}
54+
} else {
55+
$chromePath = "C:\Program Files\Google\Chrome\Application\chrome.exe"
56+
Write-Host "Using system Chrome: $chromePath"
57+
}
58+
}
59+
}
60+
61+
# Set environment variables
62+
$env:WEBDRIVER_PATH = $chromedriverPath
63+
$env:CHROME_PATH = $chromePath
64+
$env:RUST_LOG = "debug"
65+
$env:RUST_BACKTRACE = "1"
66+
$env:ANGLE_DEFAULT_PLATFORM = "swiftshader"
67+
68+
Write-Host "Environment variables set:"
69+
Write-Host "WEBDRIVER_PATH: $env:WEBDRIVER_PATH"
70+
Write-Host "CHROME_PATH: $env:CHROME_PATH"
71+
Write-Host "RUST_LOG: $env:RUST_LOG"
72+
Write-Host "RUST_BACKTRACE: $env:RUST_BACKTRACE"
73+
74+
# Verify paths exist
75+
if (-not (Test-Path $env:WEBDRIVER_PATH)) {
76+
Write-Error "Chromedriver executable not found at: $env:WEBDRIVER_PATH"
77+
Write-Host "Available chromedriver locations:"
78+
Get-ChildItem -Path "C:\Program Files\Google\Chrome\Application\" -Name "chromedriver*" -ErrorAction SilentlyContinue
79+
Get-ChildItem -Path "C:\Program Files (x86)\Google\Chrome\Application\" -Name "chromedriver*" -ErrorAction SilentlyContinue
80+
exit 1
81+
}
82+
83+
if (-not (Test-Path $env:CHROME_PATH)) {
84+
Write-Error "Chrome not found at: $env:CHROME_PATH"
85+
exit 1
86+
}
87+
88+
# Test Chrome version
89+
try {
90+
$chromeVersion = & "$env:CHROME_PATH" --version 2>&1
91+
Write-Host "Chrome version: $chromeVersion"
92+
} catch {
93+
Write-Host "Failed to get Chrome version: $_"
94+
}
95+
96+
# Test chromedriver version
97+
try {
98+
$chromedriverVersion = & "$env:WEBDRIVER_PATH" --version 2>&1
99+
Write-Host "Chromedriver version: $chromedriverVersion"
100+
} catch {
101+
Write-Host "Failed to get chromedriver version: $_"
102+
}
103+
104+
Write-Host "=== Windows environment setup completed ==="

.github/workflows/ci.yml

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,65 @@ jobs:
7272
matrix:
7373
os: [ubuntu-latest, windows-latest, macos-latest]
7474
runs-on: ${{ matrix.os }}
75+
timeout-minutes: ${{ matrix.os == 'windows-latest' && 30 || 10 }}
7576
steps:
7677
- name: Setup Chrome
7778
uses: browser-actions/setup-chrome@v1
7879
with:
7980
chrome-version: 'latest'
8081
install-chromedriver: true
82+
id: setup-chrome
83+
8184
- uses: actions/checkout@v4
85+
8286
- uses: dtolnay/rust-toolchain@stable
83-
- run: cargo test --workspace --features plotly_ndarray,plotly_image,static_export_default --exclude plotly_kaleido
84-
- if: ${{ matrix.os == 'windows-latest' }}
87+
88+
# Cache cargo registry for all platforms
89+
- name: Cache cargo registry
90+
uses: actions/cache@v4
91+
with:
92+
path: |
93+
~/.cargo/registry/index/
94+
~/.cargo/registry/cache/
95+
~/.cargo/git/db/
96+
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
97+
restore-keys: |
98+
${{ runner.os }}-cargo-registry-
99+
100+
# Windows-specific environment setup for static export tests
101+
- name: Setup Windows environment for static export
102+
if: matrix.os == 'windows-latest'
103+
run: |
104+
.\.github\scripts\setup-windows-static-export.ps1 `
105+
-ChromeVersion "${{ steps.setup-chrome.outputs.chrome-version }}" `
106+
-ChromePath "${{ steps.setup-chrome.outputs.chrome-path }}" `
107+
-ChromeDriverPath "${{ steps.setup-chrome.outputs.chromedriver-path }}"
108+
109+
# Run tests on non-Windows platforms
110+
- name: Run tests (non-Windows)
111+
if: matrix.os != 'windows-latest'
112+
run: cargo test --verbose --workspace --features plotly_ndarray,plotly_image,static_export_default --exclude plotly_kaleido
113+
114+
# Run tests on Windows with Chrome WebDriver
115+
- name: Run tests (Windows)
116+
if: matrix.os == 'windows-latest'
117+
shell: pwsh
118+
run: |
119+
# Set environment variables for WebDriver
120+
$env:WEBDRIVER_PATH = "${{ steps.setup-chrome.outputs.chromedriver-path }}"
121+
$env:CHROME_PATH = "${{ steps.setup-chrome.outputs.chrome-path }}"
122+
$env:RUST_LOG = "debug"
123+
$env:RUST_BACKTRACE = "1"
124+
$env:ANGLE_DEFAULT_PLATFORM = "swiftshader"
125+
126+
Write-Host "Environment variables set:"
127+
Write-Host "WEBDRIVER_PATH: $env:WEBDRIVER_PATH"
128+
Write-Host "CHROME_PATH: $env:CHROME_PATH"
129+
130+
cargo test --verbose --workspace --features plotly_ndarray,plotly_image,chromedriver --exclude plotly_kaleido
131+
132+
# Windows-specific cleanup
133+
- if: matrix.os == 'windows-latest'
85134
run: gci -recurse -filter "*example*"
86135

87136
code-coverage:
@@ -145,6 +194,8 @@ jobs:
145194
targets: wasm32-unknown-unknown
146195
- run: cd ${{ github.workspace }}/examples/wasm-yew/${{ matrix.example }} && cargo build --target wasm32-unknown-unknown
147196

197+
198+
148199
build_book:
149200
name: Build Book
150201
runs-on: ubuntu-latest
@@ -156,6 +207,7 @@ jobs:
156207
with:
157208
chrome-version: 'latest'
158209
install-chromedriver: true
210+
id: setup-chrome
159211

160212
- uses: dtolnay/rust-toolchain@stable
161213
- run: cargo install mdbook --no-default-features --features search --vers "^0.4" --locked --quiet

docs/book/src/fundamentals/static_image_export.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ plotly = { version = "0.13", features = ["static_export_default"] }
4343

4444
2. **Browser Installation**: You need Chrome/Chromium or Firefox installed
4545

46-
3. **Environment Variable** (optional): Set `WEBDRIVER_PATH` to specify custom WebDriver location
46+
3. **Environment Variable** (optional): Set `WEBDRIVER_PATH` to specify custom WebDriver binary location (should point to the full executable path)
4747
```bash
4848
export WEBDRIVER_PATH=/path/to/chromedriver
4949
```

plotly_static/build.rs

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@ use webdriver_downloader::prelude::*;
1212
#[cfg(all(feature = "geckodriver", feature = "chromedriver"))]
1313
compile_error!("Only one of 'geckodriver' or 'chromedriver' features can be enabled at a time.");
1414

15-
// Define the WEBDRIVER_BIN constant based on the enabled feature
16-
#[cfg(feature = "geckodriver")]
17-
const WEBDRIVER_BIN: &str = "geckodriver";
18-
19-
#[cfg(feature = "chromedriver")]
20-
const WEBDRIVER_BIN: &str = "chromedriver";
15+
// Enforce that at least one driver feature is enabled
16+
#[cfg(not(any(feature = "geckodriver", feature = "chromedriver")))]
17+
compile_error!("At least one of 'geckodriver' or 'chromedriver' features must be enabled.");
2118

2219
#[cfg(target_os = "windows")]
2320
const DRIVER_EXT: &str = ".exe";
@@ -61,33 +58,33 @@ fn user_bin_dir() -> PathBuf {
6158

6259
/// Check if a driver is already installed at the given path from environment
6360
/// variable
64-
fn is_webdriver_available(env_var: &str, executable_name: &str) -> bool {
61+
fn is_webdriver_available(env_var: &str, bin_name: &str) -> bool {
6562
// First check environment variable path
6663
if let Ok(path) = env::var(env_var) {
67-
let exe_path = if cfg!(windows) && !path.to_lowercase().ends_with(".exe") {
64+
let bin_path = if cfg!(target_os = "windows") && !path.to_lowercase().ends_with(".exe") {
6865
format!("{path}{DRIVER_EXT}")
6966
} else {
7067
path
7168
};
72-
let exe = Path::new(&exe_path);
69+
let exe = Path::new(&bin_path);
7370
if exe.exists() && exe.is_file() {
74-
println!("{executable_name} found at path specified in {env_var}: {exe_path}");
71+
println!("{bin_name} found at path specified in {env_var}: {bin_path}");
7572
return true;
7673
}
7774
}
7875

7976
// Check if webdriver exists in user's bin directory
8077
let bin_dir = user_bin_dir();
81-
let bin_path = bin_dir.join(format!("{executable_name}{DRIVER_EXT}"));
78+
let bin_path = bin_dir.join(format!("{bin_name}{DRIVER_EXT}"));
8279
if bin_path.exists() && bin_path.is_file() {
8380
println!(
8481
"{} found in user's bin directory: {}",
85-
executable_name,
82+
bin_name,
8683
bin_path.display()
8784
);
8885
println!(
8986
"cargo:rustc-env=WEBDRIVER_DOWNLOAD_PATH={}",
90-
bin_dir.to_string_lossy()
87+
bin_path.to_string_lossy()
9188
);
9289
return true;
9390
}
@@ -165,7 +162,7 @@ fn setup_driver(config: &WebdriverDownloadConfig) -> Result<()> {
165162
webdriver_bin_dir.display()
166163
)
167164
})?;
168-
let webdriver_bin = webdriver_bin_dir.join(WEBDRIVER_BIN);
165+
let webdriver_bin = webdriver_bin_dir.join(config.driver_name);
169166

170167
println!(
171168
"cargo::rerun-if-changed={}",
@@ -199,12 +196,38 @@ fn setup_driver(config: &WebdriverDownloadConfig) -> Result<()> {
199196

200197
println!(
201198
"cargo:rustc-env=WEBDRIVER_DOWNLOAD_PATH={}",
202-
webdriver_bin_dir.to_string_lossy()
199+
webdriver_bin.to_string_lossy()
203200
);
204201

205202
Ok(())
206203
}
207204

205+
#[cfg(feature = "chromedriver")]
206+
fn get_chrome_path() -> Result<PathBuf> {
207+
if let Ok(chrome_path) = env::var(CHROME_PATH_ENV) {
208+
let path = PathBuf::from(&chrome_path);
209+
if path.exists() {
210+
Ok(path)
211+
} else {
212+
Err(anyhow!("Chrome not found on path: {}", chrome_path)).with_context(|| {
213+
format!("Please set {CHROME_PATH_ENV} to a valid Chrome installation")
214+
})
215+
}
216+
} else {
217+
let new_browser_path = os_specific::chromedriver_for_testing::default_browser_path()?;
218+
let old_browser_path = os_specific::chromedriver_old::default_browser_path()?;
219+
if new_browser_path.exists() {
220+
Ok(new_browser_path)
221+
} else if old_browser_path.exists() {
222+
Ok(old_browser_path)
223+
} else {
224+
Err(anyhow!("Chrome browser not detected")).with_context(|| {
225+
format!("Use {CHROME_PATH_ENV} to point to a valid Chrome installation")
226+
})
227+
}
228+
}
229+
}
230+
208231
#[cfg(feature = "geckodriver")]
209232
fn get_firefox_path() -> Result<PathBuf> {
210233
if let Ok(firefox_path) = env::var(FIREFOX_PATH_ENV) {
@@ -234,32 +257,6 @@ fn get_firefox_path() -> Result<PathBuf> {
234257
}
235258
}
236259

237-
#[cfg(feature = "chromedriver")]
238-
fn get_chrome_path() -> Result<PathBuf> {
239-
if let Ok(chrome_path) = env::var(CHROME_PATH_ENV) {
240-
let path = PathBuf::from(&chrome_path);
241-
if path.exists() {
242-
Ok(path)
243-
} else {
244-
Err(anyhow!("Chrome not found on path: {}", chrome_path)).with_context(|| {
245-
format!("Please set {CHROME_PATH_ENV} to a valid Chrome installation")
246-
})
247-
}
248-
} else {
249-
let new_browser_path = os_specific::chromedriver_for_testing::default_browser_path()?;
250-
let old_browser_path = os_specific::chromedriver_old::default_browser_path()?;
251-
if new_browser_path.exists() {
252-
Ok(new_browser_path)
253-
} else if old_browser_path.exists() {
254-
Ok(old_browser_path)
255-
} else {
256-
Err(anyhow!("Chrome browser not detected")).with_context(|| {
257-
format!("Use {CHROME_PATH_ENV} to point to a valid Chrome installation")
258-
})
259-
}
260-
}
261-
}
262-
263260
fn get_browser_version(path: &PathBuf) -> Result<String> {
264261
let output = Command::new(path)
265262
.arg("--version")
@@ -307,16 +304,15 @@ fn main() -> Result<()> {
307304
if cfg!(feature = "webdriver_download") {
308305
println!("cargo:rerun-if-changed=src/lib.rs");
309306
let webdriver_bin_dir = user_bin_dir();
310-
let webdriver_bin = webdriver_bin_dir.join(WEBDRIVER_BIN);
311307
println!(
312308
"cargo::rerun-if-changed={}",
313-
webdriver_bin.to_string_lossy()
309+
webdriver_bin_dir.to_string_lossy()
314310
);
315311

316312
#[cfg(feature = "chromedriver")]
317313
{
318314
let config = WebdriverDownloadConfig {
319-
driver_name: WEBDRIVER_BIN,
315+
driver_name: "chromedriver",
320316
path_env: CHROMEDRIVER_PATH_ENV,
321317
get_browser_path: get_chrome_path,
322318
};
@@ -326,15 +322,33 @@ fn main() -> Result<()> {
326322
#[cfg(feature = "geckodriver")]
327323
{
328324
let config = WebdriverDownloadConfig {
329-
driver_name: WEBDRIVER_BIN,
325+
driver_name: "geckodriver",
330326
path_env: GECKODRIVER_PATH_ENV,
331327
get_browser_path: get_firefox_path,
332328
};
333329
setup_driver(&config)?;
334330
}
331+
332+
#[cfg(not(any(feature = "chromedriver", feature = "geckodriver")))]
333+
{
334+
println!("cargo::warning=No specific driver feature enabled, skipping driver setup");
335+
}
335336
} else {
336-
let msg = format!("'webdriver_download' feature disabled. Please install a {GECKODRIVER_PATH_ENV} or {CHROMEDRIVER_PATH_ENV} version manually and make the environment variable 'WEBDRIVER_PATH' point to it.");
337-
println!("cargo::warning={msg}");
337+
#[cfg(feature = "chromedriver")]
338+
{
339+
let msg = format!("'webdriver_download' feature disabled. Please install a {CHROMEDRIVER_PATH_ENV} version manually and make the environment variable 'WEBDRIVER_PATH' point to it.");
340+
println!("cargo::warning={msg}");
341+
}
342+
#[cfg(feature = "geckodriver")]
343+
{
344+
let msg = format!("'webdriver_download' feature disabled. Please install a {} version manually and make the environment variable 'WEBDRIVER_PATH' point to it.",
345+
GECKODRIVER_PATH_ENV);
346+
println!("cargo::warning={msg}");
347+
}
348+
#[cfg(not(any(feature = "chromedriver", feature = "geckodriver")))]
349+
{
350+
println!("cargo::warning='webdriver_download' feature disabled and no driver feature enabled");
351+
}
338352
}
339353
Ok(())
340354
}

0 commit comments

Comments
 (0)