@florianpat/lando-core 3.23.7-compose → 3.23.22-test1

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.
Files changed (96) hide show
  1. package/CHANGELOG.md +101 -1
  2. package/bin/lando +2 -0
  3. package/bin/lando.cmd +3 -0
  4. package/builders/_lando.js +2 -1
  5. package/components/l337-v4.js +2 -2
  6. package/config.yml +3 -2
  7. package/hooks/lando-autostart-engine.js +4 -25
  8. package/hooks/lando-run-setup.js +58 -0
  9. package/hooks/lando-setup-build-engine-darwin.js +13 -12
  10. package/hooks/lando-setup-build-engine-linux.js +14 -4
  11. package/hooks/lando-setup-build-engine-win32.js +27 -20
  12. package/hooks/lando-setup-build-engine-wsl.js +210 -0
  13. package/hooks/lando-setup-check.js +19 -0
  14. package/hooks/lando-setup-create-ca-wsl.js +34 -0
  15. package/hooks/lando-setup-create-ca.js +22 -23
  16. package/hooks/lando-setup-install-ca-darwin.js +5 -1
  17. package/hooks/lando-setup-install-ca-linux.js +4 -1
  18. package/hooks/lando-setup-install-ca-win32.js +5 -1
  19. package/hooks/lando-setup-install-ca-wsl.js +145 -0
  20. package/hooks/lando-setup-orchestrator.js +4 -4
  21. package/index.js +18 -12
  22. package/lib/app.js +2 -2
  23. package/lib/art.js +20 -8
  24. package/lib/compose.js +0 -3
  25. package/lib/daemon.js +79 -76
  26. package/lib/docker.js +2 -2
  27. package/lib/engine.js +10 -3
  28. package/lib/lando.js +2 -2
  29. package/lib/metrics.js +5 -3
  30. package/lib/updates.js +12 -2
  31. package/node_modules/nanoid/.devcontainer.json +23 -0
  32. package/node_modules/nanoid/README.md +517 -2
  33. package/node_modules/nanoid/async/index.browser.cjs +37 -2
  34. package/node_modules/nanoid/async/index.browser.js +37 -2
  35. package/node_modules/nanoid/async/index.cjs +38 -2
  36. package/node_modules/nanoid/async/index.js +38 -2
  37. package/node_modules/nanoid/async/index.native.js +33 -2
  38. package/node_modules/nanoid/index.browser.cjs +39 -1
  39. package/node_modules/nanoid/index.browser.js +39 -1
  40. package/node_modules/nanoid/index.cjs +42 -2
  41. package/node_modules/nanoid/index.js +42 -2
  42. package/node_modules/nanoid/non-secure/index.cjs +15 -2
  43. package/node_modules/nanoid/non-secure/index.js +15 -2
  44. package/node_modules/nanoid/package.json +1 -1
  45. package/node_modules/nanoid/url-alphabet/index.cjs +4 -0
  46. package/node_modules/nanoid/url-alphabet/index.js +4 -0
  47. package/package.json +7 -7
  48. package/plugins/networking/app.js +4 -2
  49. package/plugins/networking/index.js +19 -6
  50. package/plugins/proxy/builders/_proxy.js +1 -2
  51. package/release-aliases/3-EDGE +1 -1
  52. package/release-aliases/3-STABLE +1 -1
  53. package/renderers/dc2.js +2 -1
  54. package/scripts/add-to-group.sh +72 -0
  55. package/scripts/docker-engine-start.sh +15 -1
  56. package/scripts/install-docker-desktop.ps1 +11 -12
  57. package/scripts/install-system-ca-win32.ps1 +14 -14
  58. package/scripts/run-elevated.ps1 +2 -2
  59. package/scripts/semcompare.sh +142 -0
  60. package/scripts/wait-for-user.sh +1 -2
  61. package/tasks/destroy.js +3 -0
  62. package/tasks/info.js +2 -1
  63. package/tasks/init.js +35 -30
  64. package/tasks/rebuild.js +2 -8
  65. package/tasks/restart.js +2 -8
  66. package/tasks/setup.js +2 -2
  67. package/tasks/shellenv.js +2 -2
  68. package/tasks/start.js +2 -8
  69. package/tasks/stop.js +3 -0
  70. package/utils/build-config.js +2 -0
  71. package/utils/build-tooling-runner.js +2 -1
  72. package/utils/get-app.js +1 -1
  73. package/utils/get-bin-paths.js +2 -2
  74. package/utils/get-compose-x.js +1 -1
  75. package/utils/get-config-defaults.js +12 -7
  76. package/utils/get-docker-bin-path.js +6 -2
  77. package/utils/get-docker-desktop-x.js +21 -0
  78. package/utils/get-docker-x.js +3 -2
  79. package/utils/get-shellenv.js +1 -2
  80. package/utils/get-system-cas.js +25 -6
  81. package/utils/get-win32-envvar-from-wsl.js +7 -0
  82. package/utils/is-admin-user.js +9 -8
  83. package/utils/is-group-member.js +14 -7
  84. package/utils/is-wsl-interop.js +17 -4
  85. package/utils/run-elevated.js +9 -0
  86. package/utils/run-powershell-script.js +31 -5
  87. package/utils/run-tasks.js +3 -2
  88. package/utils/setup-metrics.js +10 -1
  89. package/utils/shutdown-os.js +8 -3
  90. package/utils/spawn-sync-stringer.js +1 -0
  91. package/utils/update-shell-profile.js +8 -7
  92. package/utils/validate-ca.js +31 -0
  93. package/utils/winpath-2-wslpath.js +6 -0
  94. package/utils/wslpath-2-winpath.js +6 -0
  95. package/hooks/lando-dep-check.js +0 -26
  96. package/lib/checksums.txt +0 -0
package/tasks/setup.js CHANGED
@@ -67,7 +67,7 @@ module.exports = lando => {
67
67
  // get defaults from the lando config
68
68
  const defaults = lando.config.setup;
69
69
  // determine label for build engine
70
- const buildEngine = process.platform === 'linux' ? 'docker-engine' : 'docker-desktop';
70
+ const buildEngine = process.landoPlatform === 'linux' || process.platform === 'linux' ? 'docker-engine' : 'docker-desktop';
71
71
  // default options
72
72
  const options = {
73
73
  'build-engine': {
@@ -218,7 +218,7 @@ module.exports = lando => {
218
218
 
219
219
  // print table
220
220
  console.log('');
221
- ux.table(sortBy(rows, ['row', 'weight']), columns);
221
+ ux.table(sortBy(rows, ['description', 'weight']), columns);
222
222
  console.log('');
223
223
 
224
224
  // things are good!
package/tasks/shellenv.js CHANGED
@@ -62,7 +62,7 @@ module.exports = lando => {
62
62
  console.log();
63
63
  console.log(color.bold(binPaths.join(os.EOL)));
64
64
  console.log();
65
- console.log(`Open a new shell to load the changes!`);
65
+ console.log(`Start a new terminal session to use ${color.bold(`lando`)}`);
66
66
  return;
67
67
 
68
68
  // otherwise update the shell profile
@@ -72,7 +72,7 @@ module.exports = lando => {
72
72
  console.log();
73
73
  console.log(color.bold(shellEnv.map(line => line[0]).join(os.EOL)));
74
74
  console.log();
75
- console.log(`Open a new shell or run ${color.bold(`source ${options.add}`)} to load the changes`);
75
+ console.log(`Start a new terminal session or run ${color.bold(`eval "$(lando shellenv)"`)} to use ${color.bold(`lando`)}`);
76
76
  } else {
77
77
  console.log(`Looks like ${color.green(options.add)} is already ready to go!`);
78
78
  }
package/tasks/start.js CHANGED
@@ -16,17 +16,11 @@ module.exports = lando => {
16
16
  if (app) {
17
17
  console.log(lando.cli.makeArt('appStart', {name: app.name, phase: 'pre'}));
18
18
 
19
- // run any setup if we need to but without common plugins or build engine
20
- const sopts = lando?.config?.setup;
21
- sopts.buildEngine = false;
22
- sopts.skipCommonPlugins = true;
23
- sopts.yes = true;
24
- const setupTasks = await lando.getSetupStatus(sopts);
19
+ // run setup if we need to
20
+ await require('../hooks/lando-run-setup')(lando);
25
21
 
26
22
  // Normal bootup
27
23
  try {
28
- // run a limited setup if needed
29
- if (setupTasks.length > 0) await lando.setup(sopts);
30
24
  // then start up
31
25
  await app.start();
32
26
  // determine legacy settings
package/tasks/stop.js CHANGED
@@ -10,6 +10,9 @@ module.exports = lando => ({
10
10
  // Stop it if we can!
11
11
  if (app) {
12
12
  console.log(lando.cli.makeArt('appStop', {name: app.name, phase: 'pre'}));
13
+ // run setup if we need to
14
+ await require('../hooks/lando-run-setup')(lando);
15
+ // stop
13
16
  await app.stop();
14
17
  console.log(' ');
15
18
  console.log(lando.cli.makeArt('appStop', {name: app.name, phase: 'post'}));
@@ -67,6 +67,8 @@ module.exports = options => {
67
67
  config.engineConfig = getEngineConfig(config);
68
68
  // Strip all COMPOSE_ envvars
69
69
  config.env = stripEnv('COMPOSE_');
70
+ // Disable docker CLI_HINTS
71
+ config.env.DOCKER_CLI_HINTS = false;
70
72
 
71
73
  // if composeBin is set and orchestratorBin is not set then set one to the other
72
74
  if (config.composeBin && !config.orchestratorBin) config.orchestratorBin = config.composeBin;
@@ -4,7 +4,8 @@ const _ = require('lodash');
4
4
  const path = require('path');
5
5
 
6
6
  const getContainer = (app, service) => {
7
- return app?.containers?.[service] ?? `${app.project}-${service}-1`;
7
+ const separator = _.get(app, '_config.orchestratorSeparator', '_');
8
+ return app?.containers?.[service] ?? `${app.project}${separator}${service}${separator}1`;
8
9
  };
9
10
 
10
11
  const getContainerPath = (appRoot, appMount = undefined) => {
package/utils/get-app.js CHANGED
@@ -24,7 +24,7 @@ module.exports = (files, userConfRoot) => {
24
24
  // cast the name to a string...just to make sure.
25
25
  config.name = require('../utils/slugify')(config.name);
26
26
  // slugify project
27
- config.project = config.name;
27
+ config.project = require('../utils/docker-composify')(config.name);
28
28
 
29
29
  return _.merge({}, config, {
30
30
  configFiles: files,
@@ -3,8 +3,8 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
 
6
- module.exports = ({entrypoint, file, installPath}) => {
7
- return [entrypoint, file, installPath]
6
+ module.exports = ({installPath}) => {
7
+ return [installPath]
8
8
  .filter(p => typeof p === 'string' && p !== '' && fs.existsSync(p))
9
9
  .map(p => !fs.lstatSync(p).isDirectory() ? path.dirname(p) : p)
10
10
  .filter(p => !process.env.PATH.split(path.delimiter).includes(p))
@@ -27,7 +27,7 @@ const getDockerBin = (bin, base, pathFallback = true) => {
27
27
  }
28
28
  };
29
29
 
30
- module.exports = ({orchestratorVersion = '2.29.2', userConfRoot = os.tmpdir()} = {}) => {
30
+ module.exports = ({orchestratorVersion = '2.30.3', userConfRoot = os.tmpdir()} = {}) => {
31
31
  const orchestratorBin = `docker-compose-v${orchestratorVersion}`;
32
32
  switch (process.platform) {
33
33
  case 'darwin':
@@ -5,21 +5,23 @@ const browsers = ['electron', 'chrome', 'atom-shell'];
5
5
  const path = require('path');
6
6
  const os = require('os');
7
7
 
8
- const getBuildEngineVersion = () => {
9
- switch (process.platform) {
8
+ const getBuildEngineVersion = (platform = process.landoPlatform ?? process.platform) => {
9
+ switch (platform) {
10
10
  case 'darwin':
11
- return '4.34.3';
11
+ return '4.36.0';
12
12
  case 'linux':
13
13
  return '27.3.1';
14
14
  case 'win32':
15
- return '4.34.3';
15
+ return '4.36.0';
16
+ case 'wsl':
17
+ return '4.36.0';
16
18
  }
17
19
  };
18
20
 
19
21
  // Default config
20
22
  const defaultConfig = options => ({
21
- orchestratorSeparator: '-',
22
- orchestratorVersion: '2.29.2',
23
+ orchestratorSeparator: '_',
24
+ orchestratorVersion: '2.30.3',
23
25
  configSources: [],
24
26
  coreBase: path.resolve(__dirname, '..'),
25
27
  disablePlugins: [],
@@ -29,13 +31,16 @@ const defaultConfig = options => ({
29
31
  home: os.homedir(),
30
32
  isArmed: _.includes(['arm64', 'aarch64'], process.arch),
31
33
  logLevel: 'debug',
34
+ networkLimit: 32,
32
35
  node: process.version,
33
36
  os: {
34
37
  type: os.type(),
35
38
  platform: os.platform(),
39
+ landoPlatform: process.landoPlatform ?? process.platform,
36
40
  release: os.release(),
37
41
  arch: os.arch(),
38
42
  isWsl: os.release().toLowerCase().includes('microsoft'),
43
+ isWslInterop: require('../utils/is-wsl-interop')(),
39
44
  },
40
45
  pluginDirs: [{path: path.join(__dirname, '..'), subdir: 'plugins', namespace: '@lando'}],
41
46
  plugins: [],
@@ -44,7 +49,7 @@ const defaultConfig = options => ({
44
49
  // this governs both autosetup and the defaults of lando setup
45
50
  // @TODO: orchestrator works a bit differently because it predates lando.setup() we set it elsewhere
46
51
  setup: {
47
- buildEngine: getBuildEngineVersion(),
52
+ buildEngine: getBuildEngineVersion(process.landoPlatform ?? process.platform),
48
53
  buildEngineAcceptLicense: !require('is-interactive')(),
49
54
  commonPlugins: {
50
55
  '@lando/acquia': 'latest',
@@ -3,8 +3,8 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
 
6
- module.exports = () => {
7
- switch (process.platform) {
6
+ module.exports = (platform = process.landoPlatform ?? process.platform) => {
7
+ switch (platform) {
8
8
  case 'darwin':
9
9
  return '/Applications/Docker.app/Contents/Resources/bin';
10
10
  case 'linux':
@@ -19,5 +19,9 @@ module.exports = () => {
19
19
  } else {
20
20
  return path.win32.join(programFiles + '\\Docker\\Docker\\resources\\bin');
21
21
  }
22
+ case 'wsl':
23
+ return '/mnt/wsl/docker-desktop/cli-tools/usr/bin';
24
+ default:
25
+ return '/usr/bin';
22
26
  }
23
27
  };
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ const getWinEnvar = require('../utils/get-win32-envvar-from-wsl');
4
+ const path = require('path');
5
+ const wslpath = require('./winpath-2-wslpath');
6
+
7
+ module.exports = (platform = process.landoPlatform ?? process.platform) => {
8
+ switch (platform) {
9
+ case 'darwin':
10
+ return '/Applications/Docker.app';
11
+ case 'win32': {
12
+ const programFiles = process.env.ProgramW6432 ?? process.env.ProgramFiles;
13
+ return path.win32.join(`${programFiles}\\Docker\\Docker\\Docker Desktop.exe`);
14
+ }
15
+ case 'wsl': {
16
+ const programFiles = getWinEnvar('ProgramW6432') ?? getWinEnvar('ProgramFiles');
17
+ const winpath = path.win32.join(`${programFiles}\\Docker\\Docker\\Docker Desktop.exe`);
18
+ return wslpath(winpath);
19
+ }
20
+ }
21
+ };
@@ -19,14 +19,15 @@ const getDockerBin = (bin, base, pathFallback = true) => {
19
19
  if (!fs.existsSync(binPath)) return false;
20
20
 
21
21
  // Otherwise return a normalized binpath
22
- switch (process.platform) {
22
+ switch (process.landoPlatform ?? process.platform) {
23
23
  case 'darwin': return path.posix.normalize(binPath);
24
24
  case 'linux': return path.posix.normalize(binPath);
25
25
  case 'win32': return path.win32.normalize(binPath);
26
+ case 'wsl': return path.posix.normalize(binPath);
26
27
  }
27
28
  };
28
29
 
29
30
  module.exports = () => {
30
- const base = (process.platform === 'linux') ? '/usr/bin' : require('./get-docker-bin-path')();
31
+ const base = (process.landoPlatform === 'linux' || process.platform === 'linux') ? '/usr/bin' : require('./get-docker-bin-path')();
31
32
  return getDockerBin('docker', base);
32
33
  };
@@ -29,8 +29,7 @@ module.exports = (paths = [], shell = require('./get-user-shell')()) => {
29
29
 
30
30
  default:
31
31
  return [
32
- ['# Lando'],
33
- [`export PATH="${paths}\${PATH+:$PATH}"; #landopath`, '#landopath'],
32
+ [`export PATH="${paths}:$PATH"; #landopath`, '#landopath'],
34
33
  ];
35
34
  }
36
35
  };
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
- /**
3
+ const os = require('os');
4
+
5
+ /*
4
6
  * Retrieves system Certificate Authority (CA) certificates based on the current platform.
5
7
  *
6
8
  * This function handles different platforms (macOS, Linux, Windows) and returns
@@ -15,17 +17,21 @@
15
17
  * @throws {Error} May throw errors during certificate processing, which are logged
16
18
  * to the console but do not interrupt the function's execution.
17
19
  */
18
- module.exports = (format = 'fingerprint') => {
20
+ module.exports = async ({
21
+ format = 'fingerprint',
22
+ platform = process.landoPlatform ?? process.platform,
23
+ }= {}) => {
19
24
  const fingerprints = [];
20
25
 
21
- switch (process.platform) {
26
+ switch (platform) {
22
27
  case 'darwin':
23
28
  // For macOS, we use the 'mac-ca' library which handles the formatting
24
29
  return require('mac-ca').get({format});
30
+
25
31
  case 'linux':
26
32
  // For Linux, we use the 'system-ca' library to get system certificates
27
- const {systemCertsSync} = require('system-ca');
28
- for (const cert of systemCertsSync()) {
33
+ const {systemCertsAsync} = require('system-ca');
34
+ for (const cert of await systemCertsAsync()) {
29
35
  try {
30
36
  fingerprints.push(require('./get-fingerprint')(cert));
31
37
  } catch {
@@ -48,8 +54,21 @@ module.exports = (format = 'fingerprint') => {
48
54
  }
49
55
  }
50
56
 
57
+ return fingerprints;
58
+ case 'wsl':
59
+ const {stdout} = await require('./run-command')(
60
+ 'powershell.exe',
61
+ ['-Command', 'Get-ChildItem -Path Cert:\\CurrentUser\\Root | Select-Object -ExpandProperty Thumbprint'],
62
+ );
63
+
64
+ fingerprints.push(...stdout
65
+ .split(os.EOL)
66
+ .map(fingerprint => fingerprint.trim())
67
+ .map(fingerprint => fingerprint.toLowerCase())
68
+ .filter(fingerprint => fingerprint && fingerprint !== ''));
69
+
51
70
  return fingerprints;
52
71
  default:
53
- throw new Error(`Unsupported platform: ${process.platform}`);
72
+ throw new Error(`Unsupported platform: ${platform}`);
54
73
  }
55
74
  };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ module.exports = varname => {
4
+ const args = ['-Command', `[Environment]::GetEnvironmentVariable('${varname}')`];
5
+ const {stdout} = require('./spawn-sync-stringer')('powershell.exe', args, {encoding: 'utf-8'});
6
+ return stdout.trim();
7
+ };
@@ -2,21 +2,22 @@
2
2
 
3
3
  const os = require('os');
4
4
 
5
- module.exports = user => {
5
+ module.exports = (user, {platform = process.platform} = {}) => {
6
6
  // set user to person running this process if its not set
7
7
  if (!user) user = os.userInfo().username;
8
8
 
9
9
  // differetn strokes, different folks
10
- switch (process.platform) {
10
+ switch (platform) {
11
11
  case 'darwin':
12
- return require('./is-group-member')('admin', user);
12
+ return require('./is-group-member')('admin', user, platform);
13
13
  case 'linux':
14
- return require('./is-group-member')('sudo', user)
15
- || require('./is-group-member')('admin', user)
16
- || require('./is-group-member')('wheel', user)
17
- || require('./is-group-member')('adm', user);
14
+ return require('./is-group-member')('sudo', user, platform)
15
+ || require('./is-group-member')('admin', user, platform)
16
+ || require('./is-group-member')('wheel', user, platform)
17
+ || require('./is-group-member')('adm', user, platform);
18
18
  case 'win32':
19
- return require('./is-group-member')('administrators', user);
19
+ return require('./is-group-member')('S-1-5-32-544', user, platform)
20
+ || require('./is-group-member')('administrators', user, platform);
20
21
  default:
21
22
  return false;
22
23
  }
@@ -4,35 +4,42 @@ const os = require('os');
4
4
 
5
5
  const posixCmd = user => (['groups', [user]]);
6
6
  const win32Cmd = user => ([
7
- 'powershell',
7
+ 'powershell.exe',
8
8
  [
9
9
  '-Command',
10
10
  `Get-LocalGroup | Where-Object { ($_ | Get-LocalGroupMember | Where-Object { $_.Name -like "*\\${user}" }).Count -gt 0 } | Select-Object -Property Name`, // eslint-disable-line max-len
11
11
  ],
12
12
  ]);
13
13
 
14
- module.exports = (group, user) => {
14
+ module.exports = (group, user, platform = process.platform) => {
15
15
  // @TODO: throw error if no group specified?
16
16
  // set user to person running this process if its not set
17
17
  if (!user) user = os.userInfo().username;
18
18
 
19
19
  // get the result of the membership command
20
- const cmd = process.platform === 'win32' ? win32Cmd(user) : posixCmd(user);
20
+ const cmd = platform === 'win32' ? win32Cmd(user) : posixCmd(user);
21
21
  const {status, stdout, stderr} = require('./spawn-sync-stringer')(...cmd);
22
22
 
23
23
  // if we failed for some reason
24
24
  if (status !== 0) throw new Error(`Could not determine group situation: ${stderr}`);
25
25
 
26
26
  // mac and linux
27
- if (process.platform === 'darwin' || process.platform === 'linux') {
27
+ if (platform === 'darwin' || platform === 'linux') {
28
28
  const groups = stdout.split(' ').map(group => group.trim());
29
29
  return groups.includes(group);
30
30
  }
31
31
 
32
32
  // if windows we have a long command to check
33
- if (process.platform === 'win32') {
34
- const groups = stdout.split(os.EOL).map(group => group.trim()).filter(group => group !== 'Name' && group !== '----'); // eslint-disable-line max-len
35
- return groups.includes(group);
33
+ if (platform === 'win32') {
34
+ const ids = stdout
35
+ .split(os.EOL)
36
+ .map(group => group.trim())
37
+ .filter(group => group !== 'Name' && group !== '----')
38
+ .map(group => group.toUpperCase());
39
+
40
+ const matches = ids.filter(id => id === group.toUpperCase() || id.endsWith(group.toUpperCase()));
41
+
42
+ return matches.length > 0;
36
43
  }
37
44
 
38
45
  // otherwise false?
@@ -3,9 +3,22 @@
3
3
  const fs = require('fs');
4
4
  const os = require('os');
5
5
 
6
+ const WINBIN_REGEX = /\/mnt\/.\/WINDOWS\/System32$/i;
7
+
6
8
  // Checks to see if Docker is installed via WSL/Windows interop.
7
- module.exports = engineBin => {
8
- const isWsl = os.release().toLowerCase().includes('microsoft');
9
- // Docker Desktop for Windows keeps the .exe in the same directory as the WSL binary.
10
- return isWsl && fs.existsSync(`${engineBin}.exe`);
9
+ module.exports = () => {
10
+ // return anything that is not wsl as false
11
+ if (!os.release().toLowerCase().includes('microsoft')) return false;
12
+
13
+ // if we dont have have WSL_INTEROP then
14
+ if (!process.env.WSL_INTEROP) return false;
15
+
16
+ // attempt to find there the winbin is at
17
+ const winbin = process.env.PATH.split(':').filter(path => WINBIN_REGEX.test(path));
18
+
19
+ // if we cant find anything then false
20
+ if (winbin.length === 0) return false;
21
+
22
+ // otherwise return whether our first match exists
23
+ return fs.existsSync(winbin[0]);
11
24
  };
@@ -11,6 +11,7 @@ const {spawn} = require('child_process');
11
11
 
12
12
  // get the bosmang
13
13
  const defaults = {
14
+ encode: undefined,
14
15
  env: process.env,
15
16
  debug: require('debug')('@lando/run-elevated'),
16
17
  ignoreReturnCode: false,
@@ -95,9 +96,17 @@ module.exports = (command, options, stdout = '', stderr = '') => {
95
96
  debug('elevated command %o done with code %o', command, code);
96
97
  // with run-elevate we want to clean up stderr a bit if we can eg remove the powershell shit
97
98
  if (options.method === 'run-elevated') {
99
+ const raw = stderr;
100
+
98
101
  stderr = stderr.split('. At line')[0];
99
102
  stderr = stderr.split(`${os.EOL}At `)[0];
100
103
 
104
+ // add nse if we have one
105
+ if (raw.split('NativeCommandError')[1]) {
106
+ const nse = raw.split('NativeCommandError')[1];
107
+ stderr = `${stderr}. ${nse.trim()}`;
108
+ }
109
+
101
110
  // simplify the UAC cancel error
102
111
  if (stderr.includes('The operation was canceled by the user.')) {
103
112
  stderr = 'The operation was canceled by the user.';
@@ -2,24 +2,50 @@
2
2
 
3
3
  // Modules
4
4
  const merge = require('lodash/merge');
5
+ const read = require('./read-file');
6
+ const winpath = require('./wslpath-2-winpath');
5
7
 
6
- const {spawn} = require('child_process');
8
+ const {spawn, spawnSync} = require('child_process');
9
+
10
+ const parseArgs = args => args.map(arg => arg.startsWith('-') ? arg : `"${arg}"`).join(' ');
7
11
 
8
12
  // get the bosmang
9
13
  const defaults = {
14
+ encode: undefined,
15
+ env: process.env,
10
16
  debug: require('debug')('@lando/run-powershell-script'),
11
17
  ignoreReturnCode: false,
18
+ toWSLPath: false,
12
19
  };
13
20
 
14
- module.exports = (script, args = [], options = {}, stdout = '', stderr = '') => {
15
- // @TODO: error handling?
21
+ module.exports = (script, args = [], options = {}, stdout = '', stderr = '', cargs = []) => {
16
22
  // merge our options over the defaults
17
23
  options = merge({}, defaults, options);
24
+
25
+ // if encode is not explicitly set then we need to pick a good value
26
+ if (options.encode === undefined) {
27
+ const bargs = ['Set-ExecutionPolicy', '-Scope', 'Process', '-ExecutionPolicy', 'Bypass'];
28
+ const {status} = spawnSync('powershell.exe', bargs, options);
29
+ options.encode = status !== 0;
30
+ }
31
+
32
+ // if encode is true we need to do a bunch of other stuff
33
+ if (options.encode === true) {
34
+ const command = `& {${read(script)}} ${parseArgs(args)}`;
35
+ cargs.push('-EncodedCommand', Buffer.from(command, 'utf16le').toString('base64'));
36
+
37
+ // otherwise its pretty easy but note that we may path translate to a winpath if toWSLPath is on
38
+ } else {
39
+ if (options.toWSLPath) script = winpath(script);
40
+ cargs.push('-ExecutionPolicy', 'Bypass', '-File', script, ...args);
41
+ }
42
+
43
+ // pull out debug
18
44
  const {debug} = options;
19
45
 
20
46
  // birth
21
- debug('running powershell script %o %o', script, args);
22
- const child = spawn('powershell', ['-ExecutionPolicy', 'Bypass', '-File', script].concat(args), options);
47
+ debug('running powershell script %o %o %o', script, args);
48
+ const child = spawn('powershell.exe', ['-NoProfile'].concat(cargs), options);
23
49
 
24
50
  return require('./merge-promise')(child, async () => {
25
51
  return new Promise((resolve, reject) => {
@@ -35,8 +35,9 @@ module.exports = async (tasks, {
35
35
  fallbackRendererOptions = rendererOptions;
36
36
  }
37
37
 
38
- // if terminal is DUMB then force the verbose renderer
39
- if (process?.env?.TERM === 'dumb') renderer = 'verbose';
38
+ // some sitautions just need the bare minimum
39
+ if (process?.env?.TERM === 'dumb') renderer = 'simple';
40
+ if (process?.env?.CI && !require('is-interactive')()) renderer = 'simple';
40
41
 
41
42
  const defaults = {
42
43
  ctx: {data: {}, errors: [], results: [], skipped: 0, ran: 0, total: 0},
@@ -18,10 +18,19 @@ const getMetricsContext = () => {
18
18
  module.exports = (log, config) => {
19
19
  const Metrics = require('./../lib/metrics');
20
20
  const command = _.get(config, 'command._', 'unknown');
21
+
22
+ // group by endpoints and resolve multiples
23
+ const endpoints = _(_.groupBy(config.stats, 'url'))
24
+ .map((data, url) => ({
25
+ url,
26
+ report: data.map(data => data.report).every(report => report === true),
27
+ }))
28
+ .value();
29
+
21
30
  return new Metrics({
22
31
  log,
23
32
  id: config.id,
24
- endpoints: config.stats,
33
+ endpoints,
25
34
  data: {
26
35
  command: `lando ${command}`,
27
36
  context: getMetricsContext(),
@@ -6,11 +6,12 @@ module.exports = ({
6
6
  message = 'Lando wants to restart your computer',
7
7
  password = undefined,
8
8
  type = 'restart',
9
- wait = process.platform === 'win32' ? 5 : 'now',
9
+ wait = process.landoPlatform === 'win32' || process.platform === 'win32' ? 5 : 'now',
10
+ platform = process.landoPlatform ?? process.platform,
10
11
  } = {}) => {
11
12
  debug('shutdown with %o %o', type, {message, wait});
12
13
 
13
- switch (process.platform) {
14
+ switch (platform) {
14
15
  case 'darwin':
15
16
  args.push('shutdown');
16
17
  // handle the restart type
@@ -48,6 +49,10 @@ module.exports = ({
48
49
  args.push('/c');
49
50
  args.push(message);
50
51
 
51
- return require('./run-command')('shutdown', args, {debug});
52
+ return require('./run-command')('shutdown.exe', args, {debug});
53
+ case 'wsl':
54
+ args.push('-Command');
55
+ args.push(`wsl --terminate ${process.env.WSL_DISTRO_NAME}`);
56
+ return require('./run-command')('powershell.exe', args, {debug});
52
57
  }
53
58
  };
@@ -4,6 +4,7 @@ const {spawnSync} = require('child_process');
4
4
 
5
5
  module.exports = (...args) => {
6
6
  const result = spawnSync(...args);
7
+
7
8
  // stringify and trim
8
9
  result.stdout = result.stdout.toString().trim();
9
10
  result.stderr = result.stderr.toString().trim();
@@ -6,6 +6,12 @@ const os = require('os');
6
6
  const read = require('./read-file');
7
7
  const write = require('./write-file');
8
8
 
9
+ const trim = (data = []) => {
10
+ while (data.length > 0 && data[data.length - 1] === '') data.pop();
11
+ data.push('');
12
+ return data;
13
+ };
14
+
9
15
  module.exports = (file, updates = []) => {
10
16
  // create empty file if it doesnt exist first
11
17
  if (!fs.existsSync(file)) {
@@ -17,9 +23,7 @@ module.exports = (file, updates = []) => {
17
23
  // get the content
18
24
  const content = read(file);
19
25
  // split into lines
20
- const lines = content.split('\n');
21
- // if we end up with second to last line that is empty then pop
22
- if (lines[lines.length - 2].trim() === '') lines.pop();
26
+ const lines = trim(content.split('\n'));
23
27
 
24
28
  // loops through the updates and add/update as needed
25
29
  for (const [update, search] of updates) {
@@ -31,11 +35,8 @@ module.exports = (file, updates = []) => {
31
35
  }
32
36
  }
33
37
 
34
- // if the last element doesnt contain a newline
35
- if (!lines[lines.length - 1].includes(os.EOL)) lines.push(os.EOL);
36
-
37
38
  // Write the modified content back to the file
38
- write(file, lines.join(os.EOL));
39
+ write(file, `${trim(lines).join(os.EOL)}${os.EOL}`);
39
40
 
40
41
  // handle errors
41
42
  } catch (error) {
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ const forge = require('node-forge');
4
+ const read = require('./read-file');
5
+
6
+ module.exports = (cert, key, {
7
+ debug = require('debug')('@lando/validate-script'),
8
+ } = {}) => {
9
+ try {
10
+ cert = forge.pki.certificateFromPem(read(cert));
11
+ key = forge.pki.privateKeyFromPem(read(key));
12
+
13
+ // verify the signature using the public key in the CA certificate
14
+ const md = forge.md.sha256.create();
15
+ md.update('taanab', 'utf8');
16
+ const signature = key.sign(md);
17
+
18
+ // if they dont match then throw
19
+ if (!cert.publicKey.verify(md.digest().bytes(), signature)) {
20
+ debug('CA and its private key do not match');
21
+ return false;
22
+ }
23
+
24
+ // otherwise we are good
25
+ return true;
26
+ } catch (error) {
27
+ debug('something is wrong with the CA %o', error.message);
28
+ debug('%o', error);
29
+ return false;
30
+ }
31
+ };