From f3786253f28738e0a5f115b7e7eaf49022404467 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 30 Oct 2024 12:26:29 +0100 Subject: [PATCH] Fix integration tests on Windows (#14824) This PR fixes Windows related path issues after merging #14820 --------- Co-authored-by: Jordan Pittman --- crates/node/npm/win32-arm64-msvc/README.md | 3 + crates/node/npm/win32-arm64-msvc/package.json | 27 ++++++++ crates/node/package.json | 6 +- crates/oxide/src/glob.rs | 13 ++-- crates/oxide/src/lib.rs | 23 +++++-- crates/oxide/src/paths.rs | 65 +++++++++++++++++++ crates/oxide/tests/scanner.rs | 25 ++----- packages/@tailwindcss-standalone/package.json | 2 +- packages/@tailwindcss-vite/src/index.ts | 16 +++-- pnpm-lock.yaml | 7 +- scripts/version-packages.mjs | 1 + 11 files changed, 153 insertions(+), 35 deletions(-) create mode 100644 crates/node/npm/win32-arm64-msvc/README.md create mode 100644 crates/node/npm/win32-arm64-msvc/package.json create mode 100644 crates/oxide/src/paths.rs diff --git a/crates/node/npm/win32-arm64-msvc/README.md b/crates/node/npm/win32-arm64-msvc/README.md new file mode 100644 index 000000000000..456a5cece5e8 --- /dev/null +++ b/crates/node/npm/win32-arm64-msvc/README.md @@ -0,0 +1,3 @@ +# `@tailwindcss/oxide-win32-arm64-msvc` + +This is the **arm64-pc-windows-msvc** binary for `@tailwindcss/oxide` diff --git a/crates/node/npm/win32-arm64-msvc/package.json b/crates/node/npm/win32-arm64-msvc/package.json new file mode 100644 index 000000000000..62499ee8b131 --- /dev/null +++ b/crates/node/npm/win32-arm64-msvc/package.json @@ -0,0 +1,27 @@ +{ + "name": "@tailwindcss/oxide-win32-arm64-msvc", + "version": "4.0.0-alpha.30", + "repository": { + "type": "git", + "url": "git+https://github.com/tailwindlabs/tailwindcss.git", + "directory": "crates/node/npm/win32-arm64-msvc" + }, + "os": [ + "win32" + ], + "cpu": [ + "arm64" + ], + "main": "tailwindcss-oxide.win32-arm64-msvc.node", + "files": [ + "tailwindcss-oxide.win32-arm64-msvc.node" + ], + "publishConfig": { + "provenance": true, + "access": "public" + }, + "license": "MIT", + "engines": { + "node": ">= 10" + } +} diff --git a/crates/node/package.json b/crates/node/package.json index 7ad78bcf97ea..b7ccc01d928c 100644 --- a/crates/node/package.json +++ b/crates/node/package.json @@ -20,7 +20,8 @@ "armv7-unknown-linux-gnueabihf", "x86_64-unknown-linux-musl", "x86_64-unknown-freebsd", - "i686-pc-windows-msvc" + "i686-pc-windows-msvc", + "aarch64-pc-windows-msvc" ] } }, @@ -56,6 +57,7 @@ "@tailwindcss/oxide-linux-arm64-musl": "workspace:*", "@tailwindcss/oxide-linux-x64-gnu": "workspace:*", "@tailwindcss/oxide-linux-x64-musl": "workspace:*", - "@tailwindcss/oxide-win32-x64-msvc": "workspace:*" + "@tailwindcss/oxide-win32-x64-msvc": "workspace:*", + "@tailwindcss/oxide-win32-arm64-msvc": "workspace:*" } } diff --git a/crates/oxide/src/glob.rs b/crates/oxide/src/glob.rs index 285c72d0f063..66522b69179d 100644 --- a/crates/oxide/src/glob.rs +++ b/crates/oxide/src/glob.rs @@ -237,15 +237,18 @@ mod tests { let optimized_sources = optimize_patterns(&sources); - let parent_dir = format!("{}", fs::canonicalize(base).unwrap().display()); + let parent_dir = + format!("{}{}", dunce::canonicalize(base).unwrap().display(), "/").replace('\\', "/"); // Remove the temporary directory from the base optimized_sources .into_iter() - .map(|source| GlobEntry { - // Normalize paths to use unix style separators - base: source.base.replace(&parent_dir, "").replace('\\', "/"), - pattern: source.pattern, + .map(|source| { + GlobEntry { + // Normalize paths to use unix style separators + base: source.base.replace('\\', "/").replace(&parent_dir, "/"), + pattern: source.pattern, + } }) .collect() } diff --git a/crates/oxide/src/lib.rs b/crates/oxide/src/lib.rs index 0294d9c82dbf..3cc6a5ef9a6a 100644 --- a/crates/oxide/src/lib.rs +++ b/crates/oxide/src/lib.rs @@ -7,6 +7,7 @@ use bstr::ByteSlice; use fxhash::{FxHashMap, FxHashSet}; use glob::optimize_patterns; use glob_match::glob_match; +use paths::Path; use rayon::prelude::*; use std::fs; use std::path::PathBuf; @@ -18,6 +19,7 @@ pub mod cursor; pub mod fast_skip; pub mod glob; pub mod parser; +pub mod paths; pub mod scanner; static SHOULD_TRACE: sync::LazyLock = sync::LazyLock::new( @@ -151,7 +153,8 @@ impl Scanner { self.files .iter() - .map(|x| x.to_string_lossy().into()) + .filter_map(|x| Path::from(x.clone()).canonicalize().ok()) + .map(|x| x.to_string()) .collect() } @@ -257,9 +260,18 @@ impl Scanner { false }); + fn join_paths(a: &str, b: &str) -> PathBuf { + let mut tmp = a.to_owned(); + + tmp += "/"; + tmp += b.trim_end_matches("**/*").trim_end_matches('/'); + + PathBuf::from(&tmp) + } + for path in auto_sources .iter() - .map(|source| PathBuf::from(&source.base).join(source.pattern.trim_end_matches("**/*"))) + .map(|source| join_paths(&source.base, &source.pattern)) { // Insert a glob for the base path, so we can see new files/folders in the directory itself. self.globs.push(GlobEntry { @@ -292,7 +304,8 @@ impl Scanner { // match as well. // // Instead we combine the base and the pattern as a single glob pattern. - let mut full_pattern = source.base.clone(); + let mut full_pattern = source.base.clone().replace('\\', "/"); + if !source.pattern.is_empty() { full_pattern.push('/'); full_pattern.push_str(&source.pattern); @@ -314,7 +327,9 @@ impl Scanner { continue; }; - if glob_match(&full_pattern, file_path_str) { + let file_path_str = file_path_str.replace('\\', "/"); + + if glob_match(&full_pattern, &file_path_str) { self.files.push(file_path); } } diff --git a/crates/oxide/src/paths.rs b/crates/oxide/src/paths.rs new file mode 100644 index 000000000000..ca3b345beba2 --- /dev/null +++ b/crates/oxide/src/paths.rs @@ -0,0 +1,65 @@ +use std::fmt::Display; +use std::io; +use std::path; + +#[derive(Clone)] +pub struct Path { + inner: path::PathBuf, +} + +impl From for Path { + fn from(value: path::PathBuf) -> Self { + Self { inner: value } + } +} + +impl From for Path { + fn from(value: String) -> Self { + Self { + inner: value.into(), + } + } +} + +impl From<&str> for Path { + fn from(value: &str) -> Self { + Self { + inner: value.into(), + } + } +} + +impl Display for Path { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + format!("{}", self.inner.display()).replace('\\', "/") + ) + } +} + +impl Path { + pub fn trim_prefix(&self, prefix: String) -> Self { + let prefix = prefix.replace('\\', "/"); + let my_path = self.to_string(); + + if let Some(str) = my_path.strip_prefix(&prefix) { + return str.into(); + } + + my_path.into() + } + + pub fn join(&self, component: &str) -> Self { + if component.is_empty() { + return self.clone(); + } + + self.inner.join(component).into() + } + + pub fn canonicalize(&self) -> io::Result { + Ok(dunce::canonicalize(&self.inner)?.into()) + } +} diff --git a/crates/oxide/tests/scanner.rs b/crates/oxide/tests/scanner.rs index 70c66149d1b4..6ed2fa747bca 100644 --- a/crates/oxide/tests/scanner.rs +++ b/crates/oxide/tests/scanner.rs @@ -31,7 +31,7 @@ mod scanner { } } - let base = format!("{}", dir.display()); + let base = format!("{}", dir.display()).replace('\\', "/"); // Resolve all content paths for the (temporary) current working directory let mut sources: Vec = globs @@ -51,31 +51,20 @@ mod scanner { let candidates = scanner.scan(); - let mut paths: Vec<_> = scanner - .get_files() - .into_iter() - .map(|x| x.replace(&format!("{}{}", &base, path::MAIN_SEPARATOR), "")) - .collect(); + let mut paths: Vec<_> = scanner.get_files(); for glob in scanner.get_globs() { - paths.push(format!( - "{}{}{}", - glob.base, - path::MAIN_SEPARATOR, - glob.pattern - )); + paths.push(format!("{}{}{}", glob.base, "/", glob.pattern)); } - let parent_dir = format!( - "{}{}", - fs::canonicalize(&base).unwrap().display(), - path::MAIN_SEPARATOR - ); + let parent_dir = + format!("{}{}", dunce::canonicalize(&base).unwrap().display(), "/").replace('\\', "/"); paths = paths .into_iter() .map(|x| { - x.replace(&parent_dir, "").replace('\\', "/") // Normalize paths to use unix style separators + // Normalize paths to use unix style separators + x.replace('\\', "/").replace(&parent_dir, "") }) .collect(); diff --git a/packages/@tailwindcss-standalone/package.json b/packages/@tailwindcss-standalone/package.json index 86b54ebc0577..e1fbd5fdfc27 100644 --- a/packages/@tailwindcss-standalone/package.json +++ b/packages/@tailwindcss-standalone/package.json @@ -40,7 +40,7 @@ "@parcel/watcher-linux-x64-musl": "^2.4.2-alpha.0", "@parcel/watcher-win32-x64": "^2.4.2-alpha.0", "@types/bun": "^1.1.11", - "bun": "^1.1.29", + "bun": "1.1.29", "lightningcss-darwin-arm64": "^1.25.1", "lightningcss-darwin-x64": "^1.25.1", "lightningcss-linux-arm64-gnu": "^1.25.1", diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts index a79ede7a2433..57eaf42affb5 100644 --- a/packages/@tailwindcss-vite/src/index.ts +++ b/packages/@tailwindcss-vite/src/index.ts @@ -431,7 +431,7 @@ class Root { let root = this.compiler.root if (root !== 'none' && root !== null) { - let basePath = path.posix.resolve(root.base, root.pattern) + let basePath = normalizePath(path.resolve(root.base, root.pattern)) let isDir = await fs.stat(basePath).then( (stats) => stats.isDirectory(), @@ -463,14 +463,22 @@ class Root { if (!this.compiler) return new Set() if (this.compiler.root === 'none') return new Set() + const HAS_DRIVE_LETTER = /^[A-Z]:/ + let shouldIncludeCandidatesFrom = (id: string) => { if (this.basePath === null) return true - // This a virtual module that's not on the file system - // TODO: What should we do here? + if (id.startsWith(this.basePath)) return true + + // This is a windows absolute path that doesn't match so return false + if (HAS_DRIVE_LETTER.test(id)) return false + + // We've got a path that's not absolute and not on Windows + // TODO: this is probably a virtual module -- not sure if we need to scan it if (!id.startsWith('/')) return true - return id.startsWith(this.basePath) + // This is an absolute path on POSIX and it does not match + return false } let shared = new Set() diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ade99d6bfce3..d3b7c14b2c3d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,6 +91,9 @@ importers: '@tailwindcss/oxide-linux-x64-musl': specifier: workspace:* version: link:npm/linux-x64-musl + '@tailwindcss/oxide-win32-arm64-msvc': + specifier: workspace:* + version: link:npm/win32-arm64-msvc '@tailwindcss/oxide-win32-x64-msvc': specifier: workspace:* version: link:npm/win32-x64-msvc @@ -119,6 +122,8 @@ importers: crates/node/npm/linux-x64-musl: {} + crates/node/npm/win32-arm64-msvc: {} + crates/node/npm/win32-x64-msvc: {} integrations: @@ -247,7 +252,7 @@ importers: specifier: ^1.1.11 version: 1.1.11 bun: - specifier: ^1.1.29 + specifier: 1.1.29 version: 1.1.29 lightningcss-darwin-arm64: specifier: ^1.25.1 diff --git a/scripts/version-packages.mjs b/scripts/version-packages.mjs index 91660a557818..2e3d93a3e668 100644 --- a/scripts/version-packages.mjs +++ b/scripts/version-packages.mjs @@ -28,6 +28,7 @@ const syncedWorkspaces = new Map([ 'crates/node/npm/linux-x64-gnu', 'crates/node/npm/linux-x64-musl', 'crates/node/npm/win32-x64-msvc', + 'crates/node/npm/win32-arm64-msvc', ], ], ['@tailwindcss/cli', ['packages/@tailwindcss-standalone']],