Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/core/deno/monkey-patch.ts
3583 views
1
/*
2
* monkey-patch.ts
3
*
4
* Copyright (C) 2022-2023 Posit Software, PBC
5
*/
6
7
import { debug } from "../../deno_ral/log.ts";
8
import { normalizePath } from "../path.ts";
9
import { copy } from "io/copy";
10
import { writeAll } from "io/write-all";
11
12
// Windows UNC paths can be mishandled by realPathSync
13
// (see https://github.com/quarto-dev/quarto-vscode/issues/67)
14
// so we monkey-patch to implement the absolute path and normalize
15
// parts of realPathSync (we aren't interested in the symlink
16
// resolution, and certainly not on windows that has no symlinks!)
17
Deno.realPathSync = normalizePath;
18
19
// some of our dependencies use Deno.copy and have not been ported to Deno 2
20
//
21
// deno-lint-ignore no-explicit-any
22
(Deno as any).copy = copy;
23
// deno-lint-ignore no-explicit-any
24
(Deno as any).writeAll = writeAll;
25
26
// TODO:
27
// Puppeteer (and only Puppeteer) uses Deno.run, but it still more-or-less exists
28
// in the Deno namespace.
29
30
// 2023-02-14: We're seeing a rare failure in Deno.makeTempFile{,Sync} with FileExists, so we're going to try
31
// a few times to create the file. If it fails, we'll log the error and try again.
32
// If it fails 5 times, we'll throw the error.
33
// https://github.com/denoland/deno/issues/17781
34
35
const maxAttempts = 5;
36
37
function withAttempts<T>(callable: () => T) {
38
for (let i = 0; i < maxAttempts; i++) {
39
try {
40
return callable();
41
} catch (err) {
42
if (!(err instanceof Error)) {
43
throw err;
44
}
45
if (err.message) {
46
debug("Error attempting to create temp file: " + err.message);
47
if (i === maxAttempts - 1) {
48
throw err;
49
} else {
50
debug(`Retrying... ${i + 1} of ${maxAttempts - 1}`);
51
}
52
}
53
}
54
}
55
throw new Error("Shouldn't get here");
56
}
57
58
function withAttemptsAsync<T>(callable: () => Promise<T>) {
59
const inner = (attempt: number): Promise<T> => {
60
return callable().catch((err) => {
61
if (!(err instanceof Error)) {
62
throw err;
63
}
64
if (err.message) {
65
debug("Error attempting to create temp file: " + err.message);
66
}
67
if (attempt === maxAttempts - 1) {
68
throw err;
69
} else {
70
debug(`Retrying... ${attempt + 1} of ${maxAttempts - 1}`);
71
return inner(attempt + 1);
72
}
73
});
74
};
75
return inner(0);
76
}
77
78
const oldMakeTempFile: typeof Deno.makeTempFile = Deno.makeTempFile;
79
const oldMakeTempFileSync: typeof Deno.makeTempFileSync = Deno.makeTempFileSync;
80
const oldMakeTempDir: typeof Deno.makeTempDir = Deno.makeTempDir;
81
const oldMakeTempDirSync: typeof Deno.makeTempDirSync = Deno.makeTempDirSync;
82
83
function makeTempFileSync(options?: Deno.MakeTempOptions) {
84
return withAttempts(() => oldMakeTempFileSync(options));
85
}
86
function makeTempFile(options?: Deno.MakeTempOptions) {
87
return withAttemptsAsync(() => oldMakeTempFile(options));
88
}
89
function makeTempDirSync(options?: Deno.MakeTempOptions) {
90
return withAttempts(() => oldMakeTempDirSync(options));
91
}
92
function makeTempDir(options?: Deno.MakeTempOptions) {
93
return withAttemptsAsync(() => oldMakeTempDir(options));
94
}
95
96
Deno.makeTempFile = makeTempFile;
97
Deno.makeTempFileSync = makeTempFileSync;
98
Deno.makeTempDir = makeTempDir;
99
Deno.makeTempDirSync = makeTempDirSync;
100
101
const oldReadTextFile: typeof Deno.readTextFile = Deno.readTextFile;
102
const oldReadTextFileSync: typeof Deno.readTextFileSync = Deno.readTextFileSync;
103
104
Deno.readTextFile = async (
105
path: string | URL,
106
options?: Deno.ReadFileOptions,
107
) => {
108
try {
109
const result = await oldReadTextFile(path, options);
110
return result;
111
} catch (err) {
112
if (!(err instanceof Error)) {
113
throw err;
114
}
115
if (err.message) {
116
err.message = err.message + "\n" + "Path: " + path;
117
}
118
throw err;
119
}
120
};
121
122
Deno.readTextFileSync = (path: string | URL) => {
123
try {
124
const result = oldReadTextFileSync(path);
125
return result;
126
} catch (err) {
127
if (!(err instanceof Error)) {
128
throw err;
129
}
130
if (err.message) {
131
err.message = err.message + "\n" + "Path: " + path;
132
}
133
throw err;
134
}
135
};
136
137