|
13 | 13 | #include <unistd.h> // getuid
|
14 | 14 | #endif
|
15 | 15 |
|
| 16 | +#ifdef _WIN32 |
| 17 | +#include <windows.h> |
| 18 | +#endif |
16 | 19 | namespace node {
|
17 | 20 |
|
18 | 21 | using v8::Function;
|
@@ -223,13 +226,93 @@ void CompileCacheHandler::ReadCacheFile(CompileCacheEntry* entry) {
|
223 | 226 | Debug(" success, size=%d\n", total_read);
|
224 | 227 | }
|
225 | 228 |
|
| 229 | +#ifdef _WIN32 |
| 230 | +constexpr bool IsWindowsDeviceRoot(const char c) noexcept { |
| 231 | + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); |
| 232 | +} |
| 233 | +#endif |
| 234 | + |
| 235 | +static std::string NormalisePath(std::string_view path) { |
| 236 | + std::string normalised_string(path); |
| 237 | + constexpr std::string_view file_scheme = "file://"; |
| 238 | + if (normalised_string.rfind(file_scheme, 0) == 0) { |
| 239 | + normalised_string.erase(0, file_scheme.size()); |
| 240 | + } |
| 241 | + |
| 242 | +#ifdef _WIN32 |
| 243 | + if (normalised_string.size() > 2 && |
| 244 | + IsWindowsDeviceRoot(normalised_string[0]) && |
| 245 | + normalised_string[1] == ':' && |
| 246 | + (normalised_string[2] == '/' || normalised_string[2] == '\\')) { |
| 247 | + normalised_string[0] = ToLower(normalised_string[0]); |
| 248 | + } |
| 249 | +#endif |
| 250 | + for (char& c : normalised_string) { |
| 251 | + if (c == '\\') { |
| 252 | + c = '/'; |
| 253 | + } |
| 254 | + } |
| 255 | + |
| 256 | + normalised_string = NormalizeString(normalised_string, false, "/"); |
| 257 | + return normalised_string; |
| 258 | +} |
| 259 | + |
| 260 | +// Check if a path looks like an absolute path or file URL. |
| 261 | +static bool IsAbsoluteFilePath(std::string_view path) { |
| 262 | + if (path.rfind("file://", 0) == 0) { |
| 263 | + return true; |
| 264 | + } |
| 265 | +#ifdef _WIN32 |
| 266 | + if (path.size() > 2 && IsWindowsDeviceRoot(path[0]) && |
| 267 | + (path[1] == ':' && (path[2] == '/' || path[2] == '\\'))) |
| 268 | + return true; |
| 269 | + if (path.size() > 1 && path[0] == '\\' && path[1] == '\\') return true; |
| 270 | +#endif |
| 271 | + if (path.size() > 0 && path[0] == '/') return true; |
| 272 | + return false; |
| 273 | +} |
| 274 | + |
| 275 | +static std::string GetRelativePath(std::string_view path, |
| 276 | + std::string_view base) { |
| 277 | +// On Windows, the native encoding is UTF-16, so we need to convert |
| 278 | +// the paths to wide strings before using std::filesystem::path. |
| 279 | +// On other platforms, std::filesystem::path can handle UTF-8 directly. |
| 280 | +#ifdef _WIN32 |
| 281 | + std::filesystem::path module_path( |
| 282 | + ConvertToWideString(std::string(path), CP_UTF8)); |
| 283 | + std::filesystem::path base_path( |
| 284 | + ConvertToWideString(std::string(base), CP_UTF8)); |
| 285 | +#else |
| 286 | + std::filesystem::path module_path(path); |
| 287 | + std::filesystem::path base_path(base); |
| 288 | +#endif |
| 289 | + std::filesystem::path relative = module_path.lexically_relative(base_path); |
| 290 | + auto u8str = relative.u8string(); |
| 291 | + return std::string(u8str.begin(), u8str.end()); |
| 292 | +} |
| 293 | + |
226 | 294 | CompileCacheEntry* CompileCacheHandler::GetOrInsert(Local<String> code,
|
227 | 295 | Local<String> filename,
|
228 | 296 | CachedCodeType type) {
|
229 | 297 | DCHECK(!compile_cache_dir_.empty());
|
230 | 298 |
|
231 | 299 | Utf8Value filename_utf8(isolate_, filename);
|
232 |
| - uint32_t key = GetCacheKey(filename_utf8.ToStringView(), type); |
| 300 | + std::string file_path = filename_utf8.ToString(); |
| 301 | + // If the relative path is enabled, we try to use a relative path |
| 302 | + // from the compile cache directory to the file path |
| 303 | + if (portable_ && IsAbsoluteFilePath(file_path)) { |
| 304 | + // Normalise the path to ensure it is consistent. |
| 305 | + std::string normalised_file_path = NormalisePath(file_path); |
| 306 | + std::string relative_path = |
| 307 | + GetRelativePath(normalised_file_path, normalised_compile_cache_dir_); |
| 308 | + if (!relative_path.empty()) { |
| 309 | + file_path = relative_path; |
| 310 | + Debug("[compile cache] using relative path %s from %s\n", |
| 311 | + file_path.c_str(), |
| 312 | + absolute_compile_cache_dir_.c_str()); |
| 313 | + } |
| 314 | + } |
| 315 | + uint32_t key = GetCacheKey(file_path, type); |
233 | 316 |
|
234 | 317 | // TODO(joyeecheung): don't encode this again into UTF8. If we read the
|
235 | 318 | // UTF8 content on disk as raw buffer (from the JS layer, while watching out
|
@@ -500,11 +583,15 @@ CompileCacheHandler::CompileCacheHandler(Environment* env)
|
500 | 583 | // - $NODE_VERSION-$ARCH-$CACHE_DATA_VERSION_TAG-$UID
|
501 | 584 | // - $FILENAME_AND_MODULE_TYPE_HASH.cache: a hash of filename + module type
|
502 | 585 | CompileCacheEnableResult CompileCacheHandler::Enable(Environment* env,
|
503 |
| - const std::string& dir) { |
| 586 | + const std::string& dir, |
| 587 | + bool portable) { |
504 | 588 | std::string cache_tag = GetCacheVersionTag();
|
505 |
| - std::string absolute_cache_dir_base = PathResolve(env, {dir}); |
506 |
| - std::string cache_dir_with_tag = |
507 |
| - absolute_cache_dir_base + kPathSeparator + cache_tag; |
| 589 | + std::string base_dir = dir; |
| 590 | + if (!portable) { |
| 591 | + base_dir = PathResolve(env, {dir}); |
| 592 | + } |
| 593 | + |
| 594 | + std::string cache_dir_with_tag = base_dir + kPathSeparator + cache_tag; |
508 | 595 | CompileCacheEnableResult result;
|
509 | 596 | Debug("[compile cache] resolved path %s + %s -> %s\n",
|
510 | 597 | dir,
|
@@ -546,8 +633,11 @@ CompileCacheEnableResult CompileCacheHandler::Enable(Environment* env,
|
546 | 633 | return result;
|
547 | 634 | }
|
548 | 635 |
|
549 |
| - result.cache_directory = absolute_cache_dir_base; |
| 636 | + result.cache_directory = base_dir; |
550 | 637 | compile_cache_dir_ = cache_dir_with_tag;
|
| 638 | + absolute_compile_cache_dir_ = PathResolve(env, {compile_cache_dir_}); |
| 639 | + portable_ = portable; |
| 640 | + normalised_compile_cache_dir_ = NormalisePath(absolute_compile_cache_dir_); |
551 | 641 | result.status = CompileCacheEnableStatus::ENABLED;
|
552 | 642 | return result;
|
553 | 643 | }
|
|
0 commit comments