Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/package/src/linux/installer.ts
6450 views
1
/*
2
* installer.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*
6
*/
7
import { join } from "../../../src/deno_ral/path.ts";
8
import { copySync, emptyDirSync, ensureDirSync, existsSync, walk } from "../../../src/deno_ral/fs.ts";
9
import { info } from "../../../src/deno_ral/log.ts";
10
import * as yaml from "../../../src/core/lib/external/js-yaml.js";
11
12
import { Configuration } from "../common/config.ts";
13
import { runCmd } from "../util/cmd.ts";
14
15
// Map architecture names between Quarto and package formats
16
function mapArchitecture(arch: string, format: 'deb' | 'rpm'): string {
17
if (format === 'deb') {
18
return arch === 'x86_64' ? 'amd64' : 'arm64';
19
} else { // rpm
20
return arch === 'x86_64' ? 'x86_64' : 'aarch64';
21
}
22
}
23
24
// Create nfpm configuration for DEB or RPM packages
25
async function createNfpmConfig(
26
configuration: Configuration,
27
format: 'deb' | 'rpm',
28
workingDir: string,
29
) {
30
const arch = mapArchitecture(configuration.arch, format);
31
const workingBinPath = join(
32
workingDir,
33
"opt",
34
configuration.productName.toLowerCase(),
35
"bin",
36
);
37
const workingSharePath = join(
38
workingDir,
39
"opt",
40
configuration.productName.toLowerCase(),
41
"share",
42
);
43
44
const contents: any[] = [
45
{
46
src: workingBinPath,
47
dst: "/opt/quarto/bin",
48
type: "tree",
49
},
50
{
51
src: workingSharePath,
52
dst: "/opt/quarto/share",
53
type: "tree",
54
},
55
];
56
57
// Add copyright file for DEB packages
58
if (format === 'deb') {
59
const copyrightFile = join(
60
workingDir,
61
"usr",
62
"share",
63
"doc",
64
configuration.productName.toLowerCase(),
65
"copyright",
66
);
67
contents.push({
68
src: copyrightFile,
69
dst: `/usr/share/doc/${configuration.productName.toLowerCase()}/copyright`,
70
});
71
}
72
73
const config: any = {
74
name: configuration.productName.toLowerCase(),
75
version: configuration.version,
76
arch: arch,
77
maintainer: "Posit, PBC <[email protected]>",
78
description: "Quarto is an academic, scientific, and technical publishing system built on Pandoc.",
79
homepage: "https://github.com/quarto-dev/quarto-cli",
80
license: "MIT",
81
82
contents: contents,
83
84
scripts: {
85
postinstall: join(configuration.directoryInfo.pkg, "scripts", "linux", format, "postinst"),
86
postremove: join(configuration.directoryInfo.pkg, "scripts", "linux", format, "postrm"),
87
},
88
89
overrides: {},
90
};
91
92
// Format-specific configuration
93
if (format === 'deb') {
94
config.overrides.deb = {
95
recommends: ["unzip"],
96
};
97
// Add Debian-specific metadata
98
config.section = "user/text";
99
config.priority = "optional";
100
}
101
return config;
102
}
103
104
// Build package using nfpm
105
async function buildPackageWithNfpm(
106
configuration: Configuration,
107
format: 'deb' | 'rpm',
108
) {
109
const packageExt = format === 'deb' ? 'deb' : 'rpm';
110
const arch = mapArchitecture(configuration.arch, format);
111
const packageName = `quarto-${configuration.version}-linux-${arch}.${packageExt}`;
112
113
info(`Building ${format.toUpperCase()} package: ${packageName}`);
114
115
// Prepare working directory
116
const workingDir = join(configuration.directoryInfo.out, "working");
117
info(`Preparing working directory ${workingDir}`);
118
ensureDirSync(workingDir);
119
emptyDirSync(workingDir);
120
121
// Copy bin and share directories
122
const workingBinPath = join(
123
workingDir,
124
"opt",
125
configuration.productName.toLowerCase(),
126
"bin",
127
);
128
info(`Preparing bin directory ${workingBinPath}`);
129
copySync(configuration.directoryInfo.pkgWorking.bin, workingBinPath, {
130
overwrite: true,
131
});
132
133
const workingSharePath = join(
134
workingDir,
135
"opt",
136
configuration.productName.toLowerCase(),
137
"share",
138
);
139
info(`Preparing share directory ${workingSharePath}`);
140
copySync(configuration.directoryInfo.pkgWorking.share, workingSharePath, {
141
overwrite: true,
142
});
143
144
// Create copyright file for DEB packages
145
if (format === 'deb') {
146
info("Creating copyright file");
147
const url = "https://github.com/quarto-dev/quarto-cli";
148
const copyrightText = `Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
149
Upstream-Name: Quarto
150
Source: ${url}
151
152
Files: *
153
Copyright: Posit, PBC.
154
License: MIT`;
155
156
const copyrightDir = join(workingDir, "usr", "share", "doc", configuration.productName.toLowerCase());
157
ensureDirSync(copyrightDir);
158
Deno.writeTextFileSync(join(copyrightDir, "copyright"), copyrightText);
159
}
160
161
// Create nfpm configuration
162
const nfpmConfig = await createNfpmConfig(configuration, format, workingDir);
163
const configPath = join(configuration.directoryInfo.out, "nfpm.yaml");
164
165
info("Creating nfpm configuration file");
166
Deno.writeTextFileSync(configPath, yaml.dump(nfpmConfig));
167
168
// Build package using nfpm (assumes nfpm is installed in PATH)
169
const outputPath = join(configuration.directoryInfo.out, packageName);
170
await runCmd("nfpm", [
171
"package",
172
"--config", configPath,
173
"--target", outputPath,
174
"--packager", format,
175
]);
176
177
info(`Package created: ${outputPath}`);
178
179
// Clean up
180
Deno.removeSync(configPath);
181
// Optionally remove working directory
182
// Deno.removeSync(workingDir, { recursive: true });
183
}
184
185
export async function makeInstallerDeb(
186
configuration: Configuration,
187
) {
188
await buildPackageWithNfpm(configuration, 'deb');
189
}
190
191
export async function makeInstallerRpm(
192
configuration: Configuration,
193
) {
194
await buildPackageWithNfpm(configuration, 'rpm');
195
}
196