libdragon 10.8.1 → 10.8.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Docker Libdragon
2
2
 
3
- [![Build](https://github.com/anacierdem/libdragon-docker/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/anacierdem/libdragon-docker/actions/workflows/ci.yml)
3
+ [![Build](https://github.com/anacierdem/libdragon-docker/actions/workflows/release.yml/badge.svg?branch=master)](https://github.com/anacierdem/libdragon-docker/actions/workflows/release.yml)
4
4
 
5
5
  This is a wrapper for a docker container to make managing the libdragon toolchain easier. It has the additional advantage that libdragon toolchain and library can be installed on a per-project basis instead of managing system-wide installations.
6
6
 
@@ -191,7 +191,7 @@ When you are happy with your changes, you can verify you conform to the coding s
191
191
  npm run format-check
192
192
  npm run lint-check
193
193
 
194
- You can auto-fix applicable errors by running `format` and `lint` scripts instead. Additionally, typescript is used as the type system. To be able to get away with transpiling the code during development, jsDoc flavor of types are used instead of inline ones. To check if your types, run:
194
+ You can auto-fix applicable errors by running `format` and `lint` scripts instead. Additionally, typescript is used as the type system. To be able to get away with transpiling the code during development, jsDoc flavor of types are used instead of inline ones. To check your types, run:
195
195
 
196
196
  npm run tsc
197
197
 
@@ -242,11 +242,6 @@ will init the container for this project and run `make && make install` for `ed6
242
242
 
243
243
  This is an experimental dependency management.
244
244
 
245
- ## TODOS
246
-
247
- - [ ] Skip CI checks for irrelevant changes.
248
- - [ ] Verify the NPM dependency mechanism is still working and add a test.
249
-
250
245
  ## Funding
251
246
 
252
247
  If this tool helped you, consider supporting its development by sponsoring it!
package/index.js CHANGED
@@ -18,9 +18,30 @@ const {
18
18
  const { parseParameters } = require('./modules/parameters');
19
19
  const { readProjectInfo, writeProjectInfo } = require('./modules/project-info');
20
20
 
21
+ // Note: it is not possible to merge these type definitions in a single comment
22
+ /**
23
+ * @template {any} [U=any]
24
+ * @typedef {(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never} UnionToIntersection
25
+ */
26
+ /**
27
+ * @template {any} [K=any]
28
+ * never does not break the call `info.options.CURRENT_ACTION.fn`
29
+ * @typedef {[K] extends [UnionToIntersection<K>] ? any : unknown} NoUnion
30
+ * @typedef {NoUnion<Exclude<Parameters<import('./modules/parameters').Actions[import('./modules/project-info').ActionsNoProject]['fn']>[0], undefined>>} EitherCLIOrLibdragonInfo
31
+ */
32
+
21
33
  parseParameters(process.argv)
22
34
  .then(readProjectInfo)
23
- .then((info) => info.options.CURRENT_ACTION.fn(info))
35
+ .then((info) => {
36
+ return info.options.CURRENT_ACTION.fn(
37
+ /** @type {EitherCLIOrLibdragonInfo} */ (info)
38
+ );
39
+ // This type make sure a similar restriction to this code block is enforced
40
+ // without adding unnecessary javascript.
41
+ // return isProjectAction(info)
42
+ // ? info.options.CURRENT_ACTION.fn(info)
43
+ // : info.options.CURRENT_ACTION.fn(info);
44
+ })
24
45
  .catch((e) => {
25
46
  if (e instanceof ParameterError) {
26
47
  log(chalk.red(e.message));
@@ -13,7 +13,7 @@ const {
13
13
  /**
14
14
  * @param {string} stop
15
15
  * @param {string} start
16
- * @return {Promise<string>}
16
+ * @returns {Promise<string>}
17
17
  */
18
18
  const findElf = async (stop, start = '.') => {
19
19
  start = path.resolve(start);
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  *
3
3
  * @param {import('../project-info').LibdragonInfo} libdragonInfo
4
- * @returns
5
4
  */
6
5
  function dockerHostUserParams(libdragonInfo) {
7
6
  const { uid, gid } = libdragonInfo.userInfo;
@@ -8,6 +8,7 @@ const {
8
8
  toPosixPath,
9
9
  fileExists,
10
10
  dirExists,
11
+ CommandError,
11
12
  } = require('../helpers');
12
13
 
13
14
  const { start } = require('./start');
@@ -16,7 +17,6 @@ const { installDependencies } = require('./utils');
16
17
 
17
18
  /**
18
19
  * @param {import('../project-info').LibdragonInfo} libdragonInfo
19
- * @returns
20
20
  */
21
21
  function dockerRelativeWorkdir(libdragonInfo) {
22
22
  return (
@@ -27,18 +27,14 @@ function dockerRelativeWorkdir(libdragonInfo) {
27
27
  }
28
28
 
29
29
  /**
30
- *
31
30
  * @param {import('../project-info').LibdragonInfo} libdragonInfo
32
- * @returns
33
31
  */
34
32
  function dockerRelativeWorkdirParams(libdragonInfo) {
35
33
  return ['--workdir', dockerRelativeWorkdir(libdragonInfo)];
36
34
  }
37
35
 
38
36
  /**
39
- *
40
37
  * @param {import('../project-info').LibdragonInfo} info
41
- * @returns
42
38
  */
43
39
  const exec = async (info) => {
44
40
  const parameters = info.options.EXTRA_PARAMS.slice(1);
@@ -52,17 +48,22 @@ const exec = async (info) => {
52
48
  const stdin = new PassThrough();
53
49
 
54
50
  /** @type {string[]} */
55
- const paramsWithConvertedPaths = parameters.map((item) => {
56
- if (item.startsWith('-')) {
51
+ const paramsWithConvertedPaths = await Promise.all(
52
+ parameters.map(async (item) => {
53
+ if (item.startsWith('-')) {
54
+ return item;
55
+ }
56
+ if (
57
+ item.includes(path.sep) &&
58
+ ((await fileExists(item)) || (await dirExists(item)))
59
+ ) {
60
+ return toPosixPath(
61
+ path.isAbsolute(item) ? path.relative(process.cwd(), item) : item
62
+ );
63
+ }
57
64
  return item;
58
- }
59
- if (item.includes(path.sep) && (fileExists(item) || dirExists(item))) {
60
- return toPosixPath(
61
- path.isAbsolute(item) ? path.relative(process.cwd(), item) : item
62
- );
63
- }
64
- return item;
65
- });
65
+ })
66
+ );
66
67
 
67
68
  /**
68
69
  *
@@ -101,9 +102,7 @@ const exec = async (info) => {
101
102
 
102
103
  let started = false;
103
104
  /**
104
- *
105
105
  * @param {import('fs').ReadStream=} stdin
106
- * @returns
107
106
  */
108
107
  const startOnceAndCmd = async (stdin) => {
109
108
  if (!started) {
@@ -147,14 +146,16 @@ const exec = async (info) => {
147
146
  // In the first run, pass the stdin to the process if it is not a TTY
148
147
  // o/w we loose a user input unnecesarily somehow.
149
148
  stdin:
150
- !process.stdin.isTTY &&
149
+ (!process.stdin.isTTY || undefined) &&
151
150
  /** @type {import('fs').ReadStream} */ (
152
151
  /** @type {unknown} */ (process.stdin)
153
152
  ),
154
153
  });
155
154
  } catch (e) {
155
+ if (!(e instanceof CommandError)) {
156
+ throw e;
157
+ }
156
158
  if (
157
- !e.out ||
158
159
  // TODO: is there a better way?
159
160
  !e.out.toString().includes(info.containerId)
160
161
  ) {
@@ -30,7 +30,7 @@ const { syncImageAndStart } = require('./update-and-start');
30
30
 
31
31
  /**
32
32
  * @param {import('../project-info').LibdragonInfo} info
33
- * @return {Promise<"submodule" | "subtree" | undefined>}
33
+ * @returns {Promise<"submodule" | "subtree" | undefined>}
34
34
  */
35
35
  const autoDetect = async (info) => {
36
36
  const vendorTarget = path.relative(
@@ -188,6 +188,8 @@ const autoVendor = async (info) => {
188
188
  ]);
189
189
  return info;
190
190
  }
191
+
192
+ return info;
191
193
  };
192
194
 
193
195
  /**
@@ -242,7 +244,9 @@ async function init(info) {
242
244
  info.containerId = await start(info);
243
245
 
244
246
  // We have created a new container, save the new info ASAP
245
- await initGitAndCacheContainerId(info);
247
+ await initGitAndCacheContainerId(
248
+ /** @type Parameters<initGitAndCacheContainerId>[0] */ (info)
249
+ );
246
250
 
247
251
  info = await autoVendor(info);
248
252
 
@@ -55,59 +55,61 @@ const installNPMDependencies = async (libdragonInfo) => {
55
55
 
56
56
  await Promise.all(
57
57
  deps.map(({ name, paths }) => {
58
- return new Promise((resolve, reject) => {
59
- fsClassic.access(
60
- path.join(paths[0], 'Makefile'),
61
- fsClassic.constants.F_OK,
62
- async (e) => {
63
- if (e) {
64
- // File does not exist - skip
65
- resolve();
66
- return;
67
- }
58
+ return /** @type Promise<void> */ (
59
+ new Promise((resolve, reject) => {
60
+ fsClassic.access(
61
+ path.join(paths[0], 'Makefile'),
62
+ fsClassic.constants.F_OK,
63
+ async (e) => {
64
+ if (e) {
65
+ // File does not exist - skip
66
+ resolve();
67
+ return;
68
+ }
68
69
 
69
- if (paths.length > 1) {
70
- reject(
71
- new ValidationError(
72
- `Using same dependency with different versions is not supported! ${name}`
73
- )
74
- );
75
- return;
76
- }
70
+ if (paths.length > 1) {
71
+ reject(
72
+ new ValidationError(
73
+ `Using same dependency with different versions is not supported! ${name}`
74
+ )
75
+ );
76
+ return;
77
+ }
77
78
 
78
- try {
79
- const relativePath = toPosixPath(
80
- path.relative(libdragonInfo.root, paths[0])
81
- );
82
- const containerPath = path.posix.join(
83
- CONTAINER_TARGET_PATH,
84
- relativePath
85
- );
86
- const makePath = path.posix.join(containerPath, 'Makefile');
79
+ try {
80
+ const relativePath = toPosixPath(
81
+ path.relative(libdragonInfo.root, paths[0])
82
+ );
83
+ const containerPath = path.posix.join(
84
+ CONTAINER_TARGET_PATH,
85
+ relativePath
86
+ );
87
+ const makePath = path.posix.join(containerPath, 'Makefile');
87
88
 
88
- await dockerExec(
89
- libdragonInfo,
90
- [...dockerHostUserParams(libdragonInfo)],
91
- [
92
- '/bin/bash',
93
- '-c',
94
- '[ -f ' +
95
- makePath +
96
- ' ] && make -C ' +
97
- containerPath +
98
- ' && make -C ' +
99
- containerPath +
100
- ' install',
101
- ]
102
- );
89
+ await dockerExec(
90
+ libdragonInfo,
91
+ [...dockerHostUserParams(libdragonInfo)],
92
+ [
93
+ '/bin/bash',
94
+ '-c',
95
+ '[ -f ' +
96
+ makePath +
97
+ ' ] && make -C ' +
98
+ containerPath +
99
+ ' && make -C ' +
100
+ containerPath +
101
+ ' install',
102
+ ]
103
+ );
103
104
 
104
- resolve();
105
- } catch (e) {
106
- reject(e);
105
+ resolve();
106
+ } catch (e) {
107
+ reject(e);
108
+ }
107
109
  }
108
- }
109
- );
110
- });
110
+ );
111
+ })
112
+ );
111
113
  })
112
114
  );
113
115
  }
@@ -4,6 +4,7 @@ const { checkContainerRunning } = require('./utils');
4
4
 
5
5
  /**
6
6
  * @param {import('../project-info').LibdragonInfo} libdragonInfo
7
+ * @returns {Promise<import('../project-info').LibdragonInfo | void>}
7
8
  */
8
9
  const stop = async (libdragonInfo) => {
9
10
  const running =
@@ -121,7 +121,6 @@ const destroyContainer = async (libdragonInfo) => {
121
121
  * @param {import('../project-info').LibdragonInfo} libdragonInfo
122
122
  * @param {string[]} params
123
123
  * @param {import('../helpers').SpawnOptions} options
124
- * @returns
125
124
  */
126
125
  async function runGitMaybeHost(libdragonInfo, params, options = {}) {
127
126
  assert(
@@ -201,7 +200,7 @@ async function checkContainerRunning(containerId) {
201
200
  }
202
201
 
203
202
  /**
204
- * @param {import('../project-info').LibdragonInfo} libdragonInfo
203
+ * @param {import('../project-info').LibdragonInfo & {containerId: string}} libdragonInfo
205
204
  */
206
205
  async function initGitAndCacheContainerId(libdragonInfo) {
207
206
  // If there is managed vendoring, make sure we have a git repo. `git init` is
@@ -11,6 +11,11 @@ module.exports = /** @type {const} */ ({
11
11
 
12
12
  ACCEPTED_STRATEGIES: ['submodule', 'subtree', 'manual'],
13
13
 
14
+ // These do not need a project to exist and their actions do not need the whole
15
+ // structure. Actions that need the full project information should not be
16
+ // listed here.
17
+ NO_PROJECT_ACTIONS: ['help', 'version'],
18
+
14
19
  // cli exit codes
15
20
  STATUS_OK: 0,
16
21
  STATUS_ERROR: 1,
@@ -5,6 +5,7 @@ const chalk = require('chalk').stderr;
5
5
  const { spawn } = require('child_process');
6
6
 
7
7
  const { globals } = require('./globals');
8
+ const { NO_PROJECT_ACTIONS } = require('./constants');
8
9
 
9
10
  /**
10
11
  * A structure to keep additional error information
@@ -197,26 +198,26 @@ function spawnProcess(
197
198
  resolve('');
198
199
  };
199
200
 
200
- if (!enableInTTY && stdin) {
201
+ if (!enableInTTY && stdin && command.stdin) {
201
202
  stdin.pipe(command.stdin);
202
203
  }
203
204
 
204
- if (!enableOutTTY && (globals.verbose || userCommand)) {
205
+ if (!enableOutTTY && (globals.verbose || userCommand) && command.stdout) {
205
206
  command.stdout.pipe(process.stdout);
206
207
  process.stdout.once('error', eatEpipe);
207
208
  }
208
209
 
209
- if (!inheritStdout) {
210
+ if (!inheritStdout && command.stdout) {
210
211
  command.stdout.on('data', function (data) {
211
212
  stdout.push(Buffer.from(data));
212
213
  });
213
214
  }
214
215
 
215
- if (!enableErrorTTY && (globals.verbose || userCommand)) {
216
+ if (!enableErrorTTY && (globals.verbose || userCommand) && command.stderr) {
216
217
  command.stderr.pipe(process.stderr);
217
218
  }
218
219
 
219
- if (!inheritStderr) {
220
+ if (!inheritStderr && command.stderr) {
220
221
  command.stderr.on('data', function (data) {
221
222
  stderr.push(Buffer.from(data));
222
223
  });
@@ -264,58 +265,60 @@ function spawnProcess(
264
265
  * (libdragonInfo: import('./project-info').LibdragonInfo, cmdWithParams: string[], options?: SpawnOptions, unused?: unknown): Promise<string>;
265
266
  * }} DockerExec
266
267
  */
267
- const dockerExec = /** @type {DockerExec} */ function (
268
- libdragonInfo,
269
- dockerParams,
270
- cmdWithParams,
271
- /** @type {SpawnOptions} */
272
- options
273
- ) {
274
- assert(
275
- !!libdragonInfo.containerId,
276
- new Error('Trying to invoke dockerExec without a containerId.')
277
- );
268
+ const dockerExec = /** @type {DockerExec} */ (
269
+ function (
270
+ libdragonInfo,
271
+ dockerParams,
272
+ cmdWithParams,
273
+ /** @type {SpawnOptions | undefined} */
274
+ options
275
+ ) {
276
+ assert(
277
+ !!libdragonInfo.containerId,
278
+ new Error('Trying to invoke dockerExec without a containerId.')
279
+ );
280
+
281
+ // TODO: assert for invalid args
282
+ const haveDockerParams =
283
+ Array.isArray(dockerParams) && Array.isArray(cmdWithParams);
284
+
285
+ if (!haveDockerParams) {
286
+ options = /** @type {SpawnOptions} */ (cmdWithParams);
287
+ }
278
288
 
279
- // TODO: assert for invalid args
280
- const haveDockerParams =
281
- Array.isArray(dockerParams) && Array.isArray(cmdWithParams);
289
+ const additionalParams = [];
282
290
 
283
- if (!haveDockerParams) {
284
- options = /** @type {SpawnOptions} */ (cmdWithParams);
285
- }
291
+ // Docker TTY wants in & out streams both to be a TTY
292
+ // If no options are provided, disable TTY as spawnProcess defaults to no
293
+ // inherit as well.
294
+ const enableTTY = options
295
+ ? options.inheritStdout && options.inheritStdin
296
+ : false;
297
+ const ttyEnabled = enableTTY && process.stdout.isTTY && process.stdin.isTTY;
286
298
 
287
- const additionalParams = [];
288
-
289
- // Docker TTY wants in & out streams both to be a TTY
290
- // If no options are provided, disable TTY as spawnProcess defaults to no
291
- // inherit as well.
292
- const enableTTY = options
293
- ? options.inheritStdout && options.inheritStdin
294
- : false;
295
- const ttyEnabled = enableTTY && process.stdout.isTTY && process.stdin.isTTY;
299
+ if (ttyEnabled) {
300
+ additionalParams.push('-t');
301
+ }
296
302
 
297
- if (ttyEnabled) {
298
- additionalParams.push('-t');
303
+ // Always enable stdin, also see; https://github.com/anacierdem/libdragon-docker/issues/45
304
+ // Currently we run all exec commands in stdin mode even if the actual process
305
+ // does not need any input. This will eat any user input by default.
306
+ additionalParams.push('-i');
307
+
308
+ return spawnProcess(
309
+ 'docker',
310
+ [
311
+ 'exec',
312
+ ...(haveDockerParams
313
+ ? [...dockerParams, ...additionalParams]
314
+ : additionalParams),
315
+ libdragonInfo.containerId,
316
+ ...(haveDockerParams ? cmdWithParams : dockerParams),
317
+ ],
318
+ options
319
+ );
299
320
  }
300
-
301
- // Always enable stdin, also see; https://github.com/anacierdem/libdragon-docker/issues/45
302
- // Currently we run all exec commands in stdin mode even if the actual process
303
- // does not need any input. This will eat any user input by default.
304
- additionalParams.push('-i');
305
-
306
- return spawnProcess(
307
- 'docker',
308
- [
309
- 'exec',
310
- ...(haveDockerParams
311
- ? [...dockerParams, ...additionalParams]
312
- : additionalParams),
313
- libdragonInfo.containerId,
314
- ...(haveDockerParams ? cmdWithParams : dockerParams),
315
- ],
316
- options
317
- );
318
- };
321
+ );
319
322
 
320
323
  /**
321
324
  * Recursively copies directories and files
@@ -386,8 +389,9 @@ function toNativePath(p) {
386
389
  }
387
390
 
388
391
  /**
389
- * @param {boolean} condition
392
+ * @param {any} condition
390
393
  * @param {Error} error
394
+ * @returns {asserts condition}
391
395
  */
392
396
  function assert(condition, error) {
393
397
  if (!condition) {
@@ -422,6 +426,18 @@ function log(text, verboseOnly = false) {
422
426
  }
423
427
  }
424
428
 
429
+ /**
430
+ * @param {import('./project-info').CLIInfo | import('./project-info').LibdragonInfo} info
431
+ * @returns {info is import('./project-info').LibdragonInfo}
432
+ */
433
+ function isProjectAction(info) {
434
+ return !NO_PROJECT_ACTIONS.includes(
435
+ /** @type {import('./project-info').ActionsNoProject} */ (
436
+ info.options.CURRENT_ACTION.name
437
+ )
438
+ );
439
+ }
440
+
425
441
  module.exports = {
426
442
  spawnProcess,
427
443
  toPosixPath,
@@ -436,4 +452,5 @@ module.exports = {
436
452
  CommandError,
437
453
  ParameterError,
438
454
  ValidationError,
455
+ isProjectAction,
439
456
  };
@@ -26,7 +26,7 @@ const { globals } = require('./globals');
26
26
  * @param {string[]} argv
27
27
  */
28
28
  const parseParameters = async (argv) => {
29
- /** @type CommandlineOptions */
29
+ /** @type Partial<CommandlineOptions> & {EXTRA_PARAMS: string[] } */
30
30
  const options = {
31
31
  EXTRA_PARAMS: [],
32
32
  CURRENT_ACTION: undefined,
@@ -143,7 +143,7 @@ const parseParameters = async (argv) => {
143
143
  process.exit(STATUS_BAD_PARAM);
144
144
  }
145
145
 
146
- return { options };
146
+ return { options: /** @type CommandlineOptions */ (options) };
147
147
  };
148
148
 
149
149
  module.exports = {
@@ -27,37 +27,41 @@ const {
27
27
  toPosixPath,
28
28
  assert,
29
29
  ParameterError,
30
+ isProjectAction,
30
31
  } = require('./helpers');
31
32
 
32
- // These do not need a project to exist.
33
- const NO_PROJECT_ACTIONS = /** @type {const} */ (['help', 'version']);
34
-
35
33
  /**
36
- * @typedef { typeof NO_PROJECT_ACTIONS[number] } ActionsNoProject
34
+ * @typedef { typeof import('./constants').NO_PROJECT_ACTIONS[number] } ActionsNoProject
37
35
  * @typedef { Exclude<keyof import('./parameters').Actions, ActionsNoProject> } ActionsWithProject
38
36
  * @typedef { import('./parameters').CommandlineOptions<ActionsNoProject> } ActionsNoProjectOptions
39
37
  * @typedef { import('./parameters').CommandlineOptions<ActionsWithProject> } ActionsWithProjectOptions
40
38
  *
39
+ * This is all the potential CLI combinations
41
40
  * @typedef { {
42
- * options: ActionsNoProjectOptions
41
+ * options: import('./parameters').CommandlineOptions
43
42
  * } } CLIInfo
44
43
  *
44
+ * Then readProjectInfo creates two possible set of outputs. One is for actions
45
+ * that don't need a project and one with project. This setup forces the actions
46
+ * to not use detailed information if they are listed in NO_PROJECT_ACTIONS
47
+ * @typedef { {
48
+ * options: ActionsNoProjectOptions
49
+ * } } NoProjectInfo
50
+ *
45
51
  * @typedef { {
52
+ * options: ActionsWithProjectOptions
46
53
  * root: string;
47
54
  * userInfo: os.UserInfo<string>;
48
55
  * haveProjectConfig: boolean;
49
56
  * imageName: string;
50
57
  * vendorDirectory: string;
51
58
  * vendorStrategy: import('./parameters').VendorStrategy;
52
- * containerId: string
53
- * } } ExtendedInfo
54
- *
55
- * @typedef { CLIInfo & Partial<ExtendedInfo> } LibdragonInfo
59
+ * containerId?: string
60
+ * } } LibdragonInfo
56
61
  */
57
62
 
58
63
  /**
59
64
  * @param {LibdragonInfo} libdragonInfo
60
- * @returns string
61
65
  */
62
66
  async function findContainerId(libdragonInfo) {
63
67
  const idFile = path.join(libdragonInfo.root, '.git', CACHED_CONTAINER_FILE);
@@ -109,7 +113,7 @@ async function findContainerId(libdragonInfo) {
109
113
  /**
110
114
  * @param {string} start
111
115
  * @param {string} relativeFile
112
- * @return {Promise<string>}
116
+ * @returns {Promise<string | undefined>}
113
117
  */
114
118
  async function findLibdragonRoot(
115
119
  start = '.',
@@ -139,18 +143,15 @@ async function findGitRoot() {
139
143
  }
140
144
 
141
145
  /**
142
- * @param {LibdragonInfo} optionInfo
146
+ * @param {CLIInfo} optionInfo
147
+ * @returns {Promise<LibdragonInfo | NoProjectInfo>}
143
148
  */
144
149
  const readProjectInfo = async function (optionInfo) {
145
150
  // No need to do anything here if the action does not depend on the project
146
151
  // The only exception is the init and destroy actions, which do not need an
147
152
  // existing project but readProjectInfo must always run to analyze the situation
148
- if (
149
- NO_PROJECT_ACTIONS.includes(
150
- /** @type {ActionsNoProject} */ (optionInfo.options.CURRENT_ACTION.name)
151
- )
152
- ) {
153
- return /** @type {CLIInfo} */ (optionInfo);
153
+ if (!isProjectAction(optionInfo)) {
154
+ return /** @type {NoProjectInfo} */ (optionInfo);
154
155
  }
155
156
 
156
157
  const migratedRoot = await findLibdragonRoot();
@@ -173,10 +174,16 @@ const readProjectInfo = async function (optionInfo) {
173
174
  );
174
175
  }
175
176
 
177
+ const foundRoot =
178
+ projectRoot ?? (await findNPMRoot()) ?? (await findGitRoot());
179
+ if (!foundRoot) {
180
+ log('Could not find project root, set as cwd.', true);
181
+ }
182
+
176
183
  /** @type {LibdragonInfo} */
177
184
  let info = {
178
185
  ...optionInfo,
179
- root: projectRoot ?? (await findNPMRoot()) ?? (await findGitRoot()),
186
+ root: foundRoot ?? process.cwd(),
180
187
  userInfo: os.userInfo(),
181
188
 
182
189
  // Use this to discriminate if there is a project when the command is run
@@ -190,11 +197,6 @@ const readProjectInfo = async function (optionInfo) {
190
197
  vendorStrategy: DEFAULT_STRATEGY,
191
198
  };
192
199
 
193
- if (!info.root) {
194
- log('Could not find project root, set as cwd.', true);
195
- info.root = process.cwd();
196
- }
197
-
198
200
  log(`Project root: ${info.root}`, true);
199
201
 
200
202
  if (migratedRoot) {
@@ -231,7 +233,11 @@ const readProjectInfo = async function (optionInfo) {
231
233
  // As last option fallback to default value.
232
234
 
233
235
  // If still have the container, read the image name from it
234
- if (!info.imageName && (await checkContainerAndClean(info))) {
236
+ if (
237
+ !info.imageName &&
238
+ info.containerId &&
239
+ (await checkContainerAndClean(info))
240
+ ) {
235
241
  info.imageName = (
236
242
  await spawnProcess('docker', [
237
243
  'container',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libdragon",
3
- "version": "10.8.1",
3
+ "version": "10.8.2",
4
4
  "description": "This is a docker wrapper for libdragon",
5
5
  "main": "index.js",
6
6
  "engines": {