Skip to content

Commit

A Windows runner finds the folders a build's own Wrangler config names. Resolving the config's path on Windows gave a verbatim path (\?\C:\…), in which / and .. are not read, so "directory": "../client" joined to it named nothing; drive paths now lose the prefix. The tar read-back test is skipped on Windows, whose tar takes C: for a remote host and whose files keep no Unix modes or symlinks; CI reads the archive back on Linux.

syntaqxcommitted Parent0088e7bBrowse files
2 files+32−30/2 viewed
+11−1
2323 ];
2424
2525 /** Whether `tar` can be run here. */
26+/**
27+ * Why the archive is not read back here, if it is not: no tar, or Windows,
28+ * whose tar takes `C:` for a remote host and whose files keep no Unix
29+ * modes or symlinks to check. CI reads it back on Linux.
30+ */
31+function readBackSkip(): string | false {
32+ if (process.platform === "win32") return "Windows keeps no Unix modes or symlinks to check";
33+ return !hasTar() && "no tar here";
34+}
35+
2636 function hasTar(): boolean {
2737 try {
2838 execFileSync("tar", ["--version"], { stdio: "ignore" });
7080 assert.ok(out.subarray(out.length - 1024).every((byte) => byte === 0));
7181 });
7282
73−test("tar reads the archive back: files, folders, modes, a symlink and long paths", { skip: !hasTar() && "no tar here" }, async () => {
83+test("tar reads the archive back: files, folders, modes, a symlink and long paths", { skip: readBackSkip() }, async () => {
7484 const dir = mkdtempSync(join(tmpdir(), "g1t-tar-"));
7585 try {
7686 const file = join(dir, "archive.tar.gz");
+21−2
576576 return Ok(None);
577577 };
578578 let path = dir.join(".wrangler/deploy").join(path);
579− let path = path.canonicalize().unwrap_or(path);
579+ let path = canonical(&path).unwrap_or(path);
580580 let text = std::fs::read_to_string(&path).with_context(|| format!("could not read {}", path.display()))?;
581581 let config = serde_json::from_str(&strip_jsonc(&text)).with_context(|| format!("could not read {}", path.display()))?;
582582 Ok(Some((config, path.parent().map_or_else(|| dir.to_path_buf(), Path::to_path_buf))))
583583 }
584584
585+/// The path, resolved, as a plain path. On Windows, `canonicalize` gives a
586+/// verbatim one (`\\?\C:\…`), in which `/` and `..` are not read as
587+/// separators or as the folder above: a config's `"directory": "../client"`
588+/// joined to it would name no folder. A drive path loses the prefix; a
589+/// network path keeps it, as it cannot do without.
590+fn canonical(path: &Path) -> std::io::Result<PathBuf> {
591+ let path = path.canonicalize()?;
592+ #[cfg(windows)]
593+ {
594+ let text = path.to_string_lossy();
595+ if let Some(rest) = text.strip_prefix(r"\\?\") {
596+ if !rest.starts_with(r"UNC\") {
597+ return Ok(PathBuf::from(rest));
598+ }
599+ }
600+ }
601+ Ok(path)
602+}
603+
585604 /// The entry of the Worker a framework's adapter wrote, once it has built:
586605 /// the file, or a directory's `index.js`.
587606 fn adapter_entry(dir: &Path, adapter: &Adapter) -> Option<PathBuf> {
21482167 );
21492168 let (config, base) = redirected_config(&dir).unwrap().unwrap();
21502169 assert_eq!(config.main.as_deref(), Some("index.js"));
2151− assert_eq!(base, dir.join("dist/app").canonicalize().unwrap());
2170+ assert_eq!(base, canonical(&dir.join("dist/app")).unwrap());
21522171 assert!(base.join(config.assets.unwrap().directory.unwrap()).ends_with("dist/app/../client"));
21532172 assert!(redirected_config(&project("not-redirected", &[])).unwrap().is_none());
21542173 }