libdragon 10.2.1 → 10.4.1

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.
@@ -0,0 +1,314 @@
1
+ const path = require('path');
2
+ const fsClassic = require('fs');
3
+ const fs = require('fs/promises');
4
+
5
+ const _ = require('lodash');
6
+
7
+ const {
8
+ CONTAINER_TARGET_PATH,
9
+ CACHED_CONTAINER_FILE,
10
+ } = require('../constants');
11
+
12
+ const {
13
+ fileExists,
14
+ log,
15
+ toPosixPath,
16
+ spawnProcess,
17
+ dockerExec,
18
+ dirExists,
19
+ assert,
20
+ CommandError,
21
+ } = require('../helpers');
22
+
23
+ function dockerHostUserParams(libdragonInfo) {
24
+ const { uid, gid } = libdragonInfo.userInfo;
25
+ return ['-u', `${uid >= 0 ? uid : ''}:${gid >= 0 ? gid : ''}`];
26
+ }
27
+
28
+ async function findNPMRoot() {
29
+ try {
30
+ const root = path.resolve((await runNPM(['root'])).trim(), '..');
31
+ // Only report if package.json really exists. npm fallbacks to cwd
32
+ if (await fileExists(path.join(root, 'package.json'))) {
33
+ return root;
34
+ }
35
+ } catch {
36
+ // User does not have and does not care about NPM if it didn't work
37
+ return undefined;
38
+ }
39
+ }
40
+
41
+ const installDependencies = async (libdragonInfo) => {
42
+ const buildScriptPath = path.join(
43
+ libdragonInfo.root,
44
+ libdragonInfo.vendorDirectory,
45
+ 'build.sh'
46
+ );
47
+ if (!(await fileExists(buildScriptPath))) {
48
+ throw new Error(
49
+ `build.sh not found. Make sure you have a vendored libdragon copy at ${libdragonInfo.vendorDirectory}`
50
+ );
51
+ }
52
+
53
+ libdragonInfo.showStatus && log('Installing libdragon to the container...');
54
+
55
+ await dockerExec(
56
+ libdragonInfo,
57
+ [
58
+ '--workdir',
59
+ CONTAINER_TARGET_PATH +
60
+ '/' +
61
+ toPosixPath(
62
+ path.relative(libdragonInfo.root, libdragonInfo.vendorDirectory)
63
+ ),
64
+ ...dockerHostUserParams(libdragonInfo),
65
+ ],
66
+ ['/bin/bash', './build.sh']
67
+ );
68
+
69
+ // Install other NPM dependencies if this is an NPM project
70
+ const npmRoot = await findNPMRoot();
71
+ if (npmRoot) {
72
+ const packageJsonPath = path.join(npmRoot, 'package.json');
73
+
74
+ const { dependencies, devDependencies } = require(packageJsonPath);
75
+
76
+ const deps = await Promise.all(
77
+ Object.keys({
78
+ ...dependencies,
79
+ ...devDependencies,
80
+ })
81
+ .filter((dep) => dep !== 'libdragon')
82
+ .map(async (dep) => {
83
+ const npmPath = await runNPM(['ls', dep, '--parseable=true']);
84
+ return {
85
+ name: dep,
86
+ paths: _.uniq(npmPath.split('\n').filter((f) => f)),
87
+ };
88
+ })
89
+ );
90
+
91
+ await Promise.all(
92
+ deps.map(({ name, paths }) => {
93
+ return new Promise((resolve, reject) => {
94
+ fsClassic.access(
95
+ path.join(paths[0], 'Makefile'),
96
+ fsClassic.F_OK,
97
+ async (e) => {
98
+ if (e) {
99
+ // File does not exist - skip
100
+ resolve();
101
+ return;
102
+ }
103
+
104
+ if (paths.length > 1) {
105
+ reject(
106
+ new Error(
107
+ `Using same dependency with different versions is not supported! ${name}`
108
+ )
109
+ );
110
+ return;
111
+ }
112
+
113
+ try {
114
+ const relativePath = toPosixPath(
115
+ path.relative(libdragonInfo.root, paths[0])
116
+ );
117
+ const containerPath = path.posix.join(
118
+ CONTAINER_TARGET_PATH,
119
+ relativePath
120
+ );
121
+ const makePath = path.posix.join(containerPath, 'Makefile');
122
+
123
+ await dockerExec(
124
+ libdragonInfo,
125
+ [...dockerHostUserParams(libdragonInfo)],
126
+ [
127
+ '/bin/bash',
128
+ '-c',
129
+ '[ -f ' +
130
+ makePath +
131
+ ' ] && make -C ' +
132
+ containerPath +
133
+ ' && make -C ' +
134
+ containerPath +
135
+ ' install',
136
+ ]
137
+ );
138
+
139
+ resolve();
140
+ } catch (e) {
141
+ reject(e);
142
+ }
143
+ }
144
+ );
145
+ });
146
+ })
147
+ );
148
+ }
149
+ };
150
+
151
+ /**
152
+ * Downloads the given docker image. Returns false if the local image is the
153
+ * same, new image name otherwise.
154
+ * @param libdragonInfo
155
+ * @param newImageName
156
+ * @returns false | string
157
+ */
158
+ const updateImage = async (libdragonInfo, newImageName) => {
159
+ // Will not take too much time if already have the same
160
+ const download = async () => {
161
+ libdragonInfo.showStatus &&
162
+ log(`Downloading docker image: ${newImageName}`);
163
+ await spawnProcess(
164
+ 'docker',
165
+ ['pull', newImageName],
166
+ false,
167
+ libdragonInfo.showStatus
168
+ );
169
+ };
170
+
171
+ const getDigest = async () =>
172
+ await spawnProcess(
173
+ 'docker',
174
+ ['images', '-q', '--no-trunc', newImageName],
175
+ false,
176
+ libdragonInfo.showStatus
177
+ );
178
+
179
+ // Attempt to compare digests if the new image name is the same
180
+ // Even if they are not the same tag, it is possible to have a different
181
+ // image but we already attempt a download in any case. It would just take
182
+ // less time as we already have the layers.
183
+ if (libdragonInfo.imageName === newImageName) {
184
+ const existingDigest = await getDigest();
185
+ await download();
186
+ const newDigest = await getDigest();
187
+
188
+ if (existingDigest === newDigest) {
189
+ libdragonInfo.showStatus && log(`Image is the same: ${newImageName}`);
190
+ return false;
191
+ }
192
+ } else {
193
+ await download();
194
+ }
195
+
196
+ libdragonInfo.showStatus && log(`Image is different: ${newImageName}`);
197
+ return newImageName;
198
+ };
199
+
200
+ const destroyContainer = async (libdragonInfo) => {
201
+ if (libdragonInfo.containerId) {
202
+ await spawnProcess('docker', [
203
+ 'container',
204
+ 'rm',
205
+ libdragonInfo.containerId,
206
+ '--force',
207
+ ]);
208
+ }
209
+
210
+ await checkContainerAndClean({
211
+ ...libdragonInfo,
212
+ containerId: undefined, // We just destroyed it
213
+ });
214
+ };
215
+
216
+ /**
217
+ * Invokes host git with provided params. If host does not have git, falls back
218
+ * to the docker git, with the nix user set to the user running libdragon.
219
+ */
220
+ async function runGitMaybeHost(libdragonInfo, params, interactive = 'full') {
221
+ assert(
222
+ libdragonInfo.vendorStrategy !== 'manual',
223
+ new Error('Should never run git if vendoring strategy is manual.')
224
+ );
225
+ try {
226
+ return await spawnProcess(
227
+ 'git',
228
+ ['-C', libdragonInfo.root, ...params],
229
+ false,
230
+ // Windows git is breaking the TTY somehow - disable interactive for now
231
+ // We are not able to display progress for the initial clone b/c of this
232
+ /^win/.test(process.platform) ? false : interactive
233
+ );
234
+ } catch (e) {
235
+ if (!(e instanceof CommandError)) {
236
+ return await dockerExec(
237
+ libdragonInfo,
238
+ // Use the host user when initializing git as we will need access
239
+ [...dockerHostUserParams(libdragonInfo)],
240
+ ['git', ...params],
241
+ false,
242
+ interactive
243
+ );
244
+ }
245
+ throw e;
246
+ }
247
+ }
248
+
249
+ function runNPM(params) {
250
+ return spawnProcess(
251
+ /^win/.test(process.platform) ? 'npm.cmd' : 'npm',
252
+ params
253
+ );
254
+ }
255
+
256
+ async function checkContainerAndClean(libdragonInfo) {
257
+ const id =
258
+ libdragonInfo.containerId &&
259
+ (
260
+ await spawnProcess('docker', [
261
+ 'container',
262
+ 'ls',
263
+ '-qa',
264
+ '-f id=' + libdragonInfo.containerId,
265
+ ])
266
+ ).trim();
267
+
268
+ // Container does not exist, clean the id up
269
+ if (!id) {
270
+ const containerIdFile = path.join(
271
+ libdragonInfo.root,
272
+ '.git',
273
+ CACHED_CONTAINER_FILE
274
+ );
275
+ if (await fileExists(containerIdFile)) {
276
+ await fs.rm(containerIdFile);
277
+ }
278
+ }
279
+ return id ? libdragonInfo.containerId : undefined;
280
+ }
281
+
282
+ async function checkContainerRunning(containerId) {
283
+ const running = (
284
+ await spawnProcess('docker', [
285
+ 'container',
286
+ 'ls',
287
+ '-q',
288
+ '-f id=' + containerId,
289
+ ])
290
+ ).trim();
291
+ return running ? containerId : undefined;
292
+ }
293
+
294
+ async function tryCacheContainerId(libdragonInfo) {
295
+ const gitFolder = path.join(libdragonInfo.root, '.git');
296
+ if (await dirExists(gitFolder)) {
297
+ await fs.writeFile(
298
+ path.join(gitFolder, CACHED_CONTAINER_FILE),
299
+ libdragonInfo.containerId
300
+ );
301
+ }
302
+ }
303
+
304
+ module.exports = {
305
+ installDependencies,
306
+ updateImage,
307
+ destroyContainer,
308
+ checkContainerRunning,
309
+ checkContainerAndClean,
310
+ dockerHostUserParams,
311
+ tryCacheContainerId,
312
+ runGitMaybeHost,
313
+ findNPMRoot,
314
+ };
@@ -1,13 +1,18 @@
1
1
  module.exports = {
2
2
  DOCKER_HUB_IMAGE: 'ghcr.io/dragonminded/libdragon:latest',
3
- PROJECT_NAME: process.env.npm_package_name,
4
-
5
3
  LIBDRAGON_GIT: 'https://github.com/DragonMinded/libdragon',
6
4
  LIBDRAGON_BRANCH: 'trunk',
7
5
  LIBDRAGON_SUBMODULE: 'libdragon',
8
6
  CONTAINER_TARGET_PATH: '/libdragon',
9
-
10
7
  LIBDRAGON_PROJECT_MANIFEST: '.libdragon',
11
8
  CACHED_CONTAINER_FILE: 'libdragon-docker-container',
12
- IMAGE_FILE: 'docker-image',
9
+ CONFIG_FILE: 'config.json',
10
+ DEFAULT_STRATEGY: 'submodule',
11
+
12
+ // cli exit codes
13
+ STATUS_OK: 0,
14
+ STATUS_ERROR: 1,
15
+ STATUS_BAD_PARAM: 2,
16
+
17
+ IMAGE_FILE: 'docker-image', // deprecated
13
18
  };
@@ -0,0 +1,5 @@
1
+ const globals = {
2
+ verbose: false,
3
+ };
4
+
5
+ module.exports = { globals };