@lakutata/builder 3.1.3 → 3.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -1
- package/README.zh-CN.md +7 -1
- package/dist/esm/index.js +5 -0
- package/dist/esm/lib/Archive.js +3 -2
- package/dist/esm/lib/Bundle.js +2 -1
- package/dist/esm/lib/Directories.js +18 -0
- package/dist/esm/lib/Executable.js +27 -6
- package/dist/esm/lib/Installer.js +28 -14
- package/dist/esm/lib/NativeRuntime.js +27 -3
- package/dist/esm/lib/Processes.js +3 -2
- package/dist/esm/lib/Tools.js +98 -19
- package/dist/esm/lib/linux/Linux.js +60 -10
- package/dist/esm/lib/mac/Mac.js +39 -11
- package/dist/esm/lib/mobile/Addons.js +675 -0
- package/dist/esm/lib/mobile/Node.js +190 -0
- package/dist/esm/lib/mobile/Stage.js +180 -0
- package/dist/esm/lib/nwjs/Addons.js +310 -0
- package/dist/esm/lib/nwjs/Package.js +149 -0
- package/dist/esm/lib/nwjs/Runtime.js +188 -0
- package/dist/esm/lib/nwjs/Stage.js +92 -0
- package/dist/esm/lib/win/Windows.js +68 -45
- package/dist/types/index.d.ts +7 -0
- package/dist/types/lib/Bundle.d.ts +5 -0
- package/dist/types/lib/Directories.d.ts +8 -0
- package/dist/types/lib/Executable.d.ts +7 -0
- package/dist/types/lib/Installer.d.ts +37 -4
- package/dist/types/lib/Processes.d.ts +2 -1
- package/dist/types/lib/Tools.d.ts +47 -1
- package/dist/types/lib/linux/Linux.d.ts +2 -1
- package/dist/types/lib/mac/Mac.d.ts +1 -1
- package/dist/types/lib/mobile/Addons.d.ts +154 -0
- package/dist/types/lib/mobile/Node.d.ts +89 -0
- package/dist/types/lib/mobile/Stage.d.ts +111 -0
- package/dist/types/lib/nwjs/Addons.d.ts +69 -0
- package/dist/types/lib/nwjs/Package.d.ts +56 -0
- package/dist/types/lib/nwjs/Runtime.d.ts +120 -0
- package/dist/types/lib/nwjs/Stage.d.ts +104 -0
- package/dist/types/lib/win/Windows.d.ts +30 -1
- package/package.json +2 -2
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { copyFileSync, lstatSync, mkdirSync, readdirSync, readlinkSync } from 'node:fs';
|
|
2
|
-
import { stat, mkdir, writeFile, rm } from 'node:fs/promises';
|
|
2
|
+
import { stat, mkdir, readFile, writeFile, rm } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { archiveDirectory } from '../Archive.js';
|
|
5
|
+
import { decodePng, writeLinuxIcons } from '../Icons.js';
|
|
5
6
|
import { runCommand } from '../Processes.js';
|
|
6
7
|
import { ensureTool } from '../Tools.js';
|
|
7
8
|
import { embeddedShell, INSTALLER_HOOKS, NATIVE_HOOKS } from '../Scripts.js';
|
|
@@ -18,11 +19,47 @@ const RUNTIME_DEPENDS = {
|
|
|
18
19
|
apk: ['libstdc++', 'libgcc'],
|
|
19
20
|
archlinux: ['gcc-libs']
|
|
20
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* The libraries of the system a desktop application of Chromium (NW.js) loads, by package: the deb ones of Electron, and
|
|
24
|
+
* the atomic operations the Node.js of NW.js loads (libnode.so needs libatomic.so.1, which only the compilers install)
|
|
25
|
+
*/
|
|
26
|
+
const DESKTOP_DEPENDS = {
|
|
27
|
+
deb: ['libgtk-3-0', 'libnotify4', 'libnss3', 'libxss1', 'libxtst6', 'xdg-utils', 'libatspi2.0-0', 'libuuid1', 'libsecret-1-0', 'libasound2', 'libgbm1', 'libatomic1'],
|
|
28
|
+
rpm: ['gtk3', 'libnotify', 'nss', 'libXScrnSaver', 'libXtst', 'xdg-utils', 'at-spi2-core', 'libuuid', 'libsecret', 'alsa-lib', 'mesa-libgbm', 'libatomic'],
|
|
29
|
+
apk: [],
|
|
30
|
+
archlinux: []
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The desktop entry of a desktop application, which the menus of the desktops list
|
|
34
|
+
* @param plan
|
|
35
|
+
* @param executable
|
|
36
|
+
*/
|
|
37
|
+
function desktopEntry(plan, executable) {
|
|
38
|
+
return [
|
|
39
|
+
'[Desktop Entry]',
|
|
40
|
+
'Type=Application',
|
|
41
|
+
`Name=${plan.productName}`,
|
|
42
|
+
`Comment=${plan.description.replace(/\s+/g, ' ')}`,
|
|
43
|
+
`Exec="${plan.prefix}/${executable}" %U`,
|
|
44
|
+
`Icon=${plan.name}`,
|
|
45
|
+
'Terminal=false',
|
|
46
|
+
'Categories=Utility;',
|
|
47
|
+
''
|
|
48
|
+
].join('\n');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The lines refreshing the menus and the icons of the desktops after the installation and the removal of a desktop
|
|
52
|
+
* application, where their tools are installed
|
|
53
|
+
*/
|
|
54
|
+
const DESKTOP_REFRESH = [
|
|
55
|
+
'command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database -q /usr/share/applications || true',
|
|
56
|
+
'command -v gtk-update-icon-cache >/dev/null 2>&1 && gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor || true'
|
|
57
|
+
];
|
|
21
58
|
/**
|
|
22
59
|
* The architecture of the packages (the one of Go, which nFPM translates for each package)
|
|
23
60
|
*/
|
|
24
|
-
function packageArch() {
|
|
25
|
-
return { x64: 'amd64', arm64: 'arm64', ia32: '386', arm: 'arm7' }[
|
|
61
|
+
function packageArch(plan) {
|
|
62
|
+
return { x64: 'amd64', arm64: 'arm64', ia32: '386', arm: 'arm7' }[plan.arch] ?? plan.arch;
|
|
26
63
|
}
|
|
27
64
|
/**
|
|
28
65
|
* The characters of the globs, which nFPM reads in the sources of the contents (the chunks of Turbopack are named
|
|
@@ -78,7 +115,7 @@ function packageFile(plan, target) {
|
|
|
78
115
|
const arch = { x64: 'x86_64', arm64: 'aarch64' }[process.arch] ?? process.arch;
|
|
79
116
|
switch (target) {
|
|
80
117
|
case 'deb':
|
|
81
|
-
return `${plan.name}_${plan.version}_${packageArch()}.deb`;
|
|
118
|
+
return `${plan.name}_${plan.version}_${packageArch(plan)}.deb`;
|
|
82
119
|
case 'rpm':
|
|
83
120
|
return `${plan.name}-${plan.version}-1.${arch}.rpm`;
|
|
84
121
|
case 'apk':
|
|
@@ -276,7 +313,8 @@ function packageScripts(plan, target) {
|
|
|
276
313
|
//Not indented: the lines of the script are the ones of its file
|
|
277
314
|
...application ? [scriptAction(target, hook), 'if [ -n "$lakutata_action" ]; then', ...embeddedShell(application, plan.prefix, '"$lakutata_action"'), 'fi'] : [],
|
|
278
315
|
...native ? embeddedShell(native, plan.prefix, '"$@"') : [],
|
|
279
|
-
...service.after[hook] ?? []
|
|
316
|
+
...service.after[hook] ?? [],
|
|
317
|
+
...plan.desktop && (hook === 'postinstall' || hook === 'postremove' || hook === 'postupgrade') ? DESKTOP_REFRESH : []
|
|
280
318
|
];
|
|
281
319
|
if (lines.length)
|
|
282
320
|
scripts[hook] = ['#!/bin/sh', 'set -e', ...lines, ''].join('\n');
|
|
@@ -290,14 +328,15 @@ function packageScripts(plan, target) {
|
|
|
290
328
|
* @param targets
|
|
291
329
|
* @param work
|
|
292
330
|
* @param outdir
|
|
331
|
+
* @param progress Called with what is being downloaded (nFPM)
|
|
293
332
|
*/
|
|
294
|
-
export async function buildLinuxPackages(plan, targets, work, outdir) {
|
|
333
|
+
export async function buildLinuxPackages(plan, targets, work, outdir, progress) {
|
|
295
334
|
await mkdir(work, { recursive: true });
|
|
296
335
|
const files = [];
|
|
297
336
|
const service = plan.service;
|
|
298
337
|
for (const target of targets) {
|
|
299
338
|
if (target === 'tar.gz') {
|
|
300
|
-
files.push(await archiveDirectory(plan, packageArch(), work, outdir));
|
|
339
|
+
files.push(await archiveDirectory(plan, packageArch(plan), work, outdir));
|
|
301
340
|
continue;
|
|
302
341
|
}
|
|
303
342
|
const directory = path.join(work, target);
|
|
@@ -305,6 +344,17 @@ export async function buildLinuxPackages(plan, targets, work, outdir) {
|
|
|
305
344
|
const contents = packageContents(plan.directory, plan.prefix, directory);
|
|
306
345
|
if (plan.addToPath)
|
|
307
346
|
contents.push({ src: `${plan.prefix}/${plan.program}`, dst: `/usr/bin/${plan.program}`, type: 'symlink' });
|
|
347
|
+
if (plan.desktop) {
|
|
348
|
+
//Its entry in the menus of the desktops, its icons in the theme hicolor
|
|
349
|
+
await writeFile(path.join(directory, 'desktop'), desktopEntry(plan, plan.desktop.executable));
|
|
350
|
+
contents.push({ src: path.join(directory, 'desktop'), dst: `/usr/share/applications/${plan.name}.desktop`, file_info: { mode: 0o644 } });
|
|
351
|
+
if (plan.desktop.icon) {
|
|
352
|
+
for (const icon of await writeLinuxIcons(decodePng(await readFile(plan.desktop.icon), plan.desktop.icon), path.join(directory, 'icons'))) {
|
|
353
|
+
const size = path.basename(icon, '.png');
|
|
354
|
+
contents.push({ src: icon, dst: `/usr/share/icons/hicolor/${size}/apps/${plan.name}.png`, file_info: { mode: 0o644 } });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
308
358
|
if (service) {
|
|
309
359
|
await writeFile(path.join(directory, 'environment'), environmentFile(service));
|
|
310
360
|
contents.push({ src: path.join(directory, 'environment'), dst: `/etc/${plan.name}/${plan.name}.env`, type: 'config|noreplace', file_info: { mode: 0o640 } });
|
|
@@ -331,7 +381,7 @@ export async function buildLinuxPackages(plan, targets, work, outdir) {
|
|
|
331
381
|
}
|
|
332
382
|
const config = {
|
|
333
383
|
name: plan.name,
|
|
334
|
-
arch: packageArch(),
|
|
384
|
+
arch: packageArch(plan),
|
|
335
385
|
platform: 'linux',
|
|
336
386
|
version: plan.version,
|
|
337
387
|
maintainer: plan.maintainer,
|
|
@@ -341,7 +391,7 @@ export async function buildLinuxPackages(plan, targets, work, outdir) {
|
|
|
341
391
|
...plan.license ? { license: plan.license } : {},
|
|
342
392
|
...plan.section ? { section: plan.section } : {},
|
|
343
393
|
...plan.priority ? { priority: plan.priority } : {},
|
|
344
|
-
depends: [...new Set([...RUNTIME_DEPENDS[target], ...plan.depends])],
|
|
394
|
+
depends: [...new Set([...RUNTIME_DEPENDS[target], ...plan.desktop ? DESKTOP_DEPENDS[target] : [], ...plan.depends])],
|
|
345
395
|
...plan.recommends.length ? { recommends: plan.recommends } : {},
|
|
346
396
|
contents: contents,
|
|
347
397
|
scripts: common,
|
|
@@ -349,7 +399,7 @@ export async function buildLinuxPackages(plan, targets, work, outdir) {
|
|
|
349
399
|
};
|
|
350
400
|
//JSON is YAML
|
|
351
401
|
await writeFile(path.join(directory, 'nfpm.yaml'), JSON.stringify(config, null, 2));
|
|
352
|
-
const nfpm = await ensureTool('nfpm');
|
|
402
|
+
const nfpm = await ensureTool('nfpm', progress);
|
|
353
403
|
const file = path.join(outdir, packageFile(plan, target));
|
|
354
404
|
await rm(file, { force: true });
|
|
355
405
|
const packaged = await runCommand(nfpm, ['package', '--config', path.join(directory, 'nfpm.yaml'), '--packager', target, '--target', file], directory);
|
package/dist/esm/lib/mac/Mac.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { chmod,
|
|
1
|
+
import { chmod, mkdir, readFile, rm, stat, symlink, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { archiveDirectory } from '../Archive.js';
|
|
4
|
+
import { copyDirectory } from '../Directories.js';
|
|
4
5
|
import { runCommand } from '../Processes.js';
|
|
5
6
|
import { embeddedShell } from '../Scripts.js';
|
|
6
7
|
/**
|
|
7
8
|
* The installers of macOS: the package of its installer, and the archive of the directory of the executable
|
|
8
9
|
*/
|
|
9
|
-
export const MAC_TARGETS = ['pkg', 'tar.gz'];
|
|
10
|
+
export const MAC_TARGETS = ['pkg', 'dmg', 'tar.gz'];
|
|
10
11
|
/**
|
|
11
12
|
* The architecture of the packages
|
|
12
13
|
*/
|
|
13
|
-
function packageArch() {
|
|
14
|
-
return
|
|
14
|
+
function packageArch(plan) {
|
|
15
|
+
return plan.arch;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* A text of a property list
|
|
@@ -103,7 +104,7 @@ function preInstall(plan) {
|
|
|
103
104
|
return [
|
|
104
105
|
'#!/bin/sh',
|
|
105
106
|
'set -e',
|
|
106
|
-
`if [ -e ${doubleQuoted(`${plan.prefix}/${plan.program}`)} ]; then lakutata_action=upgrade; else lakutata_action=install; fi`,
|
|
107
|
+
`if [ -e ${doubleQuoted(plan.desktop ? plan.prefix : `${plan.prefix}/${plan.program}`)} ]; then lakutata_action=upgrade; else lakutata_action=install; fi`,
|
|
107
108
|
`if [ -n "$INSTALLER_TEMP" ]; then echo "$lakutata_action" > ${ACTION_FILE}; fi`,
|
|
108
109
|
...hooks.preinstall ? embeddedShell(hooks.preinstall, plan.prefix, '"$lakutata_action"') : [],
|
|
109
110
|
''
|
|
@@ -223,6 +224,26 @@ function uninstall(plan) {
|
|
|
223
224
|
''
|
|
224
225
|
].join('\n');
|
|
225
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* The disk image of a desktop application (dmg): its bundle and a link to /Applications, where its user drags it
|
|
229
|
+
* @param plan
|
|
230
|
+
* @param work
|
|
231
|
+
* @param outdir
|
|
232
|
+
*/
|
|
233
|
+
async function diskImage(plan, work, outdir) {
|
|
234
|
+
if (!plan.desktop)
|
|
235
|
+
throw new Error('The disk images (dmg) are made for the desktop applications (NW.js): the other applications are installed by pkg');
|
|
236
|
+
const volume = path.join(work, 'dmg');
|
|
237
|
+
await rm(volume, { recursive: true, force: true });
|
|
238
|
+
await copyDirectory(path.join(plan.directory, plan.desktop.executable), path.join(volume, plan.desktop.executable));
|
|
239
|
+
await symlink('/Applications', path.join(volume, 'Applications'));
|
|
240
|
+
const file = path.join(outdir, `${plan.name}-${plan.version}-${packageArch(plan)}.dmg`);
|
|
241
|
+
await rm(file, { force: true });
|
|
242
|
+
const created = await runCommand('hdiutil', ['create', '-volname', plan.productName, '-srcfolder', volume, '-ov', '-format', 'UDZO', file], work);
|
|
243
|
+
if (created.code !== 0)
|
|
244
|
+
throw new Error(`The disk image cannot be made: ${created.output.trim()}`);
|
|
245
|
+
return { target: 'dmg', file: file, size: (await stat(file)).size };
|
|
246
|
+
}
|
|
226
247
|
/**
|
|
227
248
|
* Make the installers of macOS of an application: the package installed by its installer (pkgbuild, productbuild), the
|
|
228
249
|
* tar.gz archive of the directory of the executable
|
|
@@ -236,7 +257,11 @@ export async function buildMacPackages(plan, targets, work, outdir) {
|
|
|
236
257
|
const files = [];
|
|
237
258
|
for (const target of targets) {
|
|
238
259
|
if (target === 'tar.gz') {
|
|
239
|
-
files.push(await archiveDirectory(plan, packageArch(), work, outdir));
|
|
260
|
+
files.push(await archiveDirectory(plan, packageArch(plan), work, outdir));
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (target === 'dmg') {
|
|
264
|
+
files.push(await diskImage(plan, work, outdir));
|
|
240
265
|
continue;
|
|
241
266
|
}
|
|
242
267
|
//The files installed, from the root of the system
|
|
@@ -246,9 +271,11 @@ export async function buildMacPackages(plan, targets, work, outdir) {
|
|
|
246
271
|
await rm(scripts, { recursive: true, force: true });
|
|
247
272
|
const prefix = path.join(root, ...plan.prefix.split('/'));
|
|
248
273
|
await mkdir(path.dirname(prefix), { recursive: true });
|
|
249
|
-
|
|
250
|
-
await
|
|
251
|
-
if (plan.
|
|
274
|
+
//A desktop application: its bundle into /Applications (removed by its user, as the other applications)
|
|
275
|
+
await copyDirectory(plan.desktop ? path.join(plan.directory, plan.desktop.executable) : plan.directory, prefix);
|
|
276
|
+
if (!plan.desktop)
|
|
277
|
+
await writeFile(path.join(prefix, 'uninstall'), uninstall(plan), { mode: 0o755 });
|
|
278
|
+
if (plan.addToPath && !plan.desktop) {
|
|
252
279
|
await mkdir(path.join(root, 'usr', 'local', 'bin'), { recursive: true });
|
|
253
280
|
await symlink(path.posix.relative('/usr/local/bin', `${plan.prefix}/${plan.program}`), path.join(root, 'usr', 'local', 'bin', plan.program));
|
|
254
281
|
}
|
|
@@ -270,14 +297,15 @@ export async function buildMacPackages(plan, targets, work, outdir) {
|
|
|
270
297
|
const built = await runCommand('pkgbuild', ['--root', root, '--identifier', plan.appId, '--version', plan.version, '--install-location', '/', '--scripts', scripts, '--ownership', 'recommended', component], work);
|
|
271
298
|
if (built.code !== 0)
|
|
272
299
|
throw new Error(`The pkg package cannot be made: ${built.output.trim()}`);
|
|
273
|
-
const file = path.join(outdir, `${plan.name}-${plan.version}-${packageArch()}.pkg`);
|
|
300
|
+
const file = path.join(outdir, `${plan.name}-${plan.version}-${packageArch(plan)}.pkg`);
|
|
274
301
|
await rm(file, { force: true });
|
|
275
302
|
//Installed on the Macs of the architecture of the program only (productbuild gives both)
|
|
276
303
|
const distribution = path.join(work, 'distribution.xml');
|
|
277
304
|
const synthesized = await runCommand('productbuild', ['--synthesize', '--package', component, distribution], work);
|
|
278
305
|
if (synthesized.code !== 0)
|
|
279
306
|
throw new Error(`The pkg package cannot be made: ${synthesized.output.trim()}`);
|
|
280
|
-
|
|
307
|
+
//A desktop application of Intel runs on the Macs of Apple silicon too (Rosetta)
|
|
308
|
+
const architectures = `hostArchitectures="${packageArch(plan) === 'arm64' ? 'arm64' : plan.desktop ? 'x86_64,arm64' : 'x86_64'}"`;
|
|
281
309
|
const options = await readFile(distribution, 'utf8');
|
|
282
310
|
await writeFile(distribution, /hostArchitectures="[^"]*"/.test(options) ? options.replace(/hostArchitectures="[^"]*"/, architectures) : options.replace('<options ', `<options ${architectures} `));
|
|
283
311
|
const product = await runCommand('productbuild', ['--distribution', distribution, '--package-path', work, '--identifier', plan.appId, '--version', plan.version, file], work);
|