Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/package/src/common/dependencies/dependencies.ts
6451 views
1
/*
2
* dependencies.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*
6
*/
7
8
import { join } from "../../../../src/deno_ral/path.ts";
9
import { info, warning } from "../../../../src/deno_ral/log.ts";
10
import { PlatformConfiguration } from "../config.ts";
11
12
import { dartSass } from "./dartsass.ts";
13
import { deno_dom } from "./deno_dom.ts";
14
import { esBuild } from "./esbuild.ts";
15
import { pandoc } from "./pandoc.ts";
16
import { archiveUrl } from "../archive-binary-dependencies.ts";
17
import { typst } from "./typst.ts";
18
import { verapdf } from "./verapdf.ts";
19
20
// The list of binary dependencies for Quarto
21
export const kDependencies = [
22
deno_dom(version("DENO_DOM")),
23
pandoc(version("PANDOC")),
24
dartSass(version("DARTSASS")),
25
esBuild(version("ESBUILD")),
26
typst(version("TYPST")),
27
verapdf(version("VERAPDF")),
28
];
29
30
// Defines a binary dependency for Quarto
31
export interface Dependency {
32
name: string;
33
bucket: string;
34
version: string;
35
// If true, this dependency is only archived to S3 but not downloaded during configure.
36
// Use for optional dependencies installed separately via `quarto install`.
37
archiveOnly?: boolean;
38
architectureDependencies: Record<
39
string,
40
ArchitectureDependency
41
>;
42
}
43
44
// Defines the specific Platform dependencies for
45
// a given architecture
46
export interface ArchitectureDependency {
47
"darwin"?: PlatformDependency;
48
"linux"?: PlatformDependency;
49
"windows"?: PlatformDependency;
50
}
51
52
// Defines an individual binary dependency, specific
53
// to a Platform (and architecture)
54
export interface PlatformDependency {
55
filename: string;
56
url: string;
57
configure(config: PlatformConfiguration, path: string): Promise<void>;
58
}
59
60
function version(env: string) {
61
const version = Deno.env.get(env);
62
if (!version) {
63
throw Error(`${env} isn't defined with dependency version`);
64
} else {
65
return version;
66
}
67
}
68
69
export async function configureDependency(
70
dependency: Dependency,
71
targetDir: string,
72
config: PlatformConfiguration,
73
) {
74
// Skip archive-only dependencies (installed separately via `quarto install`)
75
if (dependency.archiveOnly) {
76
info(`Skipping ${dependency.name} (archive-only)`);
77
return;
78
}
79
80
info(`Preparing ${dependency.name} (${config.os} - ${config.arch})`);
81
const archDep = dependency.architectureDependencies[config.arch];
82
83
if (archDep) {
84
const platformDep = archDep[config.os];
85
const vendor = Deno.env.get("QUARTO_VENDOR_BINARIES");
86
let targetFile = "";
87
if (platformDep && (vendor === undefined || vendor === "true")) {
88
info(`Downloading ${dependency.name}`);
89
90
try {
91
targetFile = await downloadBinaryDependency(
92
dependency,
93
platformDep,
94
targetDir,
95
);
96
} catch (error) {
97
const msg =
98
`Failed to Download ${dependency.name}\nAre you sure that version ${dependency.version} of ${dependency.bucket} has been archived using './quarto-bld archive-bin-deps'?\n${error.message}`;
99
throw new Error(msg);
100
}
101
}
102
103
if (platformDep) {
104
info(`Configuring ${dependency.name}`);
105
await platformDep.configure(config, targetFile);
106
}
107
108
if (targetFile) {
109
info(`Cleaning up`);
110
Deno.removeSync(targetFile);
111
}
112
} else {
113
throw new Error(
114
`The architecture ${config.arch} is missing the dependency ${dependency.name}`,
115
);
116
}
117
118
info(`${dependency.name} complete.\n`);
119
}
120
121
async function downloadBinaryDependency(
122
dependency: Dependency,
123
platformDependency: PlatformDependency,
124
targetDir: string,
125
) {
126
const targetFile = join(targetDir, platformDependency.filename);
127
const dlUrl = archiveUrl(dependency, platformDependency);
128
129
info("Downloading " + dlUrl);
130
info("to " + targetFile);
131
const response = await fetch(dlUrl);
132
if (response.status === 200) {
133
const blob = await response.blob();
134
135
const bytes = await blob.arrayBuffer();
136
const data = new Uint8Array(bytes);
137
138
Deno.writeFileSync(
139
targetFile,
140
data,
141
);
142
return targetFile;
143
} else {
144
throw new Error(response.statusText);
145
}
146
}
147
148