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