libdragon 11.0.1 → 11.0.3

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.
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs/promises');
2
2
  const path = require('path');
3
3
 
4
- const { destroyContainer } = require('./utils');
4
+ const { destroyContainer } = require('../utils');
5
5
  const { CONFIG_FILE, LIBDRAGON_PROJECT_MANIFEST } = require('../constants');
6
6
  const { fileExists, dirExists, log, ValidationError } = require('../helpers');
7
7
  const chalk = require('chalk');
@@ -13,8 +13,8 @@ const {
13
13
  } = require('../helpers');
14
14
 
15
15
  const { start } = require('./start');
16
- const { dockerHostUserParams } = require('./docker-utils');
17
- const { installDependencies } = require('./utils');
16
+ const { dockerHostUserParams } = require('../docker-utils');
17
+ const { installDependencies } = require('../utils');
18
18
 
19
19
  /**
20
20
  * @param {import('../project-info').LibdragonInfo} libdragonInfo
@@ -10,7 +10,8 @@ const {
10
10
  updateImage,
11
11
  runGitMaybeHost,
12
12
  destroyContainer,
13
- } = require('./utils');
13
+ ensureGit,
14
+ } = require('../utils');
14
15
 
15
16
  const {
16
17
  LIBDRAGON_PROJECT_MANIFEST,
@@ -109,9 +110,8 @@ const autoVendor = async (info) => {
109
110
  }
110
111
 
111
112
  // Container re-init breaks file modes assume there is git for this case.
112
- // TODO: we should remove the unnecessary inits in the future.
113
113
  if (!process.env.DOCKER_CONTAINER) {
114
- await runGitMaybeHost(info, ['init']);
114
+ await ensureGit(info);
115
115
  }
116
116
 
117
117
  // TODO: TS thinks this is already defined
@@ -172,6 +172,8 @@ const autoVendor = async (info) => {
172
172
  // This will throw if git user name/email is not set up. Let's not assume
173
173
  // anything for now. This means subtree is not supported for someone without
174
174
  // git on the host machine.
175
+ // TODO: this is probably creating an unnecessary commit for someone who
176
+ // just created a git repo and knows what they are doing.
175
177
  await runGitMaybeHost(info, [
176
178
  'commit',
177
179
  '--allow-empty',
@@ -262,6 +264,7 @@ async function init(info) {
262
264
  // We have created a new container, save the new info ASAP
263
265
  // When in a container, we should already have git
264
266
  // Re-initing breaks file modes anyways
267
+ // TODO: if this fails, we leave the project in a bad state
265
268
  await initGitAndCacheContainerId(
266
269
  /** @type Parameters<initGitAndCacheContainerId>[0] */ (info)
267
270
  );
@@ -289,7 +292,7 @@ module.exports = /** @type {const} */ ({
289
292
  usage: {
290
293
  name: 'init',
291
294
  summary: 'Create a libdragon project in the current directory.',
292
- description: `Creates a libdragon project in the current directory. Every libdragon project will have its own docker container instance. If you are in a git repository or an NPM project, libdragon will be initialized at their root also marking there with a \`.libdragon\` folder. Do not remove the \`.libdragon\` folder and commit its contents if you are using source control, as it keeps persistent libdragon project information.
295
+ description: `Creates a libdragon project in the current directory. Every libdragon project will have its own docker container instance. If you are in a git repository or an NPM project, libdragon will be initialized at their root also marking there with a \`.libdragon\` folder. When running in a submodule, initializion will take place at that level rather than the superproject. Do not remove the \`.libdragon\` folder and commit its contents if you are using source control, as it keeps persistent libdragon project information.
293
296
 
294
297
  By default, a git repository and a submodule at \`./libdragon\` will be created to automatically update the vendored libdragon files on subsequent \`update\`s. If you intend to opt-out from this feature, see the \`--strategy manual\` flag to provide your self-managed libdragon copy. The default behaviour is intended for users who primarily want to consume libdragon as is.
295
298
 
@@ -1,4 +1,4 @@
1
- const { installDependencies } = require('./utils');
1
+ const { installDependencies } = require('../utils');
2
2
  const { start } = require('./start');
3
3
 
4
4
  /**
@@ -14,7 +14,7 @@ const {
14
14
  checkContainerAndClean,
15
15
  checkContainerRunning,
16
16
  destroyContainer,
17
- } = require('./utils');
17
+ } = require('../utils');
18
18
 
19
19
  /**
20
20
  * Create a new container
@@ -1,6 +1,6 @@
1
1
  const { spawnProcess, ValidationError } = require('../helpers');
2
2
 
3
- const { checkContainerRunning } = require('./utils');
3
+ const { checkContainerRunning } = require('../utils');
4
4
 
5
5
  /**
6
6
  * @param {import('../project-info').LibdragonInfo} libdragonInfo
@@ -5,7 +5,7 @@ const {
5
5
  installDependencies,
6
6
  updateImage,
7
7
  destroyContainer,
8
- } = require('./utils');
8
+ } = require('../utils');
9
9
  const { start } = require('./start');
10
10
 
11
11
  /**
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  *
3
- * @param {import('../project-info').LibdragonInfo} libdragonInfo
3
+ * @param {import('./project-info').LibdragonInfo} libdragonInfo
4
4
  */
5
5
  function dockerHostUserParams(libdragonInfo) {
6
6
  const { uid, gid } = libdragonInfo.userInfo;
@@ -5,14 +5,14 @@ const _ = require('lodash');
5
5
 
6
6
  const { dockerHostUserParams } = require('./docker-utils');
7
7
 
8
- const { CONTAINER_TARGET_PATH } = require('../constants');
8
+ const { CONTAINER_TARGET_PATH } = require('./constants');
9
9
  const {
10
10
  fileExists,
11
11
  toPosixPath,
12
12
  spawnProcess,
13
13
  dockerExec,
14
14
  ValidationError,
15
- } = require('../helpers');
15
+ } = require('./helpers');
16
16
 
17
17
  async function findNPMRoot() {
18
18
  try {
@@ -29,7 +29,7 @@ async function findNPMRoot() {
29
29
 
30
30
  /**
31
31
  * Install other NPM dependencies if this is an NPM project
32
- * @param {import('../project-info').LibdragonInfo} libdragonInfo
32
+ * @param {import('./project-info').LibdragonInfo} libdragonInfo
33
33
  */
34
34
  const installNPMDependencies = async (libdragonInfo) => {
35
35
  const npmRoot = await findNPMRoot();
@@ -5,9 +5,9 @@ const fs = require('fs/promises');
5
5
  const {
6
6
  checkContainerAndClean,
7
7
  initGitAndCacheContainerId,
8
- } = require('./actions/utils');
8
+ } = require('./utils');
9
9
 
10
- const { findNPMRoot } = require('./actions/npm-utils');
10
+ const { findNPMRoot } = require('./npm-utils');
11
11
 
12
12
  const {
13
13
  LIBDRAGON_PROJECT_MANIFEST,
@@ -105,8 +105,7 @@ async function findContainerId(libdragonInfo) {
105
105
  if (longId.length === 64) {
106
106
  // This shouldn't happen but if the user somehow deleted the .git folder
107
107
  // (we don't have the container id file at this point) we can recover the
108
- // project. `git init` is safe anyways and it is not executed if strategy
109
- // is `manual`
108
+ // project. This is safe and it is not executed if strategy is `manual`
110
109
  await initGitAndCacheContainerId({
111
110
  ...libdragonInfo,
112
111
  containerId: longId,
@@ -1,10 +1,7 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs/promises');
3
3
 
4
- const {
5
- CONTAINER_TARGET_PATH,
6
- CACHED_CONTAINER_FILE,
7
- } = require('../constants');
4
+ const { CONTAINER_TARGET_PATH, CACHED_CONTAINER_FILE } = require('./constants');
8
5
 
9
6
  const {
10
7
  fileExists,
@@ -16,13 +13,13 @@ const {
16
13
  CommandError,
17
14
  ValidationError,
18
15
  toNativePath,
19
- } = require('../helpers');
16
+ } = require('./helpers');
20
17
 
21
18
  const { dockerHostUserParams } = require('./docker-utils');
22
19
  const { installNPMDependencies } = require('./npm-utils');
23
20
 
24
21
  /**
25
- * @param {import('../project-info').LibdragonInfo} libdragonInfo
22
+ * @param {import('./project-info').LibdragonInfo} libdragonInfo
26
23
  */
27
24
  const installDependencies = async (libdragonInfo) => {
28
25
  const buildScriptPath = path.join(
@@ -54,7 +51,7 @@ const installDependencies = async (libdragonInfo) => {
54
51
  /**
55
52
  * Downloads the given docker image. Returns false if the local image is the
56
53
  * same, true otherwise.
57
- * @param {import('../project-info').LibdragonInfo} libdragonInfo
54
+ * @param {import('./project-info').LibdragonInfo} libdragonInfo
58
55
  * @param {string} newImageName
59
56
  */
60
57
  const updateImage = async (libdragonInfo, newImageName) => {
@@ -98,7 +95,7 @@ const updateImage = async (libdragonInfo, newImageName) => {
98
95
  };
99
96
 
100
97
  /**
101
- * @param {import('../project-info').LibdragonInfo} libdragonInfo
98
+ * @param {import('./project-info').LibdragonInfo} libdragonInfo
102
99
  */
103
100
  const destroyContainer = async (libdragonInfo) => {
104
101
  assert(
@@ -128,9 +125,9 @@ const destroyContainer = async (libdragonInfo) => {
128
125
 
129
126
  /**
130
127
  *
131
- * @param {import('../project-info').LibdragonInfo} libdragonInfo
128
+ * @param {import('./project-info').LibdragonInfo} libdragonInfo
132
129
  * @param {string[]} params
133
- * @param {import('../helpers').SpawnOptions} options
130
+ * @param {import('./helpers').SpawnOptions} options
134
131
  */
135
132
  async function runGitMaybeHost(libdragonInfo, params, options = {}) {
136
133
  assert(
@@ -139,9 +136,30 @@ async function runGitMaybeHost(libdragonInfo, params, options = {}) {
139
136
  );
140
137
  try {
141
138
  const isWin = /^win/.test(process.platform);
139
+
140
+ // When using host's git the actual top level can be higher in the tree
141
+ // rather that at the root of the project. We need to find it to run some
142
+ // git operations like subtree.
143
+ const gitRoot = (
144
+ await spawnProcess(
145
+ 'git',
146
+ ['-C', libdragonInfo.root, 'rev-parse', '--show-toplevel'],
147
+ { inheritStdin: false }
148
+ ).catch(() => {
149
+ // Either this is not a git repo or the host does not have git
150
+ // We might also screw something up but we can live with it for now
151
+ return '';
152
+ })
153
+ ).trim();
154
+
142
155
  return await spawnProcess(
143
156
  'git',
144
- ['-C', libdragonInfo.root, ...params],
157
+ [
158
+ '-C',
159
+ libdragonInfo.root,
160
+ ...(gitRoot ? ['--git-dir', `${gitRoot}/.git`] : []),
161
+ ...params,
162
+ ],
145
163
  // Windows git is breaking the TTY somehow - disable TTY for now
146
164
  // We are not able to display progress for the initial clone b/c of this
147
165
  // Enable progress otherwise.
@@ -171,7 +189,7 @@ async function runGitMaybeHost(libdragonInfo, params, options = {}) {
171
189
  }
172
190
 
173
191
  /**
174
- * @param {import('../project-info').LibdragonInfo} libdragonInfo
192
+ * @param {import('./project-info').LibdragonInfo} libdragonInfo
175
193
  */
176
194
  async function checkContainerAndClean(libdragonInfo) {
177
195
  assert(
@@ -229,20 +247,31 @@ async function checkContainerRunning(containerId) {
229
247
  }
230
248
 
231
249
  /**
232
- * @param {import('../project-info').LibdragonInfo & {containerId: string}} libdragonInfo
250
+ * @param {import('./project-info').LibdragonInfo & {containerId: string}} libdragonInfo
233
251
  */
234
252
  async function initGitAndCacheContainerId(libdragonInfo) {
235
253
  if (!libdragonInfo.containerId) {
236
254
  return;
237
255
  }
238
256
 
239
- // If there is managed vendoring, make sure we have a git repo. `git init` is
240
- // safe anyways...
257
+ // If there is managed vendoring, make sure we have a git repo.
241
258
  if (libdragonInfo.vendorStrategy !== 'manual') {
242
- await runGitMaybeHost(libdragonInfo, ['init']);
259
+ await ensureGit(libdragonInfo);
243
260
  }
244
261
 
245
- const gitFolder = path.join(libdragonInfo.root, '.git');
262
+ const rootGitFolder = (
263
+ await spawnProcess('git', [
264
+ 'rev-parse',
265
+ '--show-superproject-working-tree',
266
+ ]).catch(() => {
267
+ // Probably host does not have git, can ignore
268
+ return '';
269
+ })
270
+ ).trim();
271
+
272
+ // Fallback to the potential git root on the project root if there is no parent
273
+ // git project.
274
+ const gitFolder = path.join(rootGitFolder || libdragonInfo.root, '.git');
246
275
  if (await dirExists(gitFolder)) {
247
276
  await fs.writeFile(
248
277
  path.join(gitFolder, CACHED_CONTAINER_FILE),
@@ -251,6 +280,29 @@ async function initGitAndCacheContainerId(libdragonInfo) {
251
280
  }
252
281
  }
253
282
 
283
+ /**
284
+ * Makes sure there is a parent git repository. If not, it will create one at
285
+ * project root.
286
+ * @param {import('./project-info').LibdragonInfo} info
287
+ */
288
+ async function ensureGit(info) {
289
+ const gitRoot = (
290
+ await runGitMaybeHost(info, ['rev-parse', '--show-toplevel']).catch(() => {
291
+ // Probably host does not have git, can ignore
292
+ return '';
293
+ })
294
+ ).trim();
295
+
296
+ // If the host does not have git installed, this will not run unless we
297
+ // have already initialized it via the container, in which case we would
298
+ // have it as the git root. This is not expected to mess with host git flows
299
+ // where there is a git working tree higher in the host filesystem, which
300
+ // the container does not have access to.
301
+ if (!gitRoot) {
302
+ await runGitMaybeHost(info, ['init']);
303
+ }
304
+ }
305
+
254
306
  module.exports = {
255
307
  installDependencies,
256
308
  updateImage,
@@ -259,4 +311,5 @@ module.exports = {
259
311
  checkContainerAndClean,
260
312
  initGitAndCacheContainerId,
261
313
  runGitMaybeHost,
314
+ ensureGit,
262
315
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libdragon",
3
- "version": "11.0.1",
3
+ "version": "11.0.3",
4
4
  "description": "This is a docker wrapper for libdragon",
5
5
  "main": "index.js",
6
6
  "engines": {