@localctl/cli 0.4.0 โ 0.4.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 +50 -18
- package/package.json +1 -1
- package/src/commands/uninstall.js +6 -1
- package/src/index.js +3 -0
- package/src/lib/clusterProvision.js +3 -3
- package/src/lib/hostsFile.js +21 -2
- package/src/lib/toolInstall.js +72 -2
package/README.md
CHANGED
|
@@ -75,17 +75,19 @@ JSON file per app.
|
|
|
75
75
|
|---|---|
|
|
76
76
|
| **macOS** or **Windows** | Windows commands run in PowerShell. |
|
|
77
77
|
| **Node.js 18+** | Needed to install the CLI from npm. |
|
|
78
|
-
| **Container engine** | [Podman Desktop](https://podman-desktop.io/), running. See [supported container engines](#supported-container-engines). |
|
|
78
|
+
| **Container engine** | [Podman Desktop](https://podman-desktop.io/) (or Docker Desktop / Rancher Desktop), running. See [supported container engines](#supported-container-engines). |
|
|
79
79
|
| **Homebrew** or **winget** | Used once by `localctl setup` to install missing tools. |
|
|
80
80
|
|
|
81
81
|
`localctl setup` installs `k3d`, `kubectl`, `tilt`, `mkcert` and `helm` for you if they're missing.
|
|
82
|
+
On Windows, Tilt isn't on winget, so it's downloaded from its GitHub release into
|
|
83
|
+
`~.localctl ools` and added to your user PATH.
|
|
82
84
|
|
|
83
85
|
### Supported container engines
|
|
84
86
|
|
|
85
87
|
| Engine | Status |
|
|
86
88
|
|---|---|
|
|
87
89
|
| [Podman Desktop](https://podman-desktop.io/) | โ
Tested |
|
|
88
|
-
| [Docker Desktop](https://www.docker.com/products/docker-desktop/) | ๐งช Experimental โ
|
|
90
|
+
| [Docker Desktop](https://www.docker.com/products/docker-desktop/) | ๐งช Experimental โ setup and app deploy verified on Windows |
|
|
89
91
|
| [Rancher Desktop](https://rancherdesktop.io/) | ๐งช Experimental โ not yet tested |
|
|
90
92
|
|
|
91
93
|
Experimental engines are detected and should work, since k3d only needs a Docker-compatible API,
|
|
@@ -106,7 +108,9 @@ the local image registry, trusts the `*.local.test` certificate, and updates you
|
|
|
106
108
|
is idempotent: run it again any time to repair your environment.
|
|
107
109
|
|
|
108
110
|
You'll see up to two one-time prompts during setup: **mkcert** asking to trust its local
|
|
109
|
-
certificate authority, and **
|
|
111
|
+
certificate authority, and **admin rights** to write the `*.local.test` hosts entries (your
|
|
112
|
+
`sudo` password on macOS, a UAC prompt on Windows). Approve both: without the hosts entries, apps
|
|
113
|
+
run but their addresses don't resolve.
|
|
110
114
|
|
|
111
115
|
**Pre-releases** are published under the `beta` tag: `npm install -g @localctl/cli@beta`.
|
|
112
116
|
|
|
@@ -120,7 +124,8 @@ Update available: 0.2.0 -> 0.3.0
|
|
|
120
124
|
Run npm install -g @localctl/cli to update.
|
|
121
125
|
```
|
|
122
126
|
|
|
123
|
-
Update with `npm install -g @localctl/cli`.
|
|
127
|
+
Update with `npm install -g @localctl/cli`. On a pre-release you're also told about newer
|
|
128
|
+
versions on your own channel (e.g. `beta`). The check never slows a command down, is skipped in
|
|
124
129
|
CI, and can be turned off with `LOCALCTL_NO_UPDATE_CHECK=1`.
|
|
125
130
|
|
|
126
131
|
<details>
|
|
@@ -204,6 +209,16 @@ localctl app down
|
|
|
204
209
|
|
|
205
210
|
This removes only that app. The shared cluster keeps running for everything else.
|
|
206
211
|
|
|
212
|
+
<details>
|
|
213
|
+
<summary><b>App is ready but <code>https://<app>.local.test</code> doesn't open?</b></summary>
|
|
214
|
+
|
|
215
|
+
If `localctl app status` shows `1/1` but the browser can't reach the address, the hosts file
|
|
216
|
+
entry is missing: the `sudo` or UAC prompt was declined or missed. Run `localctl hosts sync` and
|
|
217
|
+
approve the prompt. More cases, with cause and fix:
|
|
218
|
+
[**Troubleshooting**](https://psilvmoreira.github.io/localctl/troubleshooting/).
|
|
219
|
+
|
|
220
|
+
</details>
|
|
221
|
+
|
|
207
222
|
> **Tip:** no app of your own yet? Clone the repo and try a ready-made example:
|
|
208
223
|
> [`node-app`](https://github.com/psilvmoreira/localctl/tree/master/examples/node-app) (Node.js + Postgres),
|
|
209
224
|
> [`python-app`](https://github.com/psilvmoreira/localctl/tree/master/examples/python-app) (Python + Redis), or
|
|
@@ -211,7 +226,8 @@ This removes only that app. The shared cluster keeps running for everything else
|
|
|
211
226
|
|
|
212
227
|
## Commands
|
|
213
228
|
|
|
214
|
-
Run `localctl <command> --help` for every option
|
|
229
|
+
Run `localctl <command> --help` for every option, or see the full
|
|
230
|
+
[**CLI reference**](https://psilvmoreira.github.io/localctl/cli-reference/).
|
|
215
231
|
|
|
216
232
|
<details open>
|
|
217
233
|
<summary><b>Machine setup</b></summary>
|
|
@@ -220,7 +236,7 @@ Run `localctl <command> --help` for every option.
|
|
|
220
236
|
|---|---|
|
|
221
237
|
| `localctl setup` | Install or repair the infrastructure: container engine, cluster, TLS, hosts. Idempotent. |
|
|
222
238
|
| `localctl doctor` | Health check of the active project's environment. |
|
|
223
|
-
| `localctl hosts sync` / `list` |
|
|
239
|
+
| `localctl hosts sync` / `list` | Write or list the `*.local.test` entries in your hosts file. Asks for admin rights when needed. |
|
|
224
240
|
| `localctl uninstall [-y]` | Remove every cluster, registry, hosts entry, certificate and state file `localctl` created. |
|
|
225
241
|
|
|
226
242
|
</details>
|
|
@@ -235,7 +251,7 @@ Run `localctl <command> --help` for every option.
|
|
|
235
251
|
| `localctl app down` | Stop the dev loop and remove the app. Keeps its data. |
|
|
236
252
|
| `localctl app reload [-a <name>]` | Force a rebuild and redeploy without waiting for a file change. |
|
|
237
253
|
| `localctl app status [-a <name>] [-A]` | One app's detail inside its repository, or a table of every app. |
|
|
238
|
-
| `localctl app logs
|
|
254
|
+
| `localctl app logs [name] [-f]` | Show or follow an app's logs. Inside its repository the name is optional. |
|
|
239
255
|
| `localctl app exec [cmd...]` | Open a shell (default `sh`) in the app's pod. |
|
|
240
256
|
| `localctl app prune [-y]` | Delete leftover data (volumes, secrets) of apps already taken down. |
|
|
241
257
|
| `localctl app secrets set <KEY> [value]` | Store a secret as a Kubernetes Secret, never in `config.json`. |
|
|
@@ -318,11 +334,13 @@ The full documentation lives at **[psilvmoreira.github.io/localctl](https://psil
|
|
|
318
334
|
|---|---|
|
|
319
335
|
| [Getting started](https://psilvmoreira.github.io/localctl/getting-started/) | Install and first deploy, step by step |
|
|
320
336
|
| [Architecture](https://psilvmoreira.github.io/localctl/architecture/) | Every component, why it was chosen, multi-project support |
|
|
337
|
+
| [CLI commands](https://psilvmoreira.github.io/localctl/cli-reference/) | Every command and option |
|
|
321
338
|
| [Config schema](https://psilvmoreira.github.io/localctl/config-schema/) | Every `.local/config.json` field |
|
|
322
339
|
| [Debugging](https://psilvmoreira.github.io/localctl/debugging/) | Attach a debugger in Node, Python, Go, Java and .NET |
|
|
323
340
|
| [Adding tools](https://psilvmoreira.github.io/localctl/adding-tools/) | Write your own per-app or cluster-wide addon |
|
|
324
341
|
| [Troubleshooting](https://psilvmoreira.github.io/localctl/troubleshooting/) | Known issues, with cause and fix |
|
|
325
342
|
| [Uninstalling](https://psilvmoreira.github.io/localctl/uninstalling/) | Full teardown reference |
|
|
343
|
+
| [Contributing](https://psilvmoreira.github.io/localctl/contributing/) | Local setup, tests, pull requests, dependency policy, docs site |
|
|
326
344
|
| [Releasing](https://psilvmoreira.github.io/localctl/releasing/) | How versions are cut and published |
|
|
327
345
|
|
|
328
346
|
## Releases and versioning
|
|
@@ -333,15 +351,21 @@ The full documentation lives at **[psilvmoreira.github.io/localctl](https://psil
|
|
|
333
351
|
with notes and the package tarball.
|
|
334
352
|
- Versions follow [Semantic Versioning](https://semver.org). Before `1.0.0`, minor versions may
|
|
335
353
|
contain breaking changes.
|
|
336
|
-
-
|
|
354
|
+
- Every pull request shows a **release preview**: the version that merging it would publish,
|
|
355
|
+
including any unreleased commits already on `master`.
|
|
356
|
+
- npm releases are published from GitHub Actions through
|
|
357
|
+
[trusted publishing](https://docs.npmjs.com/trusted-publishers) (no npm tokens) with
|
|
337
358
|
[provenance](https://docs.npmjs.com/generating-provenance-statements). The npm package page links
|
|
338
359
|
each version to the exact commit and workflow run that built it.
|
|
360
|
+
- Dependencies and GitHub Actions are kept up to date by Dependabot, with every action pinned to a
|
|
361
|
+
commit SHA.
|
|
339
362
|
|
|
340
363
|
## Contributing
|
|
341
364
|
|
|
342
|
-
Issues and pull requests are welcome.
|
|
365
|
+
Issues and pull requests are welcome. The full guide (constraints, dependency policy, working on
|
|
366
|
+
the docs site) is in [**Contributing**](https://psilvmoreira.github.io/localctl/contributing/).
|
|
343
367
|
|
|
344
|
-
1. Fork the repository and create a branch
|
|
368
|
+
1. Fork the repository and create a branch from an up-to-date `master`.
|
|
345
369
|
2. Make your change and run the tests:
|
|
346
370
|
```sh
|
|
347
371
|
cd cli
|
|
@@ -350,15 +374,19 @@ Issues and pull requests are welcome.
|
|
|
350
374
|
npm run test:pack # the published package installs and runs
|
|
351
375
|
```
|
|
352
376
|
3. Open a pull request with a [Conventional Commits](https://www.conventionalcommits.org/) title.
|
|
353
|
-
|
|
377
|
+
PRs are squash-merged, so the title decides the next version. GitHub pre-fills it from the
|
|
378
|
+
branch name, which fails the title check: edit it.
|
|
354
379
|
|
|
355
380
|
| Title | Release |
|
|
356
381
|
|---|---|
|
|
357
|
-
| `fix: ...` | Patch (`0.
|
|
358
|
-
| `feat: ...` | Minor (`0.
|
|
359
|
-
| `feat!: ...` | Major (`0.
|
|
382
|
+
| `fix: ...`, `perf: ...` | Patch (`0.4.0` โ `0.4.1`) |
|
|
383
|
+
| `feat: ...` | Minor (`0.4.1` โ `0.5.0`) |
|
|
384
|
+
| `feat!: ...` | Major (`0.5.0` โ `1.0.0`) |
|
|
360
385
|
| `docs:` `chore:` `ci:` `refactor:` `test:` | No release |
|
|
361
386
|
|
|
387
|
+
4. Check the **release preview** on the `pr-title` check and wait for every check to pass
|
|
388
|
+
(title, tests on Linux/macOS/Windows ร Node 18/22, docs build, non-empty diff).
|
|
389
|
+
|
|
362
390
|
<details>
|
|
363
391
|
<summary><b>Repository layout</b></summary>
|
|
364
392
|
|
|
@@ -374,8 +402,10 @@ localctl/
|
|
|
374
402
|
โโโ cluster/manifests/ cluster-level manifests (TLS store, addon namespace)
|
|
375
403
|
โโโ schema/ JSON Schema for .local/config.json
|
|
376
404
|
โโโ examples/ ready-to-run sample apps
|
|
377
|
-
โโโ docs/ documentation
|
|
378
|
-
|
|
405
|
+
โโโ docs/ documentation pages (MkDocs Material, deployed to GitHub Pages)
|
|
406
|
+
โโโ overrides/ docs site template overrides (landing page)
|
|
407
|
+
โโโ bin/ bootstrap and uninstall scripts for source installs
|
|
408
|
+
โโโ .github/ CI, release and docs workflows, Dependabot config
|
|
379
409
|
```
|
|
380
410
|
|
|
381
411
|
</details>
|
|
@@ -388,8 +418,10 @@ npm uninstall -g @localctl/cli # the CLI itself
|
|
|
388
418
|
```
|
|
389
419
|
|
|
390
420
|
`localctl uninstall` asks for confirmation (skip with `-y`) and is safe to re-run. It leaves the
|
|
391
|
-
shared tools (`k3d`, `kubectl`, `tilt`, `mkcert`, `node`) and mkcert's root CA installed,
|
|
392
|
-
other projects may use them. It prints the exact commands to remove them
|
|
421
|
+
shared tools (`k3d`, `kubectl`, `tilt`, `mkcert`, `helm`, `node`) and mkcert's root CA installed,
|
|
422
|
+
since other projects may use them. It prints the exact commands to remove them for your OS
|
|
423
|
+
(`brew uninstall ...` on macOS; `winget uninstall ...` plus the `~.localctl ools` folder for
|
|
424
|
+
Tilt on Windows). Installed from
|
|
393
425
|
source with the bootstrap script? Use `./bin/uninstall.sh` or `./bin/uninstall.ps1` instead.
|
|
394
426
|
Details: [**Uninstalling**](https://psilvmoreira.github.io/localctl/uninstalling/).
|
|
395
427
|
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
|
52
|
+
installIfMissing('k3d', 'k3d', 'k3d.k3d');
|
|
53
53
|
installIfMissing('kubectl', 'kubernetes-cli', 'Kubernetes.kubectl');
|
|
54
|
-
installIfMissing('tilt', 'tilt',
|
|
54
|
+
installIfMissing('tilt', 'tilt', installTiltWindows);
|
|
55
55
|
installIfMissing('mkcert', 'mkcert', 'FiloSottile.mkcert');
|
|
56
56
|
installIfMissing('helm', 'helm', 'Helm.Helm');
|
|
57
57
|
|
package/src/lib/hostsFile.js
CHANGED
|
@@ -24,6 +24,20 @@ function listApps() {
|
|
|
24
24
|
return Object.keys(registry);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// The Windows counterpart of `sudo cp`: copies src over the hosts file from an elevated
|
|
28
|
+
// PowerShell, which raises a UAC prompt. Returns false if the prompt is declined or the copy
|
|
29
|
+
// fails. The inner command goes through -EncodedCommand so paths need no nested quoting.
|
|
30
|
+
function copyElevatedWindows(src) {
|
|
31
|
+
const quote = (s) => `'${s.replace(/'/g, "''")}'`;
|
|
32
|
+
const inner = `Copy-Item -LiteralPath ${quote(src)} -Destination ${quote(HOSTS_PATH)} -Force`;
|
|
33
|
+
const encoded = Buffer.from(inner, 'utf16le').toString('base64');
|
|
34
|
+
const res = spawnSync('powershell', [
|
|
35
|
+
'-NoProfile', '-NonInteractive', '-Command',
|
|
36
|
+
`Start-Process powershell -Verb RunAs -Wait -WindowStyle Hidden -ArgumentList '-NoProfile','-NonInteractive','-EncodedCommand','${encoded}'`,
|
|
37
|
+
], { stdio: 'ignore' });
|
|
38
|
+
return res.status === 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
27
41
|
function writeHosts(next, current) {
|
|
28
42
|
if (next === current) {
|
|
29
43
|
logger.info('Hosts file already up to date.');
|
|
@@ -38,8 +52,13 @@ function writeHosts(next, current) {
|
|
|
38
52
|
const tmp = path.join(os.tmpdir(), 'localctl-hosts-new');
|
|
39
53
|
fs.writeFileSync(tmp, next);
|
|
40
54
|
if (process.platform === 'win32') {
|
|
41
|
-
logger.warn('Need Administrator rights to update the hosts file.
|
|
42
|
-
|
|
55
|
+
logger.warn('Need Administrator rights to update the hosts file. Approve the Windows prompt to continue.');
|
|
56
|
+
if (copyElevatedWindows(tmp) && fs.readFileSync(HOSTS_PATH, 'utf8') === next) {
|
|
57
|
+
logger.success(`Updated ${HOSTS_PATH}`);
|
|
58
|
+
} else {
|
|
59
|
+
logger.warn('Hosts file not updated, so *.local.test addresses won\'t resolve. Run in an elevated PowerShell:');
|
|
60
|
+
console.log(` Copy-Item "${tmp}" "${HOSTS_PATH}" -Force`);
|
|
61
|
+
}
|
|
43
62
|
} else {
|
|
44
63
|
logger.warn('Need sudo to update the hosts file.');
|
|
45
64
|
const res = spawnSync('sudo', ['cp', tmp, HOSTS_PATH], { stdio: 'inherit' });
|
package/src/lib/toolInstall.js
CHANGED
|
@@ -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
|
-
//
|
|
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 };
|