@localctl/cli 0.3.0 → 0.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.
package/README.md CHANGED
@@ -318,6 +318,7 @@ The full documentation lives at **[psilvmoreira.github.io/localctl](https://psil
318
318
  |---|---|
319
319
  | [Getting started](https://psilvmoreira.github.io/localctl/getting-started/) | Install and first deploy, step by step |
320
320
  | [Architecture](https://psilvmoreira.github.io/localctl/architecture/) | Every component, why it was chosen, multi-project support |
321
+ | [CLI commands](https://psilvmoreira.github.io/localctl/cli-reference/) | Every command and option |
321
322
  | [Config schema](https://psilvmoreira.github.io/localctl/config-schema/) | Every `.local/config.json` field |
322
323
  | [Debugging](https://psilvmoreira.github.io/localctl/debugging/) | Attach a debugger in Node, Python, Go, Java and .NET |
323
324
  | [Adding tools](https://psilvmoreira.github.io/localctl/adding-tools/) | Write your own per-app or cluster-wide addon |
@@ -339,7 +340,8 @@ The full documentation lives at **[psilvmoreira.github.io/localctl](https://psil
339
340
 
340
341
  ## Contributing
341
342
 
342
- Issues and pull requests are welcome.
343
+ Issues and pull requests are welcome. The full guide (constraints, dependency policy, working on
344
+ the docs site) is in [**Contributing**](https://psilvmoreira.github.io/localctl/contributing/).
343
345
 
344
346
  1. Fork the repository and create a branch.
345
347
  2. Make your change and run the tests:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localctl/cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "localctl - local Kubernetes dev platform CLI",
5
5
  "keywords": [
6
6
  "kubernetes",
@@ -91,7 +91,12 @@ async function uninstall(opts) {
91
91
  logger.success('Uninstall complete.');
92
92
  console.log('');
93
93
  console.log('Left in place (remove yourself if you want them gone too):');
94
- console.log(' brew uninstall k3d kubectl tilt mkcert node # only if nothing else needs them');
94
+ if (process.platform === 'win32') {
95
+ console.log(' winget uninstall k3d.k3d Kubernetes.kubectl FiloSottile.mkcert Helm.Helm # only if nothing else needs them');
96
+ console.log(' Remove-Item -Recurse -Force ~\\.localctl\\tools # tilt, if localctl installed it');
97
+ } else {
98
+ console.log(' brew uninstall k3d kubectl tilt mkcert helm # only if nothing else needs them');
99
+ }
95
100
  console.log(" mkcert -uninstall # removes the root CA from trust stores - affects EVERY");
96
101
  console.log(' # mkcert-issued cert on this machine, not just *.local.test');
97
102
  }
package/src/index.js CHANGED
@@ -2,6 +2,9 @@ const { Command } = require('commander');
2
2
  const { version } = require('../package.json');
3
3
 
4
4
  require('./lib/updateCheck').start(version);
5
+ // Tools localctl downloaded itself (e.g. tilt on Windows) work even in a terminal opened before
6
+ // they were added to the user's PATH.
7
+ require('./lib/toolInstall').addToolsDirToPath();
5
8
 
6
9
  const program = new Command();
7
10
  program
@@ -4,7 +4,7 @@ const path = require('path');
4
4
  const yaml = require('js-yaml');
5
5
  const { run, capture, sleepSync, commandExists } = require('./exec');
6
6
  const { detectEngine, warnIfExperimental } = require('./engine');
7
- const { installIfMissing } = require('./toolInstall');
7
+ const { installIfMissing, installTiltWindows } = require('./toolInstall');
8
8
  const { ensureInsecureRegistry } = require('./podman');
9
9
  const { DOMAIN } = require('./constants');
10
10
  const logger = require('./logger');
@@ -49,9 +49,9 @@ function provisionCluster({ clusterName, httpPort, httpsPort, registryPort }) {
49
49
  ensureInsecureRegistry(registryPort);
50
50
  }
51
51
 
52
- installIfMissing('k3d', 'k3d', 'k3d-io.k3d');
52
+ installIfMissing('k3d', 'k3d', 'k3d.k3d');
53
53
  installIfMissing('kubectl', 'kubernetes-cli', 'Kubernetes.kubectl');
54
- installIfMissing('tilt', 'tilt', 'Tilt.dev.tilt');
54
+ installIfMissing('tilt', 'tilt', installTiltWindows);
55
55
  installIfMissing('mkcert', 'mkcert', 'FiloSottile.mkcert');
56
56
  installIfMissing('helm', 'helm', 'Helm.Helm');
57
57
 
@@ -1,7 +1,72 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
1
3
  const { commandExists, run } = require('./exec');
2
4
  const logger = require('./logger');
5
+ const { HOME_STATE_DIR } = require('./paths');
3
6
 
4
- // macId: Homebrew formula name. winId: winget package id.
7
+ // Tools that have no package-manager package on a platform get downloaded here instead. The
8
+ // directory is added to the user's PATH for new terminals, and to this process's PATH by
9
+ // addToolsDirToPath() on every run, so the current terminal needs no restart.
10
+ const TOOLS_DIR = path.join(HOME_STATE_DIR, 'tools');
11
+
12
+ function prependToPath(dir) {
13
+ if (!fs.existsSync(dir)) return;
14
+ const entries = (process.env.PATH || '').split(path.delimiter);
15
+ if (!entries.includes(dir)) process.env.PATH = [dir, ...entries].join(path.delimiter);
16
+ }
17
+
18
+ function addToolsDirToPath() {
19
+ prependToPath(TOOLS_DIR);
20
+ }
21
+
22
+ // winget puts portable packages (k3d, kubectl, helm, mkcert) behind links in this directory and
23
+ // adds it to PATH for new terminals only. Adding it here lets the rest of `localctl setup` use a
24
+ // tool winget just installed.
25
+ function addWingetLinksToPath() {
26
+ if (process.env.LOCALAPPDATA) prependToPath(path.join(process.env.LOCALAPPDATA, 'Microsoft', 'WinGet', 'Links'));
27
+ }
28
+
29
+ function powershell(script) {
30
+ run('powershell', ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', script]);
31
+ }
32
+
33
+ // Tilt isn't published to winget. Same steps as Tilt's own install.ps1 (latest release zip from
34
+ // GitHub), but into TOOLS_DIR and with the directory added to the user's PATH, which install.ps1
35
+ // leaves to you.
36
+ function installTiltWindows() {
37
+ logger.step('Installing tilt from its GitHub release (not available on winget)...');
38
+ powershell(`
39
+ $ErrorActionPreference = 'Stop'
40
+ $ProgressPreference = 'SilentlyContinue'
41
+ $dir = '${TOOLS_DIR.replace(/'/g, "''")}'
42
+ $version = (Invoke-RestMethod 'https://api.github.com/repos/tilt-dev/tilt/releases/latest').tag_name.TrimStart('v')
43
+ $url = "https://github.com/tilt-dev/tilt/releases/download/v$version/tilt.$version.windows.x86_64.zip"
44
+ $tmp = Join-Path $env:TEMP "localctl-tilt-$version"
45
+ if (Test-Path $tmp) { Remove-Item -Recurse -Force $tmp }
46
+ New-Item -ItemType Directory -Force -Path $tmp, $dir | Out-Null
47
+ Write-Host "Downloading $url"
48
+ Invoke-WebRequest $url -OutFile "$tmp\\tilt.zip"
49
+ Expand-Archive "$tmp\\tilt.zip" -DestinationPath $tmp
50
+ Move-Item -Force "$tmp\\tilt.exe" "$dir\\tilt.exe"
51
+ Remove-Item -Recurse -Force $tmp
52
+ # Raw registry value, so entries like %USERPROFILE%\\bin stay unexpanded (REG_EXPAND_SZ).
53
+ $key = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment', $true)
54
+ $userPath = [string]$key.GetValue('Path', '', 'DoNotExpandEnvironmentNames')
55
+ if ((($userPath -split ';') | Where-Object { $_ -eq $dir }).Count -eq 0) {
56
+ $key.SetValue('Path', (($userPath.TrimEnd(';'), $dir) -join ';').TrimStart(';'), 'ExpandString')
57
+ # Setting any user variable through .NET broadcasts WM_SETTINGCHANGE, so terminals opened
58
+ # from now on pick up the new PATH without signing out.
59
+ [Environment]::SetEnvironmentVariable('LOCALCTL_PATH_REFRESH', '1', 'User')
60
+ [Environment]::SetEnvironmentVariable('LOCALCTL_PATH_REFRESH', $null, 'User')
61
+ }
62
+ $key.Close()
63
+ `);
64
+ addToolsDirToPath();
65
+ logger.success(`tilt installed in ${TOOLS_DIR} (added to your PATH for new terminals)`);
66
+ }
67
+
68
+ // macId: Homebrew formula name. winId: winget package id, or a function that installs the tool
69
+ // when winget doesn't have it.
5
70
  function installIfMissing(bin, macId, winId) {
6
71
  if (commandExists(bin)) {
7
72
  logger.success(`${bin} already installed`);
@@ -14,6 +79,10 @@ function installIfMissing(bin, macId, winId) {
14
79
  logger.step(`Installing ${macId} via brew...`);
15
80
  run('brew', ['install', macId]);
16
81
  } else if (process.platform === 'win32') {
82
+ if (typeof winId === 'function') {
83
+ winId();
84
+ return;
85
+ }
17
86
  if (!commandExists('winget')) {
18
87
  throw new Error('winget is required to install missing tools (ships with modern Windows / App Installer).');
19
88
  }
@@ -22,9 +91,10 @@ function installIfMissing(bin, macId, winId) {
22
91
  'install', '--id', winId, '-e', '--source', 'winget',
23
92
  '--accept-package-agreements', '--accept-source-agreements',
24
93
  ]);
94
+ addWingetLinksToPath();
25
95
  } else {
26
96
  throw new Error(`"${bin}" is missing and automatic install isn't supported on this platform. Install it manually.`);
27
97
  }
28
98
  }
29
99
 
30
- module.exports = { installIfMissing };
100
+ module.exports = { installIfMissing, installTiltWindows, addToolsDirToPath, TOOLS_DIR };