docker-client-mx 1.35.0
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/LICENSE +21 -0
- package/README.md +233 -0
- package/bin/docker-client-mx.js +42 -0
- package/build/icons/icon-1024.png +0 -0
- package/build/icons/icon-128.png +0 -0
- package/build/icons/icon-16.png +0 -0
- package/build/icons/icon-256.png +0 -0
- package/build/icons/icon-32.png +0 -0
- package/build/icons/icon-48.png +0 -0
- package/build/icons/icon-512.png +0 -0
- package/build/icons/icon-64.png +0 -0
- package/build/icons/icon.ico +0 -0
- package/build/icons/icon.iconset/icon_128x128.png +0 -0
- package/build/icons/icon.iconset/icon_128x128@2x.png +0 -0
- package/build/icons/icon.iconset/icon_16x16.png +0 -0
- package/build/icons/icon.iconset/icon_16x16@2x.png +0 -0
- package/build/icons/icon.iconset/icon_256x256.png +0 -0
- package/build/icons/icon.iconset/icon_256x256@2x.png +0 -0
- package/build/icons/icon.iconset/icon_32x32.png +0 -0
- package/build/icons/icon.iconset/icon_32x32@2x.png +0 -0
- package/build/icons/icon.iconset/icon_512x512.png +0 -0
- package/build/icons/icon.iconset/icon_512x512@2x.png +0 -0
- package/build/icons/icon.png +0 -0
- package/dist/docker-desktop-mx/browser/chunk-64WWLMUP.js +39 -0
- package/dist/docker-desktop-mx/browser/chunk-N4VBBC4W.js +1 -0
- package/dist/docker-desktop-mx/browser/favicon.ico +0 -0
- package/dist/docker-desktop-mx/browser/index.html +14 -0
- package/dist/docker-desktop-mx/browser/main-CTIRTSOI.js +5 -0
- package/dist/docker-desktop-mx/browser/styles-JS3HDDI4.css +1 -0
- package/dist-electron/api.js +10 -0
- package/dist-electron/api.js.map +1 -0
- package/dist-electron/assistant-key.js +70 -0
- package/dist-electron/assistant-key.js.map +1 -0
- package/dist-electron/assistant-models.js +19 -0
- package/dist-electron/assistant-models.js.map +1 -0
- package/dist-electron/assistant-tools.js +335 -0
- package/dist-electron/assistant-tools.js.map +1 -0
- package/dist-electron/assistant.js +302 -0
- package/dist-electron/assistant.js.map +1 -0
- package/dist-electron/attention.js +75 -0
- package/dist-electron/attention.js.map +1 -0
- package/dist-electron/channels.js +113 -0
- package/dist-electron/channels.js.map +1 -0
- package/dist-electron/compose-files.js +104 -0
- package/dist-electron/compose-files.js.map +1 -0
- package/dist-electron/compose.js +271 -0
- package/dist-electron/compose.js.map +1 -0
- package/dist-electron/container-events.js +188 -0
- package/dist-electron/container-events.js.map +1 -0
- package/dist-electron/containers.js +165 -0
- package/dist-electron/containers.js.map +1 -0
- package/dist-electron/context-menu.js +56 -0
- package/dist-electron/context-menu.js.map +1 -0
- package/dist-electron/contexts.js +346 -0
- package/dist-electron/contexts.js.map +1 -0
- package/dist-electron/crash.js +129 -0
- package/dist-electron/crash.js.map +1 -0
- package/dist-electron/diagnosis.js +338 -0
- package/dist-electron/diagnosis.js.map +1 -0
- package/dist-electron/docker-client.js +284 -0
- package/dist-electron/docker-client.js.map +1 -0
- package/dist-electron/engine.js +145 -0
- package/dist-electron/engine.js.map +1 -0
- package/dist-electron/event-store.js +146 -0
- package/dist-electron/event-store.js.map +1 -0
- package/dist-electron/events.js +132 -0
- package/dist-electron/events.js.map +1 -0
- package/dist-electron/exec.js +138 -0
- package/dist-electron/exec.js.map +1 -0
- package/dist-electron/files.js +407 -0
- package/dist-electron/files.js.map +1 -0
- package/dist-electron/health.js +92 -0
- package/dist-electron/health.js.map +1 -0
- package/dist-electron/host-overview.js +50 -0
- package/dist-electron/host-overview.js.map +1 -0
- package/dist-electron/host-shell.js +196 -0
- package/dist-electron/host-shell.js.map +1 -0
- package/dist-electron/i18n.js +58 -0
- package/dist-electron/i18n.js.map +1 -0
- package/dist-electron/image-history.js +87 -0
- package/dist-electron/image-history.js.map +1 -0
- package/dist-electron/images.js +141 -0
- package/dist-electron/images.js.map +1 -0
- package/dist-electron/ipc.js +783 -0
- package/dist-electron/ipc.js.map +1 -0
- package/dist-electron/links.js +46 -0
- package/dist-electron/links.js.map +1 -0
- package/dist-electron/logs.js +153 -0
- package/dist-electron/logs.js.map +1 -0
- package/dist-electron/main.js +494 -0
- package/dist-electron/main.js.map +1 -0
- package/dist-electron/merged-logs.js +127 -0
- package/dist-electron/merged-logs.js.map +1 -0
- package/dist-electron/navigation.js +37 -0
- package/dist-electron/navigation.js.map +1 -0
- package/dist-electron/ndjson.js +30 -0
- package/dist-electron/ndjson.js.map +1 -0
- package/dist-electron/networks.js +507 -0
- package/dist-electron/networks.js.map +1 -0
- package/dist-electron/port-conflicts.js +106 -0
- package/dist-electron/port-conflicts.js.map +1 -0
- package/dist-electron/preload.js +257 -0
- package/dist-electron/preload.js.map +1 -0
- package/dist-electron/pull.js +220 -0
- package/dist-electron/pull.js.map +1 -0
- package/dist-electron/redact.js +129 -0
- package/dist-electron/redact.js.map +1 -0
- package/dist-electron/registry-auth.js +150 -0
- package/dist-electron/registry-auth.js.map +1 -0
- package/dist-electron/renew.js +162 -0
- package/dist-electron/renew.js.map +1 -0
- package/dist-electron/restart-policy.js +58 -0
- package/dist-electron/restart-policy.js.map +1 -0
- package/dist-electron/run-command.js +146 -0
- package/dist-electron/run-command.js.map +1 -0
- package/dist-electron/run.js +151 -0
- package/dist-electron/run.js.map +1 -0
- package/dist-electron/self-update.js +163 -0
- package/dist-electron/self-update.js.map +1 -0
- package/dist-electron/servers.js +108 -0
- package/dist-electron/servers.js.map +1 -0
- package/dist-electron/settings.js +146 -0
- package/dist-electron/settings.js.map +1 -0
- package/dist-electron/ssh.js +574 -0
- package/dist-electron/ssh.js.map +1 -0
- package/dist-electron/stats.js +209 -0
- package/dist-electron/stats.js.map +1 -0
- package/dist-electron/streams.js +63 -0
- package/dist-electron/streams.js.map +1 -0
- package/dist-electron/system.js +123 -0
- package/dist-electron/system.js.map +1 -0
- package/dist-electron/terminal-transcript.js +55 -0
- package/dist-electron/terminal-transcript.js.map +1 -0
- package/dist-electron/updates.js +136 -0
- package/dist-electron/updates.js.map +1 -0
- package/dist-electron/volume-backup.js +203 -0
- package/dist-electron/volume-backup.js.map +1 -0
- package/dist-electron/volume-files.js +124 -0
- package/dist-electron/volume-files.js.map +1 -0
- package/dist-electron/volumes.js +253 -0
- package/dist-electron/volumes.js.map +1 -0
- package/dist-electron/wiring-watch.js +93 -0
- package/dist-electron/wiring-watch.js.map +1 -0
- package/dist-electron/wiring.js +71 -0
- package/dist-electron/wiring.js.map +1 -0
- package/dist-electron/wsl.js +167 -0
- package/dist-electron/wsl.js.map +1 -0
- package/package.json +125 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.quoteArg = quoteArg;
|
|
4
|
+
exports.buildRunCommand = buildRunCommand;
|
|
5
|
+
exports.readRunCommand = readRunCommand;
|
|
6
|
+
const docker_client_1 = require("./docker-client");
|
|
7
|
+
/**
|
|
8
|
+
* Het `docker run`-commando waarmee je een bestaande container opnieuw maakt.
|
|
9
|
+
*
|
|
10
|
+
* De omgekeerde weg van `toCreateOptions` uit het startformulier: daar wordt een formulier een
|
|
11
|
+
* create-body, hier wordt een bestaande container weer een commando. Alleen lezen — dit levert
|
|
12
|
+
* tekst op om te kopiëren, en voert niets uit.
|
|
13
|
+
*
|
|
14
|
+
* De kern is een vergelijking met de image. `Config.Env` van een container bevat ook de `PATH`
|
|
15
|
+
* en alles wat de Dockerfile zette; zonder dat eraf te halen krijg je een commando van tien
|
|
16
|
+
* regels waarvan je er twee zelf hebt meegegeven. Hetzelfde geldt voor het commando, het
|
|
17
|
+
* entrypoint, de werkmap en de gebruiker: alleen wat afwijkt van de image hoort erin.
|
|
18
|
+
*/
|
|
19
|
+
/** Wat zonder aanhalingstekens kan. Alles wat een shell anders zou lezen, gaat tussen quotes. */
|
|
20
|
+
const SAFE = /^[\w@%+=:,./-]+$/;
|
|
21
|
+
/** Netwerken waar `--network` niets toevoegt: dat is waar een container standaard in komt. */
|
|
22
|
+
const DEFAULT_NETWORKS = new Set(['', 'default', 'bridge']);
|
|
23
|
+
/** Restart policies die niets betekenen: geen beleid is Docker's standaard. */
|
|
24
|
+
const NO_RESTART = new Set(['', 'no']);
|
|
25
|
+
/**
|
|
26
|
+
* Eén argument, klaar voor een shell. Enkele quotes, want daarbinnen betekent niets iets — en
|
|
27
|
+
* een enkele quote in de waarde zelf sluit af, ontsnapt en opent opnieuw: `'\''`.
|
|
28
|
+
*/
|
|
29
|
+
function quoteArg(value) {
|
|
30
|
+
if (value !== '' && SAFE.test(value)) {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
return `'${value.split("'").join("'\\''")}'`;
|
|
34
|
+
}
|
|
35
|
+
function sameList(left, right) {
|
|
36
|
+
return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
|
|
37
|
+
}
|
|
38
|
+
/** De poorten, één `-p` per gepubliceerde poort. IPv4 en IPv6 leveren dezelfde regel op; die telt één keer. */
|
|
39
|
+
function portArgs(container) {
|
|
40
|
+
const args = [];
|
|
41
|
+
const seen = new Set();
|
|
42
|
+
for (const [port, bindings] of Object.entries(container.HostConfig?.PortBindings ?? {})) {
|
|
43
|
+
// `80/tcp` is de standaard en schrijf je niet uit; `53/udp` wel.
|
|
44
|
+
const target = port.endsWith('/tcp') ? port.slice(0, -4) : port;
|
|
45
|
+
for (const binding of bindings ?? []) {
|
|
46
|
+
const hostPort = binding.HostPort ?? '';
|
|
47
|
+
const hostIp = binding.HostIp ?? '';
|
|
48
|
+
const address = hostIp === '' || hostIp === '0.0.0.0' || hostIp === '::' ? '' : `${hostIp}:`;
|
|
49
|
+
const value = hostPort === '' ? target : `${address}${hostPort}:${target}`;
|
|
50
|
+
if (!seen.has(value)) {
|
|
51
|
+
seen.add(value);
|
|
52
|
+
args.push(value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return args;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* De volumes. `Binds` is wat er met `-v` meegegeven is en daarmee de bron; staat die leeg, dan
|
|
60
|
+
* leiden we het af uit `Mounts` — dat is hoe een container uit een create-body eruitziet.
|
|
61
|
+
*/
|
|
62
|
+
function volumeArgs(container) {
|
|
63
|
+
const binds = container.HostConfig?.Binds ?? [];
|
|
64
|
+
if (binds.length > 0) {
|
|
65
|
+
// `:rw` is de standaard en alleen ruis; `:ro` en de rest blijven staan.
|
|
66
|
+
return binds.map((bind) => (bind.endsWith(':rw') ? bind.slice(0, -3) : bind));
|
|
67
|
+
}
|
|
68
|
+
return (container.Mounts ?? [])
|
|
69
|
+
.filter((mount) => mount.Type === 'volume' || mount.Type === 'bind')
|
|
70
|
+
.map((mount) => {
|
|
71
|
+
const source = mount.Type === 'volume' ? (mount.Name ?? '') : (mount.Source ?? '');
|
|
72
|
+
return `${source}:${mount.Destination ?? ''}${mount.RW === false ? ':ro' : ''}`;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function restartArg(container) {
|
|
76
|
+
const policy = container.HostConfig?.RestartPolicy;
|
|
77
|
+
const name = policy?.Name ?? '';
|
|
78
|
+
if (NO_RESTART.has(name)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const maximum = policy?.MaximumRetryCount ?? 0;
|
|
82
|
+
return name === 'on-failure' && maximum > 0 ? `${name}:${String(maximum)}` : name;
|
|
83
|
+
}
|
|
84
|
+
/** Het commando op één regel, plus hoeveel `-e` erin staan. */
|
|
85
|
+
function buildRunCommand(container, image) {
|
|
86
|
+
const config = container.Config;
|
|
87
|
+
const imageConfig = image.Config;
|
|
88
|
+
const parts = ['docker', 'run', '-d'];
|
|
89
|
+
if (config?.Tty === true && config.OpenStdin === true) {
|
|
90
|
+
parts.push('-it');
|
|
91
|
+
}
|
|
92
|
+
const name = (container.Name ?? '').replace(/^\//, '');
|
|
93
|
+
if (name !== '') {
|
|
94
|
+
parts.push('--name', quoteArg(name));
|
|
95
|
+
}
|
|
96
|
+
for (const port of portArgs(container)) {
|
|
97
|
+
parts.push('-p', quoteArg(port));
|
|
98
|
+
}
|
|
99
|
+
for (const volume of volumeArgs(container)) {
|
|
100
|
+
parts.push('-v', quoteArg(volume));
|
|
101
|
+
}
|
|
102
|
+
// Alleen wat niet al in de image staat: de rest heeft de Dockerfile gezet.
|
|
103
|
+
const imageEnv = new Set(imageConfig?.Env ?? []);
|
|
104
|
+
const env = (config?.Env ?? []).filter((entry) => !imageEnv.has(entry));
|
|
105
|
+
for (const entry of env) {
|
|
106
|
+
parts.push('-e', quoteArg(entry));
|
|
107
|
+
}
|
|
108
|
+
const network = container.HostConfig?.NetworkMode ?? '';
|
|
109
|
+
if (!DEFAULT_NETWORKS.has(network)) {
|
|
110
|
+
parts.push('--network', quoteArg(network));
|
|
111
|
+
}
|
|
112
|
+
const restart = restartArg(container);
|
|
113
|
+
if (restart !== null) {
|
|
114
|
+
parts.push('--restart', quoteArg(restart));
|
|
115
|
+
}
|
|
116
|
+
if (config?.WorkingDir !== undefined && config.WorkingDir !== '' && config.WorkingDir !== imageConfig?.WorkingDir) {
|
|
117
|
+
parts.push('-w', quoteArg(config.WorkingDir));
|
|
118
|
+
}
|
|
119
|
+
if (config?.User !== undefined && config.User !== '' && config.User !== imageConfig?.User) {
|
|
120
|
+
parts.push('-u', quoteArg(config.User));
|
|
121
|
+
}
|
|
122
|
+
if (container.HostConfig?.Privileged === true) {
|
|
123
|
+
parts.push('--privileged');
|
|
124
|
+
}
|
|
125
|
+
if (!sameList(config?.Entrypoint, imageConfig?.Entrypoint)) {
|
|
126
|
+
parts.push('--entrypoint', quoteArg((config?.Entrypoint ?? []).join(' ')));
|
|
127
|
+
}
|
|
128
|
+
parts.push(quoteArg(config?.Image ?? container.Image ?? ''));
|
|
129
|
+
if (!sameList(config?.Cmd, imageConfig?.Cmd)) {
|
|
130
|
+
parts.push(...(config?.Cmd ?? []).map(quoteArg));
|
|
131
|
+
}
|
|
132
|
+
return { command: parts.join(' '), envCount: env.length };
|
|
133
|
+
}
|
|
134
|
+
/** Het run-commando van deze container, met de image erbij om tegen af te zetten. */
|
|
135
|
+
async function readRunCommand(id) {
|
|
136
|
+
try {
|
|
137
|
+
const { docker } = (0, docker_client_1.getConnection)();
|
|
138
|
+
const container = (await docker.getContainer(id).inspect());
|
|
139
|
+
const image = (await docker.getImage(container.Image ?? '').inspect());
|
|
140
|
+
return { ok: true, ...buildRunCommand(container, image) };
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
return { ok: false, problem: (0, docker_client_1.readableError)(err, (0, docker_client_1.getConnection)().endpoint).message };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=run-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-command.js","sourceRoot":"","sources":["../electron/run-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toCreateOptions = toCreateOptions;
|
|
4
|
+
exports.describeRunProblem = describeRunProblem;
|
|
5
|
+
exports.runContainer = runContainer;
|
|
6
|
+
const containers_1 = require("./containers");
|
|
7
|
+
const docker_client_1 = require("./docker-client");
|
|
8
|
+
const i18n_1 = require("./i18n");
|
|
9
|
+
const port_conflicts_1 = require("./port-conflicts");
|
|
10
|
+
/**
|
|
11
|
+
* Zet het formulier om in de body die de Engine API verwacht.
|
|
12
|
+
*
|
|
13
|
+
* Apart en geëxporteerd omdat hier de vertaalslagen zitten die je makkelijk verkeerd doet:
|
|
14
|
+
* een poort heet in `ExposedPorts` en `PortBindings` `80/tcp` en niet `80`, een lege hostpoort
|
|
15
|
+
* betekent "kies maar een vrije" en niet "publiceer niet", een mount is één string met
|
|
16
|
+
* dubbele punten in plaats van een object, en een alias hangt niet aan de container maar aan
|
|
17
|
+
* het netwerk waar hij aan gekoppeld wordt.
|
|
18
|
+
*/
|
|
19
|
+
function toCreateOptions(options) {
|
|
20
|
+
const exposed = {};
|
|
21
|
+
const bindings = {};
|
|
22
|
+
for (const port of options.ports) {
|
|
23
|
+
const key = `${String(port.containerPort)}/${port.protocol}`;
|
|
24
|
+
exposed[key] = {};
|
|
25
|
+
// Een lege hostpoort laat Docker zelf een vrije poort kiezen; dat is iets anders dan de
|
|
26
|
+
// poort niet publiceren, want dan zou hij hier helemaal niet mogen staan.
|
|
27
|
+
bindings[key] = [{ HostPort: port.hostPort === null ? '' : String(port.hostPort) }];
|
|
28
|
+
}
|
|
29
|
+
const binds = options.volumes.map((volume) => volume.readOnly ? `${volume.source}:${volume.target}:ro` : `${volume.source}:${volume.target}`);
|
|
30
|
+
const create = {
|
|
31
|
+
Image: options.image,
|
|
32
|
+
Env: options.env.map((item) => `${item.key}=${item.value}`),
|
|
33
|
+
ExposedPorts: exposed,
|
|
34
|
+
HostConfig: { PortBindings: bindings, Binds: binds, RestartPolicy: { Name: options.restart } },
|
|
35
|
+
};
|
|
36
|
+
// Geen naam meesturen betekent dat Docker er zelf een verzint; een lege string zou hij
|
|
37
|
+
// afwijzen.
|
|
38
|
+
if (options.name !== null && options.name !== '') {
|
|
39
|
+
create.name = options.name;
|
|
40
|
+
}
|
|
41
|
+
if (options.network !== null && options.network !== '') {
|
|
42
|
+
create.HostConfig = { ...create.HostConfig, NetworkMode: options.network };
|
|
43
|
+
// De alias hoort bij de koppeling aan dít netwerk, dus onder `EndpointsConfig` met de
|
|
44
|
+
// netwerknaam als sleutel. Onder een andere sleutel dan `NetworkMode` doet de daemon er
|
|
45
|
+
// niets mee, zonder te klagen.
|
|
46
|
+
if (options.networkAlias !== null && options.networkAlias !== '') {
|
|
47
|
+
create.NetworkingConfig = { EndpointsConfig: { [options.network]: { Aliases: [options.networkAlias] } } };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return create;
|
|
51
|
+
}
|
|
52
|
+
function describeError(err) {
|
|
53
|
+
return err instanceof Error ? err.message : String(err);
|
|
54
|
+
}
|
|
55
|
+
/** Vertaalt een mislukte start naar iets waar je wat aan hebt. */
|
|
56
|
+
function describeRunProblem(err, options) {
|
|
57
|
+
const status = err?.statusCode;
|
|
58
|
+
const text = describeError(err).toLowerCase();
|
|
59
|
+
// Ook een verdwenen netwerk komt als 404, dus eerst op de tekst kijken: anders zou de
|
|
60
|
+
// melding zeggen dat de image weg is terwijl die er gewoon is.
|
|
61
|
+
if (status === 404 && text.includes('network')) {
|
|
62
|
+
return (0, i18n_1.t)({
|
|
63
|
+
en: `Network '${options.network ?? ''}' no longer exists. Pick another one.`,
|
|
64
|
+
nl: `Netwerk '${options.network ?? ''}' bestaat niet meer. Kies een ander.`,
|
|
65
|
+
de: `Netzwerk '${options.network ?? ''}' existiert nicht mehr. Nehmen Sie ein anderes.`,
|
|
66
|
+
fr: `Le réseau '${options.network ?? ''}' n’existe plus. Choisissez-en un autre.`,
|
|
67
|
+
es: `La red '${options.network ?? ''}' ya no existe. Elige otra.`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (text.includes('user defined network')) {
|
|
71
|
+
return (0, i18n_1.t)({
|
|
72
|
+
en: `An alias only works on a network you made yourself, not on '${options.network ?? ''}'.`,
|
|
73
|
+
nl: `Een alias werkt alleen op een netwerk dat je zelf gemaakt hebt, niet op '${options.network ?? ''}'.`,
|
|
74
|
+
de: `Ein Alias funktioniert nur in einem selbst angelegten Netzwerk, nicht in '${options.network ?? ''}'.`,
|
|
75
|
+
fr: `Un alias ne fonctionne que sur un réseau que vous avez créé vous-même, pas sur '${options.network ?? ''}'.`,
|
|
76
|
+
es: `Un alias solo funciona en una red que hayas creado tú, no en '${options.network ?? ''}'.`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (status === 404) {
|
|
80
|
+
return (0, i18n_1.t)({
|
|
81
|
+
en: `Image '${options.image}' is gone. Pull it again.`,
|
|
82
|
+
nl: `Image '${options.image}' is er niet meer. Haal hem opnieuw op.`,
|
|
83
|
+
de: `Image '${options.image}' ist weg. Holen Sie es erneut.`,
|
|
84
|
+
fr: `L’image '${options.image}' a disparu. Retéléchargez-la.`,
|
|
85
|
+
es: `La image '${options.image}' ya no está. Vuelve a descargarla.`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (status === 409 || text.includes('already in use')) {
|
|
89
|
+
return (0, i18n_1.t)({
|
|
90
|
+
en: `The name '${options.name ?? ''}' is already in use by another container.`,
|
|
91
|
+
nl: `De naam '${options.name ?? ''}' is al in gebruik door een andere container.`,
|
|
92
|
+
de: `Der Name '${options.name ?? ''}' wird schon von einem anderen Container benutzt.`,
|
|
93
|
+
fr: `Le nom '${options.name ?? ''}' est déjà utilisé par un autre conteneur.`,
|
|
94
|
+
es: `El nombre '${options.name ?? ''}' ya lo usa otro contenedor.`,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// Deze komt als 500, dus op de tekst en niet op de code.
|
|
98
|
+
if (text.includes('port is already allocated') || text.includes('address already in use')) {
|
|
99
|
+
return (0, i18n_1.t)({
|
|
100
|
+
en: 'One of the host ports is already taken. Choose another, or stop whatever is listening on it now.',
|
|
101
|
+
nl: 'Een van de hostpoorten is al bezet. Kies een andere, of stop wat er nu op luistert.',
|
|
102
|
+
de: 'Einer der Host-Ports ist schon belegt. Nehmen Sie einen anderen, oder stoppen Sie, was gerade darauf lauscht.',
|
|
103
|
+
fr: 'L’un des ports hôtes est déjà pris. Choisissez-en un autre, ou arrêtez ce qui écoute dessus en ce moment.',
|
|
104
|
+
es: 'Uno de los puertos del host ya está ocupado. Elige otro, o detén lo que esté escuchando ahí ahora.',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (text.includes('invalid mount') || text.includes('bind source path does not exist')) {
|
|
108
|
+
return (0, i18n_1.t)({
|
|
109
|
+
en: 'One of the volumes is wrong: the source path does not exist, or the target path is not an absolute path in the container.',
|
|
110
|
+
nl: 'Een van de volumes klopt niet: het bronpad bestaat niet, of het doelpad is geen absoluut pad in de container.',
|
|
111
|
+
de: 'Eines der Volumes stimmt nicht: den Quellpfad gibt es nicht, oder der Zielpfad ist kein absoluter Pfad im Container.',
|
|
112
|
+
fr: 'L’un des volumes est incorrect : le chemin source n’existe pas, ou le chemin cible n’est pas un chemin absolu dans le conteneur.',
|
|
113
|
+
es: 'Uno de los volumes no es correcto: la ruta de origen no existe, o la ruta de destino no es una ruta absoluta en el contenedor.',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return (0, i18n_1.t)({
|
|
117
|
+
en: `Starting failed: ${describeError(err)}`,
|
|
118
|
+
nl: `Starten mislukte: ${describeError(err)}`,
|
|
119
|
+
de: `Starten fehlgeschlagen: ${describeError(err)}`,
|
|
120
|
+
fr: `Le démarrage a échoué : ${describeError(err)}`,
|
|
121
|
+
es: `El inicio ha fallado: ${describeError(err)}`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Maakt een container van een image en start hem.
|
|
126
|
+
*
|
|
127
|
+
* Twee stappen bij de daemon, maar één handeling voor de gebruiker: een container die wel
|
|
128
|
+
* gemaakt maar niet gestart is, is een restant waar niemand om vroeg. Lukt het starten niet,
|
|
129
|
+
* dan ruimen we hem daarom weer op.
|
|
130
|
+
*/
|
|
131
|
+
async function runContainer(options) {
|
|
132
|
+
const { docker } = (0, docker_client_1.getConnection)();
|
|
133
|
+
let container;
|
|
134
|
+
try {
|
|
135
|
+
container = await docker.createContainer(toCreateOptions(options));
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
return { ok: false, problem: describeRunProblem(err, options) };
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
await container.start();
|
|
142
|
+
return { ok: true, id: container.id };
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
// Docker's eigen tekst erbij: daar staat de poort in, en in onze samenvatting niet.
|
|
146
|
+
const problem = await (0, port_conflicts_1.explainPortConflict)(describeRunProblem(err, options), containers_1.listContainers, { raw: describeError(err) });
|
|
147
|
+
await container.remove({ force: true }).catch(() => undefined);
|
|
148
|
+
return { ok: false, problem };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../electron/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describeUpdateError = describeUpdateError;
|
|
4
|
+
exports.configureSelfUpdate = configureSelfUpdate;
|
|
5
|
+
exports.stopSelfUpdate = stopSelfUpdate;
|
|
6
|
+
exports.readAppUpdate = readAppUpdate;
|
|
7
|
+
exports.checkForAppUpdate = checkForAppUpdate;
|
|
8
|
+
exports.installAppUpdate = installAppUpdate;
|
|
9
|
+
const i18n_1 = require("./i18n");
|
|
10
|
+
/**
|
|
11
|
+
* De app die zichzelf bijwerkt, met electron-updater.
|
|
12
|
+
*
|
|
13
|
+
* De bron is de nieuwste release op Codeberg: `releases/download/latest/` wijst daar altijd
|
|
14
|
+
* naar, en de job `installer` hangt er `latest.yml` naast de installer aan (zie
|
|
15
|
+
* RELEASING.md). electron-updater leest dat bestand, vergelijkt de versie, haalt de installer
|
|
16
|
+
* binnen en controleert de sha512 die erin staat.
|
|
17
|
+
*
|
|
18
|
+
* Alleen de geïnstalleerde app op Windows. De npm-versie wordt door npm bijgewerkt, en de
|
|
19
|
+
* installers voor macOS en Linux bouwt CI niet, dus daar is geen `latest-*.yml`.
|
|
20
|
+
*
|
|
21
|
+
* Binnenhalen gaat vanzelf, installeren niet: de app draait meestal in het systeemvak en wordt
|
|
22
|
+
* zelden afgesloten, en een app die onder je handen herstart is erger dan een die een dag achter
|
|
23
|
+
* loopt. Wie afsluit krijgt de nieuwe versie er stil bij; wie niet wil wachten, klikt op
|
|
24
|
+
* herstarten.
|
|
25
|
+
*/
|
|
26
|
+
/** Het eerste zoeken, even na het starten: niet tegelijk met alles wat de app dan al doet. */
|
|
27
|
+
const FIRST_CHECK_MS = 30_000;
|
|
28
|
+
/** Daarna zo vaak. Er komt hooguit een paar keer per week een release. */
|
|
29
|
+
const CHECK_EVERY_MS = 4 * 60 * 60 * 1000;
|
|
30
|
+
let deps = null;
|
|
31
|
+
let status = { state: 'unavailable' };
|
|
32
|
+
let announced = null;
|
|
33
|
+
let timers = [];
|
|
34
|
+
/**
|
|
35
|
+
* Maakt van een fout van electron-updater één regel. Zijn meldingen bevatten de hele
|
|
36
|
+
* HTTP-respons, en die past niet op de instellingenpagina.
|
|
37
|
+
*/
|
|
38
|
+
function describeUpdateError(err) {
|
|
39
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40
|
+
// Tussen het maken van de release en het aanhangen van de installer (een paar minuten, of
|
|
41
|
+
// langer als die job mislukt) heeft de nieuwste release nog geen latest.yml.
|
|
42
|
+
if (/\b404\b/.test(message)) {
|
|
43
|
+
return (0, i18n_1.t)({
|
|
44
|
+
en: 'The latest release has no installer yet. Try again later.',
|
|
45
|
+
nl: 'De nieuwste release heeft nog geen installer. Probeer het later nog eens.',
|
|
46
|
+
de: 'Die neueste Release hat noch keinen Installer. Versuchen Sie es später noch einmal.',
|
|
47
|
+
fr: 'La dernière release n’a pas encore d’installateur. Réessayez plus tard.',
|
|
48
|
+
es: 'La última release todavía no tiene instalador. Inténtalo más tarde.',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (/ENOTFOUND|EAI_AGAIN|ECONNREFUSED|ETIMEDOUT|ERR_INTERNET_DISCONNECTED|net::/.test(message)) {
|
|
52
|
+
return (0, i18n_1.t)({
|
|
53
|
+
en: 'Codeberg cannot be reached. Are you online?',
|
|
54
|
+
nl: 'Codeberg is niet bereikbaar. Is er internet?',
|
|
55
|
+
de: 'Codeberg ist nicht erreichbar. Sind Sie online?',
|
|
56
|
+
fr: 'Codeberg est injoignable. Êtes-vous en ligne ?',
|
|
57
|
+
es: 'No se puede contactar con Codeberg. ¿Tienes conexión?',
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const first = message.split('\n', 1)[0]?.trim() ?? '';
|
|
61
|
+
return first.length > 160 ? `${first.slice(0, 157)}...` : first;
|
|
62
|
+
}
|
|
63
|
+
function set(next) {
|
|
64
|
+
status = next;
|
|
65
|
+
deps?.changed(readAppUpdate());
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Hangt de luisteraars aan de updater en plant het zoeken. Wordt één keer aangeroepen door
|
|
69
|
+
* main.ts; zonder deze aanroep (de smoke test, een unittest) is alles `unavailable`.
|
|
70
|
+
*/
|
|
71
|
+
function configureSelfUpdate(next) {
|
|
72
|
+
stopSelfUpdate();
|
|
73
|
+
deps = next;
|
|
74
|
+
announced = null;
|
|
75
|
+
const updater = next.updater;
|
|
76
|
+
if (updater === null) {
|
|
77
|
+
status = { state: 'unavailable' };
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
status = { state: 'idle' };
|
|
81
|
+
updater.autoDownload = true;
|
|
82
|
+
updater.autoInstallOnAppQuit = true;
|
|
83
|
+
// Differentieel binnenhalen zoekt de blockmap van de vorige versie onder dezelfde naam als
|
|
84
|
+
// de nieuwe. Met een vaste bestandsnaam en `latest` in het pad is dat altijd de nieuwe, dus
|
|
85
|
+
// halen we gewoon de hele installer.
|
|
86
|
+
updater.disableDifferentialDownload = true;
|
|
87
|
+
updater.on('checking-for-update', () => set({ state: 'checking' }));
|
|
88
|
+
updater.on('update-not-available', () => set({ state: 'upToDate', checkedAt: Date.now() }));
|
|
89
|
+
updater.on('update-available', (info) => set({ state: 'downloading', version: info.version, percent: 0 }));
|
|
90
|
+
updater.on('download-progress', (progress) => {
|
|
91
|
+
if (status.state === 'downloading') {
|
|
92
|
+
set({ ...status, percent: Math.round(progress.percent) });
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
updater.on('update-downloaded', (info) => {
|
|
96
|
+
set({ state: 'ready', version: info.version });
|
|
97
|
+
if (announced !== info.version) {
|
|
98
|
+
announced = info.version;
|
|
99
|
+
next.ready(info.version);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
updater.on('error', (err) => {
|
|
103
|
+
// Een fout na het binnenhalen (bijvoorbeeld bij een volgende zoekronde) laat de klaarstaande
|
|
104
|
+
// versie staan: die is gewoon nog te installeren.
|
|
105
|
+
if (status.state !== 'ready') {
|
|
106
|
+
set({ state: 'error', problem: describeUpdateError(err) });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
const tick = () => {
|
|
110
|
+
if (next.automatic()) {
|
|
111
|
+
void checkForAppUpdate();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
timers = [setTimeout(tick, FIRST_CHECK_MS), setInterval(tick, CHECK_EVERY_MS)];
|
|
115
|
+
for (const timer of timers) {
|
|
116
|
+
timer.unref();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** Stopt het geplande zoeken. Voor de tests, en voor een tweede `configureSelfUpdate`. */
|
|
120
|
+
function stopSelfUpdate() {
|
|
121
|
+
for (const timer of timers) {
|
|
122
|
+
clearTimeout(timer);
|
|
123
|
+
}
|
|
124
|
+
timers = [];
|
|
125
|
+
}
|
|
126
|
+
/** De versie die draait en waar het bijwerken staat. */
|
|
127
|
+
function readAppUpdate() {
|
|
128
|
+
return { current: deps?.currentVersion ?? '', status };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Zoekt nu. Terwijl er al gezocht of binnengehaald wordt, of als er al een versie klaarstaat,
|
|
132
|
+
* doet dit niets: een tweede ronde zou alleen hetzelfde nog een keer binnenhalen.
|
|
133
|
+
*/
|
|
134
|
+
async function checkForAppUpdate() {
|
|
135
|
+
const updater = deps?.updater ?? null;
|
|
136
|
+
if (updater === null || status.state === 'checking' || status.state === 'downloading' || status.state === 'ready') {
|
|
137
|
+
return readAppUpdate();
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
await updater.checkForUpdates();
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
// Meestal meldt de updater het ook via 'error'; dit vangt wat daar niet langskomt. Via
|
|
144
|
+
// readAppUpdate, want tijdens het wachten kan de stand door een event veranderd zijn.
|
|
145
|
+
if (readAppUpdate().status.state !== 'ready') {
|
|
146
|
+
set({ state: 'error', problem: describeUpdateError(err) });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return readAppUpdate();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Installeert de binnengehaalde versie: de app sluit af, de installer draait stil en start de
|
|
153
|
+
* app daarna weer. Zonder klaarstaande versie gebeurt er niets.
|
|
154
|
+
*/
|
|
155
|
+
function installAppUpdate() {
|
|
156
|
+
const updater = deps?.updater ?? null;
|
|
157
|
+
if (updater === null || status.state !== 'ready') {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
deps?.beforeInstall();
|
|
161
|
+
updater.quitAndInstall(true, true);
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=self-update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-update.js","sourceRoot":"","sources":["../electron/self-update.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HostKeyInbox = void 0;
|
|
4
|
+
exports.testServer = testServer;
|
|
5
|
+
const node_os_1 = require("node:os");
|
|
6
|
+
const contexts_1 = require("./contexts");
|
|
7
|
+
const docker_client_1 = require("./docker-client");
|
|
8
|
+
const i18n_1 = require("./i18n");
|
|
9
|
+
const ssh_1 = require("./ssh");
|
|
10
|
+
/**
|
|
11
|
+
* Servers testen en een onbekende hostsleutel vertrouwen, voor de instellingen. Los van ipc.ts
|
|
12
|
+
* zodat het zonder Electron te testen is.
|
|
13
|
+
*/
|
|
14
|
+
/** Een tcp-adres waar niets op antwoordt blijft anders ruim twintig seconden hangen. */
|
|
15
|
+
const TEST_TIMEOUT_MS = 15_000;
|
|
16
|
+
/**
|
|
17
|
+
* De hostsleutels die een test tegenkwam en nog niet vertrouwd zijn. Vertrouwen kan alleen
|
|
18
|
+
* een sleutel die hier staat: de renderer noemt een host en een vingerafdruk, maar de sleutel
|
|
19
|
+
* zelf komt van de server en niet uit de renderer.
|
|
20
|
+
*/
|
|
21
|
+
class HostKeyInbox {
|
|
22
|
+
home;
|
|
23
|
+
pending = new Map();
|
|
24
|
+
constructor(home = (0, node_os_1.homedir)()) {
|
|
25
|
+
this.home = home;
|
|
26
|
+
}
|
|
27
|
+
remember(name, key) {
|
|
28
|
+
this.pending.set(name, key);
|
|
29
|
+
}
|
|
30
|
+
trust(name, shown) {
|
|
31
|
+
const key = this.pending.get(name);
|
|
32
|
+
if (key === undefined || (0, ssh_1.fingerprint)(key) !== shown) {
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
problem: (0, i18n_1.t)({
|
|
36
|
+
en: `There is no host key for ${name} to trust. Test the connection again.`,
|
|
37
|
+
nl: `Er is geen hostsleutel van ${name} om te vertrouwen. Test de verbinding opnieuw.`,
|
|
38
|
+
de: `Es gibt keinen Hostschlüssel für ${name}, dem vertraut werden könnte. Testen Sie die Verbindung noch einmal.`,
|
|
39
|
+
fr: `Il n’y a pas de clé d’hôte pour ${name} à approuver. Testez à nouveau la connexion.`,
|
|
40
|
+
es: `No hay ninguna clave de host de ${name} en la que confiar. Prueba la conexión otra vez.`,
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
(0, ssh_1.appendKnownHost)(name, key, this.home);
|
|
45
|
+
this.pending.delete(name);
|
|
46
|
+
return { ok: true };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.HostKeyInbox = HostKeyInbox;
|
|
50
|
+
function withTimeout(work, endpoint, timeoutMs) {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
const timer = setTimeout(() => {
|
|
53
|
+
reject(Object.assign(new Error((0, i18n_1.t)({
|
|
54
|
+
en: `No answer from ${endpoint}.`,
|
|
55
|
+
nl: `Geen antwoord van ${endpoint}.`,
|
|
56
|
+
de: `Keine Antwort von ${endpoint}.`,
|
|
57
|
+
fr: `Aucune réponse de ${endpoint}.`,
|
|
58
|
+
es: `No hay respuesta de ${endpoint}.`,
|
|
59
|
+
})), { code: 'ETIMEDOUT' }));
|
|
60
|
+
}, timeoutMs);
|
|
61
|
+
work.then((value) => {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
resolve(value);
|
|
64
|
+
}, (err) => {
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Maakt een eigen verbinding, vraagt de versie op en ruimt hem weer op. De verbinding van de
|
|
72
|
+
* app zelf blijft staan: een test hoort niet stilletjes van context te wisselen.
|
|
73
|
+
*/
|
|
74
|
+
async function testServer(host, tlsDir, inbox, connect = docker_client_1.connectionFromHost, timeoutMs = TEST_TIMEOUT_MS) {
|
|
75
|
+
const support = (0, contexts_1.describeSupport)(host);
|
|
76
|
+
if (!support.supported) {
|
|
77
|
+
return { ok: false, problem: support.reason ?? host, unknownHostKey: null };
|
|
78
|
+
}
|
|
79
|
+
let connection;
|
|
80
|
+
try {
|
|
81
|
+
connection = connect(host, tlsDir);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
return { ok: false, problem: err instanceof Error ? err.message : String(err), unknownHostKey: null };
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const version = await withTimeout(connection.docker.version(), connection.endpoint, timeoutMs);
|
|
88
|
+
return { ok: true, version: version.Version, os: version.Os, arch: version.Arch };
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
const denied = (0, ssh_1.deniedHostKey)(err);
|
|
92
|
+
// Alleen een host die we nog niet kennen valt te vertrouwen. Een veranderde sleutel niet:
|
|
93
|
+
// dat hoort iemand met ssh-keygen na te kijken, niet met één klik weg te drukken.
|
|
94
|
+
if (denied?.verdict === 'unknown') {
|
|
95
|
+
inbox.remember(denied.name, denied.key);
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
problem: (0, docker_client_1.readableError)(err, connection.endpoint).message,
|
|
99
|
+
unknownHostKey: { name: denied.name, type: (0, ssh_1.hostKeyType)(denied.key), fingerprint: (0, ssh_1.fingerprint)(denied.key) },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return { ok: false, problem: (0, docker_client_1.readableError)(err, connection.endpoint).message, unknownHostKey: null };
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
connection.close?.();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=servers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"servers.js","sourceRoot":"","sources":["../electron/servers.ts"],"names":[],"mappings":"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"}
|