diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index e316f6558..001bbe1cd 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -43,7 +43,7 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - name: Build and push Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true @@ -72,7 +72,7 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - name: Build and push Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true @@ -85,12 +85,19 @@ jobs: container: image: ghcr.io/jdx/mise:dev needs: [dev] + env: + GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v4 - run: cargo install --path . --debug - run: mise trust --all - run: mise install -y - - run: mise run test + - name: mise run test + uses: nick-fields/retry@v3 + with: + timeout_minutes: 30 + max_attempts: 3 + command: mise run test dockerhub: runs-on: ubuntu-latest steps: @@ -110,7 +117,7 @@ jobs: with: images: jdxcode/mise - name: Build and push Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..2e2e1ccd4 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,42 @@ +name: mise-docs + +on: + push: + paths: + - "docs/**" + branches: + - main + pull_request: + paths: + - "docs/**" + branches: + - main + +concurrency: + group: mise-docs-release-${{ github.head_ref }} + cancel-in-progress: true + +env: + MISE_EXPERIMENTAL: 1 + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # for lastUpdated + - uses: jdx/mise-action@v2 + with: + install_args: bun + working_directory: docs + - run: bun install + working-directory: docs + - run: bun run docs:build + working-directory: docs + - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + run: mise run release-docs + working-directory: docs + env: + AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dad6c35ab..2d5d23164 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: release on: push: tags: ["v*"] - branches: ["release", "win"] + branches: ["release", "win", "docs"] workflow_dispatch: concurrency: @@ -250,20 +250,18 @@ jobs: - build-tarball-win steps: - uses: actions/checkout@v4 + - uses: crazy-max/ghaction-import-gpg@v6 with: - path: mise - - uses: actions/checkout@v4 - with: - repository: jdx/mise-docs - path: mise-docs - token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + gpg_private_key: ${{ secrets.MISE_GPG_KEY }} + git_user_signingkey: true + git_commit_gpgsign: true - name: cache zipsign id: cache-zipsign uses: actions/cache@v4 with: path: ~/.cargo/bin/zipsign key: cargo-zipsign - - run: ./mise/scripts/setup-zipsign.sh + - run: ./scripts/setup-zipsign.sh env: ZIPSIGN: ${{ secrets.ZIPSIGN }} - name: Install fd-find @@ -281,12 +279,6 @@ jobs: with: key: ${{ secrets.RTX_SSH_KEY }} known_hosts: ${{ secrets.RTX_KNOWN_HOSTS_AUR }} - - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.MISE_GPG_KEY }} - git_user_signingkey: true - git_commit_gpgsign: true - workdir: mise-docs - uses: actions/download-artifact@v4 with: { path: artifacts } - run: ls -R artifacts @@ -299,16 +291,13 @@ jobs: mise-v*.zip merge-multiple: true - run: ls -R artifacts - - run: mise/scripts/release.sh + - run: scripts/release.sh env: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} - - name: mise-docs push - if: startsWith(github.event.ref, 'refs/tags/v') - run: git push - working-directory: mise-docs + GITHUB_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: GitHub Release Assets uses: softprops/action-gh-release@v2 if: startsWith(github.event.ref, 'refs/tags/v') @@ -362,14 +351,15 @@ jobs: runs-on: ubuntu-22.04 container: ghcr.io/jdx/mise:alpine timeout-minutes: 30 - needs: [e2e-linux] - if: startsWith(github.event.ref, 'refs/tags/v') + needs: [release] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Bump APKBUILD run: sudo -Eu packager ./scripts/release-alpine.sh env: - ALPINE_PUB_KEY: ${{ secrets.ALPINE_PUB_KEY }} + ALPINE_GITLAB_TOKEN: ${{ secrets.ALPINE_GITLAB_TOKEN }} + ALPINE_KEY_ID: ${{ secrets.ALPINE_KEY_ID }} ALPINE_PRIV_KEY: ${{ secrets.ALPINE_PRIV_KEY }} - GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} + ALPINE_PUB_KEY: ${{ secrets.ALPINE_PUB_KEY }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.idea/git_toolbox_blame.xml b/.idea/git_toolbox_blame.xml new file mode 100644 index 000000000..7dc124965 --- /dev/null +++ b/.idea/git_toolbox_blame.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/mise.iml b/.idea/mise.iml index 26265d4cb..ff4628d83 100644 --- a/.idea/mise.iml +++ b/.idea/mise.iml @@ -26,17 +26,17 @@ - - + + - + - \ No newline at end of file + diff --git a/.markdownlint.json b/.markdownlint.json index a36edfc88..a69775f0a 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,6 +1,7 @@ { "MD004": false, "MD013": false, + "MD029": false, "MD033": false, "MD040": false, "MD041": false diff --git a/.mise/tasks/release-docs b/.mise/tasks/release-docs new file mode 100755 index 000000000..dcd339804 --- /dev/null +++ b/.mise/tasks/release-docs @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -xeuo pipefail + +export AWS_REGION=auto +export AWS_ENDPOINT_URL=https://6e243906ff257b965bcae8025c2fc344.r2.cloudflarestorage.com + +bun run docs:build + +if [ $((RANDOM % 30)) -eq 0 ]; then + # delete old assets only roughly 1/30 times + # deleting old assets can break the site for people currently on it + # but it's also good to keep things tidy + aws s3 rm --recursive s3://mise/assets/ + aws s3 rm --recursive --exclude "*" --include "*.html" s3://mise/ +fi + +aws s3 cp --recursive .vitepress/dist s3://mise/ diff --git a/.mise/tasks/release-plz b/.mise/tasks/release-plz index c21ebeda5..c30755d4a 100755 --- a/.mise/tasks/release-plz +++ b/.mise/tasks/release-plz @@ -13,7 +13,7 @@ if ! echo "$released_versions" | grep -q "^$cur_version$"; then changelog="$(echo "$changelog" | tail -n +3)" git tag "v$cur_version" -s -m "$changelog" git push --tags - gh release create "v$cur_version" --title "v$cur_version" --notes "$changelog" + gh release create "v$cur_version" --title "v$cur_version" --notes "$changelog" --draft exit 0 fi diff --git a/CHANGELOG.md b/CHANGELOG.md index e070fbe61..ebde8e7aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,319 @@ # Changelog +## [2024.8.7](https://github.com/jdx/mise/compare/v2024.8.6..v2024.8.7) - 2024-08-16 + +### ๐Ÿ› Bug Fixes + +- mise treats escaped newlines in env files differently than dotenvy by [@roele](https://github.com/roele) in [#2455](https://github.com/jdx/mise/pull/2455) +- wait for spawned tasks to die before exiting by [@jdx](https://github.com/jdx) in [#2461](https://github.com/jdx/mise/pull/2461) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- update dependency vitepress to v1.3.2 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2450](https://github.com/jdx/mise/pull/2450) + +## [2024.8.6](https://github.com/jdx/mise/compare/v2024.8.5..v2024.8.6) - 2024-08-12 + +### ๐Ÿ› Bug Fixes + +- spm backend doesn't allow a GitHub repo name containing a dot by [@roele](https://github.com/roele) in [#2449](https://github.com/jdx/mise/pull/2449) + +### ๐Ÿšœ Refactor + +- renamed tool_request_version to tool_request to match the class by [@jdx](https://github.com/jdx) in [76a611a](https://github.com/jdx/mise/commit/76a611ac0f3cfbc7ac58fdc87a528e86ef73507e) + +### ๐Ÿ“š Documentation + +- fix typos again by [@kianmeng](https://github.com/kianmeng) in [#2446](https://github.com/jdx/mise/pull/2446) +- add executable permission after installation by [@kianmeng](https://github.com/kianmeng) in [#2447](https://github.com/jdx/mise/pull/2447) + +## [2024.8.5](https://github.com/jdx/mise/compare/v2024.8.4..v2024.8.5) - 2024-08-03 + +### ๐Ÿš€ Features + +- show friendly errors when not in verbose/debug mode by [@jdx](https://github.com/jdx) in [#2431](https://github.com/jdx/mise/pull/2431) +- allow installing cargo packages with `--git` by [@jdx](https://github.com/jdx) in [#2430](https://github.com/jdx/mise/pull/2430) +- some ux improvements to `mise sync nvm` by [@jdx](https://github.com/jdx) in [#2432](https://github.com/jdx/mise/pull/2432) + +### ๐Ÿ› Bug Fixes + +- display untrusted file on error by [@jdx](https://github.com/jdx) in [#2423](https://github.com/jdx/mise/pull/2423) +- `mise trust` issue with unstable hashing by [@jdx](https://github.com/jdx) in [#2427](https://github.com/jdx/mise/pull/2427) +- use newer eza in e2e test by [@jdx](https://github.com/jdx) in [eec3989](https://github.com/jdx/mise/commit/eec3989d8602ebc10304adbd5ded0574fc2981f0) +- take out home directory paths from `mise dr` output by [@jdx](https://github.com/jdx) in [#2433](https://github.com/jdx/mise/pull/2433) + +### ๐Ÿ” Other Changes + +- use pub(crate) to get notified about dead code by [@jdx](https://github.com/jdx) in [#2426](https://github.com/jdx/mise/pull/2426) + +## [2024.8.4](https://github.com/jdx/mise/compare/v2024.8.3..v2024.8.4) - 2024-08-02 + +### ๐Ÿ› Bug Fixes + +- alpine key madness by [@jdx](https://github.com/jdx) in [a7156e0](https://github.com/jdx/mise/commit/a7156e0042cf10fc3d43723ffd6a92860b4faa0a) +- alpine github key by [@jdx](https://github.com/jdx) in [a52b68d](https://github.com/jdx/mise/commit/a52b68d024a8ce9955bd84347cc591b249717312) +- alpine github key by [@jdx](https://github.com/jdx) in [ebc923f](https://github.com/jdx/mise/commit/ebc923ff3c140c6c282bb0c1a2896ad758b4a3c2) +- spm - cannot install package with null release name field by [@roele](https://github.com/roele) in [#2419](https://github.com/jdx/mise/pull/2419) + +### ๐Ÿ” Other Changes + +- removed dead code by [@jdx](https://github.com/jdx) in [#2416](https://github.com/jdx/mise/pull/2416) + +## [2024.8.3](https://github.com/jdx/mise/compare/v2024.8.2..v2024.8.3) - 2024-08-01 + +### ๐Ÿงช Testing + +- clean up global config test by [@jdx](https://github.com/jdx) in [c9f2ec5](https://github.com/jdx/mise/commit/c9f2ec514082c6b1816c52378ce5c29d24aa73cc) + +### ๐Ÿ” Other Changes + +- set extra alpine key by [@jdx](https://github.com/jdx) in [c6b152b](https://github.com/jdx/mise/commit/c6b152bd1864b49c392ad64becbff1b1722be52f) +- test alpine releases by [@jdx](https://github.com/jdx) in [08f7730](https://github.com/jdx/mise/commit/08f77301c772eb55cee376908f9d907e42c7fe4b) +- perform alpine at the very end by [@jdx](https://github.com/jdx) in [7c31e17](https://github.com/jdx/mise/commit/7c31e17cc6ff612298c8bdb335d86cab95c9473b) +- chmod by [@jdx](https://github.com/jdx) in [a3fe85b](https://github.com/jdx/mise/commit/a3fe85b7b71faecb220b33d6cc3b630884b4343a) +- added jq/gh to alpine docker by [@jdx](https://github.com/jdx) in [e1514cf](https://github.com/jdx/mise/commit/e1514cf95cc625085530c12afc6a7ceb57ff0b64) + +## [2024.8.2](https://github.com/jdx/mise/compare/v2024.8.1..v2024.8.2) - 2024-08-01 + +### ๐Ÿ› Bug Fixes + +- windows bug fixes by [@jdx](https://github.com/jdx) in [465ea89](https://github.com/jdx/mise/commit/465ea894f317eda025783e66a68f58ab10319790) +- made cmd! work on windows by [@jdx](https://github.com/jdx) in [c0cef5b](https://github.com/jdx/mise/commit/c0cef5b0941b476badfdbb4f46f24b117d72698d) +- got node to install on windows by [@jdx](https://github.com/jdx) in [e5aa94e](https://github.com/jdx/mise/commit/e5aa94ecb14c7700823ff7dd58a6e633ced5e054) +- windows shims by [@jdx](https://github.com/jdx) in [fc2cd48](https://github.com/jdx/mise/commit/fc2cd489babe834546424831a9613e1d0558aa7d) +- windows paths by [@jdx](https://github.com/jdx) in [a06bcce](https://github.com/jdx/mise/commit/a06bcce484ce405342e68a1ac5dbb667db376f5e) + +### ๐Ÿ” Other Changes + +- fix build by [@jdx](https://github.com/jdx) in [9d85182](https://github.com/jdx/mise/commit/9d8518249c783819a82366f8541f1ea20959e771) +- dry-run alpine releases by [@jdx](https://github.com/jdx) in [0ef2727](https://github.com/jdx/mise/commit/0ef2727905ce904e44b25cfe46c29645fd41405a) +- update bun version in e2e test by [@jdx](https://github.com/jdx) in [f4b339f](https://github.com/jdx/mise/commit/f4b339f7974dbb261e7e8a387d082f4090e01f21) +- fix bun test by [@jdx](https://github.com/jdx) in [00d7054](https://github.com/jdx/mise/commit/00d70543a5f3e0db891b7bfb505e65dacb66d8f0) + +## [2024.8.1](https://github.com/jdx/mise/compare/v2024.8.0..v2024.8.1) - 2024-08-01 + +### ๐Ÿ› Bug Fixes + +- various windows bug fixes by [@jdx](https://github.com/jdx) in [90b02eb](https://github.com/jdx/mise/commit/90b02eb49055bc7d458cd3cbfb0de00119539dfb) +- ignore PROMPT_DIRTRIM in diffing logic by [@jdx](https://github.com/jdx) in [7b5563c](https://github.com/jdx/mise/commit/7b5563cd007edf26bc17f07e6cddabacad451e00) + +### ๐Ÿ“š Documentation + +- added information on rolling alpine tokens by [@jdx](https://github.com/jdx) in [bd693b0](https://github.com/jdx/mise/commit/bd693b02fb4d1060ff7a07dcea07b4a7c5584a8b) + +### ๐Ÿ” Other Changes + +- mark releases as draft until they have been fully released by [@jdx](https://github.com/jdx) in [508f125](https://github.com/jdx/mise/commit/508f125dcea9c6d0457b59c36293204d25adc7ef) +- fix windows builds by [@jdx](https://github.com/jdx) in [91c90a2](https://github.com/jdx/mise/commit/91c90a2b2d373998433c64196254f7e4d0d8cd82) +- fix alpine release builds by [@jdx](https://github.com/jdx) in [a7534bb](https://github.com/jdx/mise/commit/a7534bbdd961e6a16852c947f1594d6a52034e58) +- only edit releases when not a dry run by [@jdx](https://github.com/jdx) in [2255522](https://github.com/jdx/mise/commit/2255522b5045e45ce0dea3699f6555a22a271971) + +## [2024.8.0](https://github.com/jdx/mise/compare/v2024.7.5..v2024.8.0) - 2024-08-01 + +### ๐Ÿ“š Documentation + +- Fix 'mise x' command snippet in the Continuous Integration section by [@mollyIV](https://github.com/mollyIV) in [#2411](https://github.com/jdx/mise/pull/2411) + +### ๐Ÿ” Other Changes + +- retry mise tests for docker-dev-test workflow by [@jdx](https://github.com/jdx) in [cc014dd](https://github.com/jdx/mise/commit/cc014dde3dedd1d891dab62fc37e4633dc995226) +- add BSD-2-Clause to allowed dep licenses by [@jdx](https://github.com/jdx) in [b4ea53c](https://github.com/jdx/mise/commit/b4ea53c4b2b01103ed93fc185dbca858730c3207) +- create new alpine gitlab token to replace the expired one by [@jdx](https://github.com/jdx) in [b30db04](https://github.com/jdx/mise/commit/b30db04aaa1f13ef0dcdf02e6df2f2afbdd73c94) + +### New Contributors + +* @mollyIV made their first contribution in [#2411](https://github.com/jdx/mise/pull/2411) + +## [2024.7.5](https://github.com/jdx/mise/compare/v2024.7.4..v2024.7.5) - 2024-07-29 + +### ๐Ÿ› Bug Fixes + +- mise use does not create a local .mise.toml anymore by [@roele](https://github.com/roele) in [#2406](https://github.com/jdx/mise/pull/2406) +- transform `master` to `ref:master` in ls-remote for zig by [@chasinglogic](https://github.com/chasinglogic) in [#2409](https://github.com/jdx/mise/pull/2409) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- bump openssl from 0.10.64 to 0.10.66 by [@dependabot[bot]](https://github.com/dependabot[bot]) in [#2397](https://github.com/jdx/mise/pull/2397) + +### New Contributors + +* @chasinglogic made their first contribution in [#2409](https://github.com/jdx/mise/pull/2409) + +## [2024.7.4](https://github.com/jdx/mise/compare/v2024.7.3..v2024.7.4) - 2024-07-19 + +### ๐Ÿš€ Features + +- added MISE_LIBGIT2 setting by [@jdx](https://github.com/jdx) in [#2386](https://github.com/jdx/mise/pull/2386) + +### ๐Ÿ› Bug Fixes + +- keep RUBYLIB env var by [@jdx](https://github.com/jdx) in [#2387](https://github.com/jdx/mise/pull/2387) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- update dependency vitepress to v1.3.1 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2376](https://github.com/jdx/mise/pull/2376) +- update docker/build-push-action action to v6 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2377](https://github.com/jdx/mise/pull/2377) + +## [2024.7.3](https://github.com/jdx/mise/compare/v2024.7.2..v2024.7.3) - 2024-07-14 + +### ๐Ÿ” Other Changes + +- Use correct capitalization of GitHub by [@jahands](https://github.com/jahands) in [#2372](https://github.com/jdx/mise/pull/2372) +- loosen git2 requirements by [@jdx](https://github.com/jdx) in [#2374](https://github.com/jdx/mise/pull/2374) + +### New Contributors + +* @jahands made their first contribution in [#2372](https://github.com/jdx/mise/pull/2372) + +## [2024.7.2](https://github.com/jdx/mise/compare/v2024.7.1..v2024.7.2) - 2024-07-13 + +### ๐Ÿš€ Features + +- support env vars in plugin urls by [@roele](https://github.com/roele) in [#2370](https://github.com/jdx/mise/pull/2370) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- update rust crate self_update to 0.41 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2359](https://github.com/jdx/mise/pull/2359) +- update dependency vitepress to v1.3.0 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2358](https://github.com/jdx/mise/pull/2358) + +## [2024.7.1](https://github.com/jdx/mise/compare/v2024.7.0..v2024.7.1) - 2024-07-08 + +### ๐Ÿ” Other Changes + +- Fix link to Python venv activation doc section by [@gzurowski](https://github.com/gzurowski) in [#2353](https://github.com/jdx/mise/pull/2353) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- update built to 0.7.4 and git2 to 0.19.0 by [@roele](https://github.com/roele) in [#2357](https://github.com/jdx/mise/pull/2357) + +### New Contributors + +* @gzurowski made their first contribution in [#2353](https://github.com/jdx/mise/pull/2353) + +## [2024.7.0](https://github.com/jdx/mise/compare/v2024.6.6..v2024.7.0) - 2024-07-03 + +### ๐Ÿ“š Documentation + +- update actions/checkout version by [@light-planck](https://github.com/light-planck) in [#2349](https://github.com/jdx/mise/pull/2349) + +### New Contributors + +* @light-planck made their first contribution in [#2349](https://github.com/jdx/mise/pull/2349) + +## [2024.6.6](https://github.com/jdx/mise/compare/v2024.6.5..v2024.6.6) - 2024-06-20 + +### ๐Ÿ› Bug Fixes + +- improve error message for missing plugins by [@jdx](https://github.com/jdx) in [#2313](https://github.com/jdx/mise/pull/2313) + +### ๐Ÿ” Other Changes + +- Update configuration.md by [@jdx](https://github.com/jdx) in [a2f19cb](https://github.com/jdx/mise/commit/a2f19cbc655058472009d000c77d1fc8df8612fd) +- Update index.md by [@jdx](https://github.com/jdx) in [d9ef467](https://github.com/jdx/mise/commit/d9ef467ee9ef026039fa2220163f21a2214ebbfc) +- Update index.md by [@jdx](https://github.com/jdx) in [63739c8](https://github.com/jdx/mise/commit/63739c880dbfefdecab282736710d496d7e88dbc) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- bump curve25519-dalek from 4.1.2 to 4.1.3 by [@dependabot[bot]](https://github.com/dependabot[bot]) in [#2306](https://github.com/jdx/mise/pull/2306) + +## [2024.6.5](https://github.com/jdx/mise/compare/v2024.6.4..v2024.6.5) - 2024-06-18 + +### ๐Ÿ” Other Changes + +- Fixes nix flake by [@laozc](https://github.com/laozc) in [#2305](https://github.com/jdx/mise/pull/2305) + +### New Contributors + +* @laozc made their first contribution in [#2305](https://github.com/jdx/mise/pull/2305) + +## [2024.6.4](https://github.com/jdx/mise/compare/v2024.6.3..v2024.6.4) - 2024-06-15 + +### ๐Ÿ› Bug Fixes + +- allow glob patterns in task outputs and sources by [@adamdickinson](https://github.com/adamdickinson) in [#2286](https://github.com/jdx/mise/pull/2286) + +### New Contributors + +* @adamdickinson made their first contribution in [#2286](https://github.com/jdx/mise/pull/2286) + +## [2024.6.3](https://github.com/jdx/mise/compare/v2024.6.2..v2024.6.3) - 2024-06-10 + +### ๐Ÿ› Bug Fixes + +- github API rate limiting could be handled more explicitly by [@roele](https://github.com/roele) in [#2274](https://github.com/jdx/mise/pull/2274) +- group prefix not applied for script tasks by [@roele](https://github.com/roele) in [#2273](https://github.com/jdx/mise/pull/2273) +- mise plugins ls returns error immediately after install by [@roele](https://github.com/roele) in [#2271](https://github.com/jdx/mise/pull/2271) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- update dependency vitepress to v1.2.3 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2277](https://github.com/jdx/mise/pull/2277) +- update rust crate regex to v1.10.5 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2278](https://github.com/jdx/mise/pull/2278) +- update rust crate regex to v1.10.5 by [@renovate[bot]](https://github.com/renovate[bot]) in [577de17](https://github.com/jdx/mise/commit/577de1757c4bb4e6421d3e281c44825a8b8788b8) + +## [2024.6.2](https://github.com/jdx/mise/compare/v2024.6.1..v2024.6.2) - 2024-06-07 + +### ๐Ÿ› Bug Fixes + +- after installing the latest version, mise rolls back to the previous one by [@roele](https://github.com/roele) in [#2258](https://github.com/jdx/mise/pull/2258) + +### ๐Ÿ“š Documentation + +- add SPM backend page by [@kattouf](https://github.com/kattouf) in [#2252](https://github.com/jdx/mise/pull/2252) + +## [2024.6.1](https://github.com/jdx/mise/compare/v2024.6.0..v2024.6.1) - 2024-06-03 + +### ๐Ÿš€ Features + +- SPM(Swift Package Manager) backend by [@kattouf](https://github.com/kattouf) in [#2241](https://github.com/jdx/mise/pull/2241) + +### ๐Ÿ› Bug Fixes + +- mise up node fails by [@roele](https://github.com/roele) in [#2243](https://github.com/jdx/mise/pull/2243) + +### ๐Ÿ“š Documentation + +- fixed syntax by [@jdx](https://github.com/jdx) in [56083f8](https://github.com/jdx/mise/commit/56083f858a4ee28a020a414c1addf0c2bb7968af) + +### ๐Ÿงช Testing + +- set GITHUB_TOKEN in dev-test by [@jdx](https://github.com/jdx) in [4334313](https://github.com/jdx/mise/commit/4334313da52c13d7f87656fb0e7978e4cf1f5d2f) + +### ๐Ÿ” Other Changes + +- Update getting-started.md: nushell by [@chrmod](https://github.com/chrmod) in [#2248](https://github.com/jdx/mise/pull/2248) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- update rust crate demand to v1.2.4 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2246](https://github.com/jdx/mise/pull/2246) +- update rust crate zip to v2.1.2 by [@renovate[bot]](https://github.com/renovate[bot]) in [#2247](https://github.com/jdx/mise/pull/2247) + +### New Contributors + +* @chrmod made their first contribution in [#2248](https://github.com/jdx/mise/pull/2248) + +## [2024.6.0](https://github.com/jdx/mise/compare/v2024.5.28..v2024.6.0) - 2024-06-01 + +### ๐Ÿ” Other Changes + +- bump itertools by [@jdx](https://github.com/jdx) in [#2238](https://github.com/jdx/mise/pull/2238) +- migrate docs repo into this repo by [@jdx](https://github.com/jdx) in [#2237](https://github.com/jdx/mise/pull/2237) + +## [2024.5.28](https://github.com/jdx/mise/compare/v2024.5.27..v2024.5.28) - 2024-05-31 + +### ๐Ÿ› Bug Fixes + +- download keeps failing if it takes more than 30s by [@roele](https://github.com/roele) in [#2224](https://github.com/jdx/mise/pull/2224) +- settings unset does not work by [@roele](https://github.com/roele) in [#2230](https://github.com/jdx/mise/pull/2230) +- cleaner community-developed plugin warning by [@jdx](https://github.com/jdx) in [8dcf0f3](https://github.com/jdx/mise/commit/8dcf0f3a746fcae74d944412b6f0e141ded88860) +- correct `mise use` ordering by [@jdx](https://github.com/jdx) in [#2234](https://github.com/jdx/mise/pull/2234) + +### ๐Ÿšœ Refactor + +- forge -> backend by [@jdx](https://github.com/jdx) in [#2227](https://github.com/jdx/mise/pull/2227) + +### ๐Ÿงช Testing + +- added reset() to more tests by [@jdx](https://github.com/jdx) in [5a6ea6a](https://github.com/jdx/mise/commit/5a6ea6afb9855827b5e6216aa20760dd45f5502f) + ## [2024.5.27](https://github.com/jdx/mise/compare/v2024.5.26..v2024.5.27) - 2024-05-31 ### ๐Ÿšœ Refactor diff --git a/Cargo.lock b/Cargo.lock index d59e72c55..f83a4c664 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,9 +62,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -77,33 +77,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -126,13 +126,14 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "assert_cmd" -version = "2.0.14" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" +checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" dependencies = [ "anstyle", "bstr", "doc-comment", + "libc", "predicates", "predicates-core", "predicates-tree", @@ -141,9 +142,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" +checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" dependencies = [ "flate2", "futures-core", @@ -173,12 +174,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -199,9 +194,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -214,20 +209,20 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata 0.4.6", + "regex-automata 0.4.7", "serde", ] [[package]] name = "built" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17" +checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4" dependencies = [ "chrono", "git2", @@ -253,9 +248,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "calm_io" @@ -278,13 +273,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.98" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -293,6 +288,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.38" @@ -303,7 +304,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -339,9 +340,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", "clap_derive", @@ -349,9 +350,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -361,27 +362,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clap_mangen" -version = "0.2.20" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1dd95b5ebb5c1c54581dd6346f3ed6a79a3eef95dd372fc2ac13d535535300e" +checksum = "f17415fd4dfbea46e3274fcd8d368284519b358654772afb700dc2e8d2b24eeb" dependencies = [ "clap", "roff", @@ -420,7 +421,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -437,9 +438,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "confique" @@ -505,15 +506,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -569,21 +570,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] name = "curve25519-dalek" -version = "4.1.2" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest", "fiat-crypto", - "platforms", "rustc_version", "subtle", "zeroize", @@ -597,14 +597,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] name = "demand" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d167ad7844a6bbd8b6a2abb593281e5ad6a555907cdf53dd78df93b43ef50d0b" +checksum = "911255fd44dad0c6b5675764410acef128715644cbb68e5fad6a503ead70db0a" dependencies = [ "console", "once_cell", @@ -638,7 +638,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -671,13 +671,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -706,9 +706,9 @@ dependencies = [ [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "ed25519" @@ -737,9 +737,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" dependencies = [ "serde", ] @@ -752,18 +752,18 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", ] [[package]] name = "env_logger" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", @@ -861,14 +861,14 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -879,9 +879,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" dependencies = [ "crc32fast", "miniz_oxide", @@ -1001,7 +1001,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -1063,11 +1063,11 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "git2" -version = "0.18.3" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", "libgit2-sys", "log", @@ -1076,6 +1076,12 @@ dependencies = [ "url", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "globset" version = "0.4.14" @@ -1085,8 +1091,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -1095,7 +1101,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "ignore", "walkdir", ] @@ -1155,7 +1161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22074da8bba2ef26fc1737ae6c777b5baab5524c2dc403b5c6a76166766ccda5" dependencies = [ "cfg-if", - "nix", + "nix 0.26.4", "serde", "widestring", "windows-sys 0.48.0", @@ -1175,9 +1181,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", @@ -1185,12 +1191,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -1198,9 +1204,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "humansize" @@ -1219,9 +1225,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -1238,19 +1244,21 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.26.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http", "hyper", "hyper-util", "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", + "webpki-roots", ] [[package]] @@ -1271,9 +1279,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", @@ -1332,7 +1340,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.6", + "regex-automata 0.4.7", "same-file", "walkdir", "winapi-util", @@ -1356,9 +1364,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1416,18 +1424,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - -[[package]] -name = "itertools" -version = "0.12.1" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -1446,18 +1445,18 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1475,21 +1474,21 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a" [[package]] name = "libgit2-sys" -version = "0.16.2+1.7.2" +version = "0.17.0+1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" dependencies = [ "cc", "libc", @@ -1505,6 +1504,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall", +] + [[package]] name = "libssh2-sys" version = "0.3.0" @@ -1521,9 +1531,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" dependencies = [ "cc", "libc", @@ -1551,9 +1561,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matchers" @@ -1566,9 +1576,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -1599,7 +1609,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -1616,30 +1626,31 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "mise" -version = "2024.5.27" +version = "2024.8.7" dependencies = [ "assert_cmd", - "base64 0.22.1", + "base64", "built", "calm_io", "chrono", @@ -1662,18 +1673,19 @@ dependencies = [ "flate2", "fslock", "git2", + "glob", "globset", - "globwalk", "heck 0.5.0", "home", "humantime", "indenter", - "indexmap 2.2.6", + "indexmap 2.4.0", "indicatif", "indoc", "insta", - "itertools 0.12.1", + "itertools", "log", + "nix 0.29.0", "num_cpus", "once_cell", "openssl", @@ -1695,6 +1707,7 @@ dependencies = [ "shell-words", "signal-hook", "simplelog", + "siphasher 1.0.1", "strum", "sys-info", "tabled", @@ -1747,6 +1760,18 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1830,11 +1855,11 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -1851,7 +1876,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -1862,9 +1887,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -1874,12 +1899,12 @@ dependencies = [ [[package]] name = "os_pipe" -version = "1.1.5" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1948,9 +1973,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" dependencies = [ "memchr", "thiserror", @@ -1959,9 +1984,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" dependencies = [ "pest", "pest_generator", @@ -1969,22 +1994,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] name = "pest_meta" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" dependencies = [ "once_cell", "pest", @@ -1998,7 +2023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.4.0", ] [[package]] @@ -2036,7 +2061,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] @@ -2056,7 +2081,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -2087,17 +2112,11 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "platforms" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" - [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "powerfmt" @@ -2107,15 +2126,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" -version = "3.1.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ "anstyle", "difflib", @@ -2127,15 +2149,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -2177,9 +2199,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.84" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -2193,6 +2215,54 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +dependencies = [ + "bytes", + "rand", + "ring", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -2254,23 +2324,23 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -2284,13 +2354,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", ] [[package]] @@ -2301,18 +2371,18 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "async-compression", - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-core", @@ -2332,6 +2402,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", "rustls", "rustls-native-certs", "rustls-pemfile", @@ -2392,9 +2463,9 @@ dependencies = [ [[package]] name = "roff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" +checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" [[package]] name = "rustc-demangle" @@ -2402,6 +2473,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2417,7 +2494,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno 0.3.9", "libc", "linux-raw-sys", @@ -2426,11 +2503,11 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ - "log", + "once_cell", "ring", "rustls-pki-types", "rustls-webpki", @@ -2440,9 +2517,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -2453,25 +2530,25 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ - "base64 0.22.1", + "base64", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" dependencies = [ "ring", "rustls-pki-types", @@ -2510,11 +2587,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -2523,9 +2600,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -2533,9 +2610,9 @@ dependencies = [ [[package]] name = "self-replace" -version = "1.3.7" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525db198616b2bcd0f245daf7bfd8130222f7ee6af9ff9984c19a61bf1160c55" +checksum = "f7828a58998685d8bf5a3c5e7a3379a5867289c20828c3ee436280b44b598515" dependencies = [ "fastrand 1.9.0", "tempfile", @@ -2544,9 +2621,9 @@ dependencies = [ [[package]] name = "self_update" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4997484b55df069a4773d822715695b2cc27b23829eca2a4b41690e948bdeb" +checksum = "469a3970061380c19852269f393e74c0fe607a4e23d85267382cf25486aa8de5" dependencies = [ "either", "flate2", @@ -2573,40 +2650,41 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -2645,12 +2723,12 @@ dependencies = [ [[package]] name = "shared_child" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" +checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" dependencies = [ "libc", - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -2665,6 +2743,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -2702,9 +2786,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "similar" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "simplelog" @@ -2723,6 +2807,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -2734,9 +2824,9 @@ dependencies = [ [[package]] name = "slug" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" dependencies = [ "deunicode", "wasm-bindgen", @@ -2782,31 +2872,31 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2821,9 +2911,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" dependencies = [ "proc-macro2", "quote", @@ -2832,9 +2922,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "sys-info" @@ -2874,9 +2964,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -2885,14 +2975,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand 2.1.0", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2960,7 +3051,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -2971,7 +3062,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", "test-case-core", ] @@ -2994,27 +3085,27 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -3062,9 +3153,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -3077,18 +3168,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3103,9 +3193,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ "rustls", "rustls-pki-types", @@ -3127,9 +3217,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -3139,20 +3229,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", @@ -3176,15 +3266,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -3341,9 +3431,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "untrusted" @@ -3353,9 +3443,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -3376,8 +3466,8 @@ checksum = "169665ca600da05053b6c2df83d243fc45cf58e8373dd7b939aaf87f664629fe" dependencies = [ "clap", "heck 0.5.0", - "indexmap 2.2.6", - "itertools 0.13.0", + "indexmap 2.4.0", + "itertools", "kdl", "log", "miette", @@ -3391,9 +3481,9 @@ dependencies = [ [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" @@ -3409,17 +3499,17 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "versions" -version = "6.2.0" +version = "6.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a8931f8d167b6448076020e70b9de46dcf5ea1731212481a092d0071c4ac5b" +checksum = "f25d498b63d1fdb376b4250f39ab3a5ee8d103957346abacd911e2d8b612c139" dependencies = [ - "itertools 0.12.1", + "itertools", "nom", "serde", ] @@ -3437,9 +3527,9 @@ dependencies = [ [[package]] name = "vte_generate_state_changes" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" dependencies = [ "proc-macro2", "quote", @@ -3481,34 +3571,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -3518,9 +3609,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3528,28 +3619,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -3557,18 +3648,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ "rustls-pki-types", ] [[package]] name = "which" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" +checksum = "3d9c5ed668ee1f17edb3b627225343d210006a90bb1e3745ce1f30b1fb115075" dependencies = [ "either", "home", @@ -3600,11 +3691,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3622,7 +3713,7 @@ dependencies = [ "windows-core", "windows-implement", "windows-interface", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -3631,7 +3722,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -3642,7 +3733,7 @@ checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -3653,7 +3744,7 @@ checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.74", ] [[package]] @@ -3671,7 +3762,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -3691,18 +3791,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -3713,9 +3813,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -3725,9 +3825,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -3737,15 +3837,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -3755,9 +3855,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -3767,9 +3867,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -3779,9 +3879,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -3791,15 +3891,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.9" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -3867,6 +3967,27 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + [[package]] name = "zeroize" version = "1.8.1" @@ -3875,16 +3996,16 @@ checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" [[package]] name = "zip" -version = "2.1.1" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd56a4d5921bc2f99947ac5b3abe5f510b1be7376fdc5e9fce4a23c6a93e87c" +checksum = "40dd8c92efc296286ce1fbd16657c5dbefff44f1b4ca01cc5f517d8b7b3d3e2e" dependencies = [ "arbitrary", "crc32fast", "crossbeam-utils", "displaydoc", "flate2", - "indexmap 2.2.6", + "indexmap 2.4.0", "memchr", "thiserror", "zopfli", @@ -3892,11 +4013,11 @@ dependencies = [ [[package]] name = "zipsign-api" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba5aa1827d6b1a35a29b3413ec69ce5f796e4d897e3e5b38f461bef41d225ea" +checksum = "6413a546ada9dbcd0b9a3e0b0880581279e35047bce9797e523b3408e1df607c" dependencies = [ - "base64 0.21.7", + "base64", "ed25519-dalek", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 6fada764e..34b10ea41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.5.27" +version = "2024.8.7" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] @@ -62,9 +62,9 @@ eyre = "0.6.12" filetime = "0.2.23" flate2 = "1.0.30" fslock = "0.2.1" -git2 = "0.18.3" +git2 = "<1" +glob = "0.3.1" globset = "0.4.14" -globwalk = "0.9.1" heck = "0.5" home = "0.5.9" humantime = "2.1.0" @@ -72,11 +72,11 @@ indenter = "0.3.3" indexmap = { version = "2.2.6", features = ["serde"] } indicatif = { version = "0.17.8", features = ["default", "improved_unicode"] } indoc = "2.0.5" -itertools = "0.12.1" +itertools = "0.13" log = "0.4.21" num_cpus = "1.16.0" once_cell = "1.19.0" -openssl = { version = "0.10.64", optional = true } +openssl = { version = "0.10.66", optional = true } path-absolutize = "3.1.1" petgraph = "0.6.4" rand = "0.8.5" @@ -87,7 +87,7 @@ reqwest = { version = "0.12", default-features = false, features = [ "gzip", ] } rmp-serde = "1.3.0" -self_update = { version = "0.40", default-features = false, features = [ +self_update = { version = "0.41", default-features = false, features = [ "archive-tar", "compression-flate2", "signatures", @@ -100,6 +100,7 @@ shell-escape = "0.1.5" shell-words = "1.1.0" signal-hook = "0.3.17" simplelog = { version = "0.12.2" } +siphasher = "1" strum = { version = "0.26.2", features = ["derive"] } sys-info = "0.9.1" tabled = { version = "0.15.0", features = ["ansi"] } @@ -124,10 +125,11 @@ xx = { version = "1.0.0", features = ["glob"] } zip = { version = "2", default-features = false, features = ["deflate"] } [target.'cfg(unix)'.dependencies] -exec = "0.3.1" +exec = "0.3" +nix = {version="0.29", features=["signal", "user"]} [build-dependencies] -built = { version = "0.7.2", features = ["chrono", "git2"] } +built = { version = "0.7", features = ["chrono", "git2"] } [dev-dependencies] assert_cmd = "2.0.14" diff --git a/README.md b/README.md index 644fceb90..def1c504a 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.run | sh $ ~/.local/bin/mise --version -mise 2024.5.27 +mise 2024.8.7 ``` or install a specific a version: @@ -44,7 +44,7 @@ or install a specific a version: ```sh-session $ curl https://mise.run | MISE_VERSION=v2024.5.16 sh $ ~/.local/bin/mise --version -mise 2024.5.27 +mise 2024.8.7 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 7de26dad4..6cf9584a1 100644 --- a/default.nix +++ b/default.nix @@ -1,8 +1,8 @@ -{ pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, openssl }: +{ pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, openssl, git }: rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.5.27"; + version = "2024.8.7"; src = lib.cleanSource ./.; @@ -22,17 +22,17 @@ rustPlatform.buildRustPackage { ] ++ lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.Security darwin.apple_sdk.frameworks.SystemConfiguration ]; prePatch = '' - substituteInPlace ./test/data/plugins/**/bin/* \ - --replace '#!/usr/bin/env bash' '#!${bash}/bin/bash' - substituteInPlace ./src/fake_asdf.rs ./src/cli/reshim.rs \ - --replace '#!/bin/sh' '#!${bash}/bin/sh' + substituteInPlace ./src/test.rs ./test/data/plugins/**/bin/* \ + --replace '/usr/bin/env bash' '${bash}/bin/bash' + substituteInPlace ./src/fake_asdf.rs ./src/cli/generate/git_pre_commit.rs ./src/cli/generate/snapshots/*.snap \ + --replace '/bin/sh' '${bash}/bin/sh' substituteInPlace ./src/env_diff.rs \ --replace '"bash"' '"${bash}/bin/bash"' - substituteInPlace ./test/cwd/.mise/tasks/filetask \ - --replace '#!/usr/bin/env bash' '#!${bash}/bin/bash' substituteInPlace ./src/cli/direnv/exec.rs \ --replace '"env"' '"${coreutils}/bin/env"' \ --replace 'cmd!("direnv"' 'cmd!("${direnv}/bin/direnv"' + substituteInPlace ./src/git.rs ./src/test.rs \ + --replace '"git"' '"${git}/bin/git"' ''; # Skip the test_plugin_list_urls as it uses the .git folder, which diff --git a/deny.toml b/deny.toml index 9aaa8da3b..1e3d35adf 100644 --- a/deny.toml +++ b/deny.toml @@ -91,6 +91,7 @@ ignore = [ allow = [ "Apache-2.0 WITH LLVM-exception", "Apache-2.0", + "BSD-2-Clause", "BSD-3-Clause", "BSL-1.0", "ISC", diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..2c8e6b299 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,176 @@ +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +# VitePress +.vitepress/cache +.vitepress/dist diff --git a/docs/.mise.toml b/docs/.mise.toml new file mode 100644 index 000000000..5da73af9e --- /dev/null +++ b/docs/.mise.toml @@ -0,0 +1,12 @@ +tasks.dev = "bun run docs:dev" +tasks.build = "bun run docs:build" + +[tasks."commit-and-push"] +depends = ["build"] +run = [ + "git ci -pm docs", + "git push", +] + +[tools] +bun = 'latest' diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 000000000..b66226893 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,152 @@ +import { defineConfig } from 'vitepress' + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: "mise-en-place", + description: "mise-en-place documentation", + lang: 'en-US', + lastUpdated: true, + appearance: 'dark', + sitemap: { + hostname: 'https://mise.jdx.dev', + }, + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + outline: 'deep', + nav: [ + { text: 'Dev Tools', link: '/dev-tools/' }, + { text: 'Environments', link: '/environments' }, + { text: 'Tasks', link: '/tasks/' }, + ], + sidebar: [ + { text: 'Getting Started', link: '/getting-started' }, + { text: 'About', link: '/about' }, + { text: 'Coming from rtx', link: '/rtx' }, + { text: 'Configuration', link: '/configuration' }, + { text: 'Continuous Integration', link: '/continuous-integration' }, + { text: 'Demo', link: '/demo' }, + { text: 'FAQs', link: '/faq' }, + { text: 'How I Use mise', link: '/how-i-use-mise' }, + { text: 'IDE Integration', link: '/ide-integration' }, + { text: 'Paranoid', link: '/paranoid' }, + { text: 'Registry', link: '/registry' }, + { text: 'Plugins', link: '/plugins' }, + { text: 'Team', link: '/team' }, + { text: 'Contributing', link: '/contributing' }, + { text: 'Tips & Tricks', link: '/tips-and-tricks' }, + { + text: 'Dev Tools', + link: '/dev-tools/', + items: [ + { text: 'Aliases', link: '/dev-tools/aliases' }, + { text: 'Comparison to asdf', link: '/dev-tools/comparison-to-asdf' }, + { text: 'Shims', link: '/dev-tools/shims' }, + { + text: 'Backends', + link: '/dev-tools/backends/', + items: [ + { text: 'asdf', link: '/dev-tools/backends/asdf' }, + { text: 'cargo', link: '/dev-tools/backends/cargo' }, + { text: 'go', link: '/dev-tools/backends/go' }, + { text: 'npm', link: '/dev-tools/backends/npm' }, + { text: 'pipx', link: '/dev-tools/backends/pipx' }, + { text: 'spm', link: '/dev-tools/backends/spm' }, + { text: 'ubi', link: '/dev-tools/backends/ubi' }, + ] + } + ], + }, + { + text: 'Environments', + link: '/environments', + items: [ + { text: 'direnv', link: '/direnv' }, + { text: 'Profiles', link: '/profiles' }, + { text: 'Templates', link: '/templates' }, + ], + }, + { + text: 'Tasks', + link: '/tasks/', + items: [ + {text: 'Running Tasks', link: '/tasks/running-tasks'}, + {text: 'Script Tasks', link: '/tasks/script-tasks'}, + {text: 'TOML Tasks', link: '/tasks/toml-tasks'}, + ], + }, + { + text: 'Languages', + items: [ + { text: 'Bun', link: '/lang/bun' }, + { text: 'Deno', link: '/lang/deno' }, + { text: 'Erlang', link: '/lang/erlang' }, + { text: 'Go', link: '/lang/go' }, + { text: 'Java', link: '/lang/java' }, + { text: 'Node.js', link: '/lang/node' }, + { text: 'Python', link: '/lang/python' }, + { text: 'Ruby', link: '/lang/ruby' }, + { text: 'Rust', link: '/lang/rust' }, + ] + }, + { + text: 'Internals', + items: [ + { text: 'Cache Behavior', link: '/cache-behavior' }, + { text: 'Directory Structure', link: '/directories' }, + { text: 'Project Roadmap', link: '/project-roadmap' }, + ], + }, + { + text: 'CLI Reference', + link: '/cli/', + items: [ + { text: 'Global Flags', link: '/cli/global-flags' } + ] + }, + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/jdx/mise' } + ], + + editLink: { + pattern: 'https://github.com/jdx/mise/edit/main/docs/:path', + }, + search: { + provider: 'algolia', + options: { + indexName: 'rtx', + appId: '1452G4RPSJ', + apiKey: 'ad09b96a7d2a30eddc2771800da7a1cf', + insights: true, + } + }, + footer: { + message: 'Licensed under the MIT License. Maintained by @jdx and friends.', + copyright: 'Copyright ยฉ 2024 @jdx', + }, + carbonAds: { + code: 'CWYIPKQN', + placement: 'misejdxdev', + }, + }, + markdown: { + // languages: [ + // "elisp" + // ] + }, + head: [ + [ + 'script', + { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=G-B69G389C8T' } + ], + [ + 'script', + {}, + `window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', 'G-B69G389C8T');` + ] + ], +}) diff --git a/docs/LICENSE b/docs/LICENSE new file mode 100644 index 000000000..a548a770b --- /dev/null +++ b/docs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 jdx + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..6af9b4bb4 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,3 @@ +# mise-docs + +This repository contains the documentation website for the runtime executor [mise](https://github.com/jdx/mise). The website is powered by [VitePress](https://vitepress.dev/). diff --git a/docs/about.md b/docs/about.md new file mode 100644 index 000000000..65fa0ad0a --- /dev/null +++ b/docs/about.md @@ -0,0 +1,42 @@ +# About + +`mise` (pronounced "meez") or "mise-en-place" is a development environment setup tool. +The name refers to a French culinary phrase that roughly translates to "setup" or "put in place". +The idea is that before one begins cooking, they should have all their utensils and ingredients +ready to go in their place. + +`mise` does the same for your projects. Using its `.mise.toml` config file, +you'll have a consistent way to setup and interact with your projects no matter what +language they're written in. + +Its functionality is grouped into 3 categories described below. + +`mise` installs and manages dev tools/runtimes like node, python, or terraform both +simplifying installing these tools and allowing you to specify which version of these +tools to use in different projects. `mise` supports [hundreds](/plugins.md) of dev tools. + +`mise` manages environment variables letting you specify configuration like +`AWS_ACCESS_KEY_ID` that may differ between projects. It can also be used to +automatically activate a [Python virtualenv](/lang/python) when entering projects too. + +`mise` is a task runner that can be used to share common tasks within +a project among developers and make things like running tasks on file changes +easy. + +## Contact + +`mise` is mostly built and maintained by me, [Jeff Dickey](https://jdx.dev). The goal is +to make local development of software easy and consistent across languages. I +have spent many years building dev tools and thinking about the problems that `mise` +addresses. + +I try to use the first-person in these docs since the reality is it's generally me +writing them and I think it makes it more interesting having a bit of my personality +in the text. + +This project is simply a labor of love. I am making it because I want to make +your life as a developer easier. I hope you find it useful. Feedback is a massive +driver for me. If you have anything positive or negative to say-even if it's just +to say hi-please reach out to me either on [Twitter](https://twitter.com/jdxcode), +[Mastodon](https://fosstodon.org/@jdx), [Discord](https://discord.gg/UBa7pJUN7Z), +or `jdx at this domain`. diff --git a/docs/bun.lockb b/docs/bun.lockb new file mode 100755 index 000000000..cda29d781 Binary files /dev/null and b/docs/bun.lockb differ diff --git a/docs/bun.md b/docs/bun.md deleted file mode 100644 index 052b9204e..000000000 --- a/docs/bun.md +++ /dev/null @@ -1 +0,0 @@ -See [mise.jdx.dev](https://mise.jdx.dev/lang/bun.html) for more information. diff --git a/docs/cache-behavior.md b/docs/cache-behavior.md new file mode 100644 index 000000000..3a14883ab --- /dev/null +++ b/docs/cache-behavior.md @@ -0,0 +1,31 @@ +# Cache Behavior + +mise makes use of caching in many places in order to be efficient. The details about how long to keep +cache for should eventually all be configurable. There may be gaps in the current behavior where +things are hardcoded, but I'm happy to add more settings to cover whatever config is needed. + +Below I explain the behavior it uses around caching. If you're seeing behavior where things don't appear +to be updating, this is a good place to start. + +## Plugin/Runtime Cache + +Each plugin has a cache that's stored in `~/$MISE_CACHE_DIR/`. It stores +the list of versions available for that plugin (`mise ls-remote `), the legacy filenames (see below), +the list of aliases, the bin directories within each runtime installation, and the result of +running `exec-env` after the runtime was installed. + +Remote versions are updated daily by default. The file is zlib messagepack, if you want to view it you can +run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). + +```sh +cat ~/$MISE_CACHE_DIR/node/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode +``` + +Note that the caching of `exec-env` may be problematic if the script isn't simply exporting +static values. The vast majority of `exec-env` scripts only export static values, but if you're +working with a plugin that has a dynamic `exec-env` submit +a ticket and we can try to figure out what to do. + +Caching `exec-env` massively improved the performance of mise since it requires calling bash +every time mise is initialized. Ideally, we can keep this +behavior. diff --git a/docs/cli/global-flags.md b/docs/cli/global-flags.md new file mode 100644 index 000000000..d699cd0b4 --- /dev/null +++ b/docs/cli/global-flags.md @@ -0,0 +1,28 @@ +# Global Flags + +These flags are available for all commands in the CLI. They may not always +do anything though. + +## `-C, --cd ` + +Change directory before running command + +## `-q, --quiet` + +Suppress non-error messages + +## `-v, --verbose...` + +Show extra output (use -vv for even more) + +## `-y, --yes` + +Answer yes to all confirmation prompts + +## `-h, --help` + +Print help (see a summary with '-h') + +## `-V, --version` + +Print version diff --git a/docs/cli-reference.md b/docs/cli/index.md similarity index 98% rename from docs/cli-reference.md rename to docs/cli/index.md index ce2c6c975..32ce7da78 100644 --- a/docs/cli-reference.md +++ b/docs/cli/index.md @@ -167,6 +167,7 @@ Examples: go npm pipx + spm ubi ``` @@ -446,9 +447,9 @@ Examples: ## `mise generate github-action [OPTIONS]` ```text -[experimental] Generate a Github Action workflow file +[experimental] Generate a GitHub Action workflow file -This command generates a Github Action workflow file that runs a mise task like `mise run ci` +This command generates a GitHub Action workflow file that runs a mise task like `mise run ci` when you push changes to your repository. Usage: generate github-action [OPTIONS] @@ -471,7 +472,7 @@ Examples: $ mise generate github-action --write --task=ci $ git commit -m "feat: add new feature" - $ git push # runs `mise run ci` on Github + $ git push # runs `mise run ci` on GitHub ``` ## `mise implode [OPTIONS]` @@ -1025,7 +1026,7 @@ In .mise.toml, tasks take this form: outputs = ["dist/**/*.js"] Alternatively, tasks can be defined as standalone scripts. -These must be located in the `.mise/tasks` directory. +These must be located in the `.mise/tasks`, `mise/tasks` or `.config/mise/tasks` directory. The name of the script will be the name of the tasks. $ cat .mise/tasks/build<`. Add this section to `.mise.toml` if you want +to share the plugin location/revision with other developers in your project. + +This is similar +to [`MISE_SHORTHANDS`](https://github.com/jdx/mise#mise_shorthands_fileconfigmiseshorthandstoml) +but doesn't require a separate file. + +### `[aliases]` - Tool version aliases + +The following makes `mise install node@my_custom_node` install node-20.x +this can also be specified in a [plugin](/dev-tools/aliases.md). +note adding an alias will also add a symlink, in this case: + +```sh +~/.local/share/mise/installs/node/20 -> ./20.x.x +``` + +```toml +my_custom_node = '20' +``` + +## Global config: `~/.config/mise/config.toml` + +mise can be configured in `~/.config/mise/config.toml`. It's like local `.mise.toml` files except +that +it is used for all directories. + +```toml +[tools] +# global tool versions go here +# you can set these with `mise use -g` +node = 'lts' +python = ['3.10', '3.11'] + +[settings] +# plugins can read the versions files used by other version managers (if enabled by the plugin) +# for example, .nvmrc in the case of node's nvm +legacy_version_file = true # enabled by default (unlike asdf) +legacy_version_file_disable_tools = ['python'] # disable for specific tools + +# configure `mise install` to always keep the downloaded archive +always_keep_download = false # deleted after install by default +always_keep_install = false # deleted on failure by default + +# configure how frequently (in minutes) to fetch updated plugin repository changes +# this is updated whenever a new runtime is installed +# (note: this isn't currently implemented but there are plans to add it: https://github.com/jdx/mise/issues/128) +plugin_autoupdate_last_check_duration = '1 week' # set to 0 to disable updates + +# config files with these prefixes will be trusted by default +trusted_config_paths = [ + '~/work/my-trusted-projects', +] + +verbose = false # set to true to see full installation output, see `MISE_VERBOSE` +asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `MISE_ASDF_COMPAT` +http_timeout = 30 # set the timeout for http requests in seconds, see `MISE_HTTP_TIMEOUT` +jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. +raw = false # set to true to directly pipe plugins to stdin/stdout/stderr +yes = false # set to true to automatically answer yes to all prompts + +not_found_auto_install = true # see MISE_NOT_FOUND_AUTO_INSTALL +task_output = "prefix" # see Tasks Runner for more information +paranoid = false # see MISE_PARANOID + +shorthands_file = '~/.config/mise/shorthands.toml' # path to the shorthands file, see `MISE_SHORTHANDS_FILE` +disable_default_shorthands = false # disable the default shorthands, see `MISE_DISABLE_DEFAULT_SHORTHANDS` +disable_tools = ['node'] # disable specific tools, generally used to turn off core tools + +env_file = '.env' # load env vars from a dotenv file, see `MISE_ENV_FILE` + +experimental = true # enable experimental features + +# configure messages displayed when entering directories with config files +status = { missing_tools = "if_other_versions_installed", show_env = false, show_tools = false } +``` + +## System config: `/etc/mise/config.toml` + +Similar to `~/.config/mise/config.toml` but for all users on the system. This is useful for +setting defaults for all users. + +## `.tool-versions` + +The `.tool-versions` file is asdf's config file and it can be used in mise just like `.mise.toml`. +It isn't as flexible so it's recommended to use `.mise.toml` instead. It can be useful if you +already have a lot of `.tool-versions` files or work on a team that uses asdf. + +Here is an example with all the supported syntax: + +```text +node 20.0.0 # comments are allowed +ruby 3 # can be fuzzy version +shellcheck latest # also supports "latest" +jq 1.6 +erlang ref:master # compile from vcs ref +go prefix:1.19 # uses the latest 1.19.x versionโ€”needed in case "1.19" is an exact match +shfmt path:./shfmt # use a custom runtime +node lts # use lts version of node (not supported by all plugins) + +node sub-2:lts # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) +python sub-0.1:latest # install python-3.10 if the latest is 3.11 +``` + +See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on +this file format. + +## Scopes + +Both `.mise.toml` and `.tool-versions` support "scopes" which modify the behavior of the version: + +- `ref:` - compile from a vcs (usually git) ref +- `prefix:` - use the latest version that matches the prefix. Useful for Go since `1.20` + would only match `1.20` exactly but `prefix:1.20` will match `1.20.1` and `1.20.2` etc. +- `path:` - use a custom compiled version at the given path. One use-case is to re-use + Homebrew tools (e.g.: `path:/opt/homebrew/opt/node@20`). +- `sub-:` - subtracts PARTIAL_VERSION from ORIG_VERSION. This can + be used to express something like "2 versions behind lts" such as `sub-2:lts`. Or 1 minor + version behind the latest version: `sub-0.1:latest`. + +## Legacy version files + +mise supports "legacy version files" just like asdf. They're language-specific files +like `.node-version` +and `.python-version`. These are ideal for setting the runtime version of a project without forcing +other developers to use a specific tool like mise/asdf. + +They support aliases, which means you can have an `.nvmrc` file with `lts/hydrogen` and it will work +in mise and nvm. Here are some of the supported legacy version files: + +| Plugin | "Legacy" (Idiomatic) Files | +|-----------|----------------------------------------------------| +| crystal | `.crystal-version` | +| elixir | `.exenv-version` | +| go | `.go-version`, `go.mod` | +| java | `.java-version`, `.sdkmanrc` | +| node | `.nvmrc`, `.node-version` | +| python | `.python-version` | +| ruby | `.ruby-version`, `Gemfile` | +| terraform | `.terraform-version`, `.packer-version`, `main.tf` | +| yarn | `.yarnrc` | + +In mise these are enabled by default. You can disable them +with `mise settings set legacy_version_file false`. +There is a performance cost to having these when they're parsed as it's performed by the plugin in +`bin/parse-version-file`. However these are [cached](/cache-behavior) so it's not a huge deal. +You may not even notice. + +::: info +asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies +that they shouldn't be usedโ€”which is definitely not the case IMO. I prefer the term "idiomatic" +version files since they're version files not specific to asdf/mise and can be used by other tools. +(`.nvmrc` being a notable exception, which is tied to a specific tool.) +::: + +## Settings + +The following is a list of all of mise's settings. These can be set via `mise settings set`, +by directly modifying `~/.config/mise/config.toml` or local config, or via environment variables. + +Some of them also can be set via global CLI flags. + +### `activate_aggressive` + +* Type: `bool` +* Env: `MISE_ACTIVATE_AGGRESSIVE` +* Default: `false` + +Pushes tools' bin-paths to the front of PATH instead of allowing modifications of PATH after +activation to take precedence. + +For example, if you have the following in your `.mise.toml`: + +```toml +[tools] +node = '20' +python = '3.12' +``` + +But you also have this in your `~/.zshrc`: + +```sh +eval "$(mise activate zsh)" +PATH="/some/other/python:$PATH" +``` + +What will happen is `/some/other/python` will be used instead of the python installed by mise. This +means +you typically want to put `mise activate` at the end of your shell config so nothing overrides it. + +If you want to always use the mise versions of tools despite what is in your shell config, set this +to `true`. +In that case, using this example again, `/some/other/python` will be after mise's python in PATH. + +### `asdf_compat` + +* Type: `bool` +* Env: `MISE_ASDF_COMPAT` +* Default: `false` + +Only output `.tool-versions` files in `mise local|global` which will be usable by asdf. +This disables mise functionality that would otherwise make these files incompatible with asdf such +as non-pinned versions. + +This will also change the default global tool config to be `~/.tool-versions` instead +of `~/.config/mise/config.toml`. + +### `disable_tools` + +* Type: `string[]` (comma-delimited) +* Env: `MISE_DISABLE_TOOLS` +* Default: `[]` + +Disables the specified tools. Separate with `,`. Generally used for core plugins but works with any +tool. + +### `libgit2` + +* Type: `bool` +* Env: `MISE_LIBGIT2` +* Default: `true` + +Use libgit2 for git operations. This is generally faster but may not be as compatible if the +system's libgit2 is not the same version as the one used by mise. + +### `status.missing_tools` + +* Type: `enum` +* Env: `MISE_STATUS_MISSING_TOOLS` +* Default: `if_other_versions_installed` + +| Choice | Description | +|-----------------------------------------|----------------------------------------------------------------------------| +| `if_other_versions_installed` [default] | Show the warning only when the tool has at least 1 other version installed | +| `always` | Always show the warning | +| `never` | Never show the warning | + +Show a warning if tools are not installed when entering a directory with a `.mise.toml` file. + +::: tip +Disable tools with [`disable_tools`](#disable_tools). +::: + +### `status.show_env` + +* Type: `bool` +* Env: `MISE_STATUS_SHOW_ENV` +* Default: `false` + +Show configured env vars when entering a directory with a `.mise.toml` file. + +### `status.show_tools` + +* Type: `bool` +* Env: `MISE_STATUS_SHOW_TOOLS` +* Default: `false` + +Show active tools when entering a directory with a `.mise.toml` file. + +## Environment variables + +mise can also be configured via environment variables. The following options are available: + +### `MISE_DATA_DIR` + +Default: `~/.local/share/mise` or `$XDG_DATA_HOME/mise` + +This is the directory where mise stores plugins and tool installs. These are not supposed to be +shared +across machines. + +### `MISE_CACHE_DIR` + +Default (Linux): `~/.cache/mise` or `$XDG_CACHE_HOME/mise` +Default (macOS): `~/Library/Caches/mise` or `$XDG_CACHE_HOME/mise` + +This is the directory where mise stores internal cache. This is not supposed to be shared +across machines. It may be deleted at any time mise is not running. + +### `MISE_TMP_DIR` + +Default: [`std::env::temp_dir()`](https://doc.rust-lang.org/std/env/fn.temp_dir.html) implementation +in rust + +This is used for temporary storage such as when installing tools. + +### `MISE_SYSTEM_DIR` + +Default: `/etc/mise` + +This is the directory where mise stores system-wide configuration. + +### `MISE_GLOBAL_CONFIG_FILE` + +Default: `$MISE_CONFIG_DIR/config.toml` (Usually ~/.config/mise/config.toml) + +This is the path to the config file. + +### `MISE_DEFAULT_TOOL_VERSIONS_FILENAME` + +Set to something other than ".tool-versions" to have mise look for `.tool-versions` files but with +a different name. + +### `MISE_DEFAULT_CONFIG_FILENAME` + +Set to something other than `.mise.toml` to have mise look for `.mise.toml` config files with a +different name. + +### `MISE_ENV` + +Enables environment-specific config files such as `.mise.development.toml`. +Use this for different env vars or different tool versions in +development/staging/production environments. See +[Profiles](/profiles) for more on how +to use this feature. + +### `MISE_ENV_FILE` + +Set to a filename to read from env from a dotenv file. e.g.: `MISE_ENV_FILE=.env`. +Uses [dotenvy](https://crates.io/crates/dotenvy) under the hood. + +### `MISE_USE_VERSIONS_HOST` + +Default: `true` + +Set to "false" to disable using [mise-versions](https://mise-versions.jdx.dev) as +a quick way for mise to query for new versions. This host regularly grabs all the +latest versions of core and community plugins. It's faster than running a plugin's +`list-all` command and gets around GitHub rate limiting problems when using it. + +See [FAQ](/faq#new-version-of-a-tool-is-not-available) for more information. + +### `MISE_${PLUGIN}_VERSION` + +Set the version for a runtime. For example, `MISE_NODE_VERSION=20` will use regardless +of what is set in `.tool-versions`/`.mise.toml`. + +### `MISE_LEGACY_VERSION_FILE=1` + +Plugins can read the versions files used by other version managers (if enabled by the plugin) +for example, `.nvmrc` in the case of node's nvm. See [legacy version files](#legacy-version-files) +for more +information. + +Set to "0" to disable legacy version file parsing. + +### `MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS=node,python` + +Disable legacy version file parsing for specific tools. Separate with `,`. + +### `MISE_USE_TOML=0` + +Set to `1` to default to using `.mise.toml` in `mise local` instead of `.tool-versions` for +configuration. + +For now this is not used by `mise use` which will only use `.mise.toml` unless `--path` is +specified. + +### `MISE_TRUSTED_CONFIG_PATHS` + +This is a list of paths that mise will automatically mark as +trusted. They can be separated with `:`. + +### `MISE_LOG_LEVEL=trace|debug|info|warn|error` + +These change the verbosity of mise. + +You can also use `MISE_DEBUG=1`, `MISE_TRACE=1`, and `MISE_QUIET=1` as well as +`--log-level=trace|debug|info|warn|error`. + +### `MISE_LOG_FILE=~/mise.log` + +Output logs to a file. + +### `MISE_LOG_FILE_LEVEL=trace|debug|info|warn|error` + +Same as `MISE_LOG_LEVEL` but for the log _file_ output level. This is useful if you want +to store the logs but not have them litter your display. + +### `MISE_ALWAYS_KEEP_DOWNLOAD=1` + +Set to "1" to always keep the downloaded archive. By default it is deleted after install. + +### `MISE_ALWAYS_KEEP_INSTALL=1` + +Set to "1" to always keep the install directory. By default it is deleted on failure. + +### `MISE_VERBOSE=1` + +This shows the installation output during `mise install` and `mise plugin install`. +This should likely be merged so it behaves the same as `MISE_DEBUG=1` and we don't have +2 configuration for the same thing, but for now it is its own config. + +Equivalent to `MISE_LOG_LEVEL=debug`. + +### `MISE_QUIET=1` + +Equivalent to `MISE_LOG_LEVEL=warn`. + +### `MISE_PARANOID=0` + +Enables extra-secure behavior. See [Paranoid](/paranoid). + +### `MISE_HTTP_TIMEOUT` + +Set the timeout for http requests in seconds. The default is `30`. + +### `MISE_JOBS=1` + +Set the number plugins or runtimes to install in parallel. The default is `4`. + +### `MISE_RAW=1` + +Set to "1" to directly pipe plugin scripts to stdin/stdout/stderr. By default stdin is disabled +because when installing a bunch of plugins in parallel you won't see the prompt. Use this if a +plugin accepts input or otherwise does not seem to be installing correctly. + +Sets `MISE_JOBS=1` because only 1 plugin script can be executed at a time. + +### `MISE_SHORTHANDS_FILE=~/.config/mise/shorthands.toml` + +Use a custom file for the shorthand aliases. This is useful if you want to share plugins within +an organization. + +Shorthands make it so when a user runs something like `mise install elixir` mise will +automatically install the [asdf-elixir](https://github.com/asdf-vm/asdf-elixir) plugin. By +default, it uses the shorthands in +[`src/default_shorthands.rs`](https://github.com/jdx/mise/blob/main/src/default_shorthands.rs). + +The file should be in this toml format: + +```toml +elixir = "https://github.com/my-org/mise-elixir.git" +node = "https://github.com/my-org/mise-node.git" +``` + +### `MISE_DISABLE_DEFAULT_SHORTHANDS=1` + +Disables the shorthand aliases for installing plugins. You will have to specify full URLs when +installing plugins, e.g.: `mise plugin install node https://github.com/asdf-vm/asdf-node.git` + +### `MISE_YES=1` + +This will automatically answer yes or no to prompts. This is useful for scripting. + +### `MISE_NOT_FOUND_AUTO_INSTALL=true` + +Set to false to disable the "command not found" handler to autoinstall missing tool versions. +Disable this +if experiencing strange behavior in your shell when a command is not foundโ€”but please submit a +ticket to +help diagnose problems. + +### `MISE_TASK_OUTPUT=prefix` + +This controls the output of `mise run`. It can be one of: + +- `prefix` - (default if jobs > 1) print by line with the prefix of the task name +- `interleave` - (default if jobs == 1) display stdout/stderr as it comes in + +### `MISE_EXPERIMENTAL=1` + +Enables experimental features. I generally will publish new features under +this config which needs to be enabled to use them. While a feature is marked +as "experimental" its behavior may change or even disappear in any release. + +The idea is experimental features can be iterated on this way so we can get +the behavior right, but once that label goes away you shouldn't expect things +to change without a proper deprecationโ€”and even then it's unlikely. + +Also, I very often will use experimental as a beta flag as well. New +functionality that I want to test with a smaller subset of users I will often +push out under experimental mode even if it's not related to an experimental +feature. + +If you'd like to help me out, consider enabling it even if you don't have +a particular feature you'd like to try. Also, if something isn't working +right, try disabling it if you can. + +### `MISE_ALL_COMPILE=1` + +Default: false unless running NixOS or Alpine (let me know if others should be added) + +Do not use precompiled binaries for all languages. Useful if running on a Linux distribution +like Alpine that does not use glibc and therefore likely won't be able to run precompiled binaries. + +Note that this needs to be setup for each language. File a ticket if you notice a language that is +not +working with this config. + +### `MISE_FISH_AUTO_ACTIVATE=1` + +Configures the vendor_conf.d script for fish shell to automatically activate. +This file is automatically used in homebrew and potentially other installs to +automatically activate mise without configuring. + +Defaults to enabled, set to "0" to disable. diff --git a/docs/contact.md b/docs/contact.md new file mode 100644 index 000000000..e7b1815e7 --- /dev/null +++ b/docs/contact.md @@ -0,0 +1,17 @@ +# Contact + +`mise` is mostly built and maintained by me, [Jeff Dickey](https://jdx.dev). The goal is +to make local development of software easy and consistent across languages. I +have spent many years building dev tools and thinking about the problems that `mise` +addresses. + +I try to use the first-person in these docs since the reality is it's generally me +writing them and I think it makes it more interesting having a bit of my personality +in the text. + +This project is simply a labor of love. I am making it because I want to make +your life as a developer easier. I hope you find it useful. Feedback is a massive +driver for me. If you have anything positive or negative to say-even if it's just +to say hi-please reach out to me either on [Twitter](https://twitter.com/jdxcode), +[Mastodon](https://fosstodon.org/@jdx), [Discord](https://discord.gg/UBa7pJUN7Z), +or `jdx at this domain`. diff --git a/docs/continuous-integration.md b/docs/continuous-integration.md new file mode 100644 index 000000000..aef704dbf --- /dev/null +++ b/docs/continuous-integration.md @@ -0,0 +1,72 @@ +# Continuous integration + +You can use Mise in continuous integration environments to provision the environment with the tools the project needs. +We recommend that your project pins the tools to a specific version to ensure the environment is reproducible. + +## Any CI provider + +Continuous integration pipelines allow running arbitrary commands. You can use this to install Mise and run `mise install` to install the tools: + +```yaml +script: | + curl https://mise.run | sh + mise install +``` + +To ensure you run the version of the tools installed by Mise, make sure you run them through the `mise x` command: + +```yaml +script: | + mise x -- npm test +``` + +Alternatively, you can add the [shims](/dev-tools/shims.md) directory to your `PATH`, if the CI provider allows it. + +## GitHub Actions + +If you use GitHub Actions, we provide a [mise-action](https://github.com/jdx/mise-action) that wraps the installation of Mise and the tools. All you need to do is to add the action to your workflow: + +```yaml +name: test +on: + pull_request: + branches: + - main + push: + branches: + - main +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: jdx/mise-action@v2 + with: + version: 2023.12.0 # [default: latest] mise version to install + install: true # [default: true] run `mise install` + cache: true # [default: true] cache mise using GitHub's cache + # automatically write this .tool-versions file + experimental: true # [default: false] enable experimental features + tool_versions: | + shellcheck 0.9.0 + # or, if you prefer .mise.toml format: + mise_toml: | + [tools] + shellcheck = "0.9.0" + - run: shellcheck scripts/*.sh +``` + +## Xcode Cloud + +If you are using Xcode Cloud, you can use custom `ci_post_clone.sh` [build script](https://developer.apple.com/documentation/xcode/writing-custom-build-scripts) to install Mise. Here's an example: + +```bash +#!/bin/sh +curl https://mise.run | sh +export PATH="$HOME/.local/bin:$PATH" + +mise install # Installs the tools in .mise.toml +eval "$(mise activate bash --shims)" # Adds the activated tools to $PATH + +swiftlint {args} +``` diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 000000000..2ca3da2b2 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,174 @@ +# Contributing + +Before submitting a PR, unless it's something obvious, consider filing an issue or simply mention what you plan to do in the [Discord](https://discord.gg/UBa7pJUN7Z). +PRs are often either rejected or need to change significantly after submission so make sure before you start working on something it won't be a wasted effort. + +## Dev Container + +There is a docker setup that makes development with mise easier. It is especially helpful for running the E2E tests. +Here's some example ways to use it: + +```sh +mise run docker:cargo build +mise run docker:cargo test +mise run docker:mise --help # run `mise --help` in the dev container +mise run docker:mise run test:e2e # run the e2e tests inside of the docker container +mise run docker:e2e # shortcut for `mise run docker:mise run test:e2e` +``` + +## Testing + +### Unit Tests + +Unit tests are used for fast, relatively simple logic. They can be run with `cargo test`. The dev container is recommended +for executing since it does not require having a proper local setup. + +To run locally you will need to first disable mise if you are using it. + +:::code-group + +```sh [dev container] +mise run docker:cargo test +``` + +```sh [local] +cargo test +``` + +::: + +### E2E Tests + +Like unit tests, the e2e tests should be run either in the dev container (recommended) or with mise disabled locally. + +:::code-group + +```sh [dev container] +mise run docker:e2e +``` + +```sh [local] +mise run test:e2e +``` + +::: + +Slow tests do not run by default or on PRs. They can be manually enabled with `TEST_ALL=1`. + +## Dependencies + +- [rust](https://www.rust-lang.org/) stable 1.70.0+ (I test with the beta channel locally, but CI uses stable, you can use whatever) +- [just](https://github.com/casey/just) this should be removed in favor of mise tasks but it's still used for some things. + +## Tasks + +Mise uses mise itself to run tasks. See available tasks with `mise tasks`: + +```sh +~/src/mise โฏ mise tasks +build ~/src/mise/.mise.toml +clean ~/src/mise/.mise.toml +docker:cargo run cargo inside of development docker โ€ฆ ~/src/mise/.mise.toml +docker:e2e run e2e tests inside of development docโ€ฆ ~/src/mise/.mise.toml +docker:image build docker image from Dockerfile ~/src/mise/.mise.toml +docker:mise run mise inside of development docker cโ€ฆ ~/src/mise/.mise.toml +format ~/src/mise/.mise.toml +lint ~/src/mise/.mise/config.toml +lint:fix ~/src/mise/.mise.toml +release ~/src/mise/.mise.toml +render ~/src/mise/.mise.toml +render:completions ~/src/mise/.mise.toml +render:help ~/src/mise/.mise.toml +render:mangen ~/src/mise/.mise.toml +signal-test ~/src/mise/.mise.toml +snapshots Update test snapshots ~/src/mise/.mise.toml +test ~/src/mise/.mise.toml +test:e2e ~/src/mise/.mise.toml +``` + +## Setup + +Shouldn't require anything special I'm aware of, but `mise run build` is a good sanity check to run and make sure it's all working. + +## Pre-commit hook + +You can optionally run a pre-commit hook which lints the codebase and updates generated code. +To do this, install [lefthook](https://github.com/evilmartians/lefthook) and run `lefthook install`. + +## Running the CLI + +Even if using the devcontainer, it's a good idea to create a shim to make it easy to launch mise. I use the following shim +in `~/.local/bin/@mise`: + +```sh +#!/bin/sh +exec cargo run -q --all-features --manifest-path ~/src/mise/Cargo.toml -- "$@" +``` + +::: note +Don't forget to change the manifest path to the correct path for your setup. +::: + +Then if that is in PATH just use `@mise` to run mise by compiling it on the fly. + +```sh +@mise --help +@mise run docker:e2e +eval "$(@mise activate zsh)" +@mise activate fish | source +``` + +## Releasing + +Run `mise run release -x [minor|patch]`. (minor if it is the first release in a month) + +## Linting + +- Lint codebase: `mise run lint` +- Lint and fix codebase: `mise run lint:fix` + +## Generating readme and shell completion files + +```sh +mise run render +``` + +## Testing packaging + +This is only necessary to test if actually changing the packaging setup. + +### Ubuntu (apt) + +This is for arm64, but you can change the arch to amd64 if you want. + +```sh +docker run -ti --rm ubuntu +apt update -y +apt install -y gpg sudo wget curl +sudo install -dm 755 /etc/apt/keyrings +wget -qO - https://mise.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/mise-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.gpg arch=arm64] https://mise.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/mise.list +apt update +apt install -y mise +mise -V +``` + +### Amazon Linux 2 (yum) + +```sh +docker run -ti --rm amazonlinux +yum install -y yum-utils +yum-config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo +yum install -y mise +mise -v +``` + +### Fedora (dnf) + +```sh +docker run -ti --rm fedora +dnf install -y dnf-plugins-core +dnf config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo +dnf install -y mise +mise -v +``` diff --git a/docs/demo.md b/docs/demo.md new file mode 100644 index 000000000..e1b1ba4d5 --- /dev/null +++ b/docs/demo.md @@ -0,0 +1,7 @@ +# 30 Second Demo + +The following shows using mise to install different versions +of [node](https://nodejs.org). +Note that calling `which node` gives us a real path to node, not a shim. + +[![demo](https://github.com/jdx/mise/blob/main/docs/demo.gif?raw=true)](https://github.com/jdx/mise/blob/main/docs/demo.gif) diff --git a/docs/deno.md b/docs/deno.md deleted file mode 100644 index 1ece4928b..000000000 --- a/docs/deno.md +++ /dev/null @@ -1 +0,0 @@ -Moved to [mise.jdx.dev/lang/deno.html](https://mise.jdx.dev/lang/deno.html). diff --git a/docs/dev-tools/aliases.md b/docs/dev-tools/aliases.md new file mode 100644 index 000000000..cec6d5bbd --- /dev/null +++ b/docs/dev-tools/aliases.md @@ -0,0 +1,37 @@ +# Aliases + +mise supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS +versions of runtimes. For example, you may want to specify `lts-hydrogen` as the version for +so you can use set it with `node lts-hydrogen` in `.tool-versions`/`.mise.toml`. + +User aliases can be created by adding an `alias.` section to `~/.config/mise/config.toml`: + +```toml +[alias.node] +my_custom_20 = '20' +``` + +Plugins can also provide aliases via a `bin/list-aliases` script. Here is an example showing node.js +versions: + +```bash +#!/usr/bin/env bash + +echo "lts-hydrogen 18" +echo "lts-gallium 16" +echo "lts-fermium 14" +``` + +::: info +Because this is mise-specific functionality not currently used by asdf it isn't likely to be in any +plugin currently, but plugin authors can add this script without impacting asdf users. +::: + +## Templates + +Alias values can be templates, see [Templates](/templates) for details. + +```toml +[alias.node] +current = "{{exec(command='node --version')}}" +``` diff --git a/docs/dev-tools/backends/asdf.md b/docs/dev-tools/backends/asdf.md new file mode 100644 index 000000000..0d4f62295 --- /dev/null +++ b/docs/dev-tools/backends/asdf.md @@ -0,0 +1,22 @@ +# asdf Backend + +asdf is the original backend for mise. It's the default if no backend is specified, +e.g.: `mise i ripgrep` will use [asdf](https://gitlab.com/wt0f/asdf-ripgrep) but `mise i cargo:ripgrep` +will use the [cargo](./cargo) backend. You can explicitly specify the asdf backend with `mise i asdf:ripgrep`. +If you wish. + +There are [hundreds of plugins](https://github.com/mise-plugins/registry) available in the +[mise registry](https://github.com/mise-plugins) and you can also install plugins from git +repos or local directories. + +::: warning +Take care using plugins as well as anything else you get from the internet. CLIs are +unfortunately capable of doing a lot of damage to your system if a bad actor manages to +get into your system through a plugin or other tool. +::: + +## Writing asdf plugins for mise + +See the asdf documentation for more information on [writing plugins](https://asdf-vm.com/plugins/create.html). + +_TODO: document special features only available in mise._ diff --git a/docs/dev-tools/backends/cargo.md b/docs/dev-tools/backends/cargo.md new file mode 100644 index 000000000..b645a6c16 --- /dev/null +++ b/docs/dev-tools/backends/cargo.md @@ -0,0 +1,61 @@ +# Cargo Backend + +You may install packages directly from [Cargo Crates](https://crates.io/) even if there +isn't an asdf plugin for it. + +The code for this is inside of the mise repository at [`./src/backend/cargo.rs`](https://github.com/jdx/mise/blob/main/src/backend/cargo.rs). + +## Dependencies + +This relies on having `cargo` installed. You can either install it on your +system via [rustup](https://rustup.rs/): + +```sh +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +Or you can install it via mise: + +```sh +mise use -g rust +``` + +## Usage + +The following installs the latest version of [eza](https://crates.io/crates/eza) and +sets it as the active version on PATH: + +```sh +$ mise use -g cargo:eza +$ eza --version +eza - A modern, maintained replacement for ls +v0.17.1 [+git] +https://github.com/eza-community/eza +``` + +The version will be set in `~/.config/mise/config.toml` with the following format: + +```toml +[tools] +"cargo:eza" = "latest" +``` + +## Configuration + +Set these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable listed. + +### `cargo_binstall` + +* Type: `bool` +* Env: `MISE_CARGO_BINSTALL` +* Default: `true` + +If true, mise will use `cargo binstall` instead of `cargo install` if +[`cargo-binstall`](https://crates.io/crates/cargo-binstall) is installed and on PATH. +This makes installing CLIs with cargo _much_ faster by downloading precompiled binaries. + +You can install it with mise: + +```sh +mise use -g cargo-binstall +``` diff --git a/docs/dev-tools/backends/go.md b/docs/dev-tools/backends/go.md new file mode 100644 index 000000000..b6c52b4bb --- /dev/null +++ b/docs/dev-tools/backends/go.md @@ -0,0 +1,30 @@ +# Go Backend + +You may install packages directly via [go install](https://go.dev/doc/install) even if there +isn't an asdf plugin for it. + +The code for this is inside of the mise repository at [`./src/backend/go.rs`](https://github.com/jdx/mise/blob/main/src/backend/go.rs). + +## Dependencies + +This relies on having `go` installed. Which you can install via mise: + +```sh +mise use -g go +``` + +::: tip +Any method of installing `go` is fine if you want to install go some other way. +mise will use whatever `go` is on PATH. +::: + +## Usage + +The following installs the latest version of [hivemind](https://github.com/DarthSim/hivemind) and +sets it as the active version on PATH: + +```sh +$ mise use -g go:github.com/DarthSim/hivemind +$ hivemind --help +Hivemind version 1.1.0 +``` diff --git a/docs/dev-tools/backends/index.md b/docs/dev-tools/backends/index.md new file mode 100644 index 000000000..019ac46e4 --- /dev/null +++ b/docs/dev-tools/backends/index.md @@ -0,0 +1,17 @@ +# Backends + +In addition to asdf plugins, you can also directly install CLIs with some package managers. + +* [asdf](/dev-tools/backends/asdf) +* [Cargo](/dev-tools/backends/cargo) +* [Go](/dev-tools/backends/go) +* [NPM](/dev-tools/backends/npm) +* [Pipx](/dev-tools/backends/pipx) +* [SPM](/dev-tools/backends/spm) +* [Ubi](/dev-tools/backends/ubi) +* [More coming soon!](https://github.com/jdx/mise/discussions/1250) + +::: tip +If you'd like to contribute a new backend to mise, they're not difficult to write. +See [`./src/backend/`](https://github.com/jdx/mise/tree/main/src/backend) for examples. +::: diff --git a/docs/dev-tools/backends/npm.md b/docs/dev-tools/backends/npm.md new file mode 100644 index 000000000..2455fcbe1 --- /dev/null +++ b/docs/dev-tools/backends/npm.md @@ -0,0 +1,33 @@ +# npm Backend + +You may install packages directly from [npmjs.org](https://npmjs.org/) even if there +isn't an asdf plugin for it. + +The code for this is inside of the mise repository at [`./src/backend/npm.rs`](https://github.com/jdx/mise/blob/main/src/backend/npm.rs). + +## Dependencies + +This relies on having `npm` installed. You can install it with or without mise. +Here is how to install `npm` with mise: + +```sh +mise use -g node +``` + +## Usage + +The following installs the latest version of [prettier](https://www.npmjs.com/package/prettier) +and sets it as the active version on PATH: + +```sh +$ mise use -g npm:prettier +$ prettier --version +3.1.0 +``` + +The version will be set in `~/.config/mise/config.toml` with the following format: + +```toml +[tools] +"npm:prettier" = "latest" +``` diff --git a/docs/dev-tools/backends/pipx.md b/docs/dev-tools/backends/pipx.md new file mode 100644 index 000000000..62c0c6434 --- /dev/null +++ b/docs/dev-tools/backends/pipx.md @@ -0,0 +1,54 @@ +# pipx Backend + +You may install python packages directly from: + +- PyPI +- Git +- GitHub +- Http + +The code for this is inside of the mise repository at [`./src/backend/pipx.rs`](https://github.com/jdx/mise/blob/main/src/backend/pipx.rs). + +## Dependencies + +This relies on having `pipx` installed. You can install it with or without mise. +Here is how to install `pipx` with mise: + +```sh +mise use -g python +pip install --user pipx +``` + +Other installation instructions can be found [here](https://pipx.pypa.io/latest/installation/) + +## Usage + +The following installs the latest version of [black](https://github.com/psf/black) +and sets it as the active version on PATH: + +```sh +$ mise use -g pipx:psf/black +$ black --version +black, 24.3.0 +``` + +The version will be set in `~/.config/mise/config.toml` with the following format: + +```toml +[tools] +"pipx:psf/black" = "latest" +``` + +### Supported Pipx Syntax + +| Description | Usage | +| ------------------------------------- | ------------------------------------------------------ | +| PyPI shorthand latest version | `pipx:black` | +| PyPI shorthand for specific version | `pipx:black@24.3.0` | +| GitHub shorthand for latest version | `pipx:psf/black` | +| GitHub shorthand for specific version | `pipx:psf/black@24.3.0` | +| Git syntax for latest version | `pipx:git+https://github.com/psf/black` | +| Git syntax for a branch | `pipx:git+https://github.com/psf/black.git@main` | +| Https with zipfile | `pipx:https://github.com/psf/black/archive/18.9b0.zip` | + +Other syntax may work but is unsupported and untested. diff --git a/docs/dev-tools/backends/spm.md b/docs/dev-tools/backends/spm.md new file mode 100644 index 000000000..1bfbb14b1 --- /dev/null +++ b/docs/dev-tools/backends/spm.md @@ -0,0 +1,44 @@ +# SPM Backend + +You may install executables managed by [Swift Package Manager](https://www.swift.org/documentation/package-manager) directly from GitHub releases. + +The code for this is inside of the mise repository at [`./src/backend/spm.rs`](https://github.com/jdx/mise/blob/main/src/backend/spm.rs). + +## Dependencies + +This relies on having `swift` installed. You can install it according to the [instructions](https://www.swift.org/install). + +> [!NOTE] +> If you have Xcode installed and selected in your system via `xcode-select`, Swift is already available through the toolchain embedded in the Xcode installation. + +## Usage + +The following installs the latest version of `tuist` +and sets it as the active version on PATH: + +```sh +$ mise use -g spm:tuist/tuist +$ tuist --help +OVERVIEW: Generate, build and test your Xcode projects. + +USAGE: tuist +... +``` + +The version will be set in `~/.config/mise/config.toml` with the following format: + +```toml +[tools] +"spm:tuist/tuist" = "latest" +``` + +### Supported Syntax + +| Description | Usage | +| --------------------------------------------- | --------------------------------------------------------- | +| GitHub shorthand for latest release version | `spm:tuist/tuist` | +| GitHub shorthand for specific release version | `spm:tuist/tuist@4.15.0` | +| GitHub url for latest release version | `spm:https://github.com/tuist/tuist.git` | +| GitHub url for specific release version | `spm:https://github.com/tuist/tuist.git@4.15.0` | + +Other syntax may work but is unsupported and untested. diff --git a/docs/dev-tools/backends/ubi.md b/docs/dev-tools/backends/ubi.md new file mode 100644 index 000000000..581ad16bf --- /dev/null +++ b/docs/dev-tools/backends/ubi.md @@ -0,0 +1,42 @@ +# Ubi Backend + +You may install GitHub Releases and URL packages directly using [ubi](https://github.com/houseabsolute/ubi) backend. + +The code for this is inside of the mise repository at [`./src/backend/ubi.rs`](https://github.com/jdx/mise/blob/main/src/backend/ubi.rs). + +## Dependencies + +This relies on having `ubi` installed. You can install it with or without mise. +Here is how to install `ubi` with mise: + +```sh +mise use -g cargo:ubi +``` + +## Usage + +The following installs the latest version of goreleaser +and sets it as the active version on PATH: + +```sh +$ mise use -g ubi:goreleaser/goreleaser +$ goreleaser --version +1.25.1 +``` + +The version will be set in `~/.config/mise/config.toml` with the following format: + +```toml +[tools] +"ubi:goreleaser/goreleaser" = "latest" +``` + +### Supported Ubi Syntax + +| Description | Usage | +| --------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| GitHub shorthand for latest release version | `ubi:goreleaser/goreleaser` | +| GitHub shorthand for specific release version | `ubi:goreleaser/goreleaser@1.25.1` | +| URL syntax | `ubi:https://github.com/goreleaser/goreleaser/releases/download/v1.16.2/goreleaser_Darwin_arm64.tar.gz` | + +Other syntax may work but is unsupported and untested. diff --git a/docs/dev-tools/comparison-to-asdf.md b/docs/dev-tools/comparison-to-asdf.md new file mode 100644 index 000000000..d2bc68bfa --- /dev/null +++ b/docs/dev-tools/comparison-to-asdf.md @@ -0,0 +1,106 @@ +# Comparison to asdf + +mise can be used as a drop-in replacement for asdf. It supports the same `.tool-versions` files that +you may have used with asdf and uses asdf plugins. It will not, however, reuse existing asdf directories +(so you'll need to either reinstall them or move them), and 100% compatibility is not a design goal. + +Casual users coming from asdf have generally found mise to just be a faster, easier to use asdf. + +:::tip +Make sure you have a look at [environments](/environments.html) and [tasks](/tasks/) which +are major portions of mise that have no asdf equivalent. +::: + +## UX + +![CleanShot 2024-01-28 at 12 36 20@2x](https://github.com/jdx/mise-docs/assets/216188/47f381d7-1566-4b78-9260-3b85a21dd6ec) + +Some commands are the same in asdf but others have been changed. Everything that's possible +in asdf should be possible in mise but may use slightly different syntax. mise has more forgiving commands, +such as using fuzzy-matching, e.g.: `mise install node@20`. While in asdf you _can_ run +`asdf install node latest:20`, you can't use `latest:20` in a `.tool-versions` file or many other places. +In `mise` you can use fuzzy-matching everywhere. + +asdf requires several steps to install a new runtime if the plugin isn't installed, e.g.: + +```sh +asdf plugin add node +asdf install node latest:20 +asdf local node latest:20 +``` + +In `mise` this can all be done in a single step which installs the plugin, installs the runtime, +and sets the version: + +```sh +mise use node@20 +``` + +If you have an existing `.tool-versions` file, or `.mise-toml`, you can install all plugins +and runtimes with a single command: + +```sh +mise install +``` + +I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like +having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). +`mise` makes heavy use of aliases so you don't need to remember if it's `mise plugin add node` or +`mise plugin install node`. If I can guess what you meant, then I'll try to get mise to respond +in the right way. + +That said, there are a lot of great things about asdf. It's the best multi-runtime manager out there +and I've really been impressed with the plugin system. Most of the design decisions the authors made +were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. + +## Performance + +asdf made (what I consider) a poor design decision to use shims that go between a call to a runtime +and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, +which then calls `asdf exec`, which then calls the correct version of node. + +These shims have terrible performance, adding ~120ms to every runtime call. `mise activate` does not use shims and instead +updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo GIF at the top of this README +that `mise` isn't actually used when calling `node -v` for this reason. The performance is +identical to running node without using mise. + +I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup +of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written +in bash which certainly makes it challenging to be performant, however I think the real problem is the +shim design. I don't think it's possible to fix that without a complete rewrite. + +mise does call an internal command `mise hook-env` every time the directory has changed, but because +it's written in Rust, this is very quickโ€”taking ~10ms on my machine. 4ms if there are no changes, 14ms if it's +a full reload. + +tl;dr: asdf adds overhead (~120ms) when calling a runtime, mise adds a small amount of overhead (~5ms) +when the prompt loads. + +## Command Compatibility + +In nearly all places you can use the exact syntax that works in asdf, however this likely won't +show up in the help or CLI reference. If you're coming from asdf and comfortable with that way of +working you can almost always use the same syntax with mise, e.g.: + +```sh +mise install node 20.0.0 +mise local node 20.0.0 +``` + +It's not recommended though. You almost always want to modify config files and install things so +`mise use node@20` saves an extra command. Also, the "@" in the command is preferred since it allows +you to install multiple tools at once: `mise use|install node@20 node@18`. Also, there are edge cases +where it's not possibleโ€”or at least very challengingโ€”for us to definitively know which syntax is being +used and so we default to mise-style. While there aren't many of these, asdf-compatibility is done +as a "best-effort" in order to make transitioning from asdf feel familiar for those users who can +rely on their muscle memory. Ensuring asdf-syntax works with everything is not a design goal. + +## Extra backends + +mise has support for backends other than asdf plugins. For example you can install CLIs +directly from cargo and npm: + +```sh +mise use -g cargo:ripgrep@14 +mise use -g npm:prettier@3 +``` diff --git a/docs/dev-tools/index.md b/docs/dev-tools/index.md new file mode 100644 index 000000000..e507b4697 --- /dev/null +++ b/docs/dev-tools/index.md @@ -0,0 +1,135 @@ +# Dev Tools + +_Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](/plugins)._ + +::: tip +New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4) for a gentler introduction. +::: + +mise is a tool for managing programming language and tool versions. For example, use this to install +a particular version of Node.js and ruby for a project. Using `mise activate`, you can have your +shell automatically switch to the correct node and ruby versions when you `cd` into the project's +directory. Other projects on your machine can use a different set of versions. + +mise is inspired by [asdf](https://asdf-vm.com) and uses asdf's vast [plugin ecosystem](https://github.com/rtx-plugins/registry) +under the hood. However, it is _much_ faster than asdf and has a more friendly user experience. +For more on how mise compares to asdf, [see below](./comparison-to-asdf). + +mise can be configured in many ways. The most typical is by `.mise.toml`, but it's also compatible +with asdf `.tool-versions` files. It can also use idiomatic version files like `.node-version` and +`.ruby-version`. See [Configuration](/configuration) for more. + +* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](/configuration#env---arbitrary-environment-variables) for different project directories. +* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](/tasks/) used to build and test projects. + +## How it works + +mise hooks into your shell (with `mise activate zsh`) and sets the `PATH` +environment variable to point your shell to the correct runtime binaries. When you `cd` into a +directory containing a `.tool-versions`/`.mise.toml` file, mise will automatically set the +appropriate tool versions in `PATH`. + +::: info +mise does not modify "cd". It actually runs every time the prompt is _displayed_. +See the [FAQ](/faq#what-does-mise-activate-do). +::: + +After activating, every time your prompt displays it will call `mise hook-env` to fetch new +environment variables. +This should be very fast. It exits early if the directory wasn't changed or `.tool-versions`/`.mise.toml` files haven't been modified. + +Unlike asdf which uses shim files to dynamically locate runtimes when they're called, mise modifies +`PATH` ahead of time so the runtimes are called directly. This is not only faster since it avoids +any overhead, but it also makes it so commands like `which node` work as expected. This also +means there isn't any need to run `asdf reshim` after installing new runtime binaries. + +You should note that mise does not directly install these tools. +Instead, it leverages plugins to install runtimes. +See [plugins](/plugins) below. + +## Common commands + +Here are some of the most important commands when it comes to working with dev tools. + +### `mise use` + +For some users, `mise use` might be the only command you need to learn. It will do the following: + +- Install the tool's plugin if needed +- Install the specified version +- Set the version as active (it's in PATH) + +`mise use node@20` will install the latest version of node-20 and create/update the .tool-versions/.mise.toml +config file in the local directory. Anytime you're in that directory, that version of node will be used. + +`mise use -g node@20` will do the same but update the global config (~/.config/mise/config.toml) so +unless there is a config file in the local directory hierarchy, node-20 will be the default version for +the user. + +### `mise install` + +`mise install` will install but not activate toolsโ€”meaning it will download/build/compile the tool +into `~/.local/share/mise/installs` but you won't be able to use it without "setting" the version +in a `.tool-versions` or `.mise-toml` file. + +::: tip +If you're coming from asdf, there is no need to also run `mise plugin add` to first install +the plugin, that will be done automatically if needed. Of course, you can manually install plugins +if you wish or you want to use a plugin not in the default registry. +::: + +There are many ways it can be used: + +* `mise install node@20.0.0` - install a specific version +* `mise install node@20` - install the latest version matching this prefix +* `mise install node` - install whatever version of node currently specified in .tool-versions/.mise.toml +* `mise install` - install all plugins and tools + +### `mise local|global` + +`mise local` and `mise global` are command which only modify the `.tool-versions` or `.mise.toml` files. +These are hidden from the CLI help and remain for asdf-compatibility. The recommended approach is +to use `mise use` instead because that will do the same thing but also install the tool if it does +not already exists. + +### `mise exec`|`mise x` + +`mise x` can be used for one-off commands using specific tools. e.g.: if you want to run a script with python3.12: + +```sh +mise x python@3.12 -- ./myscript.py +``` + +Python will be installed if it is not already. `mise x` will read local/global `.tool-versions`/`.mise-toml` files +as well, so if you don't want to use `mise activate` or shims you can use mise by just prefixing commands with +`mise x --`: + +```sh +$ mise use node@20 +$ mise x -- node -v +20.x.x +``` + +::: tip +If you use this a lot, an alias can be helpful: + +```sh +alias mx="mise x --" +``` + +::: + +Similarly, `mise run` can be used to [execute tasks](/tasks/) which will also activate the mise environment with all of your tools. + +## Tool Options + +mise plugins may accept configuration in the form of tool options specified in `mise.toml`: + +```toml +[tools] +# send arbitrary options to the plugin, passed as: +# MISE_TOOL_OPTS__FOO=bar +mytool = { version = '3.10', foo = 'bar' } +``` + +Unfortunately at the time of this writing, it's not possible to specify this via the CLI in `mise use` or other commands though. See diff --git a/docs/dev-tools/shims.md b/docs/dev-tools/shims.md new file mode 100644 index 000000000..843bee69a --- /dev/null +++ b/docs/dev-tools/shims.md @@ -0,0 +1,194 @@ +# Shims + +::: tip +The [beginner's guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4), and my [blog post](https://jdx.dev/posts/2024-04-13-shims-how-they-work-in-mise-en-place/) are helpful resources to dive deeper into shims. +::: + +While the PATH design of mise works great in most cases, there are some situations where shims are +preferable. One example is when calling mise binaries from an IDE. + +To support this, mise does have a shim dir that can be used. It's located at `~/.local/share/mise/shims`. + +```sh +$ mise use -g node@20 +$ npm install -g prettier@3.1.0 +$ mise reshim # may be required if new shims need to be created after installing packages +$ ~/.local/share/mise/shims/node -v +v20.0.0 +$ ~/.local/share/mise/shims/prettier -v +3.1.0 +``` + +::: tip +`mise activate --shims` is a shorthand for adding the shims directory to PATH. +::: + +::: info +`mise reshim` actually should get called automatically if you're using npm so an explicit reshim should not be necessary +in that scenario. Also, this bears repeating but: `mise reshim` just creates/removes the shims. People use it as a +"fix it" button but it really should only be necessary if `~/.local/share/mise/shims` doesn't contain something it should. + +mise also runs a reshim anytime a tool is installed/updated/removed so you don't need to use it for those scenarios. + +Also don't put things in there manually, mise will just delete it next reshim. +::: + +## Shims vs PATH + +In general, I recommend using PATH (`mise activate`) instead of shims for _interactive_ situations. The +way activate works is every time the prompt is displayed, mise-en-place will determine what PATH and other +env vars should be and export them. This is why it doesn't work well for non-interactive situations like +scripts. The prompt never gets displayed so you have to manually call `mise hook-env` to get mise to update +the env vars. + +Also, if you run a set of commands in a single line like the following: + +```sh +cd ~ +cd ~/src/proj1 && node -v && cd ~/src/proj2 && node -v +``` + +Using `mise activate`, this will use the tools from `~`, not from `~/src/proj1` or `~/src/proj2` even +after the directory changed because the prompt never got displayed. That might be obvious to you, not sure, +what I'm trying to convey though is just think of mise running just before your prompt gets displayedโ€”because +that literally is what is happening. It's not a magical utility that is capable of having your environment +always setup perfectly in every situation even though it might normally "feel" that way. + +Note that shims _will_ work with the inline example above. + +::: info +This may be fixable at least for some shells if they support a hook for directory change, however +some investigation will need to be done. See [#1294](https://github.com/jdx/mise/issues/1294) for details. +::: + +### `which` + +`which` is a command that I personally find great value in. shims effectively "break" `which` and +cause it to show the location of the shim. Of course `mise which` will show the location but I prefer +the "cleanliness" of running `which node` and getting back a real path with a version number inside of it. +e.g: + +```sh +$ which node +/Users/jdx/.mise/installs/node/20/bin/node +``` + +### Env vars and shims + +A downside of shims is the "mise environment" is only loaded when a shim is called. This means if you +set an environment variable in `.mise.toml`, it will only be run when a shim is called. So the following +only works under `mise activate`: + +```sh +$ mise set NODE_ENV=production +$ echo $NODE_ENV +production +``` + +But this will work in either: + +```sh +$ mise set NODE_ENV=production +$ node -p process.env.NODE_ENV +production +``` + +Also, `mise x|exec` and `mise r|run` can be used to get the environment even if you don't need any mise +tools: + +```sh +$ mise set NODE_ENV=production +$ mise x -- bash -c "echo \$NODE_ENV" +production +$ mise r some_task_that_uses_NODE_ENV +production +``` + +::: tip +In general, [tasks](/tasks/) are a good way to ensure that the mise environment is always loaded so +this isn't a problem. +::: + +## Hook on `cd` + +Some version managers modify the behavior of `cd`. That might seem like the ideal method of making a version +manager, it has tons of gaps. It doesn't work if you use `pushd|popd` or other commands that modify PWDโ€”though +some shells have a "chpwd" hook that would. It doesn't run if you modify the `.mise.toml` file. + +The upside is that it doesn't run as frequently but since mise is written in rust the cost for executing +mise is negligible (~4-5ms). + +## .zshrc/.bashrc files + +rc files like `.zshrc` are unusual. It's a script but also runs only for interactive sessions. If you need +to access tools provided by mise inside of an rc file you have 2 options: + +::: code-group + +```sh [hook-env] +eval "$(mise activate zsh)" +eval "$(mise hook-env -s zsh)" +node some_script.js +``` + +```sh [shims] +eval "$(mise activate zsh --shims)" # should be first +eval "$(mise activate zsh)" +node some_script.js +``` + +::: + +The `hook-env` option is the one I would go with. It's a bit cleaner since you won't have the shims +inside your PATH at all. If you do go with shims, it will need to be first so they get overridden. + +## Performance + +Truthfully, you're probably not going to notice much in the way of performance with any solution here. +However, I would like to document what the tradeoffs are since it's not as simple as "shims are slow". +In asdf they are, but that's because asdf is written in bash. In mise the cost of the shims are negligible. + +First, since mise runs every time the prompt is displayed with `mise activate`, you'll pay a few ms cost +every time the prompt is displayed. Regardless of whether or not you're actively using a mise tool, you'll +pay that penalty every time you run any command. It does have some short-circuiting logic to make it faster +if there are no changes but it doesn't help much unless you have a very complex setup. + +shims have basically the same performance profile but run when the shim is called. This makes some situations +better, and some worse. + +If you are calling a shim from within a bash script like this: + +```sh +for i in {1..500}; do + node script.js +done +``` + +You'll pay the mise penalty every time you call it within the loop. However, if you did the same thing +but call a subprocess from within a shim (say, node creating a node subprocess), you will _not_ pay a new +penalty. This is because when a shim is called, mise sets up the environment with PATH for all tools and +those PATH entries will be before the shim directory. + +In other words, which is better in terms of performance just depends on how you're calling mise. Really +though I think most users won't notice a 5ms lag on their terminal so I suggest `mise activate`. + +## Neither shims nor PATH + +[I don't actually use either of these methods](https://mise.jdx.dev/how-i-use-mise.html). There are many +ways to load the mise environment that don't require either, chiefly: `mise x|exec` and `mise r|run`. + +These will both load all of the tools and env vars before executing something. I find this to be +ideal because I don't need to modify my shell rc file at all and my environment is always loaded +explicitly. I find this a "clean" way of working. + +The obvious downside is that anytime I want to use `mise` I need to prefix it with `mise exec|run`, +though I alias them to `mx|mr`. + +This is what I'd recommend if you're like me and prefer things to be precise over "easy". Or perhaps +if you're just wanting to use mise on a single project because that's what your team uses and prefer +not to use it to manage anything else on your system. IMO using a shell extension for that use-case +would be overkill. + +Part of the reason for this is I often need to make sure I'm on my development version of mise. If you +work on mise yourself I would recommend working in a similar way and disabling `mise activate` or shims +while you are working on it. diff --git a/docs/directories.md b/docs/directories.md new file mode 100644 index 000000000..24db50ff0 --- /dev/null +++ b/docs/directories.md @@ -0,0 +1,83 @@ +# Directory Structure + +The following are the directories that mise uses. + +::: tip +If you often find yourself using these directories (as I do), I suggest setting all of them to `~/.mise` for easy access. +::: + +## `~/.config/mise` + +* Override: `$MISE_CONFIG_DIR` +* Default: `${XDG_CONFIG_HOME:-$HOME/.config}/mise` + +This directory stores the global configuration file `~/.config/mise/config.toml`. This is intended to go into your +dotfiles repo to share across machines. + +## `~/.cache/mise` + +* Override: `$MISE_CACHE_DIR` +* Default: `${XDG_CACHE_HOME:-$HOME/.cache}/mise`, _macOS: `~/Library/Caches/mise`._ + +Stores internal cache that mise uses for things like the list of all available versions of a +plugin. Do not share this across machines. You may delete this directory any time mise isn't actively installing something. +Do this with `mise cache clear`. +See [Cache Behavior](/cache-behavior) for more information. + +## `~/.local/state/mise` + +* Override: `$MISE_STATE_DIR` +* Default: `${XDG_STATE_HOME:-$HOME/.local/state}/mise` + +Used for storing state local to the machine such as which config files are trusted. These should not be shared across +machines. + +## `~/.local/share/mise` + +* Override: `$MISE_DATA_DIR` +* Default: `${XDG_DATA_HOME:-$HOME/.local/share}/mise` + +This is the main directory that mise uses and is where plugins and tools are installed into. +It is nearly identical to `~/.asdf` in asdf, so much so that you may be able to get by +symlinking these together and using asdf and mise simultaneously. (Supporting this isn't a +project goal, however). + +This directory _could_ be shared across machines but only if they run the same OS/arch. In general I wouldn't advise +doing so. + +### `~/.local/share/mise/downloads` + +This is where plugins may optionally cache downloaded assets such as tarballs. Use the +`always_keep_downloads` setting to prevent mise from removing files from here. + +### `~/.local/share/mise/plugins` + +mise installs plugins to this directory when running `mise plugins install`. If you are working on a +plugin, I suggest +symlinking it manually by running: + +```sh +ln -s ~/src/mise-my-tool ~/.local/share/mise/plugins/my-tool +``` + +### `~/.local/share/mise/installs` + +This is where tools are installed to when running `mise install`. For example, `mise install +node@20.0.0` will install to `~/.local/share/mise/installs/node/20.0.0` + +This will also create other symlinks to this directory for version prefixes ("20" and "20.15") +and matching aliases ("lts", "latest"). +For example: + +```sh +$ tree ~/.local/share/mise/installs/node +20 -> ./20.15.0 +20.15 -> ./20.15.0 +lts -> ./20.15.0 +latest -> ./20.15.0 +``` + +### `~/.local/share/mise/shims` + +This is where mise places shims. Generally these are used for IDE integration or if `mise activate` +does not work for some reason. diff --git a/docs/direnv.md b/docs/direnv.md new file mode 100644 index 000000000..bb71a12f6 --- /dev/null +++ b/docs/direnv.md @@ -0,0 +1,91 @@ +# direnv + +[direnv](https://direnv.net) and mise both manage environment variables based on directory. Because +they both analyze +the current environment variables before and after their respective "hook" commands are run, they +can sometimes conflict with each other. + +If you have an issue, it's likely to do with the ordering of PATH. This means it would +really only be a problem if you were trying to manage the same tool with direnv and mise. For +example, +you may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with +python +in it as well. + +A more typical usage of direnv would be to set some arbitrary environment variables, or add +unrelated +binaries to PATH. In these cases, mise will not interfere with direnv. + +## mise inside of direnv (`use mise` in `.envrc`) + +::: warning +Update 2024-01-21: after `use mise` has been out for a while, the general impression I have is that +while it technically functions fine, +not many people use it because the DX is notably worse than either switching to mise entirely +or using `mise activate` alongside direnv. + +The project direction of mise has changed since this was written and the new direction is for it +to be capable of replacing direnv completely for any use-case. This likely won't end up as a drop-in +replacement for direnv like with asdf, but solving the same problems in different ways. +See [environments](/environments.html) +for more details. + +I have had virtually no reports of problems with `use mise` in the year it has been out. +This could be because virtually is using it, or it has been surprisingly stable. I genuinely +don't know which. If you try it or use it regularly let me know. + +While I have no immediate plans or reasons to do this now, I could see this functionality being +the target of a future deprecation. Not because it's a maintenance burden, but because it just +hasn't +seemed like a particularly useful solution and it may help focus mise on the functionality that does +work for users. +::: + +If you do encounter issues with `mise activate`, or just want to use direnv in an alternate way, +this is a simpler setup that's less likely to cause issuesโ€”at the cost of functionality. + +This may be required if you want to use direnv's `layout python` with mise. Otherwise there are +situations where mise will override direnv's PATH. `use mise` ensures that direnv always has +control. + +To do this, first use `mise` to build a `use_mise` function that you can use in `.envrc` files: + +```sh +mise direnv activate > ~/.config/direnv/lib/use_mise.sh +``` + +Now in your `.envrc` file add the following: + +```sh +use mise +``` + +direnv will now call mise to export its environment variables. You'll need to make sure to +add `use_mise` +to all projects that use mise (or use direnv's `source_up` to load it from a subdirectory). You can +also add `use mise` to `~/.config/direnv/direnvrc`. + +Note that in this method direnv typically won't know to refresh `.tool-versions` files +unless they're at the same level as a `.envrc` file. You'll likely always want to have +a `.envrc` file next to your `.tool-versions` for this reason. To make this a little +easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead +setting environment variables entirely in `.envrc`: + +```sh +export MISE_NODE_VERSION=20.0.0 +export MISE_PYTHON_VERSION=3.11 +``` + +Of course if you use `mise activate`, then these steps won't have been necessary and you can use +mise +as if direnv was not used. + +If you continue to struggle, you can also try using the [shims method](dev-tools/shims.md). + +### Do you need direnv? + +While making mise compatible with direnv is, and will always be a major goal of this project, I also +want mise to be capable of replacing direnv if needed. This is why mise includes support for +managing +env vars and [virtualenv](lang/python.md#automatic-virtualenv-activation) +for python using `.mise.toml`. diff --git a/docs/environments.md b/docs/environments.md new file mode 100644 index 000000000..aac217f9d --- /dev/null +++ b/docs/environments.md @@ -0,0 +1,129 @@ +# Environments + +Use mise to specify environment variables used for different projects. Create a `.mise.toml` file +in the root of your project directory: + +```toml +[env] +NODE_ENV = 'production' +``` + +To clear an env var, set it to `false`: + +```toml +[env] +NODE_ENV = false # unset a previously set NODE_ENV +``` + +You can also use the CLI to get/set env vars: + +```sh +$ mise set NODE_ENV=development +$ mise set NODE_ENV +development +$ mise set +key value source +NODE_ENV development .mise.toml +$ mise unset NODE_ENV +``` + +## `env._` directives + +`env._.*` define special behavior for setting environment variables. (e.g.: reading env vars +from a file). Since nested environment variables do not make sense, +we make use of this fact by creating a key named "_" which is a +TOML table for the configuration of these directives. + +### `env._.file` + +In `.mise.toml`: `env._.file` can be used to specify a [dotenv](https://dotenv.org) file to load. +It can be a string or array and uses relative or absolute paths: + +```toml +[env] +_.file = '.env' +``` + +_This uses [dotenvy](https://crates.io/crates/dotenvy) under the hood. If you have problems with +the way `env._.file` works, you will likely need to post an issue there, +not to mise since there is not much mise can do about the way that crate works._ + +Or set [`MISE_ENV_FILE=.env`](/configuration#mise-env-file) to automatically load dotenv files in any +directory. + +### `env._.path` + +`PATH` is treated specially, it needs to be defined as a string/array in `mise.path`: + +```toml +[env] +_.path = [ + # adds an absolute path + "~/.local/share/bin", + # adds a path relative to the .mise.toml, not PWD + "./node_modules/.bin", +] +``` + +### `env._.source` + +Source an external bash script and pull exported environment variables out of it: + +```toml +[env] +_.source = "./script.sh" +``` + +::: info +This **must** be a script that runs in bash as if it were executed like this: + +```sh +source ./script.sh +``` + +The shebang will be **ignored**. See [#1448](https://github.com/jdx/mise/issues/1448) +for a potential alternative that would work with binaries or other script languages. +::: + +## Multiple `env._` Directives + +It may be necessary to use multiple `env._` directives, however TOML fails with this syntax +because it has 2 identical keys in a table: + +```toml +[env] +_.source = "./script_1.sh" +_.source = "./script_2.sh" # invalid // [!code error] +``` + +For this use-case, you can optionally make `[env]` an array-of-tables instead by using `[[env]]` instead: + +```toml +[[env]] +_.source = "./script_1.sh" +[[env]] +_.source = "./script_2.sh" +``` + +It works identically but you can have multiple tables. + +## Templates + +Environment variable values can be templates, see [Templates](/templates) for details. + +```toml +[env] +LD_LIBRARY_PATH = "/some/path:{{env.LD_LIBRARY_PATH}}" +``` + +## Using env vars in other env vars + +You can use the value of an environment variable in later env vars: + +```toml +[env] +MY_PROJ_LIB = "{{config_root}}/lib" +LD_LIBRARY_PATH = "/some/path:{{env.MY_PROJ_LIB}}" +``` + +Of course the ordering matters when doing this. diff --git a/docs/errors.md b/docs/errors.md new file mode 100644 index 000000000..f96b8b9a0 --- /dev/null +++ b/docs/errors.md @@ -0,0 +1,3 @@ +# Errors + +TODO diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 000000000..5b35c537f --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,256 @@ +# FAQs + +## I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file + +You can make git ignore these files in 3 different ways: + +- Adding `.tool-versions` to project's `.gitignore` file. This has the downside that you need to + commit the change to the ignore file. +- Adding `.tool-versions` to project's `.git/info/exclude`. This file is local to your project so + there is no need to commit it. +- Adding `.tool-versions` to global gitignore (`core.excludesFile`). This will cause git to + ignore `.tool-versions` files in all projects. You can explicitly add one to a project if needed + with `git add --force .tool-versions`. + +## What is the difference between "nodejs" and "node" (or "golang" and "go")? + +These are aliased. For example, `mise use nodejs@14.0` is the same as `mise install node@14.0`. This +means it is not possible to have these be different plugins. + +This is for convenience so you don't need to remember which one is the "official" name. However if +something with the aliasing is acting up, submit a ticket or just stick to using "node" and "go". +Under the hood, when mise reads a config file or takes CLI input it will swap out "nodejs" and +"golang". + +While this change is rolling out, there is some migration code that will move installs/plugins from +the "nodejs" and "golang" directories to the new names. If this runs for you you'll see a message +but it should not run again unless there is some kind of problem. In this case, it's probably +easiest to just +run `rm -rf ~/.local/share/mise/installs/{golang,nodejs} ~/.local/share/mise/plugins/{golang,nodejs}`. + +Once most users have migrated over this migration code will be removed. + +## What does `mise activate` do? + +It registers a shell hook to run `mise hook-env` every time the shell prompt is displayed. +`mise hook-env` checks the current env vars (most importantly `PATH` but there are others like +`GOROOT` or `JAVA_HOME` for some tools) and adds/removes/updates the ones that have changed. + +For example, if you `cd` into a different directory that has `java 18` instead of `java 17` +specified, just before the next prompt is displayed the shell runs: `eval "$(mise hook-env)"` +which will execute something like this in the current shell session: + +```sh +export JAVA_HOME=$HOME/.local/share/installs/java/18 +export PATH=$HOME/.local/share/installs/java/18/bin:$PATH +``` + +In reality updating `PATH` is a bit more complex than that because it also needs to remove java-17, +but you get the idea. + +You may think that is excessive to run `mise hook-env` every time the prompt is displayed +and it should only run on `cd`, however there are plenty of +situations where it needs to run without the directory changing, for example if `.tool-versions` or +`.mise.toml` was just edited in the current shell. + +Because it runs on prompt display, if you attempt to use `mise activate` in a +non-interactive session (like a bash script), it will never call `mise hook-env` and in effect will +never modify PATH because it never displays a prompt. For this type of setup, you can either call +`mise hook-env` manually every time you wish to update PATH, or use [shims](/dev-tools/shims.md) +instead (preferred). +Or if you only need to use mise for certain commands, just prefix the commands with +[`mise x --`](./cli/#mise-exec-options-tool-version-command). +For example, `mise x -- npm test` or `mise x -- ./my_script.sh`. + +`mise hook-env` will exit early in different situations if no changes have been made. This prevents +adding latency to your shell prompt every time you run a command. You can run `mise hook-env` +yourself +to see what it outputs, however it is likely nothing if you're in a shell that has already been +activated. + +`mise activate` also creates a shell function (in most shells) called `mise`. +This is a trick that makes it possible for `mise shell` +and `mise deactivate` to work without wrapping them in `eval "$(mise shell)"`. + +## `mise activate` doesn't work in `~/.profile`, `~/.bash_profile`, `~/.zprofile` + +`mise activate` should only be used in `rc` files. These are the interactive ones used when +a real user is using the terminal. (As opposed to being executed by an IDE or something). The prompt +isn't displayed in non-interactive environments so PATH won't be modified. + +For non-interactive setups, consider using shims instead which will route calls to the correct +directory by looking at `PWD` every time they're executed. You can also call `mise exec` instead of +expecting things to be directly on PATH. You can also run `mise env` in a non-interactive shell, +however that +will only setup the global tools. It won't modify the environment variables when entering into a +different project. + +Also see the [shebang](/tips-and-tricks#shebang) example for a way to make scripts call mise to get +the runtime. +That is another way to use mise without activation. + +## mise is failing or not working right + +First try setting `MISE_DEBUG=1` or `MISE_TRACE=1` and see if that gives you more information. +You can also set `MISE_LOG_FILE_LEVEL=debug MISE_LOG_FILE=/path/to/logfile` to write logs to a file. + +If something is happening with the activate hook, you can try disabling it and +calling `eval "$(mise hook-env)"` manually. +It can also be helpful to use `mise env` which will just output environment variables that would be +set. +Also consider using [shims](/dev-tools/shims.md) which can be more compatible. + +If runtime installation isn't working right, try using the `--raw` flag which will install things in +series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact +with you for some reason this will make it work. + +Of course check the version of mise with `mise --version` and make sure it is the latest. +Use `mise self-update` +to update it. `mise cache clean` can be used to wipe the internal cache and `mise implode` can be +used +to remove everything except config. + +Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can +rule +out if the issue is with mise or if it's with a particular plugin. For example, +if `mise install python@latest` +doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. + +Lastly, there is `mise doctor` which will show diagnostic information and any warnings about issues +detected with your setup. If you submit a bug report, please include the output of `mise doctor`. + +## New version of a tool is not available + +There are 2 places that versions are cached so a brand new release might not appear right away. + +The first is that the mise CLI caches versions for 24 hours. This can be cleared +with `mise cache clear`. + +The second uses the mise-versions.jdx.dev host as a centralized +place to list all of the versions of most plugins. This is intended to speed up mise and also +get around GitHub rate limits when querying for new versions. Check that repo for your plugin to +see if it has an updated version. This service can be disabled by +setting `MISE_USE_VERSIONS_HOST=0`. + +## Windows support? + +This is something we'd like to add! + +It's not a near-term goal and it would require plugin modifications, but it should be feasible. + +## How do I use mise with http proxies? + +Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be +lowercase. + +This may not work with all plugins if they are not configured to use these env vars. +If you're having a proxy-related issue installing something specific you should post an issue on the +plugin's repository. + +## How do the shorthand plugin names map to repositories? + +e.g.: how does `mise plugin install elixir` know to fetch ? + +We maintain [an index](https://github.com/rtx-plugins/registry) of shorthands that mise uses as a +base. +This is regularly updated every time that mise has a release. This repository is stored directly +into +the codebase [here](https://github.com/jdx/mise/blob/main/src/default_shorthands.rs). + +## Does "node@20" mean the newest available version of node? + +It depends on the command. Normally, for most commands and inside of config files, "node@20" will +point to the latest _installed_ version of node-20.x. You can find this version by running +`mise latest --installed node@20` or by seeing what the `~/.local/share/mise/installs/node/20` +symlink +points to: + +```sh +$ ls -l ~/.local/share/mise/installs/node/20 +[...] /home/jdx/.local/share/mise/installs/node/20 -> node-v20.0.0-linux-x64 +``` + +There are some exceptions to this, such as the following: + +- `mise install node@20` +- `mise latest node@20` +- `mise upgrade node@20` + +These will use the latest _available_ version of node-20.x. This generally makes sense because you +wouldn't want to install a version that is already installed. + +## How do I migrate from asdf? + +First, just install mise with `mise activate` like in the getting started guide and remove asdf from +your +shell rc file. + +Then you can just run `mise install` in a directory with an asdf `.tool-versions` file and it will +install the runtimes. You could attempt to avoid this by copying the internal directory from asdf +over +to mise with `cp -r ~/.asdf ~/.local/share/mise`. That _should_ work because they use the same +structure, +however this isn't officially supported or regularly tested. Alternatively you can +set `MISE_DATA_DIR=~/.asdf` +and see what happens. + +## How compatible is mise with asdf? + +mise should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin +should be usable in mise. The commands in mise are slightly +different, such as `mise install node@20.0.0` vs `asdf install node 20.0.0`โ€”this is done so +multiple tools can be specified at once. However, asdf-style syntax is still supported: (`mise +install node 20.0.0`). This is the case for most commands, though the help for the command may +say that asdf-style syntax is supported. + +When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may +not be possible to support every command identically, but +we should attempt to make things as consistent as possible. + +This isn't important for usability reasons so much as making it so plugins continue to work that +call asdf commands. + +If you need to switch to/from asdf or work in a project with asdf users, you can set +[`MISE_ASDF_COMPAT=1`](/configuration#mise_asdf_compat1). That prevents +mise from writing `.tool-versions` files that will not be +compatible with asdf. Also consider using `.mise.toml` instead which won't conflict with asdf +setups. + +## mise isn't working when calling from tmux or another shell initialization script + +`mise activate` will not update PATH until the shell prompt is displayed. So if you need to access a +tool provided by mise before the prompt is displayed you can either +[add the shims to your PATH](getting-started.html#2-add-mise-shims-to-path) e.g. + +```bash +export PATH="$HOME/.local/share/mise/shims:$PATH" +python --version # will work after adding shims to PATH +``` + +Or you can manually call `hook-env`: + +```bash +eval "$(mise activate bash)" +eval "$(mise hook-env)" +python --version # will work only after calling hook-env explicitly +``` + +For more information, see [What does `mise activate` do?](#what-does-mise-activate-do) + +## How do I disable/force CLI color output? + +mise uses [console.rs](https://docs.rs/console/latest/console/fn.colors_enabled.html) which +honors the [clicolors spec](https://bixense.com/clicolors/): + +- `CLICOLOR != 0`: ANSI colors are supported and should be used when the program isnโ€™t piped. +- `CLICOLOR == 0`: Donโ€™t output ANSI color escape codes. +- `CLICOLOR_FORCE != 0`: ANSI colors should be enabled no matter what. + +## Is mise secure? + +Providing a secure supply chain is incredibly important. mise already provides a more secure +experience when compared to asdf. Security-oriented evaluations and contributions are welcome. +We also urge users to look after the plugins they use, and urge plugin authors to look after +the users they serve. + +For more details see [SECURITY.md](https://github.com/jdx/mise/blob/main/SECURITY.md). diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 000000000..2fae0f4fc --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,425 @@ +# Getting Started + +Using mise typically involves 3 steps: + +1. Installing the CLI +2. Activating mise or adding its shims to PATH +3. Adding tools to mise + +## Quickstart + +### 1. Install `mise` CLI + +First we need to download the mise CLI. +See [below](#alternate-installation-methods) for alternate installation methods. +This directory is simply a suggestion. +mise can be installed anywhere. + +```sh +$ curl https://mise.run | sh +$ ~/.local/bin/mise --version +mise 2024.x.x +``` + +::: tip +"~/.local/bin" does not need to be in PATH. mise will automatically add its own directory to PATH +when activated. +::: + +### 2a. Activate mise + +`mise activate` is one way to setup mise but alternatively you can +use [shims](dev-tools/shims.md), [direnv](./direnv), or skip +this step entirely. If you skip it, then tools like `npm` and `node` will not be in PATH. You'll +need to prefix +commands with `mise exec` or run tasks with `mise run` in order to use tools managed with mise. + +Make sure you restart your shell session after modifying your rc file in order for it to take +effect. Also note that +this uses `~/.local/bin/mise` as the binary location since that's what uses by +default. If you've +installed mise by some other means it may be on PATH or somewhere different. + +::: code-group + +```sh [bash] +echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc +``` + +```sh [zsh] +echo 'eval "$(~/.local/bin/mise activate zsh)"' >> ~/.zshrc +``` + +```sh [fish] +echo '~/.local/bin/mise activate fish | source' >> ~/.config/fish/config.fish +``` + +::: + +### 2b. Alternative: Add mise shims to PATH + +If you prefer to use shims, you can run the following to use mise without activating it. +You can use .bashrc/.zshrc instead of .bash_profile/.zprofile if you prefer to only use +mise in interactive sessions (.bash_profile/.zprofile will work in non-interactive places +like scripts or IDEs). + +::: code-group + +```sh [bash] +# note that bash will read from ~/.profile or ~/.bash_profile if the latter exists +# ergo, you may want to check to see which is defined on your system and only append to the existing file +echo 'export PATH="$HOME/.local/share/mise/shims:$PATH"' >> ~/.bash_profile +``` + +```sh [zsh] +echo 'export PATH="$HOME/.local/share/mise/shims:$PATH"' >> ~/.zprofile +``` + +```sh [fish] +fish_add_path ~/.local/share/mise/shims +``` + +:::tip +You can also run `mise activate --shims` which will do the above for you. +::: + +:::info +mise respects [`MISE_DATA_DIR`](/configuration) and [`XDG_DATA_HOME`](/configuration) if you'd like +to change these locations. +::: + +### 3. Adding tools to mise + +:::info +Of course, if using mise solely for [environment management](/environments) +or [running tasks](/tasks/) +this step is not necessary. +::: + +Install node and set it as the global default: + +```sh +$ mise use --global node@20 +$ node -v +v20.x.x +``` + +If you did not activate mise or add its shims to PATH, then you'll need to run the following: + +```sh +$ mise use --global node@20 +$ mise exec -- node -v +v20.x.x +``` + +:::tip +Use `mise x -- node -v` or set a shell alias in your shell's rc file like `alias x="mise x --"` to +save some keystrokes. +::: + +## Alternate Installation Methods + +### + +Note that it isn't necessary for `mise` to be on `PATH`. If you run the activate script in your +shell's rc +file, mise will automatically add itself to `PATH`. + +```sh +curl https://mise.run | sh +``` + +Options: + +- `MISE_DEBUG=1` โ€“ enable debug logging +- `MISE_QUIET=1` โ€“ disable non-error output +- `MISE_INSTALL_PATH=/some/path` โ€“ change the binary path (default: `~/.local/bin/mise`) +- `MISE_VERSION=v2024.5.17` โ€“ install a specific version + +If you want to verify the install script hasn't been tampered with: + +```sh +gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 0x7413A06D +curl https://mise.jdx.dev/install.sh.sig | gpg --decrypt > install.sh +# ensure the above is signed with the mise release key +sh ./install.sh +``` + +or if you're allergic to `| sh`: + +::: code-group + +```sh [macos-arm64] +curl https://mise.jdx.dev/mise-latest-macos-arm64 > ~/.local/bin/mise +chmod +x ~/.local/bin/mise +``` + +```sh [macos-x64] +curl https://mise.jdx.dev/mise-latest-macos-x64 > ~/.local/bin/mise +chmod +x ~/.local/bin/mise +``` + +```sh [linux-x64] +curl https://mise.jdx.dev/mise-latest-linux-x64 > ~/.local/bin/mise +chmod +x ~/.local/bin/mise +``` + +```sh [linux-arm64] +curl https://mise.jdx.dev/mise-latest-linux-arm64 > ~/.local/bin/mise +chmod +x ~/.local/bin/mise +``` + +::: + +It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/bin` or whatever. + +Supported os/arch: + +- `macos-x64` +- `macos-arm64` +- `linux-x64` +- `linux-x64-musl` +- `linux-arm64` +- `linux-arm64-musl` +- `linux-armv6` +- `linux-armv6-musl` +- `linux-armv7` +- `linux-armv7-musl` + +If you need something else, compile it with `cargo install mise` (see below). +[Windows isn't currently supported.](https://github.com/jdx/mise/discussions/66) + +### apk + +For Alpine Linux: + +```sh +apk add mise +``` + +_mise lives in +the [community repository](https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/mise/APKBUILD)._ + +### apt + +For installation on Ubuntu/Debian: + +::: code-group + +```sh [amd64] +apt update -y && apt install -y gpg sudo wget curl +sudo install -dm 755 /etc/apt/keyrings +wget -qO - https://mise.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/mise-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.gpg arch=amd64] https://mise.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/mise.list +sudo apt update +sudo apt install -y mise +``` + +```sh [arm64] +apt update -y && apt install -y gpg sudo wget curl +sudo install -dm 755 /etc/apt/keyrings +wget -qO - https://mise.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/mise-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.gpg arch=arm64] https://mise.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/mise.list +sudo apt update +sudo apt install -y mise +``` + +::: + +### aur + +For Arch Linux: + +```sh +git clone https://aur.archlinux.org/mise.git +cd mise +makepkg -si +``` + +### Cargo + +Build from source with Cargo: + +```sh +cargo install mise +``` + +Do it faster with [cargo-binstall](https://github.com/cargo-bins/cargo-binstall): + +```sh +cargo install cargo-binstall +cargo binstall mise +``` + +Build from the latest commit in main: + +```sh +cargo install mise --git https://github.com/jdx/mise --branch main +``` + +### dnf + +For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: + +```sh +dnf install -y dnf-plugins-core +dnf config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo +dnf install -y mise +``` + +### Docker + +```sh +docker run jdxcode/mise x node@20 -- node -v +``` + +### Homebrew + +```sh +brew install mise +``` + +### npm + +mise is available on npm as a precompiled binary. This isn't a Node.js packageโ€”just distributed +via npm. This is useful for JS projects that want to setup mise via `package.json` or `npx`. + +```sh +npm install -g @jdxcode/mise +``` + +Use npx if you just want to test it out for a single command without fully installing: + +```sh +npx @jdxcode/mise exec python@3.11 -- python some_script.py +``` + +### GitHub Releases + +Download the latest release from [GitHub](https://github.com/jdx/mise/releases). + +```sh +curl https://github.com/jdx/mise/releases/download/v2024.1.0/mise-v2024.1.0-linux-x64 > /usr/local/bin/mise +chmod +x /usr/local/bin/mise +``` + +### MacPorts + +```sh +sudo port install mise +``` + +### nix + +For the Nix package manager, at release 23.05 or later: + +```sh +nix-env -iA mise +``` + +You can also import the package directly using +`mise-flake.packages.${system}.mise`. It supports all default Nix +systems. + +### yum + +```sh +yum install -y yum-utils +yum-config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo +yum install -y mise +``` + +## Shells + +### Bash + +```sh +echo 'eval "$(mise activate bash)"' >> ~/.bashrc +``` + +### Zsh + +```sh +echo 'eval "$(mise activate zsh)"' >> "${ZDOTDIR-$HOME}/.zshrc" +``` + +### Fish + +```sh +echo 'mise activate fish | source' >> ~/.config/fish/config.fish +``` + +::: tip +For homebrew and possibly other installs mise is automatically activated so +this is not necessary. + +See [`MISE_FISH_AUTO_ACTIVATE=1`](/configuration#mise_fish_auto_activate1) for more information. +::: + +### Nushell + +Nu +does [not support `eval`](https://www.nushell.sh/book/how_nushell_code_gets_run.html#eval-function) +Install Mise by appending `env.nu` and `config.nu`: + +```nushell +' +let mise_path = $nu.default-config-dir | path join mise.nu +^mise activate nu | save $mise_path --force +' | save $nu.env-path --append +"\nuse mise.nu" | save $nu.config-path --append +``` + +If you prefer to keep your dotfiles clean you can save it to a different directory then +update `$env.NU_LIB_DIRS`: + +```nushell +"\n$env.NU_LIB_DIRS ++= ($mise_path | path dirname | to nuon)" | save $nu.env-path --append +``` + +### Xonsh + +Since `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a +bit off startup time by using a pure Python import: add the code below to, for +example, `~/.config/xonsh/mise.py` config file and `import mise` it in `~/.config/xonsh/rc.xsh`: + +```python +from pathlib import Path +from xonsh.built_ins import XSH + +ctx = XSH.ctx +mise_init = subprocess.run([Path('~/bin/mise').expanduser(),'activate','xonsh'],capture_output=True,encoding="UTF-8").stdout +XSH.builtins.execx(mise_init,'exec',ctx,filename='mise') +``` + +Or continue to use `rc.xsh`/`.xonshrc`: + +```sh +echo 'execx($(~/bin/mise activate xonsh))' >> ~/.config/xonsh/rc.xsh # or ~/.xonshrc +``` + +Given that `mise` replaces both shell env `$PATH` and OS environ `PATH`, watch out that your configs +don't have these two set differently (might +throw `os.environ['PATH'] = xonsh.built_ins.XSH.env.get_detyped('PATH')` at the end of a config to +make sure they match) + +### Something else? + +Adding a new shell is not hard at all since very little shell code is +in this project. +[See here](https://github.com/jdx/mise/tree/main/src/shell) for how +the others are implemented. If your shell isn't currently supported +I'd be happy to help you get yours integrated. + +## Uninstalling + +Use `mise implode` to uninstall mise. This will remove the mise binary and all of its data. Use +`mise implode --help` for more information. + +Alternatively, manually remove the following directories to fully clean up: + +- `~/.local/share/mise` (can also be `MISE_DATA_DIR` or `XDG_DATA_HOME/mise`) +- `~/.local/state/mise` (can also be `MISE_STATE_DIR` or `XDG_STATE_HOME/mise`) +- `~/.config/mise` (can also be `MISE_CONFIG_DIR` or `XDG_CONFIG_HOME/mise`) +- on Linux: `~/.cache/mise` (can also be `MISE_CACHE_DIR` or `XDG_CACHE_HOME/mise`) +- on macOS: `~/Library/Caches/mise` (can also be `MISE_CACHE_DIR`) diff --git a/docs/go.md b/docs/go.md deleted file mode 100644 index d4e61f552..000000000 --- a/docs/go.md +++ /dev/null @@ -1 +0,0 @@ -Moved to [mise.jdx.dev/lang/go.html](https://mise.jdx.dev/lang/go.html). diff --git a/docs/how-i-use-mise.md b/docs/how-i-use-mise.md new file mode 100644 index 000000000..f5d06e4ac --- /dev/null +++ b/docs/how-i-use-mise.md @@ -0,0 +1,122 @@ +# How I use mise + +This is a very different doc than the rest of the site. It's not my +intention to make this valuable to anyone. In fact it may end up being +useful to 0 people. + +I'm probably the strangest user of mise out there. My use case is the +most atypical for a number of reasons I'll get to. That said, I often +find myself saying to friends "you know the way I use mise..." and thought +it might be useful to actually write down the way I use it in case +anyone is interested. + +This is an advanced article. I'm not going to take the time to explain +the tools and techniques here. If you're curious, file an issue or ask +me in the Discord. + +## My setup + +I use a mac with fish shell and am a heavy homebrew user. I've been using +both for over a decade. + +My main editor(s) are JetBrains products (IntelliJ, RustRover, Webstorm). +I also use nvim as a secondary editor (Astronvim with some minimal config). +I probably spend 70% of my time in JetBrains. + +I tend to keep a terminal open (kitty) while working in JetBrains. I do not +often run tests or builds with in the IDE. Not sure why, just never been +in the habit of that. (Because of that these docs and possibly mise support in +IDEs may not be what it should be-it's just not how I work personally). + +## `mise activate` + +Unlike most mise users, I don't use `mise activate` or +shims at all unless I'm explicitly testing them-and that's rarely the +case. It certainly doesn't go into my `~/.config/fish/config.fish`. + +Because I work on mise itself, I often need to rebuild it and run the code from my repo. For this, I have the following bash shim located in +`~/bin/@mise`: + +```fish +#!/usr/bin/env bash +set -euo pipefail + +exec cargo run -q --all-features --manifest-path ~/src/mise/Cargo.toml -- "$@" +``` + +:::info +The "@" prefix I use for things that will perform a rebuild-i.e.: they're slow. +::: + +This way I can easily test mise in any directory with `@mise`. I probably +run this more often than without just out of habit. For example, if I want to test `mise activate` in zsh: + +```sh +zsh +eval "$(@mise activate zsh)" +``` + +## Minimal tools + +Might be surprising to folks but I don't use too many mise plugins. Well +I have a lot in my config, but I don't actually use them. They're for +testing. + +I tend to basically just use core plugins. I like mise for managing +things where I really care about the major version (like node). If it's +something like `shfmt` or `jq` I don't really care about the version. +I just want the latest and for me, I find `brew` to be better suited to +that purpose. + +I recognize that some people really like locking down their versions +across a team to keep things consistent. I think that's great too. +Part of this is that I'm currently at Amazon where the tooling story +is complicated let's just say-not in a bad way, just one where +integrating mise into the setup isn't as straightforward as a smaller +company would be. + +Outside of Amazon I have a handful of open source projects, mostly +mise-related and mostly fairly simple. Also mostly rust where I don't +use mise anyways. + +The one big exception here is node which I quite like mise for. I assume +others do to because it's by far the most popular language. You'd +probably guess that since it's my example in nearly all of the docs. + +That said, part of the reason for doing that in the docs is that it's 4 +characters and everyone knows what it is. + +## `.mise.local.toml` + +I'm a heavy user of this concept. I rarely like to actually commit `.mise.toml` +files into projects. I tend to see my mise config as my personal config that +I use within other projects that I don't particularly want to share with others. + +Of course, this goes into my global gitconfig so I can easily add this to +shared projects without submitting a PR. + +One day when tasks is out of experimental, I may do this a lot less since I +think tasks are one thing I really want to share. For me, the `[tools]` +section is just so easy to write I don't mind doing it and don't like +imposing the way that **I** setup my machine on others. + +There is a social aspect of this as well that I'm conscious of. I'm +the author of `mise`. To me it's a little self-serving to go into a project +and add a config for my own project. I'd love if _someone else_ did that +instead. + +## `~/.mise` + +I often need to access mise's internals so I do the following: + +```sh +ln -s ~/.mise ~/.config/mise +ln -s ~/.mise ~/.local/share/mise +ln -s ~/.mise ~/.local/state/mise +ln -s ~/.mise/cache ~/.cache/mise +``` + +It is good that mise generally follows XDG spec, but for tools that I interact +with a lot I like to put them at the top level like this. Obviously, +mise doesn't mind if all of these point to the same place or else it would +not work for me. diff --git a/docs/ide-integration.md b/docs/ide-integration.md new file mode 100644 index 000000000..e07f57477 --- /dev/null +++ b/docs/ide-integration.md @@ -0,0 +1,159 @@ +# IDE Integration + +IDEs work better with shims than they do environment variable modifications. The simplest way is +to add the mise shim directory to PATH. + +For IntelliJ and VSCodeโ€”and likely others, you can modify your default shell's profile +script. Your default shell can be found with: + +* macos โ€“ `dscl . -read /Users/$USER UserShell` +* linux โ€“ `getent passwd $USER | cut -d: -f7` + +You can change your default shell with `chsh -s /path/to/shell` but you may need +to first add it to `/etc/shells`. + +Once you know the right one, modify the appropriate file: + +::: code-group + +```zsh +# ~/.zprofile +eval "$(mise activate zsh --shims)" +``` + +```bash +# ~/.bash_profile or ~/.bash_login or ~/.profile +eval "$(mise activate bash --shims)" +``` + +```fish +# ~/.config/fish/config.fish +if status is-interactive + mise activate fish | source +else + mise activate fish --shims | source +end +``` + +::: + +This assumes that `mise` is on PATH. If it is not, you'll need to use the absolute path ( +e.g.: `eval "$($HOME/.local/bin/mise activate zsh)"`). + +This won't work for all of mise's functionality. For example, arbitrary env vars in `[env]` will +only be set +if a shim is executed. For this we need tighter integration with the IDE and a custom plugin. If you +feel +ambitious, take a look at existing direnv extensions for your IDE and see if you can modify it to +work for mise. +Direnv and mise work similarly and there should be a direnv extension that can be used as a starting +point. + +## Vim + +```vim +" Prepend mise shims to PATH +let $PATH = $HOME . '/.local/share/mise/shims:' . $PATH +``` + +## Neovim + +```lua +-- Prepend mise shims to PATH +vim.env.PATH = vim.env.HOME .. "/.local/share/mise/shims:" .. vim.env.PATH +``` + +## emacs + +- Traditional shims way + +```lisp +;; CLI tools installed by Mise +;; See: https://www.emacswiki.org/emacs/ExecPath +(setenv "PATH" (concat (getenv "PATH") ":/home/user/.local/share/mise/shims")) +(setq exec-path (append exec-path '("/home/user/.local/share/mise/shims"))) +``` + +- Use with package [mise.el](https://github.com/liuyinz/mise.el) + +```lisp +(require 'mise) +(add-hook 'after-init-hook #'global-mise-mode) +``` + +## Xcode + +Xcode projects can run system commands from script build phases and schemes. Since Xcode sandboxes +the execution of the script using the tool `/usr/bin/sandbox-exec`, don't expect Mise and the +automatically-activated tools to work out of the box. First, you'll need to +add `$(SRCROOT)/.mise.toml` to the list of **Input files**. This is necessary for Xcode to allow +reads to that file. Then, you can use `mise activate` to activate the tools you need: + +```bash +# -C ensures that Mise loads the configuration from the Mise configuration +# file in the project's root directory. +eval "$($HOME/.local/bin/mise activate -C $SRCROOT bash --shims)" + +swiftlint +``` + +## JetBrains Editors (IntelliJ, RustRover, PyCharm, WebStorm, RubyMine, GoLand, etc) + +Some JetBrains IDEs have direct support for mise, others have support for asdf which can be used by +first symlinking the mise tool directory which is the +same layout as asdf: + +```sh +ln -s ~/.local/share/mise ~/.asdf +``` + +Then they should show up on in Project Settings: + +![project settings](https://github.com/jdx/mise-docs/assets/216188/b34a0e3f-7af8-45c9-85b8-2c72bd1dc226) + +Or in the case of node (possibly other languages), it's under "Languages & Frameworks": + +![languages & frameworks](https://github.com/jdx/mise-docs/assets/216188/9926be1c-ab88-451a-8ace-edf2dac564b5) + +## VSCode + +While modifying `~/.zprofile` is likely the easiest solution, you can also set +the tools in `launch.json`: + +```json +{ + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${file}", + "args": [], + "osx": { + "runtimeExecutable": "mise" + }, + "linux": { + "runtimeExecutable": "mise" + }, + "runtimeArgs": [ + "x", + "--", + "node" + ] + } + ] +} +``` + +## [YOUR IDE HERE] + +I am not a heavy IDE user. I use JetBrains products but I don't actually +like to execute code directly inside of them often so I don't have much +personal advice to offer for IDEs generally. That said, people often +ask about how to get their IDE to work with mise so if you've done this +for your IDE, please consider sending a PR to this page with some +instructions (however rough they are, starting somewhere is better than +nothing). + +Also if you've found a setup that you prefer to what is listed here consider +adding it as a suggestion. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..829a48f0b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,39 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home +title: Home + +hero: + name: mise-en-place + tagline: | + The front-end to your dev env + Pronounced "MEEZ ahn plahs" + actions: + - theme: brand + text: Getting Started + link: /getting-started + - theme: alt + text: About + link: /about + - theme: alt + text: GitHub + link: https://github.com/jdx/mise + - theme: alt + text: Discord + link: https://discord.gg/UBa7pJUN7Z + +features: + - title: Dev Tools + details: mise is a polyglot tool version manager. It replaces tools like asdf, nvm, pyenv, rbenv, etc. + - title: Environments + details: mise allows you to switch sets of env vars in different project directories. It can replace direnv. + - title: Tasks + details: mise is a task runner that can replace make, or npm scripts. +--- + + diff --git a/docs/java.md b/docs/java.md deleted file mode 100644 index abd1974f1..000000000 --- a/docs/java.md +++ /dev/null @@ -1 +0,0 @@ -Moved to [mise.jdx.dev/lang/java.html](https://mise.jdx.dev/lang/java.html). diff --git a/docs/lang/bun.md b/docs/lang/bun.md new file mode 100644 index 000000000..d30178b50 --- /dev/null +++ b/docs/lang/bun.md @@ -0,0 +1,18 @@ +# Bun + +The following are instructions for using the bun mise core plugin. This is used when there isn't a +git plugin installed named "bun". + +The code for this is inside the mise repository at +[`./src/plugins/core/bun.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/bun.rs). + +## Usage + +The following installs bun and makes it the global default: + +```sh +mise use -g bun@0.7 # install bun 0.7.x +mise use -g bun@latest # install latest bun +``` + +See available versions with `mise ls-remote bun`. diff --git a/docs/lang/deno.md b/docs/lang/deno.md new file mode 100644 index 000000000..3208f1f60 --- /dev/null +++ b/docs/lang/deno.md @@ -0,0 +1,21 @@ +# Deno + +The following are instructions for using the deno mise core plugin. This is used when there isn't a +git plugin installed named "deno". + +If you want to use [asdf-deno](https://github.com/asdf-community/asdf-deno) +then run `mise plugins install deno https://github.com/asdf-community/asdf-deno`. + +The code for this is inside the mise repository at +[`./src/plugins/core/deno.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/deno.rs). + +## Usage + +The following installs deno and makes it the global default: + +```sh +mise use -g deno@1 # install deno 1.x +mise use -g deno@latest # install latest deno +``` + +See available versions with `mise ls-remote deno`. diff --git a/docs/lang/erlang.md b/docs/lang/erlang.md new file mode 100644 index 000000000..6bccd968e --- /dev/null +++ b/docs/lang/erlang.md @@ -0,0 +1,22 @@ +# Erlang + +The following are instructions for using the erlang core plugin. +This is used when there isn't a git plugin installed named "erlang". + +The code for this is inside the mise repository at +[`./src/plugins/core/erlang.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/erlang.rs). + +## Usage + +The following installs erlang and makes it the global default: + +```sh +mise use -g erlang@26 +``` + +See available versions with `mise ls-remote erlang`. + +## kerl + +The plugin uses [kerl](https://github.com/kerl/kerl) under the hood to build erlang. +See kerl's docs for information on configuring kerl. diff --git a/docs/lang/go.md b/docs/lang/go.md new file mode 100644 index 000000000..064668dc8 --- /dev/null +++ b/docs/lang/go.md @@ -0,0 +1,101 @@ +# Go + +The following are instructions for using the go mise core plugin. This is used when there isn't a +git plugin installed named "go". + +If you want to use [asdf-golang](https://github.com/kennyp/asdf-golang) +then use `mise plugins install go GIT_URL`. + +The code for this is inside the mise repository at +[`./src/plugins/core/go.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/go.rs). + +## Usage + +The following installs the latest version of go-1.21.x (if some version of 1.21.x is not already +installed) and makes it the global default: + +```sh +mise use -g go@1.21 +``` + +Minor go versions 1.20 and below require specifying `prefix` before the version number because the +first version of each series was released without a `.0` suffix, making 1.20 an exact version match: + +```sh +mise use -g go@prefix:1.20 +``` + +## Configuration + +Set these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable. + +### `go_default_packages_file` + +* Type: `string` +* Env: `MISE_GO_DEFAULT_PACKAGES_FILE` +* Default: `~/.default-go-packages` + +Packages list to install with `go install` after installing a Go version. + +### `go_download_mirror` + +* Type: `string` +* Env: `MISE_GO_DOWNLOAD_MIRROR` +* Default: `https://dl.google.com/go` + +URL to download go sdk tarballs from. + +### `go_repo` + +* Type: `string` +* Env: `MISE_GO_REPO` +* Default: `https://github.com/golang/go` + +Used to get latest go version from GitHub releases. + +### `go_set_gobin` + +* Type: `bool | null` +* Env: `MISE_GO_SET_GOBIN` +* Default: `null` + +Sets `GOBIN` to `~/.local/share/mise/go/installs/[VERSION]/bin`. This causes CLIs installed via +`go install` to have shims created for it which will have env vars from mise such as GOROOT set. + +If not using shims or not using `go install` with tools that require GOROOT, it can probably be +safely disabled. See the [go backend](https://mise.jdx.dev/dev-tools/backends/) for the preferred +method to install Go CLIs. + +### `go_set_gopath` + +* Type: `bool` +* Env: `MISE_GO_SET_GOPATH` +* Default: `false` + +Sets `GOPATH` to `~/.local/share/mise/go/installs/[VERSION]/packages`. This retains behavior from +asdf and older mise/rtx versions. There is no known reason for this to be enabled but it is available +(for now) just in case anyone relies on it. + +### `go_skip_checksum` + +* Type: `bool` +* Env: `MISE_GO_SKIP_CHECKSUM` +* Default: `false` + +Skips checksum verification of downloaded go tarballs. + +## Default packages + +mise can automatically install a default set of packages right after installing a new go version. +To enable this feature, provide a `$HOME/.default-go-packages` file that lists one packages per +line, for example: + +```text +github.com/Dreamacro/clash # allows comments +github.com/jesseduffield/lazygit +``` + +## `.go-version` file support + +mise uses a `.tool-versions` or `.mise.toml` file for auto-switching between software versions. +However it can also read go-specific version files named `.go-version`. diff --git a/docs/lang/java.md b/docs/lang/java.md new file mode 100644 index 000000000..2d2a83ccd --- /dev/null +++ b/docs/lang/java.md @@ -0,0 +1,76 @@ +# Java + +The following are instructions for using the java mise core plugin. This is used when there isn't a +git plugin installed named "java". + +If you want to use [asdf-java](https://github.com/halcyon/asdf-java) +then use `mise plugins install java GIT_URL`. + +The code for this is inside the mise repository at +[`./src/plugins/core/java.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/java.rs). + +## Usage + +The following installs the latest version of java-openjdk-17.x (if some version of openjdk-17.x is +not already installed) and makes it the global default: + +```sh +mise use -g java@openjdk-17 +mise use -g java@17 # alternate shorthands for openjdk-only +``` + +See available versions with `mise ls-remote java`. + +## macOS JAVA_HOME Integration + +Some applications in macOS rely on `/usr/libexec/java_home` to find installed Java runtimes. + +To integrate an installed Java runtime with macOS run the following commands for the proper +version (e.g. openjdk-20). + +```sh +sudo mkdir /Library/Java/JavaVirtualMachines/openjdk-20.jdk +sudo ln -s ~/.local/share/mise/installs/java/openjdk-20/Contents /Library/Java/JavaVirtualMachines/openjdk-20.jdk/Contents +``` + +> Note: Not all distributions of the Java SDK support this integration (e.g liberica). + +## Legacy version files + +The Java core plugin supports the legacy version files `.java-version` and `.sdkmanrc`. + +For `.sdkmanrc` files, mise will try to map the vendor and version to the appropriate version +string. For example, the version `20.0.2-tem` will be mapped to `temurin-20.0.2`. Due to Azul's Zulu +versioning, the version `11.0.12-zulu` will be mapped to the major version `zulu-11`. Not all +vendors available in SDKMAN are supported by mise. The following vendors are NOT supported: `bsg` ( +Bisheng), `graal` (GraalVM), `nik` (Liberica NIK). + +In case an unsupported version of java is needed, some manual work is required: + +1. Download the unsupported version to a directory (e.g `~/.sdkman/candidates/java/21.0.1-open`) +2. symlink the new version: + +```sh +ln -s ~/.sdkman/candidates/java/21.0.1-open ~/.local/share/mise/installs/java/21.0.1-open +``` + +3. If on Mac: + +```sh +mkdir ~/.local/share/mise/installs/java/21.0.1-open/Contents +mkdir ~/.local/share/mise/installs/java/21.0.1-open/Contents/MacOS + +ln -s ~/.sdkman/candidates/java/21.0.1-open ~/.local/share/mise/installs/java/21.0.1-open/Contents/Home +cp ~/.local/share/mise/installs/java/21.0.1-open/lib/libjli.dylib ~/.local/share/mise/installs/java/21.0.1-open/Contents/MacOS/libjli.dylib +``` + +4. Don't forget to make sure the cache is blocked and valid, by making sure an **empty** directory * + *exists** for your version in the [mise cache](https://mise.jdx.dev/directories.html#cache-mise): + e.g. + +```sh +$ ls -R $MISE_CACHE_DIR/java +21.0.1-open + +mise/java/21.0.1-open: +``` diff --git a/docs/lang/node.md b/docs/lang/node.md new file mode 100644 index 000000000..a54cb5534 --- /dev/null +++ b/docs/lang/node.md @@ -0,0 +1,59 @@ +# Node + +The following are instructions for using the node mise core plugin. This is used when there isn't a +git plugin installed named "node". + +If you want to use [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs) +then run `mise plugins install node https://github.com/asdf-vm/asdf-nodejs` + +The code for this is inside the mise repository at [`./src/plugins/core/node.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/node.rs). + +## Usage + +The following installs the latest version of node-20.x and makes it the global +default: + +```sh +mise use -g node@20 +``` + +## Requirements + +See [BUILDING.md](https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms) in node's documentation for +required system dependencies. + +## Configuration + +- `MISE_NODE_VERIFY` [bool]: Verify the downloaded assets using GPG. Defaults to `true`. +- `MISE_NODE_NINJA` [bool]: Use ninja instead of make to compile node. Defaults to `true` if installed. +- `MISE_NODE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries. Can also be set across all languages with [`MISE_NODE__COMPILE`](https://github.com/jdx/mise#mise_node_compile1) +- `MISE_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores +- `MISE_NODE_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-npm-packages` +- `MISE_NODE_MIRROR_URL` [string]: overrides the default mirror used for downloading the distributions +- `MISE_NODE_CFLAGS` [string]: Additional CFLAGS options (e.g., to override -O3). +- `MISE_NODE_CONFIGURE_OPTS` [string]: Additional `./configure` options. +- `MISE_NODE_MAKE_OPTS` [string]: Additional `make` options. +- `MISE_NODE_MAKE_INSTALL_OPTS` [string]: Additional `make install` options. +- `MISE_NODE_COREPACK` [bool]: Installs the default corepack shims after installing any node version that ships with [corepack](https://github.com/nodejs/corepack). + +## Default node packages + +mise-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-npm-packages` file that lists one package per line, for example: + +```text +lodash +request +express +``` + +You can specify a non-default location of this file by setting a `MISE_NODE_DEFAULT_PACKAGES_FILE` variable. + +## `.nvmrc` and `.node-version` support + +mise uses a `.tool-versions` or `.mise.toml` file for auto-switching between software versions. To ease migration, you can have also have it read an existing `.nvmrc` or `.node-version` file to find out what version of Node.js should be used. This will be used if `node` isn't defined in `.tool-versions`/`.mise.toml`. + +## "nodejs" -> "node" Alias + +You cannot install/use a plugin named "nodejs". If you attempt this, mise will just rename it to +"node". See the [FAQ](https://github.com/jdx/mise#what-is-the-difference-between-nodejs-and-node-or-golang-and-go) +for an explanation. diff --git a/docs/lang/python.md b/docs/lang/python.md new file mode 100644 index 000000000..ff0ef63ad --- /dev/null +++ b/docs/lang/python.md @@ -0,0 +1,195 @@ +# Python + +The following are instructions for using the python mise core plugin. The core plugin will be used +so long as no plugin is manually +installed named "python" using `mise plugins install python [GIT_URL]`. + +The code for this is inside of the mise repository +at [`./src/plugins/core/python.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/python.rs). + +## Usage + +The following installs the latest version of python-3.11.x and makes it the global +default: + +```sh +mise use -g python@3.11 +``` + +You can also use multiple versions of python at the same time: + +```sh +$ mise use -g python@3.10 python@3.11 +$ python -V +3.10.0 +$ python3.11 -V +3.11.0 +``` + +## Configuration + +`python-build` already has +a [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in +additional to that python in mise has a few extra configuration variables. + +Set these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable. + +### `python_pyenv_repo` + +* Type: `string` +* Env: `MISE_PYENV_REPO` +* Default: `https://github.com/pyenv/pyenv.git` + +The pyenv repo to get python-build from. + +### `python_compile` + +* Type: `bool` +* Env: `MISE_PYTHON_COMPILE` +* Default: [undefined] +* Values: + * `true` - always compile with python-build instead of downloading [precompiled binaries](#precompiled-python-binaries). + * `false` - always download precompiled binaries. + * [undefined] - use precompiled binary if one is available for the current platform, compile otherwise. + +### `python_precompiled_os` + +* Type: `string` +* Env: `MISE_PYTHON_PRECOMPILED_OS` +* Default: `"apple-darwin" | "unknown-linux-gnu" | "unknown-linux-musl"` + +Specify the OS to use for precompiled binaries. + +### `python_precompiled_arch` + +* Type: `string` +* Env: `MISE_PYTHON_PRECOMPILED_ARCH` +* Default: `"x86_64_v3" | "aarch64"` + +Specify the architecture to use for precompiled binaries. If on an old CPU, you may want to set this +to +`"x86_64"` for the most compatible binaries. +See for more information. + +### `python_patch_url` + +* Type: `string` +* Env: `MISE_PYTHON_PATCH_URL` + +A url to a patch file to pass to python-build. + +### `python_patches_directory` + +* Type: `string` +* Env: `MISE_PYTHON_PATCHES_DIRECTORY` + +A local directory containing patch files to pass to python-build. + +### `python_default_packages_file` + +* Type: `string` +* Env: `MISE_PYTHON_DEFAULT_PACKAGES_FILE` +* Default: `$HOME/.default-python-packages` + +Packages list to install with pip after installing a Python version. + +## Default Python packages + +mise can automatically install a default set of Python packages with pip right after installing a +Python version. To enable this feature, provide a `$HOME/.default-python-packages` file that lists +one package per line, for example: + +```text +ansible +pipenv +``` + +You can specify a non-default location of this file by setting a `MISE_PYTHON_DEFAULT_PACKAGES_FILE` +variable. + +## Precompiled python binaries + +By default, mise will +download [precompiled binaries](https://github.com/indygreg/python-build-standalone) +for python instead of compiling them with python-build. This makes installing python much faster. + +In addition to being faster, it also means you don't have to install all of the system dependencies +either. + +That said, there are +some [quirks](https://github.com/indygreg/python-build-standalone/blob/main/docs/quirks.rst) +with the precompiled binaries to be aware of. + +If you'd like to disable these binaries, set [`python_compile`](#python_compile) to `true`. + +These binaries may not work on older CPUs however you may opt into binaries which +are more compatible with older CPUs by setting `MISE_PYTHON_PRECOMPILED_ARCH` with +a different version. See for +more information +on this option. Set it to "x86_64" for the most compatible binaries. + +## python-build + +Optionally, mise +uses [python-build](https://github.com/pyenv/pyenv/tree/master/plugins/python-build) (part of pyenv) +to compile python runtimes, +you need to ensure +its [dependencies](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) are installed +before installing python with +python-build. + +## Troubleshooting errors with Homebrew + +If you normally use Homebrew and you see errors regarding OpenSSL, +your best bet might be using the following command to install Python: + +```sh +CFLAGS="-I$(brew --prefix openssl)/include" \ +LDFLAGS="-L$(brew --prefix openssl)/lib" \ +mise install python@latest; +``` + +Homebrew installs its own OpenSSL version, which may collide with system-expected ones. +You could even add that to your +`.profile`, +`.bashrc`, +`.zshrc`... +to avoid setting them every time + +Additionally, if you encounter issues with python-build, +you may benefit from unlinking pkg-config prior to install +([reason](https://github.com/pyenv/pyenv/issues/2823#issuecomment-1769081965)). + +```sh +brew unlink pkg-config +mise install python@latest +brew link pkg-config +``` + +Thus the entire script would look like: + +```sh +brew unlink pkg-config +CFLAGS="-I$(brew --prefix openssl)/include" \ + LDFLAGS="-L$(brew --prefix openssl)/lib" \ + mise install python@latest +brew link pkg-config +``` + +## Automatic virtualenv activation + +Python comes with virtualenv support built in, use it with `.mise.toml` configuration like +one of the following: + +```toml +[tools] +python = "3.11" # [optional] will be used for the venv + +[env] +_.python.venv = ".venv" # relative to this file's directory +_.python.venv = "/root/.venv" # can be absolute +_.python.venv = "{{env.HOME}}/.cache/venv/myproj" # can use templates +_.python.venv = { path = ".venv", create = true } # create the venv if it doesn't exist +``` + +The venv will need to be created manually with `python -m venv /path/to/venv` unless `create=true`. diff --git a/docs/lang/ruby.md b/docs/lang/ruby.md new file mode 100644 index 000000000..2ce51278e --- /dev/null +++ b/docs/lang/ruby.md @@ -0,0 +1,72 @@ +# Ruby + +The following are instructions for using the ruby mise core plugin. This is used when there isn't a +git plugin installed named "ruby". + +If you want to use [asdf-ruby](https://github.com/asdf-vm/asdf-ruby) +then use `mise plugins install ruby GIT_URL`. + +The code for this is inside the mise repository at +[`./src/plugins/core/ruby.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/ruby.rs). + +## Usage + +The following installs the latest version of ruby-3.2.x (if some version of 3.2.x is not already +installed) and makes it the global default: + +```sh +mise use -g ruby@3.2 +``` + +Behind the scenes, mise uses [`ruby-build`](https://github.com/rbenv/ruby-build) to compile ruby +from source. You can check its +[README](https://github.com/rbenv/ruby-build/blob/master/README.md) +for additional settings and some troubleshooting. + +## Configuration + +`ruby-build` already has a +[handful of settings](https://github.com/rbenv/ruby-build?tab=readme-ov-file#custom-build-configuration), +in additional to that mise has a few extra configuration variables: + +- `MISE_RUBY_INSTALL` [bool]: Build with ruby-install instead of ruby-build +- `MISE_RUBY_APPLY_PATCHES` [string]: A list of patches (files or URLs) to apply to the ruby source code +- `MISE_RUBY_VERBOSE_INSTALL` [bool]: Show verbose output during installation (passes --verbose to ruby-build) +- `MISE_RUBY_BUILD_OPTS` [string]: Command line options to pass to ruby-build when installing +- `MISE_RUBY_INSTALL_OPTS` [string]: Command line options to pass to ruby-install when installing (if MISE_RUBY_INSTALL=1) +- `MISE_RUBY_DEFAULT_PACKAGES_FILE` [string]: location of default gems file, defaults to `$HOME/.default-gems` + +## Default gems + +mise can automatically install a default set of gems right after installing a new ruby version. +To enable this feature, provide a `$HOME/.default-gems` file that lists one gem per line, for +example: + +```text +# supports comments +pry +bcat ~> 0.6.0 # supports version constraints +rubocop --pre # install prerelease version +``` + +## `.ruby-version` and `Gemfile` support + +mise uses a `.tool-versions` or `.mise.toml` file for auto-switching between software versions. +However it can also read ruby-specific version files `.ruby-version` or `Gemfile` +(if it specifies a ruby version). + +Create a `.ruby-version` file for the current version of ruby: + +```sh +ruby -v > .ruby-version +``` + +### Manually updating ruby-build + +ruby-build should update daily, however if you find versions do not yet exist you can force an +update: + +```bash +mise cache clean +mise ls-remote ruby +``` diff --git a/docs/lang/rust.md b/docs/lang/rust.md new file mode 100644 index 000000000..ccd04bfa1 --- /dev/null +++ b/docs/lang/rust.md @@ -0,0 +1,40 @@ +# Rust + +Rust is not currently offered as a core plugin. In fact, I don't think you +should actually use mise for rust development. Rust has an official version +manager called [`rustup`](https://rustup.rs/) that is better than what any of +the current mise plugins offer. + +You install [rustup](https://rustup.rs/) with the following: + +```sh +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +That said, rust is still one of the most popular languages to use in mise. +A lot of users have success with it so if you'd like to keep all of your +languages configured the same, don't feel like using mise is a bad idea either. Especially if you're only a casual rust user. + +If you're a relatively heavy rust user making use of things like channel +overrides, components, and cross-compiling, then I think you really should +just be using rustup though. The experience will be better. + +If one day we could figure out a way to provide an equivalent experience with +mise, we could revisit this. We have discussed potentially using mise as a +"front-end" to rustup where there is one rustup install that mise just manages +so you could do something like this: + +```toml +[tools] +rust = "nightly" +``` + +Where that would basically be equivalent to: + +```sh +rustup override set nightly +``` + +Frankly though, this isn't high on my priority list. Use rustup. It's great. + +Kudos for writing rust too btw, I've really enjoyed it so farโ€”this is my first rust project. diff --git a/docs/lefthook.yml b/docs/lefthook.yml new file mode 100644 index 000000000..43b0fd0c5 --- /dev/null +++ b/docs/lefthook.yml @@ -0,0 +1,6 @@ +pre-commit: + commands: + build: + glob: "*" + run: npm run docs:build + interactive: true diff --git a/docs/node.md b/docs/node.md deleted file mode 100644 index 83ea937a4..000000000 --- a/docs/node.md +++ /dev/null @@ -1 +0,0 @@ -Moved to [mise.jdx.dev/lang/node.html](https://mise.jdx.dev/lang/node.html). diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 000000000..50e291e61 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,13 @@ +{ + "name": "@mise/docs", + "private": true, + "type": "module", + "devDependencies": { + "vitepress": "1.3.2" + }, + "scripts": { + "docs:dev": "vitepress dev", + "docs:build": "vitepress build", + "docs:preview": "vitepress preview" + } +} diff --git a/docs/paranoid.md b/docs/paranoid.md new file mode 100644 index 000000000..c1b580d54 --- /dev/null +++ b/docs/paranoid.md @@ -0,0 +1,51 @@ +# Paranoid + +Paranoid is an optional behavior that locks mise down more to make it harder +for a bad actor to compromise your system. These are settings that I +personally do not use on my own system because I find the behavior too +restrictive for the benefits. + +Paranoid mode can be enabled with either `MISE_PARANOID=1` or a setting: + +```sh +mise settings set paranoid 1 +``` + +## Config files + +Normally `mise` will make sure some config files are "trusted" before loading +them. This will prompt you to confirm that you want to load the file, e.g.: + +```sh +$ mise install +mise ~/src/mise/.tool-versions is not trusted. Trust it [y/n]? +``` + +Generally only potentially dangerous config files are checked such as files +that use templates (which can execute arbitrary code) or that set env vars. +Under paranoid, however, all config files must be trusted first. + +Also, in normal mode, a config file only needs to be trusted a single time. +In paranoid, the contents of the file are hashed to check if the file changes. +If you change your config file, you'll need to trust it again. + +## Community plugins + +Community plugins can not be directly installed via short-name under paranoid. +You can install plugins that are either core, maintained by the mise team, +or plugins that mise has marked as "first-party"โ€”meaning plugins developed by +the same team that builds the tool the plugin installs. + +Other than that, say for "shfmt", you'll need to specify the full git repo +to install: + +```sh +mise plugin install shfmt https://github.com/luizm/asdf-shfmt +``` + +Unlike in normal mode where `mise plugin install shfmt` would be sufficient. + +## More? + +If you have suggestions for more that could be added to paranoid, please let +me know. diff --git a/docs/plugins.md b/docs/plugins.md new file mode 100644 index 000000000..f7ade5b9f --- /dev/null +++ b/docs/plugins.md @@ -0,0 +1,57 @@ +# Plugins + +mise uses asdf's plugin ecosystem under the hood. These plugins contain shell scripts like +`bin/install` (for installing) and `bin/list-all` (for listing all of the available versions). + +See for the list of built-in plugins shorthands. See asdf's +[Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn +more about how they work. + +## Core Plugins + +mise comes with some plugins built into the CLI written in Rust. These are new and will improve over +time. They can be easily overridden by installing a plugin with the same name, e.g.: `mise plugin install python https://github.com/asdf-community/asdf-python`. + +You can see the core plugins with `mise plugin ls --core`. + +- [Bun](/lang/bun) +- [Deno](/lang/deno) +- [Erlang](/lang/erlang) +- [Go](/lang/go) +- [Java](/lang/java) +- [NodeJS](/lang/node) +- [Python](/lang/python) +- [Ruby](/lang/ruby) + +## Plugin Authors + + is a GitHub organization for community-developed plugins. +See [SECURITY.md](https://github.com/jdx/mise/blob/main/SECURITY.md) for more details on how plugins here are treated differently. + +If you'd like your plugin to be hosted here please let me know (GH discussion or discord is fine) +and I'd be happy to host it for you. + +## Plugin Options + +mise has support for "plugin options" which is configuration specified in `.mise.toml` to change behavior +of plugins. One example of this is virtualenv on python runtimes: + +```toml +[tools] +python = {version='3.11', virtualenv='.venv'} +``` + +This will be passed to all plugin scripts as `MISE_TOOL_OPTS__VIRTUALENV=.venv`. The user can specify +any option and it will be passed to the plugin in that format. + +Currently this only supports simple strings, but we can make it compatible with more complex types +(arrays, tables) fairly easily if there is a need for it. + +## Templates + +Plugin custom repository values can be templates, see [Templates](/templates) for details. + +```toml +[plugins] +my-plugin = "https://{{ get_env(name='GIT_USR', default='empty') }}:{{ get_env(name='GIT_PWD', default='empty') }}@github.com/foo/my-plugin.git" +``` diff --git a/docs/profiles.md b/docs/profiles.md new file mode 100644 index 000000000..e22b1cf03 --- /dev/null +++ b/docs/profiles.md @@ -0,0 +1,39 @@ +# Profiles + +It's possible to have separate `.mise.toml` files in the same directory for different +environments like `development` and `production`. To enable, set `MISE_ENV` to an environment like +`development` or `production`. mise will then look for a `.mise.{MISE_ENV}.toml` file in the current directory. + +mise will also look for "local" files like `.mise.local.toml` and `.mise.{MISE_ENV}.local.toml` in +the current directory. These are intended to not be committed to version control. +(Add `.mise.local.toml` and `.mise.*.local.toml` to your `.gitignore` file.) + +The priority of these files goes in this order (bottom overrides top): + +- `.config/mise/config.toml` +- `mise/config.toml` +- `mise.toml` +- `.mise/config.toml` +- `.mise.toml` +- `.config/mise/config.local.toml` +- `mise/config.local.toml` +- `mise.local.toml` +- `.mise/config.local.toml` +- `.mise.local.toml` +- `.config/mise/config.{MISE_ENV}.toml` +- `mise/config.{MISE_ENV}.toml` +- `mise.{MISE_ENV}.toml` +- `.mise/config.{MISE_ENV}.toml` +- `.mise.{MISE_ENV}.toml` +- `.config/mise/config.{MISE_ENV}.local.toml` +- `mise/config.{MISE_ENV}.local.toml` +- `.mise/config.{MISE_ENV}.local.toml` +- `.mise.{MISE_ENV}.local.toml` + +Use `mise doctor` to see which files are being used. + +::: warning +Note that currently modifying `MISE_DEFAULT_CONFIG_FILENAME` to something other than `.mise.toml` +will not work with this feature. For now, it will disable it entirely. This may change in the +future. +::: diff --git a/docs/project-roadmap.md b/docs/project-roadmap.md new file mode 100644 index 000000000..9d9b8a2bf --- /dev/null +++ b/docs/project-roadmap.md @@ -0,0 +1,33 @@ +# Project Roadmap + +Issues marked ["enhancements"](https://github.com/jdx/mise/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) are the best way to read about ideas for future +functionality. As far as general scope however, these are likely going to be focuses for 2024: + +* Tasks - this is the newest headline feature of mise and needs to be refined, tested, and iterated on before it can come out of experimental +* Documentation website - we've outgrown what is mostly a single README +* Supply chain hardening - securing mise is very important and this topic has had a lot of interest from the community. We plan to make several improvements on this front +* Improved python development - better virtualenv integration, precompiled python binaries, and other areas are topics that frequently come up to improve +* Improved plugin development - it's unclear what we'll do exactly but in general we want to make the experience of vending tools for asdf/mise to be better and safer. +* GUI/TUI - While we're all big CLI fans, it still would be great to better visualize what tools are available, what your configuration is, and other things via some kind of UI. + +## Versioning + +mise uses [Calver](https://calver.org/) versioning (`2024.1.0`). +Breaking changes will be few but when they do happen, +they will be communicated in the CLI with plenty of notice whenever possible. + +Rather than have SemVer major releases to communicate change in large releases, +new functionality and changes can be opted-into with settings like `experimental = true`. +This way plugin authors and users can +test out new functionality immediately without waiting for a major release. + +The numbers in Calver (YYYY.MM.RELEASE) simply represent the date of the releaseโ€”not compatibility +or how many new features were added. +Each release will be small and incremental. + +## Anti-goals + +* Dependency management - mise expects you to have system dependencies (like openssl or readline) already setup and configured. This makes it different than tools like nix which manage all dependencies for you. While this seems like an obvious downside, it actually ends up making mise far easier to use than nix. That said, we would like to make managing system dependencies easier where we can but this is likely going to be simply via better docs and error messages. +* DevOps tooling - mise is designed with local development in mind. While there are certainly many devs using it for production/server roles which we support and encourage, that will never be the our focus on the roadmap. Building a better ansible/terraform/kubernetes just isn't the goal. +* Remote task caching - turbopack, moonrepo, and many others are trying to solve this (major) problem. mise's task runner will likely always just be a simple convenience around executing scripts. +* Windows support - I don't have a Windows machine and I think asdf/mise's focus on Unix tools will make supporting (non-WSL) Windows challenging if not impossible. Unless someone else wants to take on the challenge of building a Windows port I would not expect to see it happen. diff --git a/docs/public/android-chrome-192x192.png b/docs/public/android-chrome-192x192.png new file mode 100755 index 000000000..5a62092b4 Binary files /dev/null and b/docs/public/android-chrome-192x192.png differ diff --git a/docs/public/android-chrome-512x512.png b/docs/public/android-chrome-512x512.png new file mode 100755 index 000000000..ed95d3c8d Binary files /dev/null and b/docs/public/android-chrome-512x512.png differ diff --git a/docs/public/apple-touch-icon.png b/docs/public/apple-touch-icon.png new file mode 100755 index 000000000..10fac2368 Binary files /dev/null and b/docs/public/apple-touch-icon.png differ diff --git a/docs/public/favicon-16x16.png b/docs/public/favicon-16x16.png new file mode 100755 index 000000000..bfe60ca6a Binary files /dev/null and b/docs/public/favicon-16x16.png differ diff --git a/docs/public/favicon-32x32.png b/docs/public/favicon-32x32.png new file mode 100755 index 000000000..85139b164 Binary files /dev/null and b/docs/public/favicon-32x32.png differ diff --git a/docs/public/favicon.ico b/docs/public/favicon.ico new file mode 100755 index 000000000..643b1651e Binary files /dev/null and b/docs/public/favicon.ico differ diff --git a/docs/public/site.webmanifest b/docs/public/site.webmanifest new file mode 100755 index 000000000..45dc8a206 --- /dev/null +++ b/docs/public/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/docs/python.md b/docs/python.md deleted file mode 100644 index c37f95080..000000000 --- a/docs/python.md +++ /dev/null @@ -1 +0,0 @@ -Moved to [mise.jdx.dev/lang/python.html](https://mise.jdx.dev/lang/python.html) diff --git a/docs/registry.md b/docs/registry.md index f9c3452c2..efb0ce148 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -33,7 +33,7 @@ editLink: false | asciidoctorj | [asdf:gliwka/asdf-asciidoctorj](https://github.com/gliwka/asdf-asciidoctorj) | | asdf-plugin-manager | [asdf:asdf-community/asdf-plugin-manager](https://github.com/asdf-community/asdf-plugin-manager) | | assh | [asdf:zekker6/asdf-assh](https://github.com/zekker6/asdf-assh) | -| atlas | [asdf:pbr0ck3r/asdf-atlas](https://github.com/pbr0ck3r/asdf-atlas) | +| atlas | [asdf:komi1230/asdf-atlas](https://github.com/komi1230/asdf-atlas) | | auto-doc | [asdf:looztra/asdf-auto-doc](https://github.com/looztra/asdf-auto-doc) | | aws-amplify-cli | [asdf:LozanoMatheus/asdf-aws-amplify-cli](https://github.com/LozanoMatheus/asdf-aws-amplify-cli) | | aws-copilot | [asdf:NeoHsu/asdf-copilot](https://github.com/NeoHsu/asdf-copilot) | @@ -739,6 +739,7 @@ editLink: false | vhs | [asdf:chessmango/asdf-vhs](https://github.com/chessmango/asdf-vhs) | | viddy | [asdf:ryodocx/asdf-viddy](https://github.com/ryodocx/asdf-viddy) | | vim | [asdf:tsuyoshicho/asdf-vim](https://github.com/tsuyoshicho/asdf-vim) | +| virtualos | [asdf:tuist/asdf-virtualos](https://github.com/tuist/asdf-virtualos) | | vlt | [asdf:asdf-community/asdf-hashicorp](https://github.com/asdf-community/asdf-hashicorp) | | vultr-cli | [asdf:ikuradon/asdf-vultr-cli](https://github.com/ikuradon/asdf-vultr-cli) | | wasi-sdk | [asdf:coolreader18/asdf-wasi-sdk](https://github.com/coolreader18/asdf-wasi-sdk) | diff --git a/docs/rtx.md b/docs/rtx.md new file mode 100644 index 000000000..2f35f3bec --- /dev/null +++ b/docs/rtx.md @@ -0,0 +1,51 @@ +# Coming from rtx + +`mise` was formerly called `rtx`. The name was changed to avoid confusion with Nvidia's +line of graphics cards. This wasn't a legal issue, but just general confusion. When +people first hear about the project or see it posted they wouldn't realize it was talking +about a CLI tool. It was a bit difficult to search for on Google but also places like +Twitter and in Slack searches and things. This was the top complaint about `rtx` and +many people were fairly outspoken about disliking the name for this reason. `rtx` was +supposed to be a working title that I intended to change but never got around to doing. +This change should've happened earlier when there were fewer users and I apologize for +not having done that sooner knowing that this was likely going to be necessary at some point. + +To upgrade from `rtx` to `mise`, simply install `mise` and it should automatically +migrate its internal directories, moving `~/.local/share/rtx/installs/*` to `~/.local/share/mise/installs/*` +(skipping python & ruby which cannot be moved), `~/.local/share/rtx/plugins` to `~/.local/share/mise/plugins`, +and `~/.config/rtx` to `~/.config/mise` (if the destination does not exist). Python and Ruby +installs will need to be reinstalled with `mise install`. + +`mise` will continue reading `.rtx.toml` files for some time but that eventually will +be deprecated so please rename them to `.mise.toml`. `mise` will not read from `RTX_*` +env vars so those will need to be changed to `MISE_*`. Anything using a local `.rtx` or +`.config/rtx` directory will need to be moved to `.mise`/`.config/mise`. + +I apologize if this migration is not seamless however I think moving to a name that +is easier to search for and avoids confusion is better for everyone. I also apologize +for it being abruptโ€”I simply couldn't think of a way to "slow roll" this change out +while also keeping the GitHub repo. + +Users of the `rtx-action` GitHub action will need to switch to `mise-action` (and also +bump the major version to v2). + +If you build infrastructure where users may still be calling `rtx activate` in their +shell rc scripts, you can create a symlink `ln -s /path/to/mise /path/to/rtx` so +`rtx activate` still functions. + +For , we're using `~/.local/bin/mise` +as the executable PATH instead of the old directory `~/.local/share/rtx/bin/mise` +to keep things a bit cleaner. You can still use the old style if you like by setting +`MISE_INSTALL_PATH`. + +If you use shims, a `mise reshim` will be necessary to update the shims. + +Thanks for trying out my little CLI tool by the way. I find this project incredibly +fulfilling to work on and seeing people have success using. I have +tremendous passion for building dev tools and the ideas in `mise` are the product of +me thinking about building a tool like this for over a decade. + +If you aren't happy with `mise` or the way I'm running this project, even in a tiny way, +please let me know. You can [contact me privately](/about#contact) if you like. I certainly +won't take offense and I would prefer you say something rather than nothing. Otherwise +I'll never know. diff --git a/docs/ruby.md b/docs/ruby.md deleted file mode 100644 index f1be7cbba..000000000 --- a/docs/ruby.md +++ /dev/null @@ -1 +0,0 @@ -Moved to [mise.jdx.dev/lang/ruby.html](https://mise.jdx.dev/lang/ruby.html). diff --git a/docs/tasks/index.md b/docs/tasks/index.md new file mode 100644 index 000000000..265980fd3 --- /dev/null +++ b/docs/tasks/index.md @@ -0,0 +1,22 @@ +# Tasks + +You can define tasks in `.mise.toml` files or as standalone shell scripts. These are useful for things like +running linters, tests, builders, servers, and other tasks that are specific to a project. Of course, +tasks launched with mise will include the mise environmentโ€”your tools and env vars defined in `.mise.toml`. + +Here's my favorite features about mise's task runner: + +- building dependencies in parallelโ€”by default with no configuration required +- last-modified checking to avoid rebuilding when there are no changesโ€”requires minimal config +- `mise watch` to automatically rebuild on changesโ€”no configuration required, but it helps +- ability to write tasks as actual bash script files and not inside yml/json/toml strings that lack syntax highlighting and linting/checking support + +::: warning +This is an experimental feature. It is not yet stable and will likely change. Some of the docs +may not be implemented, may be implemented incorrectly, or the docs may need to be updated. +Please give feedback early since while it's experimental it's much easier to change. +::: + +## Task Environment Variables + +- `root` - the root of the project, defaults to the directory of the `.mise.toml` file diff --git a/docs/tasks/running-tasks.md b/docs/tasks/running-tasks.md new file mode 100644 index 000000000..7d60548c8 --- /dev/null +++ b/docs/tasks/running-tasks.md @@ -0,0 +1,112 @@ +# Running Tasks + +See available tasks with `mise tasks`. To show tasks hidden with property `hide=true`, use the option `--hidden`. + +List dependencies of tasks with `mise task deps [tasks]...`. + +Run a task with `mise task run`, `mise run`, or just `mise r`. +You might even want to make a shell alias like `alias mr='mise run --'` since this is likely a common command. + +By default, tasks will execute with a maximum of 4 parallel jobs. Customize this with the `--jobs` option, +`jobs` setting or `MISE_JOBS` environment variable. The output normally will be by line, prefixed with the task +label. By printing line-by-line we avoid interleaving output from parallel executions. However, if +--jobs == 1, the output will be set to `interleave`. + +To just print stdout/stderr directly, use `--interleave`, the `task_output` setting, or `MISE_TASK_OUTPUT=interleave`. + +Stdin is not read by default. To enable this, set `raw = true` on the task that needs it. This will prevent +it running in parallel with any other task-a RWMutex will get a write lock in this case. + +Extra arguments will be passed to the task, for example, if we want to run in release mode: + +```bash +mise run build --release +``` + +If there are multiple commands, the args are only passed to the last command. + +Multiple tasks/arguments can be separated with this `:::` delimiter: + +```bash +mise run build arg1 arg2 ::: test arg3 arg4 +``` + +mise will run the task named "default" if no task is specifiedโ€”and you've created one named "default". You can also alias a different task to "default". + +```bash +mise run +``` + +## Task Grouping + +Tasks can be grouped semantically by using name prefixes separated with `:`s. +For example all testing related tasks may begin with `test:`. Nested grouping +can also be used to further refine groups and simplify pattern matching. +For example running `mise run test:**:local` will match`test:units:local`, +`test:integration:local` and `test:e2e:happy:local` +(See [Wildcards](#wildcards) for more information). + +## Wildcards + +Glob style wildcards are supported when running tasks or specifying tasks +dependencies. + +Available Wildcard Patterns: + +- `?` matches any single character +- `*` matches 0 or more characters +- `**` matches 0 or more groups +- `{glob1,glob2,...}` matches any of the comma-separated glob patterns +- `[ab,...]` matches any of the characters or ranges `[a-z]` +- `[!ab,...]` matches any character not in the character set + +### Examples + +`mise run generate:{completions,docs:*}` + +And with dependencies: + +```toml +[tasks."lint:eslint"] # using a ":" means we need to add quotes +run = "eslint ." +[tasks."lint:prettier"] +run = "prettier --check ." +[tasks.lint] +depends = ["lint:*"] +``` + +## Running on file changes + +It's often handy to only execute a task if the files it uses changes. For example, we might only want +to run `cargo build` if an ".rs" file changes. This can be done with the following config: + +```toml +[tasks.build] +description = 'Build the CLI' +run = "cargo build" +sources = ['Cargo.toml', 'src/**/*.rs'] # skip running if these files haven't changed +outputs = ['target/debug/mycli'] +``` + +Now if `target/debug/mycli` is newer than `Cargo.toml` or any ".rs" file, the task will be skipped. This uses last modified timestamps. +It wouldn't be hard to add checksum support. + +## Watching files + +Run a task when the source changes with `mise watch`: + +```bash +mise watch -t build +``` + +Currently this just shells out to watchexec-which you can install however you want including with mise: `mise use -g watchexec@latest`. +This may change in the future. + +Arguments to `mise watch` will be forwarded onto watchexec. For example, to print diagnostic info: + +```bash +mise watch -t build -- --print-events --verbose +``` + +See watchexec's help with `watchexec --help` or `mise watch -- --help` to see +all of the options. diff --git a/docs/tasks/script-tasks.md b/docs/tasks/script-tasks.md new file mode 100644 index 000000000..0b8992dbe --- /dev/null +++ b/docs/tasks/script-tasks.md @@ -0,0 +1,61 @@ +# Script Tasks + +In addition to defining tasks through the configuration, they can also be defined as standalone script files in +`.mise/tasks/:task_name` such as the following build script for cargo: + +```bash +#!/usr/bin/env bash +# mise description="Build the CLI" +cargo build +``` + +Ensure that the file is executable, otherwise mise will not be able to detect it. + +:::tip +The `mise:description` comment is optional but recommended. It will be used in the output of `mise tasks`. +The other configuration for "script" tasks is supported in this format so you can specify things like the +following-note that this is parsed a TOML table: + +```bash +# mise alias="b" +# mise sources=["Cargo.toml", "src/**/*.rs"] +# mise outputs=["target/debug/mycli"] +# mise env={RUST_BACKTRACE = "1"} +# mise depends=["lint", "test"] +``` + +Assuming that file was located in `.mise/tasks/build`, it can then be run with `mise run build` (or with its alias: `mise run b`). +This script can be edited with by running `mise task edit build` (using $EDITOR). If it doesn't exist it will be created. +These are convenient for quickly making new scripts. Having the code in a bash file and not TOML helps make it work +better in editors since they can do syntax highlighting and linting more easily. They also still work great for non-mise usersโ€”though +of course they'll need to find a different way to install their dev tools the tasks might use. +::: + +## Task Grouping + +Script tasks in `.mise/tasks`, `mise/tasks`, or `.config/mise/tasks` can be grouped into +sub-directories which will automatically apply prefixes to their names +when loaded. + +### Example + +With a folder structure like below: + +```text +.mise +โ””โ”€โ”€ tasks + โ”œโ”€โ”€ build + โ””โ”€โ”€ test + โ”œโ”€โ”€ integration + โ””โ”€โ”€ units +``` + +Running `mise tasks` will give the below output: + +```text +$ mise tasks +Name Description Source +build .../.mise/tasks/build +test:integration .../.mise/tasks/test/integration +test:units .../.mise/tasks/test/units +``` diff --git a/docs/tasks/toml-tasks.md b/docs/tasks/toml-tasks.md new file mode 100644 index 000000000..e46aa9d2e --- /dev/null +++ b/docs/tasks/toml-tasks.md @@ -0,0 +1,43 @@ +# TOML-based Tasks + +Tasks can also be defined in `.mise.toml` files in different ways. This is a more "traditional" method of defining tasks: + +```toml +[tasks.cleancache] +run = "rm -rf .cache" +hide = true # hide this task from the list + +[tasks.clean] +depends = ['cleancache'] +run = "cargo clean" # runs as a shell command + +[tasks.build] +description = 'Build the CLI' +run = "cargo build" +alias = 'b' # `mise run b` + +[tasks.test] +description = 'Run automated tests' +run = [ # multiple commands are run in series + 'cargo test', + './scripts/test-e2e.sh', +] +dir = "{{cwd}}" # run in user's cwd, default is the project's base directory + +[tasks.lint] +description = 'Lint with clippy' +env = {RUST_BACKTRACE = '1'} # env vars for the script +# you can specify a multiline script instead of individual commands +run = """ +#!/usr/bin/env bash +cargo clippy +""" + +[tasks.ci] # only dependencies to be run +description = 'Run CI tasks' +depends = ['build', 'lint', 'test'] + +[tasks.release] +description = 'Cut a new release' +file = 'scripts/release.sh' # execute an external script +``` diff --git a/docs/team.md b/docs/team.md new file mode 100644 index 000000000..6c0617bc0 --- /dev/null +++ b/docs/team.md @@ -0,0 +1,61 @@ + + +# Team + +Jeff Dickey is the primary developer behind mise. He does the bulk +of development for the project. + + + +## Advisory Board + +The advisory board helps make important decisions about the project such as: + +* What features should be on the roadmap +* When should functionality move from experimental to stable +* If/when/how features should be deprecated + + + +## Contributors + +mise is an open source project which welcomes [contributions](https://github.com/jdx/mise/graphs/contributors). +We're grateful for those that have volunteered their work for the project. diff --git a/docs/templates.md b/docs/templates.md new file mode 100644 index 000000000..167e653e2 --- /dev/null +++ b/docs/templates.md @@ -0,0 +1,38 @@ +# Templates + +Templates are used in the following locations: + +- `.tool-versions` files +- `.mise.toml` files for most configuration +- _(Submit a ticket if you want to see it used elsewhere!)_ + +The following context objects are available inside templates: + +- `env: HashMap` โ€“ current environment variables +- `config_root: PathBuf` โ€“ directory containing the `.mise.toml` file + +As well as these functions: + +- `exec(command: &str) -> String` โ€“ execute a command and return the output + +Templates are parsed with [tera](https://keats.github.io/tera/docs/)โ€”which is quite powerful. For +example, this snippet will get the directory name of the project: + +```toml +[env] +PROJECT_NAME = "{{config_root | split(pat='/') | last}}" +``` + +Here's another using `exec()`: + +```toml +[alias.node] +current = "{{exec(command='node --version')}}" +``` + +Or one that uses [`get_env()`](https://keats.github.io/tera/docs/#get-env): + +```toml +[plugins] +my-plugin = "https://{{ get_env(name='GIT_USR', default='empty') }}:{{ get_env(name='GIT_PWD', default='empty') }}@github.com/foo/my-plugin.git" +``` diff --git a/docs/tips-and-tricks.md b/docs/tips-and-tricks.md new file mode 100644 index 000000000..0c428a7ad --- /dev/null +++ b/docs/tips-and-tricks.md @@ -0,0 +1,82 @@ +# Tips & Tricks + +An assortment of helpful tips for using `mise`. + +## macOS Rosetta + +If you have a need to run tools as x86_64 on Apple Silicon, this can be done with mise however you'll currently +need to use the x86_64 version of mise itself. There is an [outstanding issue](https://github.com/jdx/mise/issues/405) +to support this with an env var like MISE_ARCH=x86_64 to make it more seamless. + +A common reason for doing this is to support compiling node <=14. + +First, you'll need a copy of mise that's built for x86_64: + +```sh +$ mkdir -p ~/.local/bin +$ curl https://mise.jdx.dev/mise-latest-macos-x64 > ~/.local/bin/mise-x64 +$ chmod +x ~/.local/bin/mise-x64 +$ ~/.local/bin/mise-x64 --version +mise 2024.x.x +``` + +::: warning +If `~/.local/bin` is not in PATH, you'll need to prefix all commands with `~/.local/bin/mise-x64`. +::: + +Now you can use `mise-x64` to install tools: + +```sh +mise-x64 use -g node@20 +``` + +## Shebang + +You can specify a tool and its version in a shebang without needing to first +setup `.tool-versions`/`.mise.toml` config: + +```typescript +#!/usr/bin/env -S mise x node@20 -- node +// "env -S" allows multiple arguments in a shebang +console.log(`Running node: ${process.version}`); +``` + +This can also be useful in environments where mise isn't activated +(such as a non-interactive session). + +## CI/CD + +Using mise in CI/CD is a great way to synchronize tool versions for dev/build. + +### GitHub Actions + +mise is pretty easy to use without an action: + +```yaml +jobs: + build: + steps: + - run: | + curl https://mise.run | sh + echo "$HOME/.local/bin" >> $GITHUB_PATH + echo "$HOME/.local/share/mise/shims" >> $GITHUB_PATH +``` + +Or you can use the custom action [`jdx/mise-action`](https://github.com/jdx/mise-action): + +```yaml +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: jdx/mise-action@v1 + - run: node -v # will be the node version from `.mise.toml`/`.tool-versions` +``` + +## `mise set` + +Instead of manually editing `.mise.toml` to add env vars, you can use `mise set` instead: + +```sh +mise set NODE_ENV=production +``` diff --git a/e2e/backend/test_cargo_binstall b/e2e/backend/test_cargo_binstall index ecad09fbf..04e975f65 100644 --- a/e2e/backend/test_cargo_binstall +++ b/e2e/backend/test_cargo_binstall @@ -2,6 +2,6 @@ require_cmd cargo export MISE_CARGO_BINSTALL=1 -assert "mise x cargo:eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls -v0.17.0 [+git] +assert "mise x cargo:eza@0.18.24 -- eza -v" "eza - A modern, maintained replacement for ls +v0.18.24 [+git] https://github.com/eza-community/eza" diff --git a/e2e/backend/test_cargo_binstall_token b/e2e/backend/test_cargo_binstall_token index 0006b4326..07813f6ff 100644 --- a/e2e/backend/test_cargo_binstall_token +++ b/e2e/backend/test_cargo_binstall_token @@ -11,10 +11,10 @@ chmod u+x ~/bin/cargo-binstall export PATH="$HOME/bin:$PATH" # This should reuse the existing GITHUB_TOKEN variable -assert_contains "GITHUB_TOKEN=foobar mise install -f cargo:eza@0.17.0 2>&1" "token=foobar" +assert_contains "GITHUB_TOKEN=foobar mise install -f cargo:eza@0.18.24 2>&1" "token=foobar" # This should use the GITHUB_API_TOKEN variable -assert_contains "GITHUB_API_TOKEN=foobar mise install -f cargo:eza@0.17.0 2>&1" "token=foobar" +assert_contains "GITHUB_API_TOKEN=foobar mise install -f cargo:eza@0.18.24 2>&1" "token=foobar" # This should prefer GITHUB_API_TOKEN -assert_contains "GITHUB_TOKEN=foobar GITHUB_API_TOKEN=barquz mise install -f cargo:eza@0.17.0 2>&1" "token=foobar" +assert_contains "GITHUB_TOKEN=foobar GITHUB_API_TOKEN=barquz mise install -f cargo:eza@0.18.24 2>&1" "token=foobar" diff --git a/e2e/backend/test_cargo_compile_git_slow b/e2e/backend/test_cargo_compile_git_slow new file mode 100644 index 000000000..771ee4f68 --- /dev/null +++ b/e2e/backend/test_cargo_compile_git_slow @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +require_cmd cargo + +assert "mise x cargo:eza-community/eza@tag:v0.18.24 -- eza --version" "eza - A modern, maintained replacement for ls +v0.18.24 [+git] +https://github.com/eza-community/eza" diff --git a/e2e/backend/test_cargo_compile_slow b/e2e/backend/test_cargo_compile_slow index 168eecb87..f2c805c07 100644 --- a/e2e/backend/test_cargo_compile_slow +++ b/e2e/backend/test_cargo_compile_slow @@ -2,6 +2,6 @@ require_cmd cargo export MISE_CARGO_BINSTALL=0 -assert "mise x cargo:eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls -v0.17.0 [+git] +assert "mise x cargo:eza@0.18.24 -- eza -v" "eza - A modern, maintained replacement for ls +v0.18.24 [+git] https://github.com/eza-community/eza" diff --git a/e2e/backend/test_spm_slow b/e2e/backend/test_spm_slow new file mode 100644 index 000000000..dee818d8b --- /dev/null +++ b/e2e/backend/test_spm_slow @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Enable test when `Swift` installation will be fixed on Linux (for docker run) +# Wait for https://github.com/jdx/mise/pull/1708 +exit 0 + +mise use swift + +assert "mise x spm:nicklockwood/SwiftFormat@0.53.10 -- swiftformat --version" "0.53.10" +assert "mise x spm:https://github.com/nicklockwood/SwiftFormat.git@0.53.10 -- swiftformat --version" "0.53.10" + +# test package with resources (`templates list` command depends on resources being installed) +assert "mise x spm:SwiftGen/SwiftGen@6.6.2 --verbose -- swiftgen templates list --only colors" "colors: + - literals-swift4 + - literals-swift5 + - swift4 + - swift5 +--- +You can also specify custom templates by path, using \`templatePath\` instead of \`templateName\`. +For more information, see the documentation on GitHub or use \`swiftgen template doc\`. +" diff --git a/e2e/cli/test_sync_nvm b/e2e/cli/test_sync_nvm new file mode 100644 index 000000000..fb64014da --- /dev/null +++ b/e2e/cli/test_sync_nvm @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +export NVM_DIR="$PWD/.nvm" + +install_fake_node() { + mkdir -p "$1/bin" + echo "#!/usr/bin/env echo" >"$1/bin/node" + chmod +x "$1/bin/node" +} + +install_fake_node "$NVM_DIR/versions/node/v18.0.0" +mise sync node --nvm +mise ls +assert_contains "mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'" "node/18.0.0" + +install_fake_node "$NVM_DIR/versions/node/v20.0.0" +install_fake_node "$NVM_DIR/versions/node/v22.0.0" +install_fake_node "$MISE_DATA_DIR/installs/node/20.0.0/bin" + +mise sync node --nvm +mise ls +assert_contains "mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'" "node/22.0.0" +assert_not_contains "mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'" "node/20.0.0" +assert_contains "mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'" "node/18.0.0" diff --git a/e2e/cli/test_sync_nvm_slow b/e2e/cli/test_sync_nvm_slow new file mode 100644 index 000000000..06ec7c085 --- /dev/null +++ b/e2e/cli/test_sync_nvm_slow @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +export NVM_DIR="$PWD/.nvm" +mkdir -p "$NVM_DIR" +curl -L https://github.com/nvm-sh/nvm/archive/refs/tags/v0.40.0.tar.gz | tar -xz -C "$NVM_DIR" --strip-components=1 +. "$NVM_DIR/nvm.sh" + +nvm install 22.0.0 +mise sync node --nvm +mise ls +assert_contains "mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'" "node/22.0.0" + +# mise install node@20.0.0 +# nvm install 20.0.0 +# nvm install 18.0.0 +# mise sync node --nvm +# mise ls +# assert_contains "mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'" "node/22.0.0" +# assert_not_contains "mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'" "node/20.0.0" +# assert_contains "mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'" "node/18.0.0" diff --git a/e2e/plugins/core/test_bun b/e2e/plugins/core/test_bun index c88d47b9d..1de6eaffb 100644 --- a/e2e/plugins/core/test_bun +++ b/e2e/plugins/core/test_bun @@ -1,11 +1,11 @@ #!/usr/bin/env bash cat <.bun-version -1.0.17 +1.1.21 EOF mise i -assert_contains "mise x bun -- bun -v" "1.0.17" +assert_contains "mise x bun -- bun -v" "1.1.21" require_cmd node -assert_contains "mise x bun -- bunx oclif --version" "oclif" +assert_contains "mise x bun -- bunx cowsay \"hello world\"" "hello world" diff --git a/e2e/run_test b/e2e/run_test index 098713582..12a14879f 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -33,7 +33,7 @@ setup_isolated_env() { } create_isolated_env() { - # Create the required diretories + # Create the required directories mkdir -p "$TEST_HOME/bin" "$TEST_WORKDIR" "$TEST_TMPDIR" "$MISE_SYSTEM_DIR" "$MISE_DATA_DIR" "$MISE_STATE_DIR" "$MISE_CACHE_DIR" "$MISE_CONFIG_DIR" # The dummy plugin is required for some tests diff --git a/e2e/style.sh b/e2e/style.sh index 0170d72d0..33107a283 100644 --- a/e2e/style.sh +++ b/e2e/style.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash if [[ -n ${GITHUB_ACTION:-} ]]; then - # Output Github action annotations + # Output GitHub action annotations annotate() { local parameters="" [[ -n ${file:=${TEST_SCRIPT:-}} ]] && parameters="file=${file}" diff --git a/flake.lock b/flake.lock index f5feddac9..eece443b6 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1704161960, - "narHash": "sha256-QGua89Pmq+FBAro8NriTuoO/wNaUtugt29/qqA8zeeM=", + "lastModified": 1718428119, + "narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "63143ac2c9186be6d9da6035fa22620018c85932", + "rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5", "type": "github" }, "original": { diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 89c662054..8a0fd3081 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.5.27" +.TH mise 1 "mise 2024.8.7" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -192,6 +192,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.5.27 +v2024.8.7 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/mise.usage.kdl b/mise.usage.kdl index 3d6347677..41c6abedc 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -134,6 +134,7 @@ cmd "backends" help="Manage backends" { go npm pipx + spm ubi " } @@ -327,16 +328,16 @@ when you commit changes to your repository." } flag "-w --write" help="write to .git/hooks/pre-commit and make it executable" } - cmd "github-action" help="[experimental] Generate a Github Action workflow file" { - long_help r"[experimental] Generate a Github Action workflow file + cmd "github-action" help="[experimental] Generate a GitHub Action workflow file" { + long_help r"[experimental] Generate a GitHub Action workflow file -This command generates a Github Action workflow file that runs a mise task like `mise run ci` +This command generates a GitHub Action workflow file that runs a mise task like `mise run ci` when you push changes to your repository." after_long_help r#"Examples: $ mise generate github-action --write --task=ci $ git commit -m "feat: add new feature" - $ git push # runs `mise run ci` on Github + $ git push # runs `mise run ci` on GitHub "# flag "-n --name" help="the name of the workflow to generate" { arg "" @@ -779,7 +780,7 @@ In .mise.toml, tasks take this form: outputs = ["dist/**/*.js"] Alternatively, tasks can be defined as standalone scripts. -These must be located in the `.mise/tasks` directory. +These must be located in the `.mise/tasks`, `mise/tasks` or `.config/mise/tasks` directory. The name of the script will be the name of the tasks. $ cat .mise/tasks/build</github/home/.abuild/-640e56d3.rsa.pub -echo "$ALPINE_PRIV_KEY" >/github/home/.abuild/-640e56d3.rsa -echo "PACKAGER_PRIVKEY=\"/github/home/.abuild/-640e56d3.rsa\"" >>/github/home/.abuild/abuild.conf +echo "$ALPINE_PUB_KEY" | sudo tee "/etc/apk/keys/$ALPINE_KEY_ID.pub" +echo "$ALPINE_PUB_KEY" >"/github/home/.abuild/$ALPINE_KEY_ID.pub" +echo "$ALPINE_PRIV_KEY" >"/github/home/.abuild/$ALPINE_KEY_ID" +echo "PACKAGER_PRIVKEY=\"/github/home/.abuild/$ALPINE_KEY_ID\"" >>/github/home/.abuild/abuild.conf git config --global user.name "Jeff Dickey" git config --global user.email 6271-jdxcode@users.gitlab.alpinelinux.org -git clone https://gitlab.alpinelinux.org/alpine/aports /home/packager/aports +git clone https://gitlab.alpinelinux.org/alpine/aports.git/ /home/packager/aports cd /home/packager/aports git config --local core.hooksPath .githooks -git remote add jdxcode "https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git" +git remote add jdxcode "https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git/" git checkout -mb mise cd community/mise @@ -26,7 +28,7 @@ sed -i "s/pkgver=.*/pkgver=${MISE_VERSION#v}/" APKBUILD abuild checksum cat /github/home/.abuild/abuild.conf abuild -r -apkbuild-lint APKBUILD +#apkbuild-lint APKBUILD fails due to: SC:[AL57]:./APKBUILD:7:invalid arch '!loongarch64' git add APKBUILD diff --git a/scripts/release.sh b/scripts/release.sh index 6650af15d..f55cead34 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -5,8 +5,8 @@ echo "::group::Setup" git config --global user.name mise-en-dev git config --global user.email 123107610+mise-en-dev@users.noreply.github.com -BASE_DIR="$(cd mise && pwd)" -MISE_VERSION=$(cd mise && ./scripts/get-version.sh) +BASE_DIR="$(pwd)" +MISE_VERSION=$(./scripts/get-version.sh) RELEASE_DIR=releases export BASE_DIR MISE_VERSION RELEASE_DIR rm -rf "${RELEASE_DIR:?}/$MISE_VERSION" @@ -65,28 +65,18 @@ gpg --clearsign -u 8B81C9D17413A06D SHASUMS512.asc popd echo "::group::install.sh" -./mise/scripts/render-install.sh >"$RELEASE_DIR"/install.sh +./scripts/render-install.sh >"$RELEASE_DIR"/install.sh chmod +x "$RELEASE_DIR"/install.sh shellcheck "$RELEASE_DIR"/install.sh gpg -u 8B81C9D17413A06D --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_DIR"/install.sh if [[ "$DRY_RUN" != 1 ]]; then echo "::group::Publish npm @jdxcode/mise" - NPM_PREFIX=@jdxcode/mise ./mise/scripts/release-npm.sh + NPM_PREFIX=@jdxcode/mise ./scripts/release-npm.sh # echo "::group::Publish npm mise-cli" - # NPM_PREFIX=mise-cli ./mise/scripts/release-npm.sh + # NPM_PREFIX=mise-cli ./scripts/release-npm.sh echo "::group::Publish r2" - ./mise/scripts/publish-r2.sh + ./scripts/publish-r2.sh + echo "::group::Publish GitHub releases" + gh release edit --draft=false "$MISE_VERSION" fi - -echo "::group::Publish mise-docs" -cp ./mise/docs/registry.md ./mise-docs/registry.md -cp ./mise/docs/cli-reference.md ./mise-docs/cli/index.md -pushd mise-docs -if [[ -z $(git status -s) ]]; then - echo "No changes to docs" -else - git add cli/index.md registry.md - git commit -m "mise ${MISE_VERSION#v}" -fi -popd diff --git a/src/backend/asdf.rs b/src/backend/asdf.rs index 8ce6acfa8..1a105f0a6 100644 --- a/src/backend/asdf.rs +++ b/src/backend/asdf.rs @@ -9,6 +9,7 @@ use std::sync::{Arc, RwLock}; use clap::Command; use color_eyre::eyre::{bail, eyre, Result, WrapErr}; +use color_eyre::Section; use console::style; use itertools::Itertools; use rayon::prelude::*; @@ -155,6 +156,7 @@ impl Asdf { return Ok(None); } let versions = + // using http is not a security concern and enabling tls makes mise significantly slower match HTTP_FETCH.get_text(format!("http://mise-versions.jdx.dev/{}", self.name)) { Err(err) if http::error_code(&err) == Some(404) => return Ok(None), res => res?, @@ -510,6 +512,101 @@ impl Backend for Asdf { self.plugin_path.exists() } + fn is_installed_err(&self) -> eyre::Result<()> { + if self.is_installed() { + return Ok(()); + } + Err(eyre!("asdf plugin {} is not installed", self.id()) + .suggestion("run with --yes to install plugin automatically")) + } + + fn ensure_installed(&self, mpr: &MultiProgressReport, force: bool) -> Result<()> { + let config = Config::get(); + let settings = Settings::try_get()?; + if !force { + if self.is_installed() { + return Ok(()); + } + if !settings.yes && self.repo_url.is_none() { + let url = self.get_repo_url(&config).unwrap_or_default(); + if !is_trusted_plugin(self.name(), &url) { + warn!( + "โš ๏ธ {} is a community-developed plugin โ€“ {}", + style(&self.name).blue(), + style(url.trim_end_matches(".git")).yellow() + ); + if settings.paranoid { + bail!("Paranoid mode is enabled, refusing to install community-developed plugin"); + } + if !prompt::confirm_with_all(format!( + "Would you like to install {}?", + self.name + ))? { + Err(PluginNotInstalled(self.name.clone()))? + } + } + } + } + let prefix = format!("plugin:{}", style(&self.name).blue().for_stderr()); + let pr = mpr.add(&prefix); + let _lock = self.get_lock(&self.plugin_path, force)?; + self.install(pr.as_ref()) + } + + fn update(&self, pr: &dyn SingleReport, gitref: Option) -> Result<()> { + let plugin_path = self.plugin_path.to_path_buf(); + if plugin_path.is_symlink() { + warn!( + "plugin:{} is a symlink, not updating", + style(&self.name).blue().for_stderr() + ); + return Ok(()); + } + let git = Git::new(plugin_path); + if !git.is_repo() { + warn!( + "plugin:{} is not a git repository, not updating", + style(&self.name).blue().for_stderr() + ); + return Ok(()); + } + pr.set_message("updating git repo".into()); + let (pre, post) = git.update(gitref)?; + let sha = git.current_sha_short()?; + let repo_url = self.get_remote_url().unwrap_or_default(); + self.exec_hook_post_plugin_update(pr, pre, post)?; + pr.finish_with_message(format!( + "{repo_url}#{}", + style(&sha).bright().yellow().for_stderr(), + )); + Ok(()) + } + + fn uninstall(&self, pr: &dyn SingleReport) -> Result<()> { + if !self.is_installed() { + return Ok(()); + } + self.exec_hook(pr, "pre-plugin-remove")?; + pr.set_message("uninstalling".into()); + + let rmdir = |dir: &Path| { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", display_path(dir))); + remove_all(dir).wrap_err_with(|| { + format!( + "Failed to remove directory {}", + style(display_path(dir)).cyan().for_stderr() + ) + }) + }; + + rmdir(&self.plugin_path)?; + + Ok(()) + } + fn get_aliases(&self) -> Result> { if let Some(data) = &self.toml.list_aliases.data { return Ok(self.parse_aliases(data).into_iter().collect()); diff --git a/src/backend/cargo.rs b/src/backend/cargo.rs index a07d17fa8..5e26f79fa 100644 --- a/src/backend/cargo.rs +++ b/src/backend/cargo.rs @@ -1,5 +1,7 @@ use std::fmt::Debug; +use color_eyre::Section; +use eyre::eyre; use serde_json::Deserializer; use url::Url; @@ -34,6 +36,10 @@ impl Backend for CargoBackend { } fn _list_remote_versions(&self) -> eyre::Result> { + if self.git_url().is_some() { + // TODO: maybe fetch tags/branches from git? + return Ok(vec!["HEAD".into()]); + } self.remote_version_cache .get_or_try_init(|| { let raw = HTTP_FETCH.get_text(get_crate_url(self.name())?)?; @@ -54,17 +60,36 @@ impl Backend for CargoBackend { let config = Config::try_get()?; let settings = Settings::get(); settings.ensure_experimental("cargo backend")?; - let cmd = if self.is_binstall_enabled() { - let mut runner = CmdLineRunner::new("cargo-binstall").arg("-y"); + let install_arg = format!("{}@{}", self.name(), ctx.tv.version); + + let cmd = CmdLineRunner::new("cargo").arg("install"); + let cmd = if let Some(url) = self.git_url() { + let mut cmd = cmd.arg(format!("--git={url}")); + if let Some(rev) = ctx.tv.version.strip_prefix("rev:") { + cmd = cmd.arg(format!("--rev={rev}")); + } else if let Some(branch) = ctx.tv.version.strip_prefix("branch:") { + cmd = cmd.arg(format!("--branch={branch}")); + } else if let Some(tag) = ctx.tv.version.strip_prefix("tag:") { + cmd = cmd.arg(format!("--tag={tag}")); + } else if ctx.tv.version != "HEAD" { + Err(eyre!("Invalid cargo git version: {}", ctx.tv.version).note( + r#"You can specify "rev:", "branch:", or "tag:", e.g.: + * mise use cargo:eza-community/eza@tag:v0.18.0 + * mise use cargo:eza-community/eza@branch:main"#, + ))?; + } + cmd + } else if self.is_binstall_enabled() { + let mut cmd = CmdLineRunner::new("cargo-binstall").arg("-y"); if let Some(token) = &*GITHUB_TOKEN { - runner = runner.env("GITHUB_TOKEN", token) + cmd = cmd.env("GITHUB_TOKEN", token) } - runner + cmd.arg(install_arg) } else { - CmdLineRunner::new("cargo").arg("install") + cmd.arg(install_arg) }; - cmd.arg(&format!("{}@{}", self.name(), ctx.tv.version)) + cmd.arg("--locked") .arg("--root") .arg(ctx.tv.install_path()) .with_pr(ctx.pr.as_ref()) @@ -91,6 +116,17 @@ impl CargoBackend { let settings = Settings::get(); settings.cargo_binstall && file::which_non_pristine("cargo-binstall").is_some() } + + /// if the name is a git repo, return the git url + fn git_url(&self) -> Option { + if let Ok(url) = Url::parse(self.name()) { + Some(url) + } else if let Some((user, repo)) = self.name().split_once('/') { + format!("https://github.com/{user}/{repo}.git").parse().ok() + } else { + None + } + } } fn get_crate_url(n: &str) -> eyre::Result { diff --git a/src/backend/go.rs b/src/backend/go.rs index 35e0eb8c8..4a9234253 100644 --- a/src/backend/go.rs +++ b/src/backend/go.rs @@ -72,7 +72,7 @@ impl Backend for GoBackend { CmdLineRunner::new("go") .arg("install") - .arg(&format!("{}@{}", self.name(), version)) + .arg(format!("{}@{}", self.name(), version)) .with_pr(ctx.pr.as_ref()) .envs(self.dependency_env()?) .env("GOBIN", ctx.tv.install_path().join("bin")) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 311b551f9..1d1e146d0 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -8,7 +8,7 @@ use std::sync::{Arc, Mutex}; use clap::Command; use console::style; use contracts::requires; -use eyre::{bail, ensure, eyre, WrapErr}; +use eyre::{bail, eyre, WrapErr}; use itertools::Itertools; use rayon::prelude::*; use regex::Regex; @@ -38,6 +38,7 @@ pub mod cargo; pub mod go; pub mod npm; pub mod pipx; +pub mod spm; pub mod ubi; pub type ABackend = Arc; @@ -65,6 +66,7 @@ pub enum BackendType { Go, Npm, Pipx, + Spm, Ubi, } @@ -107,6 +109,7 @@ fn list_installed_backends() -> eyre::Result { BackendType::Npm => Arc::new(npm::NPMBackend::new(fa.name)) as ABackend, BackendType::Go => Arc::new(go::GoBackend::new(fa.name)) as ABackend, BackendType::Pipx => Arc::new(pipx::PIPXBackend::new(fa.name)) as ABackend, + BackendType::Spm => Arc::new(spm::SPMBackend::new(fa.name)) as ABackend, BackendType::Ubi => Arc::new(ubi::UbiBackend::new(fa.name)) as ABackend, } }) @@ -138,6 +141,7 @@ pub fn get(fa: &BackendArg) -> ABackend { BackendType::Npm => Arc::new(npm::NPMBackend::new(name)), BackendType::Go => Arc::new(go::GoBackend::new(name)), BackendType::Pipx => Arc::new(pipx::PIPXBackend::new(name)), + BackendType::Spm => Arc::new(spm::SPMBackend::new(name)), BackendType::Ubi => Arc::new(ubi::UbiBackend::new(name)), }) .clone() @@ -236,10 +240,18 @@ pub trait Backend: Debug + Send + Sync { _ => None, } } - fn create_symlink(&self, version: &str, target: &Path) -> eyre::Result<()> { + fn create_symlink( + &self, + version: &str, + target: &Path, + ) -> eyre::Result> { let link = self.fa().installs_path.join(version); + if link.exists() { + return Ok(None); + } file::create_dir_all(link.parent().unwrap())?; - file::make_symlink(target, &link) + let link = file::make_symlink(target, &link)?; + Ok(Some(link)) } fn list_installed_versions_matching(&self, query: &str) -> eyre::Result> { let versions = self.list_installed_versions()?; @@ -291,6 +303,12 @@ pub trait Backend: Debug + Send + Sync { fn is_installed(&self) -> bool { true } + fn is_installed_err(&self) -> eyre::Result<()> { + if self.is_installed() { + return Ok(()); + } + bail!("{} is not installed", self.id()) + } fn ensure_dependencies_installed(&self) -> eyre::Result<()> { let deps = self .get_all_dependencies(&ToolRequest::System(self.id().into()))? @@ -335,7 +353,7 @@ pub trait Backend: Debug + Send + Sync { #[requires(ctx.tv.backend.backend_type == self.get_type())] fn install_version(&self, ctx: InstallContext) -> eyre::Result<()> { - ensure!(self.is_installed(), "{} is not installed", self.id()); + self.is_installed_err()?; let config = Config::get(); let settings = Settings::try_get()?; if self.is_version_installed(&ctx.tv) { diff --git a/src/backend/npm.rs b/src/backend/npm.rs index 3dacfc999..108b15053 100644 --- a/src/backend/npm.rs +++ b/src/backend/npm.rs @@ -64,7 +64,7 @@ impl Backend for NPMBackend { CmdLineRunner::new("npm") .arg("install") .arg("-g") - .arg(&format!("{}@{}", self.name(), ctx.tv.version)) + .arg(format!("{}@{}", self.name(), ctx.tv.version)) .arg("--prefix") .arg(ctx.tv.install_path()) .with_pr(ctx.pr.as_ref()) diff --git a/src/backend/spm.rs b/src/backend/spm.rs new file mode 100644 index 000000000..b2feb74bb --- /dev/null +++ b/src/backend/spm.rs @@ -0,0 +1,377 @@ +use std::env::temp_dir; +use std::fmt::{self, Debug}; +use std::path::PathBuf; + +use git2::Repository; +use serde::de::{MapAccess, Visitor}; +use serde::Deserializer; +use serde_derive::Deserialize; +use url::Url; +use walkdir::WalkDir; + +use crate::backend::{Backend, BackendType}; +use crate::cache::CacheManager; +use crate::cli::args::BackendArg; +use crate::cmd::CmdLineRunner; +use crate::config::Settings; +use crate::install_context::InstallContext; +use crate::{file, github}; + +#[derive(Debug)] +pub struct SPMBackend { + fa: BackendArg, + remote_version_cache: CacheManager>, +} + +// https://github.com/apple/swift-package-manager +impl Backend for SPMBackend { + fn get_type(&self) -> BackendType { + BackendType::Spm + } + + fn fa(&self) -> &BackendArg { + &self.fa + } + + fn get_dependencies( + &self, + _tvr: &crate::toolset::ToolRequest, + ) -> eyre::Result> { + // TODO: swift as dependencies (wait for swift core plugin: https://github.com/jdx/mise/pull/1708) + Ok(vec![]) + } + + fn _list_remote_versions(&self) -> eyre::Result> { + let repo = SwiftPackageRepo::new(self.name())?; + self.remote_version_cache + .get_or_try_init(|| { + Ok(github::list_releases(repo.shorthand.as_str())? + .into_iter() + .map(|r| r.tag_name) + .rev() + .collect()) + }) + .cloned() + } + + fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { + let settings = Settings::get(); + settings.ensure_experimental("spm backend")?; + + let repo = SwiftPackageRepo::new(self.name())?; + let revision = if ctx.tv.version == "latest" { + self.latest_stable_version()? + .ok_or_else(|| eyre::eyre!("No stable versions found"))? + } else { + ctx.tv.version.clone() + }; + let repo_dir = self.clone_package_repo(&repo, &revision)?; + + let executables = self.get_executable_names(&repo_dir)?; + if executables.is_empty() { + return Err(eyre::eyre!("No executables found in the package")); + } + for executable in executables { + let bin_path = self.build_executable(&executable, &repo_dir, ctx)?; + let install_bin_path = ctx.tv.install_path().join("bin"); + self.copy_build_artifacts(&executable, &bin_path, &install_bin_path)?; + } + + debug!("Cleaning up temporary files"); + file::remove_all(&repo_dir)?; + + Ok(()) + } +} + +impl SPMBackend { + pub fn new(name: String) -> Self { + let fa = BackendArg::new(BackendType::Spm, &name); + Self { + remote_version_cache: CacheManager::new( + fa.cache_path.join("remote_versions-$KEY.msgpack.z"), + ), + fa, + } + } + + fn clone_package_repo( + &self, + package_repo: &SwiftPackageRepo, + revision: &str, + ) -> Result { + let tmp_repo_dir = temp_dir().join("spm").join(package_repo.dir_name(revision)); + file::remove_all(&tmp_repo_dir)?; + file::create_dir_all(tmp_repo_dir.parent().unwrap())?; + + debug!( + "Cloning swift package repo: {}, revision: {} to path: {}", + package_repo.url.as_str(), + revision, + tmp_repo_dir.display() + ); + let repo = Repository::clone(package_repo.url.as_str(), &tmp_repo_dir)?; + let (object, reference) = repo.revparse_ext(revision)?; + repo.checkout_tree(&object, None)?; + repo.set_head(reference.unwrap().name().unwrap())?; + Ok(tmp_repo_dir) + } + + fn get_executable_names(&self, repo_dir: &PathBuf) -> Result, eyre::Error> { + let package_json = cmd!( + "swift", + "package", + "dump-package", + "--package-path", + &repo_dir + ) + .read()?; + let executables = serde_json::from_str::(&package_json) + .map_err(|err| eyre::eyre!("Failed to parse package description. Details: {}", err))? + .products + .iter() + .filter(|p| p.r#type.is_executable()) + .map(|p| p.name.clone()) + .collect::>(); + debug!("Found executables: {:?}", executables); + Ok(executables) + } + + fn build_executable( + &self, + executable: &str, + repo_dir: &PathBuf, + ctx: &InstallContext<'_>, + ) -> Result { + debug!("Building swift package"); + let build_cmd = CmdLineRunner::new("swift") + .arg("build") + .arg("--configuration") + .arg("release") + .arg("--product") + .arg(executable) + .arg("--package-path") + .arg(repo_dir) + .with_pr(ctx.pr.as_ref()); + build_cmd.execute()?; + let bin_path = cmd!( + "swift", + "build", + "--configuration", + "release", + "--product", + &executable, + "--package-path", + &repo_dir, + "--show-bin-path" + ) + .read()?; + Ok(PathBuf::from(bin_path.trim().to_string())) + } + + fn copy_build_artifacts( + &self, + executable: &str, + bin_path: &PathBuf, + install_bin_path: &PathBuf, + ) -> Result<(), eyre::Error> { + debug!( + "Copying binaries to install path: {}", + install_bin_path.display() + ); + file::create_dir_all(install_bin_path)?; + file::copy(bin_path.join(executable), install_bin_path.join(executable))?; + WalkDir::new(bin_path) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| { + let ext = e.path().extension().unwrap_or_default(); + // TODO: support other platforms extensions + ext == "dylib" || ext == "bundle" + }) + .try_for_each(|e| -> Result<(), eyre::Error> { + let rel_path = e.path().strip_prefix(bin_path)?; + let install_path = install_bin_path.join(rel_path); + file::create_dir_all(install_path.parent().unwrap())?; + if e.path().is_dir() { + file::copy_dir_all(e.path(), &install_path)?; + } else { + file::copy(e.path(), &install_path)?; + } + Ok(()) + })?; + Ok(()) + } +} + +#[derive(Debug)] +struct SwiftPackageRepo { + /// https://github.com/owner/repo.git + url: Url, + /// owner/repo_name + shorthand: String, +} + +impl SwiftPackageRepo { + /// Parse the slug or the full URL of a GitHub package repository. + fn new(name: &str) -> Result { + let shorthand_regex = regex!(r"^[a-zA-Z0-9_-]+/[a-zA-Z0-9._-]+$"); + let shorthand_in_url_regex = + regex!(r"https://github.com/([a-zA-Z0-9_-]+/[a-zA-Z0-9._-]+)\.git"); + + let shorthand = if let Some(Some(m)) = + shorthand_in_url_regex.captures(name).map(|c| c.get(1)) + { + m.as_str() + } else if shorthand_regex.is_match(name) { + name + } else { + Err(eyre::eyre!("Invalid Swift package repository: {}. The repository should either be a GitHub repository slug, owner/name, or the complete URL, https://github.com/owner/name.", name))? + }; + let url_str = format!("https://github.com/{}.git", shorthand); + let url = Url::parse(&url_str)?; + + Ok(Self { + url, + shorthand: shorthand.to_string(), + }) + } + + fn dir_name(&self, revision: &str) -> String { + self.shorthand.replace('/', "-") + "@" + revision + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::config_file::reset; + use pretty_assertions::assert_str_eq; + use test_log::test; + + #[test] + fn test_spm_repo_init_by_shorthand() { + reset(); + let package_name = "nicklockwood/SwiftFormat"; + let package_repo = SwiftPackageRepo::new(package_name).unwrap(); + assert_str_eq!( + package_repo.url.as_str(), + "https://github.com/nicklockwood/SwiftFormat.git" + ); + assert_str_eq!(package_repo.shorthand, "nicklockwood/SwiftFormat"); + } + + #[test] + fn test_spm_repo_init_name() { + reset(); + assert!( + SwiftPackageRepo::new("owner/name.swift").is_ok(), + "name part can contain ." + ); + assert!( + SwiftPackageRepo::new("owner/name_swift").is_ok(), + "name part can contain _" + ); + assert!( + SwiftPackageRepo::new("owner/name-swift").is_ok(), + "name part can contain -" + ); + assert!( + SwiftPackageRepo::new("owner/name$swift").is_err(), + "name part cannot contain characters other than a-zA-Z0-9._-" + ); + } + + #[test] + fn test_spm_repo_init_by_url() { + reset(); + let package_name = "https://github.com/nicklockwood/SwiftFormat.git"; + let package_repo = SwiftPackageRepo::new(package_name).unwrap(); + assert_str_eq!( + package_repo.url.as_str(), + "https://github.com/nicklockwood/SwiftFormat.git" + ); + assert_str_eq!(package_repo.shorthand, "nicklockwood/SwiftFormat"); + } +} + +/// https://developer.apple.com/documentation/packagedescription +#[derive(Deserialize)] +struct PackageDescription { + products: Vec, +} + +#[derive(Deserialize)] +struct PackageDescriptionProduct { + name: String, + #[serde(deserialize_with = "PackageDescriptionProductType::deserialize_product_type_field")] + r#type: PackageDescriptionProductType, +} + +#[derive(Deserialize)] +enum PackageDescriptionProductType { + Executable, + Other, +} + +impl PackageDescriptionProductType { + fn is_executable(&self) -> bool { + matches!(self, Self::Executable) + } + + /// Product type is a key in the map with an undocumented value that we are not interested in and can be easily skipped. + /// + /// Example: + /// ```json + /// "type" : { + /// "executable" : null + /// } + /// ``` + /// or + /// ```json + /// "type" : { + /// "library" : [ + /// "automatic" + /// ] + /// } + /// ``` + fn deserialize_product_type_field<'de, D>( + deserializer: D, + ) -> Result + where + D: Deserializer<'de>, + { + struct TypeFieldVisitor; + + impl<'de> Visitor<'de> for TypeFieldVisitor { + type Value = PackageDescriptionProductType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map with a key 'executable' or other types") + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + if let Some(key) = map.next_key::()? { + match key.as_str() { + "executable" => { + // Skip the value by reading it into a dummy serde_json::Value + let _value: serde_json::Value = map.next_value()?; + Ok(PackageDescriptionProductType::Executable) + } + _ => { + let _value: serde_json::Value = map.next_value()?; + Ok(PackageDescriptionProductType::Other) + } + } + } else { + Err(serde::de::Error::custom("missing key")) + } + } + } + + deserializer.deserialize_map(TypeFieldVisitor) + } +} diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 5a5608a74..ea84d6ae2 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -2,6 +2,7 @@ use std::path::{Path, PathBuf}; use eyre::Result; +use crate::env::PATH_KEY; use crate::file::touch_dir; use crate::shell::{get_shell, Shell, ShellType}; use crate::{dirs, env}; @@ -97,7 +98,7 @@ impl Activate { fn prepend_path(&self, shell: &dyn Shell, p: &Path) -> String { if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { - shell.prepend_env("PATH", p.to_string_lossy().as_ref()) + shell.prepend_env(&PATH_KEY, p.to_string_lossy().as_ref()) } else { String::new() } diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index b2a30e830..30477e9da 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -27,7 +27,7 @@ pub struct AliasLs { impl AliasLs { pub fn run(self) -> Result<()> { - let config = Config::get(); + let config = Config::try_get()?; let rows = config .get_all_aliases() .iter() diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 13b2fe0fe..ab036a5cb 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -20,7 +20,7 @@ pub struct AliasSet { impl AliasSet { pub fn run(self) -> Result<()> { - let mut global_config = Config::get().global_config()?; + let mut global_config = Config::try_get()?.global_config()?; global_config.set_alias(&self.plugin, &self.alias, &self.value)?; global_config.save() } diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index efafe03e2..57d1947e7 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -18,7 +18,7 @@ pub struct AliasUnset { impl AliasUnset { pub fn run(self) -> Result<()> { - let mut global_config = Config::get().global_config()?; + let mut global_config = Config::try_get()?.global_config()?; global_config.remove_alias(&self.plugin, &self.alias)?; global_config.save() } diff --git a/src/cli/args/tool_arg.rs b/src/cli/args/tool_arg.rs index 9822dd416..7af327341 100644 --- a/src/cli/args/tool_arg.rs +++ b/src/cli/args/tool_arg.rs @@ -22,7 +22,7 @@ pub struct ToolArg { pub enum ToolVersionType { Path(PathBuf), Prefix(String), - Ref(String), + Ref(String, String), Sub { sub: String, orig_version: String }, System, Version(String), @@ -57,7 +57,9 @@ impl FromStr for ToolVersionType { fn from_str(s: &str) -> Result { Ok(match s.split_once(':') { - Some(("ref", r)) => Self::Ref(r.to_string()), + Some((ref_type @ ("ref" | "tag" | "branch" | "rev"), r)) => { + Self::Ref(ref_type.to_string(), r.to_string()) + } Some(("prefix", p)) => Self::Prefix(p.to_string()), Some(("path", p)) => Self::Path(PathBuf::from(p)), Some((p, v)) if p.starts_with("sub-") => Self::Sub { @@ -76,7 +78,7 @@ impl Display for ToolVersionType { match self { Self::Path(p) => write!(f, "path:{}", p.to_string_lossy()), Self::Prefix(p) => write!(f, "prefix:{}", p), - Self::Ref(r) => write!(f, "ref:{}", r), + Self::Ref(rt, r) => write!(f, "{rt}:{r}"), Self::Sub { sub, orig_version } => write!(f, "sub-{}:{}", sub, orig_version), Self::System => write!(f, "system"), Self::Version(v) => write!(f, "{}", v), diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 5db824142..fb9a16b64 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -58,7 +58,7 @@ fn list_versions(config: &Config, args: &[String]) -> Result<()> { miseprintln!("{}", version.version); } } else { - for (plugin, versions) in &versions.into_iter().group_by(|(_, v)| v.backend.clone()) { + for (plugin, versions) in &versions.into_iter().chunk_by(|(_, v)| v.backend.clone()) { miseprintln!("{}", plugin); for (_, tv) in versions { miseprintln!(" {}", tv.version); diff --git a/src/cli/backends/ls.rs b/src/cli/backends/ls.rs index 454003832..f73dd4a5b 100644 --- a/src/cli/backends/ls.rs +++ b/src/cli/backends/ls.rs @@ -27,6 +27,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( go npm pipx + spm ubi "# ); diff --git a/src/cli/backends/snapshots/mise__cli__backends__ls__tests__backends_list.snap b/src/cli/backends/snapshots/mise__cli__backends__ls__tests__backends_list.snap index d68bcf801..31f7a741b 100644 --- a/src/cli/backends/snapshots/mise__cli__backends__ls__tests__backends_list.snap +++ b/src/cli/backends/snapshots/mise__cli__backends__ls__tests__backends_list.snap @@ -7,4 +7,5 @@ core go npm pipx +spm ubi diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index c73eebd28..4be1ecbea 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -6,6 +6,7 @@ use xx::file; use crate::config::Config; use crate::env; +use crate::env::PATH_KEY; use crate::hash::hash_to_str; use crate::toolset::ToolsetBuilder; @@ -35,7 +36,7 @@ impl Envrc { writeln!(file, "watch_file {}", cf.to_string_lossy())?; } for (k, v) in ts.env(config)? { - if k == "PATH" { + if k == *PATH_KEY { writeln!(file, "PATH_add {}", v)?; } else { writeln!( diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 9b066c63a..b264db5f0 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -331,11 +331,13 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( ); fn section(header: &str, body: S) -> eyre::Result<()> { + let body = file::replace_paths_in_string(body); miseprintln!("\n{}: \n{}", style(header).bold(), indent_by(body, " ")); Ok(()) } fn inline_section(header: &str, body: S) -> eyre::Result<()> { + let body = file::replace_paths_in_string(body); miseprintln!("{}: {body}", style(header).bold()); Ok(()) } diff --git a/src/cli/generate/github_action.rs b/src/cli/generate/github_action.rs index a28b13f58..03b53812d 100644 --- a/src/cli/generate/github_action.rs +++ b/src/cli/generate/github_action.rs @@ -4,9 +4,9 @@ use crate::config::Settings; use crate::file::display_path; use crate::git::Git; -/// [experimental] Generate a Github Action workflow file +/// [experimental] Generate a GitHub Action workflow file /// -/// This command generates a Github Action workflow file that runs a mise task like `mise run ci` +/// This command generates a GitHub Action workflow file that runs a mise task like `mise run ci` /// when you push changes to your repository. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] @@ -78,7 +78,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ mise generate github-action --write --task=ci $ git commit -m "feat: add new feature" - $ git push # runs `mise run ci` on Github + $ git push # runs `mise run ci` on GitHub "# ); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index a91bdb910..1c51c0b28 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -8,7 +8,7 @@ use itertools::Itertools; use crate::config::{Config, Settings}; use crate::direnv::DirenvDiff; -use crate::env::{TERM_WIDTH, __MISE_DIFF}; +use crate::env::{PATH_KEY, TERM_WIDTH, __MISE_DIFF}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::shell::{get_shell, ShellType}; use crate::toolset::{Toolset, ToolsetBuilder}; @@ -42,7 +42,7 @@ impl HookEnv { let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); miseprint!("{}", hook_env::clear_old_env(&*shell))?; let mut env = ts.env(&config)?; - let env_path = env.remove("PATH"); + let env_path = env.remove(&*PATH_KEY); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); @@ -112,7 +112,7 @@ impl HookEnv { .into_iter() .filter(|p| !p.is_empty()) .join(":"); - let mut ops = vec![EnvDiffOperation::Add("PATH".into(), new_path)]; + let mut ops = vec![EnvDiffOperation::Add(PATH_KEY.to_string(), new_path)]; if let Some(input) = env::DIRENV_DIFF.deref() { match self.update_direnv_diff(input, installs, to_remove) { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 3603fd691..fd1a88e80 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -102,14 +102,11 @@ impl Ls { } fn verify_plugin(&self) -> Result<()> { - match &self.plugin { - Some(plugins) => { - for fa in plugins { - let plugin = backend::get(fa); - ensure!(plugin.is_installed(), "{fa} is not installed"); - } + if let Some(plugins) = &self.plugin { + for fa in plugins { + let plugin = backend::get(fa); + ensure!(plugin.is_installed(), "{fa} is not installed"); } - None => {} } Ok(()) } @@ -129,7 +126,7 @@ impl Ls { let mut plugins = JSONOutput::new(); for (plugin_name, runtimes) in &runtimes .into_iter() - .group_by(|(p, _, _)| p.id().to_string()) + .chunk_by(|(p, _, _)| p.id().to_string()) { let runtimes = runtimes.map(|row| row.into()).collect(); plugins.insert(plugin_name.clone(), runtimes); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index e76079f17..8c7d9886a 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -214,6 +214,10 @@ impl Cli { Settings::add_cli_matches(&matches); logger::init(); migrate::run(); + + #[cfg(windows)] + warn_windows(&args[1])?; + debug!("ARGS: {}", &args.join(" ")); match Commands::from_arg_matches(&matches) { Ok(cmd) => cmd.run(), @@ -225,6 +229,17 @@ impl Cli { } } +#[cfg(windows)] +fn warn_windows(arg1: &str) -> Result<()> { + warn!("mise is not yet supported on windows. Do not expect anything to work."); + let settings = Settings::try_get()?; + if arg1 != "settings" { + // allow running `mise settings set experimental true` + settings.ensure_experimental("windows support")?; + } + Ok(()) +} + const LONG_ABOUT: &str = indoc! {" mise is a tool for managing runtime versions. https://github.com/jdx/mise diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 97701849c..db853628f 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -95,7 +95,7 @@ impl Prune { prefix = format!("{} {} ", prefix, style("[dryrun]").bold()); } let pr = mpr.add(&prefix); - if self.dry_run || settings.yes || prompt::confirm(&format!("remove {} ?", &tv))? { + if self.dry_run || settings.yes || prompt::confirm(format!("remove {} ?", &tv))? { p.uninstall_version(&tv, pr.as_ref(), self.dry_run)?; pr.finish(); } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index f72f3f7a1..1e108487f 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -14,7 +14,7 @@ pub struct RenderHelp {} impl RenderHelp { pub fn run(self) -> Result<()> { - let readme = file::read_to_string("docs/cli-reference.md")?; + let readme = file::read_to_string("docs/cli/index.md")?; let mut current_readme = readme.split(""); let mut doc = String::new(); @@ -23,7 +23,7 @@ impl RenderHelp { doc.push_str(render_commands().as_str()); doc.push_str(current_readme.next().unwrap()); doc = remove_trailing_spaces(&doc) + "\n"; - file::write("docs/cli-reference.md", &doc)?; + file::write("docs/cli/index.md", &doc)?; Ok(()) } } @@ -125,9 +125,9 @@ mod tests { #[test] fn test_render_help() { reset(); - file::create_dir_all("docs").unwrap(); + file::create_dir_all("docs/cli").unwrap(); file::write( - "docs/cli-reference.md", + "docs/cli/index.md", indoc! {r#" @@ -135,8 +135,8 @@ mod tests { ) .unwrap(); assert_cli!("render-help"); - let readme = fs::read_to_string("docs/cli-reference.md").unwrap(); + let readme = fs::read_to_string("docs/cli/index.md").unwrap(); assert!(readme.contains("# Commands")); - file::remove_file("docs/cli-reference.md").unwrap(); + file::remove_file("docs/cli/index.md").unwrap(); } } diff --git a/src/cli/run.rs b/src/cli/run.rs index cb10d6082..12faa1d29 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -1,8 +1,6 @@ use std::collections::{BTreeMap, HashSet}; use std::io::Write; use std::iter::once; -#[cfg(unix)] -use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use std::process::{exit, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -15,7 +13,7 @@ use demand::{DemandOption, Select}; use duct::IntoExecutablePath; use either::Either; use eyre::{bail, ensure, eyre, Result}; -use globwalk::GlobWalkerBuilder; +use glob::glob; use itertools::Itertools; use once_cell::sync::Lazy; @@ -47,7 +45,7 @@ use super::args::ToolArg; /// outputs = ["dist/**/*.js"] /// /// Alternatively, tasks can be defined as standalone scripts. -/// These must be located in the `.mise/tasks` directory. +/// These must be located in the `.mise/tasks`, `mise/tasks` or `.config/mise/tasks` directory. /// The name of the script will be the name of the tasks. /// /// $ cat .mise/tasks/build<() { + *exit_status.lock().unwrap() = status.code(); + } else { + *exit_status.lock().unwrap() = Some(1); + } } let mut tasks = tasks.lock().unwrap(); tasks.remove(&task); @@ -211,6 +214,11 @@ impl Run { info!("{}", style::edim(msg)); }; + if let Some(status) = *exit_status.lock().unwrap() { + debug!("exiting with status: {status}"); + exit(status); + } + Ok(()) } @@ -340,22 +348,7 @@ impl Run { if self.dry_run { return Ok(()); } - if let Err(err) = cmd.execute() { - if let Some(ScriptFailed(_, Some(status))) = err.downcast_ref::() { - if let Some(code) = status.code() { - error!("{prefix} exited with code {code}"); - exit(code); - } else { - #[cfg(unix)] - if let Some(signal) = status.signal() { - error!("{prefix} killed by signal {signal}"); - exit(1); - } - } - } - error!("{err}"); - exit(1); - } + cmd.execute()?; trace!("{prefix} exited successfully"); Ok(()) } @@ -479,7 +472,7 @@ impl Run { fn is_glob_pattern(path: &str) -> bool { // This is the character set used for glob - // detection by globwalk + // detection by glob let glob_chars = ['*', '{', '}']; path.chars().any(|c| glob_chars.contains(&c)) @@ -512,12 +505,24 @@ fn last_modified_glob_match( if patterns.is_empty() { return Ok(None); } - let files = GlobWalkerBuilder::from_patterns(root, patterns) - .follow_links(true) - .build()? + let files = patterns + .iter() + .flat_map(|pattern| { + glob( + root.as_ref() + .join(pattern) + .to_str() + .expect("Conversion to string path failed"), + ) + .unwrap() + }) .filter_map(|e| e.ok()) - .filter(|e| e.file_type().is_file()) - .map(|e| e.path().to_owned()); + .filter(|e| { + e.metadata() + .expect("Metadata call failed") + .file_type() + .is_file() + }); last_modified_file(files) } diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 92e58ad28..067ddc520 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -11,8 +11,9 @@ use crate::{cmd, env}; /// Updates mise itself /// -/// Uses the GitHub Releases API to find the latest release and binary -/// By default, this will also update any installed plugins +/// Uses the GitHub Releases API to find the latest release and binary. +/// By default, this will also update any installed plugins. +/// Uses the `GITHUB_API_TOKEN` environment variable if set for higher rate limits. #[derive(Debug, Default, clap::Args)] #[clap(verbatim_doc_comment)] pub struct SelfUpdate { diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 1d471c498..188faf50a 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -75,9 +75,11 @@ mod tests { go_set_gopath = false go_set_goroot = true go_skip_checksum = false + http_timeout = 30 jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] + libgit2 = true node_compile = false not_found_auto_install = true paranoid = false @@ -117,9 +119,11 @@ mod tests { go_set_gopath go_set_goroot go_skip_checksum + http_timeout jobs legacy_version_file legacy_version_file_disable_tools + libgit2 node_compile not_found_auto_install paranoid diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 79ebae77d..349925af9 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -36,6 +36,7 @@ impl SettingsSet { "go_set_gopath" => parse_bool(&self.value)?, "go_set_goroot" => parse_bool(&self.value)?, "go_skip_checksum" => parse_bool(&self.value)?, + "http_timeout" => parse_i64(&self.value)?, "jobs" => parse_i64(&self.value)?, "legacy_version_file" => parse_bool(&self.value)?, "node_compile" => parse_bool(&self.value)?, @@ -139,9 +140,11 @@ pub mod tests { go_set_gopath = false go_set_goroot = true go_skip_checksum = false + http_timeout = 30 jobs = 2 legacy_version_file = false legacy_version_file_disable_tools = [] + libgit2 = true node_compile = false not_found_auto_install = true paranoid = false diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 9de68e9ff..eaa51c731 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -1,6 +1,7 @@ use eyre::Result; use toml_edit::DocumentMut; +use crate::config::settings::SettingsFile; use crate::{env, file}; /// Clears a setting @@ -17,9 +18,17 @@ impl SettingsUnset { pub fn run(self) -> Result<()> { let path = env::MISE_CONFIG_DIR.join("config.toml"); let raw = file::read_to_string(&path)?; - let mut settings: DocumentMut = raw.parse()?; + let mut config: DocumentMut = raw.parse()?; + if !config.contains_key("settings") { + return Ok(()); + } + let settings = config["settings"].as_table_mut().unwrap(); settings.remove(&self.setting); - file::write(&path, settings.to_string()) + + // validate + let _: SettingsFile = toml::from_str(&config.to_string())?; + + file::write(&path, config.to_string()) } } @@ -38,7 +47,7 @@ mod tests { fn test_settings_unset() { reset(); - assert_cli!("settings", "unset", "legacy_version_file"); + assert_cli!("settings", "unset", "jobs"); assert_cli_snapshot!("settings", @r###" activate_aggressive = false @@ -57,9 +66,11 @@ mod tests { go_set_gopath = false go_set_goroot = true go_skip_checksum = false - jobs = 2 + http_timeout = 30 + jobs = 4 legacy_version_file = true legacy_version_file_disable_tools = [] + libgit2 = true node_compile = false not_found_auto_install = true paranoid = false diff --git a/src/cli/snapshots/mise__cli__trust__tests__trust-2.snap b/src/cli/snapshots/mise__cli__trust__tests__trust-2.snap index e650db175..46078b876 100644 --- a/src/cli/snapshots/mise__cli__trust__tests__trust-2.snap +++ b/src/cli/snapshots/mise__cli__trust__tests__trust-2.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -mise untrusted ~/cwd/.test-tool-versions +mise No untrusted config files found. diff --git a/src/cli/snapshots/mise__cli__trust__tests__trust-3.snap b/src/cli/snapshots/mise__cli__trust__tests__trust-3.snap index e47fa4340..e650db175 100644 --- a/src/cli/snapshots/mise__cli__trust__tests__trust-3.snap +++ b/src/cli/snapshots/mise__cli__trust__tests__trust-3.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -mise trusted ~/cwd/.test-tool-versions +mise untrusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/mise__cli__trust__tests__trust-4.snap b/src/cli/snapshots/mise__cli__trust__tests__trust-4.snap index e650db175..e47fa4340 100644 --- a/src/cli/snapshots/mise__cli__trust__tests__trust-4.snap +++ b/src/cli/snapshots/mise__cli__trust__tests__trust-4.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -mise untrusted ~/cwd/.test-tool-versions +mise trusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/mise__cli__trust__tests__trust-5.snap b/src/cli/snapshots/mise__cli__trust__tests__trust-5.snap new file mode 100644 index 000000000..e650db175 --- /dev/null +++ b/src/cli/snapshots/mise__cli__trust__tests__trust-5.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/trust.rs +expression: output +--- +mise untrusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/mise__cli__trust__tests__trust-6.snap b/src/cli/snapshots/mise__cli__trust__tests__trust-6.snap new file mode 100644 index 000000000..e650db175 --- /dev/null +++ b/src/cli/snapshots/mise__cli__trust__tests__trust-6.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/trust.rs +expression: output +--- +mise untrusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/mise__cli__trust__tests__trust.snap b/src/cli/snapshots/mise__cli__trust__tests__trust.snap index e47fa4340..c68b92229 100644 --- a/src/cli/snapshots/mise__cli__trust__tests__trust.snap +++ b/src/cli/snapshots/mise__cli__trust__tests__trust.snap @@ -2,4 +2,6 @@ source: src/cli/trust.rs expression: output --- -mise trusted ~/cwd/.test-tool-versions +~/config/config.toml: trusted +~/.test-tool-versions: trusted +~/cwd/.test-tool-versions: trusted diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 3fb6a9f7a..52fb017da 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -73,13 +73,26 @@ impl SyncNode { let nvm_versions_path = NVM_DIR.join("versions").join("node"); let installed_versions_path = dirs::INSTALLS.join("node"); - file::remove_symlinks_with_target_prefix(&installed_versions_path, &nvm_versions_path)?; + let removed = + file::remove_symlinks_with_target_prefix(&installed_versions_path, &nvm_versions_path)?; + if !removed.is_empty() { + debug!("Removed symlinks: {removed:?}"); + } + let mut created = vec![]; let subdirs = file::dir_subdirs(&nvm_versions_path)?; for entry in sorted(subdirs) { let v = entry.trim_start_matches('v'); - tool.create_symlink(v, &nvm_versions_path.join(&entry))?; - miseprintln!("Synced node@{} from nvm", v); + let symlink = tool.create_symlink(v, &nvm_versions_path.join(&entry))?; + if let Some(symlink) = symlink { + created.push(symlink); + miseprintln!("Synced node@{} from nvm", v); + } else { + info!("Skipping node@{v} from nvm because it already exists in mise"); + } + } + if !created.is_empty() { + debug!("Created symlinks: {created:?}"); } config.rebuild_shims_and_runtime_symlinks() diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index cb71d7e78..62989b240 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -50,8 +50,13 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { + use test_log::test; + + use crate::test::reset; + #[test] fn test_pyenv() { + reset(); assert_cli!("sync", "python", "--pyenv"); } } diff --git a/src/cli/trust.rs b/src/cli/trust.rs index 8c99281ed..0db7327aa 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -7,7 +7,7 @@ use eyre::Result; use crate::config; use crate::config::{config_file, Settings, DEFAULT_CONFIG_FILENAMES}; use crate::dirs::TRUSTED_CONFIGS; -use crate::file::remove_file; +use crate::file::{display_path, remove_file}; /// Marks a config file as trusted /// @@ -32,10 +32,18 @@ pub struct Trust { /// No longer trust this config #[clap(long)] untrust: bool, + + /// Show the trusted status of config files from the current directory and its parents. + /// Does not trust or untrust any files. + #[clap(long, verbatim_doc_comment)] + show: bool, } impl Trust { pub fn run(self) -> Result<()> { + if self.show { + return self.show(); + } if self.untrust { self.untrust() } else if self.all { @@ -111,6 +119,25 @@ impl Trust { .into_iter() .find(|p| !config_file::is_trusted(p)) } + + fn show(&self) -> Result<()> { + let trusted = config::load_config_paths(&DEFAULT_CONFIG_FILENAMES) + .into_iter() + .map(|p| (display_path(&p), config_file::is_trusted(&p))) + .rev() + .collect::>(); + if trusted.is_empty() { + info!("No trusted config files found."); + } + for (dp, trusted) in trusted { + if trusted { + miseprintln!("{dp}: trusted"); + } else { + miseprintln!("{dp}: untrusted"); + } + } + Ok(()) + } } static AFTER_LONG_HELP: &str = color_print::cstr!( @@ -131,7 +158,8 @@ mod tests { #[test] fn test_trust() { reset(); - assert_cli!("trust", "--untrust"); + assert_cli!("trust", "--untrust", "--all"); + assert_cli_snapshot!("trust", "--show"); assert_cli_snapshot!("trust"); assert_cli_snapshot!("trust", "--untrust"); assert_cli_snapshot!("trust", ".test-tool-versions"); diff --git a/src/cli/unset.rs b/src/cli/unset.rs index 0a9d17832..869515654 100644 --- a/src/cli/unset.rs +++ b/src/cli/unset.rs @@ -60,6 +60,7 @@ mod tests { use insta::assert_snapshot; + use crate::test::reset; use crate::{env, file}; fn remove_config_file(filename: &str) -> PathBuf { @@ -70,6 +71,7 @@ mod tests { #[test] fn test_unset_remove() { + reset(); // Using the default file let filename = ".test.mise.toml"; let cf_path = remove_config_file(filename); diff --git a/src/cli/use.rs b/src/cli/use.rs index c681f077a..2c22440a7 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -6,8 +6,10 @@ use itertools::Itertools; use crate::cli::args::{BackendArg, ToolArg}; use crate::config::config_file::ConfigFile; -use crate::config::{config_file, Config, Settings, LOCAL_CONFIG_FILENAMES}; -use crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_GLOBAL_CONFIG_FILE}; +use crate::config::{config_file, is_global_config, Config, Settings, LOCAL_CONFIG_FILENAMES}; +use crate::env::{ + MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME, MISE_GLOBAL_CONFIG_FILE, +}; use crate::file::display_path; use crate::toolset::{InstallOptions, ToolRequest, ToolSource, ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -106,7 +108,7 @@ impl Use { let settings = Settings::try_get()?; let pin = self.pin || (settings.asdf_compat && !self.fuzzy); - for (fa, tvl) in &versions.iter().group_by(|tv| &tv.backend) { + for (fa, tvl) in &versions.iter().chunk_by(|tv| &tv.backend) { let versions: Vec = tvl .into_iter() .map(|tv| { @@ -179,15 +181,30 @@ fn config_file_from_dir(p: &Path) -> PathBuf { if !p.is_dir() { return p.to_path_buf(); } + let mise_toml = p.join(&*MISE_DEFAULT_CONFIG_FILENAME); + let tool_versions = p.join(&*MISE_DEFAULT_TOOL_VERSIONS_FILENAME); + if mise_toml.exists() { + return mise_toml; + } else if tool_versions.exists() { + return tool_versions; + } let filenames = LOCAL_CONFIG_FILENAMES .iter() .rev() + .filter(|f| is_global_config(Path::new(f))) .map(|f| f.to_string()) .collect::>(); if let Some(p) = file::find_up(p, &filenames) { return p; } - p.join(&*MISE_DEFAULT_CONFIG_FILENAME) + match is_asdf_compat() { + true => tool_versions, + false => mise_toml, + } +} + +fn is_asdf_compat() -> bool { + Settings::try_get().map_or(false, |s| s.asdf_compat) } static AFTER_LONG_HELP: &str = color_print::cstr!( @@ -217,7 +234,7 @@ mod tests { use crate::{dirs, env, file}; #[test] - fn test_use_local() { + fn test_use_local_reuse() { reset(); let cf_path = env::current_dir().unwrap().join(".test.mise.toml"); file::write(&cf_path, "").unwrap(); @@ -228,6 +245,12 @@ mod tests { tiny = "2" "###); + assert_cli_snapshot!("use", "tiny@1", "tiny@2", "tiny@3", @"mise ~/cwd/.test.mise.toml tools: tiny@1.0.1, tiny@2.1.0, tiny@3.1.0"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = ["1", "2", "3"] + "###); + assert_cli_snapshot!("use", "--pin", "tiny", @"mise ~/cwd/.test.mise.toml tools: tiny@3.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] @@ -248,7 +271,44 @@ mod tests { } #[test] - fn test_use_local_tool_versions() { + fn test_use_local_create() { + reset(); + let _ = file::remove_file(env::current_dir().unwrap().join(".test-tool-versions")); + let cf_path = env::current_dir().unwrap().join(".test.mise.toml"); + + assert_cli_snapshot!("use", "tiny@2", @"mise ~/cwd/.test.mise.toml tools: tiny@2.1.0"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = "2" + "###); + + assert_cli_snapshot!("use", "tiny@1", "tiny@2", "tiny@3", @"mise ~/cwd/.test.mise.toml tools: tiny@1.0.1, tiny@2.1.0, tiny@3.1.0"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = ["1", "2", "3"] + "###); + + assert_cli_snapshot!("use", "--pin", "tiny", @"mise ~/cwd/.test.mise.toml tools: tiny@3.1.0"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = "3.1.0" + "###); + + assert_cli_snapshot!("use", "--fuzzy", "tiny@2", @"mise ~/cwd/.test.mise.toml tools: tiny@2.1.0"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = "2" + "###); + + let p = cf_path.to_string_lossy().to_string(); + assert_cli_snapshot!("use", "--rm", "tiny", "--path", &p, @"mise ~/cwd/.test.mise.toml tools:"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @""); + + let _ = file::remove_file(&cf_path); + } + + #[test] + fn test_use_local_tool_versions_reuse() { reset(); let cf_path = env::current_dir().unwrap().join(".test-tool-versions"); file::write(&cf_path, "").unwrap(); @@ -261,6 +321,19 @@ mod tests { let _ = file::remove_file(&cf_path); } + #[test] + fn test_use_local_tool_versions_create() { + reset(); + let cf_path = env::current_dir().unwrap().join(".test-tool-versions"); + + assert_cli_snapshot!("use", "tiny@3", @"mise ~/cwd/.test-tool-versions tools: tiny@3.1.0"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + tiny 3 + "###); + + let _ = file::remove_file(&cf_path); + } + #[test] fn test_use_global() { reset(); diff --git a/src/cli/version.rs b/src/cli/version.rs index 9d0235ced..b80527541 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -78,7 +78,7 @@ fn show_latest() { } pub fn check_for_new_version(cache_duration: Duration) -> Option { - if let Some(latest) = get_latest_version(cache_duration).and_then(|v| Versioning::new(&v)) { + if let Some(latest) = get_latest_version(cache_duration).and_then(Versioning::new) { if *V < latest { return Some(latest.to_string()); } diff --git a/src/cmd.rs b/src/cmd.rs index 5cdc794cd..c5fc248ee 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -17,6 +17,7 @@ use signal_hook::iterator::Signals; use crate::config::Settings; use crate::env; +use crate::env::PATH_KEY; use crate::errors::Error::ScriptFailed; use crate::file::display_path; use crate::ui::progress_report::SingleReport; @@ -90,7 +91,18 @@ where let display_command = [display_name.into(), display_args].join(" "); debug!("$ {display_command}"); - duct::cmd(program, args) + if cfg!(windows) { + let program = program.to_string_lossy().to_string(); + let mut args = args + .iter() + .map(|s| s.to_string_lossy().to_string()) + .collect::>(); + args.insert(0, program); + args.insert(0, "/c".to_string()); + duct::cmd("cmd.exe", args) + } else { + duct::cmd(program, args) + } } pub struct CmdLineRunner<'a> { @@ -171,14 +183,14 @@ impl<'a> CmdLineRunner<'a> { pub fn prepend_path(mut self, paths: Vec) -> eyre::Result { let existing = self - .get_env("PATH") + .get_env(&PATH_KEY) .map(|c| c.to_owned()) - .unwrap_or_else(|| env::var_os("PATH").unwrap()); + .unwrap_or_else(|| env::var_os(&*PATH_KEY).unwrap()); let paths = paths .into_iter() .chain(env::split_paths(&existing)) .collect::>(); - self.cmd.env("PATH", env::join_paths(paths)?); + self.cmd.env(&*PATH_KEY, env::join_paths(paths)?); Ok(self) } @@ -311,7 +323,10 @@ impl<'a> CmdLineRunner<'a> { #[cfg(not(any(test, target_os = "windows")))] ChildProcessOutput::Signal(sig) => { if sig != SIGINT { - cmd!("kill", format!("-{sig}"), id.to_string()).run()?; + debug!("Received signal {}, {id}", sig); + let pid = nix::unistd::Pid::from_raw(id as i32); + let sig = nix::sys::signal::Signal::try_from(sig).unwrap(); + nix::sys::signal::kill(pid, sig)?; } } } diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 00df53249..e2180225a 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -219,8 +219,15 @@ impl ConfigFile for MiseToml { } } - fn plugins(&self) -> HashMap { - self.plugins.clone() + fn plugins(&self) -> eyre::Result> { + self.plugins + .clone() + .into_iter() + .map(|(k, v)| { + let v = self.parse_template(&v)?; + Ok((k, v)) + }) + .collect() } fn env_entries(&self) -> eyre::Result> { @@ -324,8 +331,23 @@ impl ConfigFile for MiseToml { Ok(trs) } - fn aliases(&self) -> AliasMap { - self.alias.clone() + fn aliases(&self) -> eyre::Result { + self.alias + .clone() + .iter() + .map(|(k, v)| { + let k = k.clone(); + let v: Result, eyre::Error> = v + .clone() + .into_iter() + .map(|(k, v)| { + let v = self.parse_template(&v)?; + Ok((k, v)) + }) + .collect(); + v.map(|v| (k, v)) + }) + .collect() } fn task_config(&self) -> &TaskConfig { @@ -878,7 +900,7 @@ mod tests { let cf = MiseToml::from_file(&dirs::HOME.join("fixtures/.mise.toml")).unwrap(); assert_debug_snapshot!(cf.env_entries().unwrap()); - assert_debug_snapshot!(cf.plugins()); + assert_debug_snapshot!(cf.plugins().unwrap()); assert_snapshot!(replace_path(&format!( "{:#?}", cf.to_tool_request_set().unwrap() @@ -898,6 +920,8 @@ mod tests { min_version = "2024.1.1" [env] foo="bar" + foo2='qux\nquux' + foo3="qux\nquux" "#}, ) .unwrap(); @@ -905,7 +929,7 @@ mod tests { let dump = cf.dump().unwrap(); let env = parse_env(file::read_to_string(&p).unwrap()); - assert_debug_snapshot!(env, @r###""foo=bar""###); + assert_debug_snapshot!(env, @r###""foo=bar\nfoo2=qux\\nquux\nfoo3=qux\nquux""###); let cf: Box = Box::new(cf); with_settings!({ assert_snapshot!(dump); @@ -923,11 +947,18 @@ mod tests { [[env]] bar="baz" + + [[env]] + foo2='qux\nquux' + bar2="qux\nquux" "#}); assert_snapshot!(env, @r###" foo=bar bar=baz + foo2=qux\nquux + bar2=qux + quux "###); } @@ -1100,6 +1131,7 @@ mod tests { assert_snapshot!(cf.dump().unwrap()); assert_snapshot!(cf); assert_debug_snapshot!(cf); + file::remove_all(&p).unwrap(); } #[test] diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index c8e17c910..466f9d576 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -60,8 +60,8 @@ pub trait ConfigFile: Debug + Send + Sync { None => None, } } - fn plugins(&self) -> HashMap { - Default::default() + fn plugins(&self) -> eyre::Result> { + Ok(Default::default()) } fn env_entries(&self) -> eyre::Result> { Ok(Default::default()) @@ -77,8 +77,8 @@ pub trait ConfigFile: Debug + Send + Sync { Ok(self.to_tool_request_set()?.into()) } fn to_tool_request_set(&self) -> eyre::Result; - fn aliases(&self) -> AliasMap { - Default::default() + fn aliases(&self) -> eyre::Result { + Ok(Default::default()) } fn task_config(&self) -> &TaskConfig { static DEFAULT_TASK_CONFIG: Lazy = Lazy::new(TaskConfig::default); @@ -201,7 +201,7 @@ pub fn trust_check(path: &Path) -> eyre::Result<()> { return Ok(()); } if cmd != "hook-env" { - let ans = prompt::confirm(format!( + let ans = prompt::confirm_with_all(format!( "{} {} is not trusted. Trust it?", style::eyellow("mise"), style::epath(path) @@ -211,7 +211,7 @@ pub fn trust_check(path: &Path) -> eyre::Result<()> { return Ok(()); } } - Err(UntrustedConfig())? + Err(UntrustedConfig(path.into()))? } static IS_TRUSTED: Lazy>> = Lazy::new(|| Mutex::new(HashSet::new())); @@ -220,7 +220,10 @@ pub fn is_trusted(path: &Path) -> bool { let mut cached = IS_TRUSTED.lock().unwrap(); let canonicalized_path = match path.canonicalize() { Ok(p) => p, - Err(_) => return false, + Err(err) => { + debug!("trust canonicalize: {err}"); + return false; + } }; if cached.contains(canonicalized_path.as_path()) { return true; @@ -240,7 +243,10 @@ pub fn is_trusted(path: &Path) -> bool { if !trusted { return false; } - } else if !(trust_path(path).exists() || ci_info::is_ci() && !cfg!(test)) { + } else if cfg!(test) || ci_info::is_ci() { + // in tests/CI we trust everything + return true; + } else if !trust_path(path).exists() { // the file isn't trusted, and we're not on a CI system where we generally assume we can // trust config files return false; @@ -253,7 +259,7 @@ pub fn trust(path: &Path) -> eyre::Result<()> { let hashed_path = trust_path(path); if !hashed_path.exists() { file::create_dir_all(hashed_path.parent().unwrap())?; - file::make_symlink(path.canonicalize()?.as_path(), &hashed_path)?; + file::make_symlink_or_file(path.canonicalize()?.as_path(), &hashed_path)?; } let trust_hash_path = hashed_path.with_extension("hash"); let hash = file_hash_sha256(path)?; diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap index ccb8ea352..0433d655e 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap @@ -1,8 +1,9 @@ --- source: src/config/config_file/mise_toml.rs -expression: cf.dump().unwrap() +expression: dump --- min_version = "2024.1.1" [env] foo="bar" - +foo2='qux\nquux' +foo3="qux\nquux" diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap index dfa7a715d..33961d141 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap @@ -10,5 +10,13 @@ MiseToml(~/cwd/.test.mise.toml): ToolRequestSet: "foo", "bar", ), + Val( + "foo2", + "qux\\nquux", + ), + Val( + "foo3", + "qux\nquux", + ), ], } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap index 59fa22dc2..274a731e6 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap @@ -25,6 +25,7 @@ ToolRequestSet { Ref { backend: BackendArg("node"), ref_: "master", + ref_type: "ref", options: {}, }, Path( diff --git a/src/config/env_directive.rs b/src/config/env_directive.rs index b07f80902..b4f2387a3 100644 --- a/src/config/env_directive.rs +++ b/src/config/env_directive.rs @@ -8,6 +8,7 @@ use indexmap::IndexMap; use crate::cmd::CmdLineRunner; use crate::config::config_file::trust_check; use crate::config::{Config, Settings}; +use crate::env::PATH_KEY; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::file::display_path; use crate::tera::{get_tera, BASE_CONTEXT}; @@ -172,13 +173,13 @@ impl EnvResults { let path = ts .list_paths() .into_iter() - .chain(env::split_paths(&env_vars["PATH"])) + .chain(env::split_paths(&env_vars[&*PATH_KEY])) .collect::>(); let cmd = CmdLineRunner::new("python3") .args(["-m", "venv", &venv.to_string_lossy()]) .envs(&env_vars) .env( - "PATH", + PATH_KEY.to_string(), env::join_paths(&path)?.to_string_lossy().to_string(), ); if ts diff --git a/src/config/mod.rs b/src/config/mod.rs index 17cf64afe..b5f497554 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -77,13 +77,11 @@ impl Config { let config_paths = load_config_paths(&config_filenames); let config_files = load_all_config_files(&config_paths, &legacy_files)?; - let repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); - let config = Self { - aliases: load_aliases(&config_files), + aliases: load_aliases(&config_files)?, project_root: get_project_root(&config_files), + repo_urls: load_plugins(&config_files)?, config_files, - repo_urls, ..Default::default() }; @@ -510,11 +508,8 @@ pub fn load_config_paths(config_filenames: &[String]) -> Vec { // The current directory is not always available, e.g. // when a directory was deleted or inside FUSE mounts. - match &*dirs::CWD { - Some(current_dir) => { - config_files.extend(file::FindUp::new(current_dir, config_filenames)); - } - None => {} + if let Some(current_dir) = &*dirs::CWD { + config_files.extend(file::FindUp::new(current_dir, config_filenames)); }; config_files.extend(global_config_files()); @@ -603,18 +598,28 @@ fn parse_config_file( } } -fn load_aliases(config_files: &ConfigMap) -> AliasMap { +fn load_aliases(config_files: &ConfigMap) -> Result { let mut aliases: AliasMap = AliasMap::new(); for config_file in config_files.values() { - for (plugin, plugin_aliases) in config_file.aliases() { + for (plugin, plugin_aliases) in config_file.aliases()? { for (from, to) in plugin_aliases { aliases.entry(plugin.clone()).or_default().insert(from, to); } } } - aliases + Ok(aliases) +} + +fn load_plugins(config_files: &ConfigMap) -> Result> { + let mut plugins = HashMap::new(); + for config_file in config_files.values() { + for (plugin, url) in config_file.plugins()? { + plugins.insert(plugin.clone(), url.clone()); + } + } + Ok(plugins) } impl Debug for Config { diff --git a/src/config/settings.rs b/src/config/settings.rs index 2c134e19c..bf9cee805 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -74,12 +74,16 @@ pub struct Settings { /// set to true to skip checksum verification when downloading go sdk tarballs #[config(env = "MISE_GO_SKIP_CHECKSUM", default = false)] pub go_skip_checksum: bool, + #[config(env = "MISE_HTTP_TIMEOUT", default = 30)] + pub http_timeout: u64, #[config(env = "MISE_JOBS", default = 4)] pub jobs: usize, #[config(env = "MISE_LEGACY_VERSION_FILE", default = true)] pub legacy_version_file: bool, #[config(env = "MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub legacy_version_file_disable_tools: BTreeSet, + #[config(env = "MISE_LIBGIT2", default = true)] + pub libgit2: bool, #[config(env = "MISE_NODE_COMPILE", default = false)] pub node_compile: bool, #[config(env = "MISE_NOT_FOUND_AUTO_INSTALL", default = true)] @@ -420,7 +424,9 @@ impl Settings { } pub fn as_dict(&self) -> eyre::Result { - Ok(self.to_string().parse()?) + let s = toml::to_string(self)?; + let table = toml::from_str(&s)?; + Ok(table) } } diff --git a/src/config/tracking.rs b/src/config/tracking.rs index 5b53b8fda..b3350fd68 100644 --- a/src/config/tracking.rs +++ b/src/config/tracking.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use eyre::Result; use crate::dirs::TRACKED_CONFIGS; -use crate::file::{create_dir_all, make_symlink}; +use crate::file::{create_dir_all, make_symlink_or_file}; use crate::hash::hash_to_str; pub struct Tracker {} @@ -15,7 +15,7 @@ impl Tracker { let tracking_path = TRACKED_CONFIGS.join(hash_to_str(&path)); if !tracking_path.exists() { create_dir_all(&*TRACKED_CONFIGS)?; - make_symlink(path, &tracking_path)?; + make_symlink_or_file(path, &tracking_path)?; } Ok(()) } diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 319c05b71..1beaff873 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -51,7 +51,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("asciidoctorj", "https://github.com/gliwka/asdf-asciidoctorj.git"), ("asdf-plugin-manager", "https://github.com/asdf-community/asdf-plugin-manager"), ("assh", "https://github.com/zekker6/asdf-assh.git"), - ("atlas", "https://github.com/pbr0ck3r/asdf-atlas.git"), + ("atlas", "https://github.com/komi1230/asdf-atlas.git"), ("auto-doc", "https://github.com/looztra/asdf-auto-doc.git"), ("aws-amplify-cli", "https://github.com/LozanoMatheus/asdf-aws-amplify-cli.git"), ("aws-copilot", "https://github.com/NeoHsu/asdf-copilot"), @@ -755,6 +755,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("vhs", "https://github.com/chessmango/asdf-vhs.git"), ("viddy", "https://github.com/ryodocx/asdf-viddy.git"), ("vim", "https://github.com/tsuyoshicho/asdf-vim.git"), + ("virtualos", "https://github.com/tuist/asdf-virtualos.git"), ("vlt", "https://github.com/asdf-community/asdf-hashicorp.git"), ("vultr-cli", "https://github.com/ikuradon/asdf-vultr-cli.git"), ("wasi-sdk", "https://github.com/coolreader18/asdf-wasi-sdk.git"), diff --git a/src/direnv.rs b/src/direnv.rs index d58079d05..874f8fdfe 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -4,6 +4,7 @@ use std::fmt::{Display, Formatter}; use std::io::Write; use std::path::{Path, PathBuf}; +use crate::env::PATH_KEY; use base64::prelude::*; use eyre::Result; use flate2::write::{ZlibDecoder, ZlibEncoder}; @@ -33,7 +34,7 @@ impl DirenvDiff { } pub fn new_path(&self) -> Vec { - let path = self.new.get("PATH"); + let path = self.new.get(&*PATH_KEY); match path { Some(path) => split_paths(path).collect(), None => vec![], @@ -41,7 +42,7 @@ impl DirenvDiff { } pub fn old_path(&self) -> Vec { - let path = self.old.get("PATH"); + let path = self.old.get(&*PATH_KEY); match path { Some(path) => split_paths(path).collect(), None => vec![], @@ -59,10 +60,14 @@ impl DirenvDiff { old.insert(0, path.into()); new.insert(0, path.into()); - self.old - .insert("PATH".into(), join_paths(&old)?.into_string().unwrap()); - self.new - .insert("PATH".into(), join_paths(&new)?.into_string().unwrap()); + self.old.insert( + PATH_KEY.to_string(), + join_paths(&old)?.into_string().unwrap(), + ); + self.new.insert( + PATH_KEY.to_string(), + join_paths(&new)?.into_string().unwrap(), + ); Ok((old, new)) } @@ -78,10 +83,14 @@ impl DirenvDiff { old.iter().position(|p| p == path).map(|i| old.remove(i)); new.iter().position(|p| p == path).map(|i| new.remove(i)); - self.old - .insert("PATH".into(), join_paths(&old)?.into_string().unwrap()); - self.new - .insert("PATH".into(), join_paths(&new)?.into_string().unwrap()); + self.old.insert( + PATH_KEY.to_string(), + join_paths(&old)?.into_string().unwrap(), + ); + self.new.insert( + PATH_KEY.to_string(), + join_paths(&new)?.into_string().unwrap(), + ); Ok((old, new)) } diff --git a/src/env.rs b/src/env.rs index 38837b17f..039a3a6b7 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,6 +1,8 @@ use std::collections::{HashMap, HashSet}; pub use std::env::*; +use std::path; use std::path::PathBuf; +use std::string::ToString; use std::sync::RwLock; use std::time::Duration; @@ -18,8 +20,13 @@ pub static ARGS: RwLock> = RwLock::new(vec![]); pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "sh".into())); // paths and directories +#[cfg(test)] +pub static HOME: Lazy = + Lazy::new(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test")); +#[cfg(not(test))] pub static HOME: Lazy = Lazy::new(|| home::home_dir().unwrap_or_else(|| PathBuf::from("/"))); + pub static EDITOR: Lazy = Lazy::new(|| var("VISUAL").unwrap_or_else(|_| var("EDITOR").unwrap_or_else(|_| "nano".into()))); @@ -32,9 +39,9 @@ pub static XDG_CACHE_HOME: Lazy = pub static XDG_CONFIG_HOME: Lazy = Lazy::new(|| var_path("XDG_CONFIG_HOME").unwrap_or_else(|| HOME.join(".config"))); pub static XDG_DATA_HOME: Lazy = - Lazy::new(|| var_path("XDG_DATA_HOME").unwrap_or_else(|| HOME.join(".local/share"))); + Lazy::new(|| var_path("XDG_DATA_HOME").unwrap_or_else(|| HOME.join(".local").join("share"))); pub static XDG_STATE_HOME: Lazy = - Lazy::new(|| var_path("XDG_STATE_HOME").unwrap_or_else(|| HOME.join(".local/state"))); + Lazy::new(|| var_path("XDG_STATE_HOME").unwrap_or_else(|| HOME.join(".local").join("state"))); pub static MISE_CACHE_DIR: Lazy = Lazy::new(|| var_path("MISE_CACHE_DIR").unwrap_or_else(|| XDG_CACHE_HOME.join("mise"))); @@ -133,11 +140,18 @@ pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS.read().unw /// essentially, this is whether we show spinners or build output on runtime install pub static PRISTINE_ENV: Lazy> = Lazy::new(|| get_pristine_env(&__MISE_DIFF, vars().collect())); -pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH") { +pub static PATH_KEY: Lazy = Lazy::new(|| { + vars() + .map(|(k, _)| k) + .find_or_first(|k| k.to_uppercase() == "PATH") + .map(|k| k.to_string()) + .unwrap_or("PATH".into()) +}); +pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get(&*PATH_KEY) { Some(path) => split_paths(path).collect(), None => vec![], }); -pub static PATH_NON_PRISTINE: Lazy> = Lazy::new(|| match var("PATH") { +pub static PATH_NON_PRISTINE: Lazy> = Lazy::new(|| match var(&*PATH_KEY) { Ok(ref path) => split_paths(path).collect(), Err(_) => vec![], }); @@ -305,7 +319,7 @@ fn get_pristine_env( let mut env = apply_patches(&orig_env, &patches); // get the current path as a vector - let path = match env.get("PATH") { + let path = match env.get(&*PATH_KEY) { Some(path) => split_paths(path).collect(), None => vec![], }; @@ -320,7 +334,7 @@ fn get_pristine_env( // put the pristine PATH back into the environment env.insert( - "PATH".into(), + PATH_KEY.to_string(), join_paths(path).unwrap().to_string_lossy().to_string(), ); env @@ -372,7 +386,9 @@ fn linux_distro() -> Option { } fn filename(path: &str) -> &str { - path.rsplit_once('/').map(|(_, file)| file).unwrap_or(path) + path.rsplit_once(path::MAIN_SEPARATOR_STR) + .map(|(_, file)| file) + .unwrap_or(path) } fn is_ninja_on_path() -> bool { diff --git a/src/env_diff.rs b/src/env_diff.rs index 5b00860b7..388da9784 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -11,6 +11,7 @@ use flate2::Compression; use itertools::Itertools; use serde_derive::{Deserialize, Serialize}; +use crate::env::PATH_KEY; use crate::{cmd, file}; #[derive(Default, Serialize, Deserialize)] @@ -139,9 +140,8 @@ impl EnvDiff { }; } for (k, v) in self.new.iter() { - match self.old.contains_key(k) { - false => patches.push(EnvDiffOperation::Add(k.into(), v.into())), - true => {} + if !self.old.contains_key(k) { + patches.push(EnvDiffOperation::Add(k.into(), v.into())) }; } @@ -161,7 +161,7 @@ fn valid_key(k: &str) -> bool { k.is_empty() || k == "_" || k == "SHLVL" - || k == "PATH" + || k == *PATH_KEY || k == "PWD" || k == "OLDPWD" || k == "HOME" @@ -170,11 +170,7 @@ fn valid_key(k: &str) -> bool { || k == "SHELLOPTS" || k == "COMP_WORDBREAKS" || k == "PS1" - // TODO: consider removing this - // this is to make the ruby plugin compatible, - // it causes ruby to attempt to call asdf to reshim the binaries - // which we don't need or want to happen - || k == "RUBYLIB" + || k == "PROMPT_DIRTRIM" // following two ignores are for exported bash functions and exported bash // functions which are multiline, they appear in the environment as e.g.: // BASH_FUNC_exported-bash-function%%=() { echo "this is an" diff --git a/src/errors.rs b/src/errors.rs index 42fe2b5cc..bc1e5886d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,9 +1,12 @@ -use eyre::Report; +use std::path::PathBuf; use std::process::ExitStatus; -use crate::toolset::{ToolRequest, ToolSource}; +use eyre::Report; use thiserror::Error; +use crate::file::display_path; +use crate::toolset::{ToolRequest, ToolSource}; + #[derive(Debug, Error)] pub enum Error { #[error("Failed to resolve {tr} from {ts}: {source:#}")] @@ -18,8 +21,11 @@ pub enum Error { VersionNotInstalled(String, String), #[error("{} exited with non-zero status: {}", .0, render_exit_status(.1))] ScriptFailed(String, Option), - #[error("Config file is not trusted.\nTrust it with `mise trust`.")] - UntrustedConfig(), + #[error( + "Config file {} is not trusted.\nTrust it with `mise trust`.", + display_path(.0) + )] + UntrustedConfig(PathBuf), } fn render_exit_status(exit_status: &Option) -> String { diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 9c31932a6..1787b998c 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -7,6 +7,7 @@ use color_eyre::eyre::ErrReport; use indoc::formatdoc; use once_cell::sync::OnceCell; +use crate::env::PATH_KEY; use crate::{env, file}; pub fn setup() -> color_eyre::Result { @@ -34,7 +35,7 @@ pub fn setup() -> color_eyre::Result { } pub fn get_path_with_fake_asdf() -> String { - let mut path = split_paths(&env::var_os("PATH").unwrap_or_default()).collect::>(); + let mut path = split_paths(&env::var_os(&*PATH_KEY).unwrap_or_default()).collect::>(); match setup() { Ok(fake_asdf_path) => { path.insert(0, fake_asdf_path); diff --git a/src/fake_asdf_windows.rs b/src/fake_asdf_windows.rs index 8f70ccac4..ab06d01bd 100644 --- a/src/fake_asdf_windows.rs +++ b/src/fake_asdf_windows.rs @@ -2,6 +2,7 @@ use std::env::{join_paths, split_paths}; use std::path::PathBuf; use crate::env; +use crate::env::PATH_KEY; #[cfg(windows)] pub fn setup() -> color_eyre::Result { @@ -10,7 +11,7 @@ pub fn setup() -> color_eyre::Result { } pub fn get_path_with_fake_asdf() -> String { - let mut path = split_paths(&env::var_os("PATH").unwrap_or_default()).collect::>(); + let mut path = split_paths(&env::var_os(&*PATH_KEY).unwrap_or_default()).collect::>(); match setup() { Ok(fake_asdf_path) => { path.insert(0, fake_asdf_path); diff --git a/src/file.rs b/src/file.rs index a3bc5791c..b4ce91bdc 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::fmt::Display; use std::fs; use std::fs::File; #[cfg(unix)] @@ -90,6 +91,34 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> Result<()> { }) } +pub fn copy, Q: AsRef>(from: P, to: Q) -> Result<()> { + let from = from.as_ref(); + let to = to.as_ref(); + trace!("cp {} {}", from.display(), to.display()); + fs::copy(from, to) + .wrap_err_with(|| { + format!( + "failed copy: {} -> {}", + display_path(from), + display_path(to) + ) + }) + .map(|_| ()) +} + +pub fn copy_dir_all, Q: AsRef>(from: P, to: Q) -> Result<()> { + let from = from.as_ref(); + let to = to.as_ref(); + trace!("cp -r {} {}", from.display(), to.display()); + recursive_ls(from)?.into_iter().try_for_each(|path| { + let relative = path.strip_prefix(from)?; + let dest = to.join(relative); + create_dir_all(dest.parent().unwrap())?; + copy(&path, &dest)?; + Ok(()) + }) +} + pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> { let path = path.as_ref(); trace!("write {}", display_path(path)); @@ -134,6 +163,13 @@ pub fn display_path>(path: P) -> String { } } +/// replaces $HOME in a string with "~" and $PATH with "$PATH", generally used to clean up output +/// after it is rendered +pub fn replace_paths_in_string(input: S) -> String { + let home = env::HOME.to_string_lossy().to_string(); + input.to_string().replace(&home, "~") +} + /// replaces "~" with $HOME pub fn replace_path>(path: P) -> PathBuf { let path = path.as_ref(); @@ -221,25 +257,52 @@ pub fn recursive_ls(dir: &Path) -> Result> { } #[cfg(unix)] -pub fn make_symlink(target: &Path, link: &Path) -> Result<()> { +pub fn make_symlink(target: &Path, link: &Path) -> Result<(PathBuf, PathBuf)> { trace!("ln -sf {} {}", target.display(), link.display()); if link.is_file() || link.is_symlink() { fs::remove_file(link)?; } symlink(target, link) .wrap_err_with(|| format!("failed to ln -sf {} {}", target.display(), link.display()))?; - Ok(()) + Ok((target.to_path_buf(), link.to_path_buf())) } #[cfg(windows)] -pub fn make_symlink(_target: &Path, _link: &Path) -> Result<()> { +//#[deprecated] +pub fn make_symlink(_target: &Path, _link: &Path) -> Result<(PathBuf, PathBuf)> { unimplemented!("make_symlink is not implemented on Windows") } -pub fn remove_symlinks_with_target_prefix(symlink_dir: &Path, target_prefix: &Path) -> Result<()> { +#[cfg(windows)] +pub fn make_symlink_or_file(target: &Path, link: &Path) -> Result<()> { + trace!("ln -sf {} {}", target.display(), link.display()); + if link.is_file() || link.is_symlink() { + // remove existing file if exists + fs::remove_file(link)?; + } + xx::file::write(link, target.to_string_lossy().to_string())?; + Ok(()) +} + +#[cfg(unix)] +pub fn make_symlink_or_file(target: &Path, link: &Path) -> Result<()> { + trace!("ln -sf {} {}", target.display(), link.display()); + if link.is_file() || link.is_symlink() { + // remove existing file if exists + fs::remove_file(link)?; + } + make_symlink(target, link)?; + Ok(()) +} + +pub fn remove_symlinks_with_target_prefix( + symlink_dir: &Path, + target_prefix: &Path, +) -> Result> { if !symlink_dir.exists() { - return Ok(()); + return Ok(vec![]); } + let mut removed = vec![]; for entry in symlink_dir.read_dir()? { let entry = entry?; let path = entry.path(); @@ -247,10 +310,11 @@ pub fn remove_symlinks_with_target_prefix(symlink_dir: &Path, target_prefix: &Pa let target = path.read_link()?; if target.starts_with(target_prefix) { fs::remove_file(&path)?; + removed.push(path); } } } - Ok(()) + Ok(removed) } #[cfg(unix)] diff --git a/src/git.rs b/src/git.rs index 0e2792ef0..a53d68dcf 100644 --- a/src/git.rs +++ b/src/git.rs @@ -7,6 +7,7 @@ use once_cell::sync::OnceCell; use xx::file; use crate::cmd; +use crate::config::Settings; use crate::file::touch_dir; pub struct Git { @@ -44,7 +45,11 @@ impl Git { pub fn repo(&self) -> Result<&git2::Repository> { self.repo.get_or_try_init(|| { - trace!("opening git repository at {:?}", self.dir); + if !Settings::get().libgit2 { + trace!("libgit2 is disabled"); + return Err(eyre!("libgit2 is disabled")); + } + trace!("opening git repository via libgit2 at {:?}", self.dir); git2::Repository::open(&self.dir) .wrap_err_with(|| format!("failed to open git repository at {:?}", self.dir)) .inspect_err(|err| warn!("{err:#}")) diff --git a/src/github.rs b/src/github.rs index 4059b6296..076628d72 100644 --- a/src/github.rs +++ b/src/github.rs @@ -3,11 +3,11 @@ use serde_derive::Deserialize; #[derive(Debug, Deserialize)] pub struct GithubRelease { pub tag_name: String, - pub name: String, - pub body: String, - pub prerelease: bool, - pub created_at: String, - pub published_at: String, + // pub name: Option, + // pub body: Option, + // pub prerelease: bool, + // pub created_at: String, + // pub published_at: Option, } pub fn list_releases(repo: &str) -> eyre::Result> { diff --git a/src/hash.rs b/src/hash.rs index 6d35d2460..e85c3657f 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,4 +1,3 @@ -use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; use std::fs::File; use std::hash::{Hash, Hasher}; @@ -8,15 +7,15 @@ use std::path::Path; use eyre::{ensure, Result}; use rayon::prelude::*; use sha2::{Digest, Sha256}; +use siphasher::sip::SipHasher; use crate::file::display_path; use crate::ui::progress_report::SingleReport; pub fn hash_to_str(t: &T) -> String { - let mut s = DefaultHasher::new(); + let mut s = SipHasher::new(); t.hash(&mut s); - let bytes = s.finish(); - format!("{bytes:x}") + format!("{:x}", s.finish()) } pub fn file_hash_sha256(path: &Path) -> Result { @@ -82,7 +81,7 @@ mod tests { #[test] fn test_hash_to_str() { - assert_eq!(hash_to_str(&"foo"), "3e8b8c44c3ca73b7"); + assert_eq!(hash_to_str(&"foo"), "e1b19adfb2e348a2"); } #[test] diff --git a/src/hook_env.rs b/src/hook_env.rs index 82a2bfb0e..24ccba1e1 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -11,6 +11,7 @@ use flate2::Compression; use itertools::Itertools; use serde_derive::{Deserialize, Serialize}; +use crate::env::PATH_KEY; use crate::env_diff::{EnvDiffOperation, EnvDiffPatches}; use crate::hash::hash_to_str; use crate::shell::Shell; @@ -141,8 +142,11 @@ fn get_mise_env_vars_hashed() -> String { pub fn clear_old_env(shell: &dyn Shell) -> String { let mut patches = env::__MISE_DIFF.reverse().to_patches(); - if let Some(path) = env::PRISTINE_ENV.deref().get("PATH") { - patches.push(EnvDiffOperation::Change("PATH".into(), path.to_string())); + if let Some(path) = env::PRISTINE_ENV.deref().get(&*PATH_KEY) { + patches.push(EnvDiffOperation::Change( + PATH_KEY.to_string(), + path.to_string(), + )); } build_env_commands(shell, &patches) } diff --git a/src/http.rs b/src/http.rs index 28b80bd67..bc6526440 100644 --- a/src/http.rs +++ b/src/http.rs @@ -10,6 +10,7 @@ use tokio::runtime::Runtime; use url::Url; use crate::cli::version; +use crate::config::Settings; use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::display_path; use crate::ui::progress_report::SingleReport; @@ -19,7 +20,8 @@ use crate::{env, file}; pub static HTTP_VERSION_CHECK: Lazy = Lazy::new(|| Client::new(Duration::from_secs(3)).unwrap()); -pub static HTTP: Lazy = Lazy::new(|| Client::new(Duration::from_secs(30)).unwrap()); +pub static HTTP: Lazy = + Lazy::new(|| Client::new(Duration::from_secs(Settings::get().http_timeout)).unwrap()); pub static HTTP_FETCH: Lazy = Lazy::new(|| Client::new(*MISE_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap()); @@ -33,7 +35,7 @@ impl Client { fn new(timeout: Duration) -> Result { Ok(Self { reqwest: Self::_new() - .timeout(timeout) + .read_timeout(timeout) .connect_timeout(timeout) .build()?, }) diff --git a/src/main.rs b/src/main.rs index c58a54e77..83aa471f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ use itertools::Itertools; use crate::cli::version::VERSION; use crate::cli::Cli; -use crate::ui::style; #[cfg(test)] #[macro_use] @@ -22,14 +21,14 @@ mod regex; mod cmd; mod backend; -pub mod build_time; +pub(crate) mod build_time; mod cache; mod cli; mod config; mod default_shorthands; mod direnv; mod dirs; -pub mod duration; +pub(crate) mod duration; mod env; mod env_diff; mod errors; @@ -37,7 +36,7 @@ mod errors; mod fake_asdf; mod file; mod git; -pub mod github; +pub(crate) mod github; mod hash; mod hook_env; mod http; @@ -54,16 +53,13 @@ mod shell; mod shims; mod shorthands; mod task; -pub mod tera; -pub mod timeout; +pub(crate) mod tera; +pub(crate) mod timeout; mod toml; mod toolset; mod ui; fn main() -> eyre::Result<()> { - #[cfg(windows)] - warn!("mise is supported on windows. Do not expect anything to work."); - let args = env::args().collect_vec(); color_eyre::install()?; @@ -79,7 +75,7 @@ fn handle_err(err: Report) -> eyre::Result<()> { return Ok(()); } } - if log::max_level() < log::LevelFilter::Debug { + if cfg!(debug_assertions) || log::max_level() < log::LevelFilter::Debug { display_friendly_err(err); exit(1); } @@ -90,6 +86,6 @@ fn display_friendly_err(err: Report) { for err in err.chain() { error!("{err}"); } - let msg = style::edim("Run with --verbose or MISE_VERBOSE=1 for more information"); + let msg = ui::style::edim("Run with --verbose or MISE_VERBOSE=1 for more information"); error!("{msg}"); } diff --git a/src/plugins/asdf_plugin.rs b/src/plugins/asdf_plugin.rs index 0dd724ae1..4903d2d7f 100644 --- a/src/plugins/asdf_plugin.rs +++ b/src/plugins/asdf_plugin.rs @@ -34,14 +34,20 @@ impl AsdfPlugin { pub fn list() -> eyre::Result { let settings = Settings::get(); - Ok(file::ls(*dirs::PLUGINS)? - .into_par_iter() - .map(|dir| { - let name = dir.file_name().unwrap().to_string_lossy().to_string(); - Box::new(AsdfPlugin::new(name)) as Box - }) - .filter(|p| !settings.disable_tools.contains(p.name())) - .collect()) + match file::ls(*dirs::PLUGINS) { + Ok(dirs) => { + let plugins = dirs + .into_par_iter() + .map(|dir| { + let name = dir.file_name().unwrap().to_string_lossy().to_string(); + Box::new(AsdfPlugin::new(name)) as Box + }) + .filter(|p| !settings.disable_tools.contains(p.name())) + .collect(); + Ok(plugins) + } + Err(_) => Ok(PluginList::new()), + } } } diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 560b3bcf9..487942b31 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -40,8 +40,7 @@ impl DenoPlugin { HTTP_FETCH.json("https://api.github.com/repos/denoland/deno/releases?per_page=100")?; let versions = releases .into_iter() - .map(|r| r.name) - .filter(|v| !v.is_empty()) + .map(|r| r.tag_name) .filter(|v| v.starts_with('v')) .map(|v| v.trim_start_matches('v').to_string()) .unique() diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 6895dd1d6..038e33f14 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -12,6 +12,7 @@ use crate::cache::CacheManager; use crate::cli::args::BackendArg; use crate::config::Settings; use crate::env; +use crate::env::PATH_KEY; use crate::http::HTTP_FETCH; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; @@ -80,7 +81,7 @@ impl CorePlugin { } pub fn path_env_with_tv_path(tv: &ToolVersion) -> Result { - let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::>(); + let mut path = env::split_paths(&env::var_os(&*PATH_KEY).unwrap()).collect::>(); path.insert(0, tv.install_path().join("bin")); Ok(env::join_paths(path)?) } @@ -97,6 +98,7 @@ impl CorePlugin { if !*env::MISE_USE_VERSIONS_HOST { return Ok(None); } + // using http is not a security concern and enabling tls makes mise significantly slower let raw = HTTP_FETCH.get_text(format!("http://mise-versions.jdx.dev/{}", &self.fa.name))?; let versions = raw .lines() diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index f16b2ea41..214ac4334 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -use eyre::Result; +use eyre::{bail, Result}; use serde_derive::Deserialize; use tempfile::tempdir_in; use url::Url; @@ -11,7 +11,7 @@ use crate::build_time::built_info; use crate::cli::args::BackendArg; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::env::MISE_NODE_MIRROR_URL; +use crate::env::{MISE_NODE_MIRROR_URL, PATH_KEY}; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; @@ -83,6 +83,28 @@ impl NodePlugin { Ok(()) } + fn install_windows(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { + match self.fetch_tarball( + ctx.pr.as_ref(), + &opts.binary_tarball_url, + &opts.binary_tarball_path, + &opts.version, + ) { + Err(e) if matches!(http::error_code(&e), Some(404)) => { + bail!("precompiled node not found {e}"); + } + e => e, + }?; + let tarball_name = &opts.binary_tarball_name; + ctx.pr.set_message(format!("extracting {tarball_name}")); + let tmp_extract_path = tempdir_in(opts.install_path.parent().unwrap())?; + file::unzip(&opts.binary_tarball_path, tmp_extract_path.path())?; + file::remove_all(&opts.install_path)?; + let slug = format!("node-v{}-{}-{}", &opts.version, os(), arch()); + file::rename(tmp_extract_path.path().join(slug), &opts.install_path)?; + Ok(()) + } + fn install_compiled(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { let tarball_name = &opts.source_tarball_name; self.fetch_tarball( @@ -153,15 +175,27 @@ impl NodePlugin { } fn node_path(&self, tv: &ToolVersion) -> PathBuf { - tv.install_path().join("bin/node") + if cfg!(windows) { + tv.install_path().join("node.exe") + } else { + tv.install_path().join("bin").join("node") + } } fn npm_path(&self, tv: &ToolVersion) -> PathBuf { - tv.install_path().join("bin/npm") + if cfg!(windows) { + tv.install_path().join("npm.cmd") + } else { + tv.install_path().join("bin").join("npm") + } } fn corepack_path(&self, tv: &ToolVersion) -> PathBuf { - tv.install_path().join("bin/corepack") + if cfg!(windows) { + tv.install_path().join("corepack.cmd") + } else { + tv.install_path().join("bin").join("corepack") + } } fn install_default_packages( @@ -184,7 +218,7 @@ impl NodePlugin { .arg("--global") .arg(package) .envs(config.env()?) - .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .env(&*PATH_KEY, CorePlugin::path_env_with_tv_path(tv)?) .execute()?; } Ok(()) @@ -203,7 +237,7 @@ impl NodePlugin { CmdLineRunner::new(corepack) .with_pr(pr) .arg("enable") - .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .env(&*PATH_KEY, CorePlugin::path_env_with_tv_path(tv)?) .execute()?; Ok(()) } @@ -220,7 +254,7 @@ impl NodePlugin { fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { pr.set_message("npm -v".into()); CmdLineRunner::new(self.npm_path(tv)) - .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .env(&*PATH_KEY, CorePlugin::path_env_with_tv_path(tv)?) .with_pr(pr) .arg("-v") .envs(config.env()?) @@ -294,13 +328,17 @@ impl Backend for NodePlugin { let settings = Settings::get(); let opts = BuildOpts::new(ctx)?; trace!("node build opts: {:#?}", opts); - if settings.node_compile { + if cfg!(windows) { + self.install_windows(ctx, &opts)?; + } else if settings.node_compile { self.install_compiled(ctx, &opts)?; } else { self.install_precompiled(ctx, &opts)?; } self.test_node(&config, &ctx.tv, ctx.pr.as_ref())?; - self.install_npm_shim(&ctx.tv)?; + if !cfg!(windows) { + self.install_npm_shim(&ctx.tv)?; + } self.test_npm(&config, &ctx.tv, ctx.pr.as_ref())?; if let Err(err) = self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref()) { warn!("failed to install default npm packages: {err:#}"); @@ -335,6 +373,10 @@ impl BuildOpts { let v = &ctx.tv.version; let install_path = ctx.tv.install_path(); let source_tarball_name = format!("node-v{v}.tar.gz"); + + #[cfg(windows)] + let binary_tarball_name = format!("node-v{v}-{}-{}.zip", os(), arch()); + #[cfg(not(windows))] let binary_tarball_name = format!("node-v{v}-{}-{}.tar.gz", os(), arch()); Ok(Self { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 0e0ce77fd..0a8f395dd 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -100,6 +100,7 @@ impl PythonPlugin { fn fetch_precompiled_remote_versions(&self) -> eyre::Result<&Vec<(String, String, String)>> { self.precompiled_cache.get_or_try_init(|| { let settings = Settings::get(); + // using http is not a security concern and enabling tls makes mise significantly slower let raw = HTTP_FETCH.get_text("http://mise-versions.jdx.dev/python-precompiled")?; let platform = format!("{}-{}", python_arch(&settings), python_os(&settings)); let versions = raw diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 1435039da..34e610a26 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -10,6 +10,7 @@ use crate::cli::args::BackendArg; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::duration::DAILY; +use crate::env::PATH_KEY; use crate::git::Git; use crate::github::GithubRelease; use crate::http::{HTTP, HTTP_FETCH}; @@ -204,7 +205,7 @@ impl RubyPlugin { Some((name, version)) => cmd = cmd.arg(name).arg("--version").arg(version), None => cmd = cmd.arg(package), }; - cmd.env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + cmd.env(&*PATH_KEY, CorePlugin::path_env_with_tv_path(tv)?) .execute()?; } Ok(()) @@ -225,7 +226,7 @@ impl RubyPlugin { .with_pr(pr) .arg("-v") .envs(config.env()?) - .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .env(&*PATH_KEY, CorePlugin::path_env_with_tv_path(tv)?) .execute() } diff --git a/src/plugins/core/zig.rs b/src/plugins/core/zig.rs index 6976698ac..bfe4afaed 100644 --- a/src/plugins/core/zig.rs +++ b/src/plugins/core/zig.rs @@ -42,7 +42,18 @@ impl ZigPlugin { fn fetch_remote_versions(&self) -> Result> { match self.core.fetch_remote_versions_from_mise() { - Ok(Some(versions)) => return Ok(versions), + Ok(Some(versions)) => { + return Ok(versions + .into_iter() + .map(|r| { + if r == "master" { + "ref:master".to_string() + } else { + r + } + }) + .collect()) + } Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } @@ -52,6 +63,13 @@ impl ZigPlugin { let versions = releases .into_iter() .map(|r| r.tag_name) + .map(|r| { + if r == "master" { + "ref:master".to_string() + } else { + r + } + }) .unique() .sorted_by_cached_key(|s| (Versioning::new(s), s.to_string())) .collect(); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 70b4d5b7f..abcdec2ba 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -11,6 +11,7 @@ use once_cell::sync::Lazy; use crate::cmd::{cmd, CmdLineRunner}; use crate::config::Settings; +use crate::env::PATH_KEY; use crate::errors::Error; use crate::errors::Error::ScriptFailed; use crate::fake_asdf::get_path_with_fake_asdf; @@ -82,7 +83,7 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { env.extend( (indexmap! { "ASDF_CONCURRENCY" => num_cpus::get().to_string(), - "PATH" => get_path_with_fake_asdf(), + &*PATH_KEY => get_path_with_fake_asdf(), "MISE_CACHE_DIR" => env::MISE_CACHE_DIR.to_string_lossy().to_string(), "MISE_CONCURRENCY" => num_cpus::get().to_string(), "MISE_DATA_DIR" => dirs::DATA.to_string_lossy().to_string(), @@ -116,11 +117,11 @@ impl ScriptManager { } pub fn prepend_path(&mut self, path: PathBuf) { - let k: OsString = "PATH".into(); + let k: OsString = PATH_KEY.to_string().into(); let mut paths = env::split_paths(&self.env[&k]).collect::>(); paths.insert(0, path); self.env - .insert("PATH".into(), env::join_paths(paths).unwrap()); + .insert(PATH_KEY.to_string().into(), env::join_paths(paths).unwrap()); } pub fn get_script_path(&self, script: &Script) -> PathBuf { diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index fc2e21bb4..08683368d 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -9,7 +9,7 @@ use versions::Versioning; use crate::backend::{backend_meta, Backend}; use crate::config::Config; -use crate::file::make_symlink; +use crate::file::make_symlink_or_file; use crate::plugins::VERSION_REGEX; use crate::{backend, file}; @@ -27,7 +27,7 @@ pub fn rebuild(config: &Config) -> Result<()> { continue; } } - make_symlink(&to, &from)?; + make_symlink_or_file(&to, &from)?; } remove_missing_symlinks(backend.clone())?; // remove install dir if empty (ignore metadata) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 555c5f6dd..679ab471d 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -86,7 +86,6 @@ impl Shell for Bash { fn set_env(&self, k: &str, v: &str) -> String { let k = shell_escape::unix::escape(k.into()); let v = shell_escape::unix::escape(v.into()); - let v = v.replace("\\n", "\n"); format!("export {k}={v}\n") } diff --git a/src/shell/fish.rs b/src/shell/fish.rs index cce2ee9c5..6b210ec76 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -108,7 +108,6 @@ impl Shell for Fish { fn set_env(&self, k: &str, v: &str) -> String { let k = shell_escape::unix::escape(k.into()); let v = shell_escape::unix::escape(v.into()); - let v = v.replace("\\n", "\n"); format!("set -gx {k} {v}\n") } diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index a2d83e25d..a7ea56099 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -90,7 +90,6 @@ impl Shell for Nushell { fn set_env(&self, k: &str, v: &str) -> String { let k = shell_escape::unix::escape(k.into()); let v = shell_escape::unix::escape(v.into()); - let v = v.replace("\\n", "\n"); let v = v.replace('\'', ""); EnvOp::Set { key: &k, val: &v }.to_string() @@ -109,13 +108,15 @@ impl Shell for Nushell { #[cfg(test)] mod tests { use insta::assert_snapshot; + use test_log::test; - use crate::test::replace_path; + use crate::test::{replace_path, reset}; use super::*; #[test] fn test_hook_init() { + reset(); let nushell = Nushell::default(); let exe = Path::new("/some/dir/mise"); assert_snapshot!(nushell.activate(exe, " --status".into())); @@ -123,22 +124,26 @@ mod tests { #[test] fn test_set_env() { + reset(); assert_snapshot!(Nushell::default().set_env("FOO", "1")); } #[test] fn test_prepend_env() { + reset(); let sh = Nushell::default(); assert_snapshot!(replace_path(&sh.prepend_env("PATH", "/some/dir:/2/dir"))); } #[test] fn test_unset_env() { + reset(); assert_snapshot!(Nushell::default().unset_env("FOO")); } #[test] fn test_deactivate() { + reset(); let deactivate = Nushell::default().deactivate(); assert_snapshot!(replace_path(&deactivate)); } diff --git a/src/shims.rs b/src/shims.rs index 6b3935e5d..592267490 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -23,7 +23,7 @@ use crate::{backend, dirs, env, fake_asdf, file, logger}; pub fn handle_shim() -> Result<()> { // TODO: instead, check if bin is in shims dir let bin_name = *env::MISE_BIN_NAME; - if regex!(r"^(mise|rtx)(\-.*)?$").is_match(bin_name) || cfg!(test) { + if regex!(r"^(mise|rtx)(\-.*)?(\.exe)?$").is_match(bin_name) || cfg!(test) { return Ok(()); } logger::init(); @@ -100,13 +100,7 @@ pub fn reshim(ts: &Toolset) -> Result<()> { for shim in shims_to_add { let symlink_path = dirs::SHIMS.join(shim); - file::make_symlink(&mise_bin, &symlink_path).wrap_err_with(|| { - eyre!( - "Failed to create symlink from {} to {}", - display_path(&mise_bin), - display_path(&symlink_path) - ) - })?; + add_shim(&mise_bin, &symlink_path)?; } for shim in shims_to_remove { let symlink_path = dirs::SHIMS.join(shim); @@ -131,6 +125,37 @@ pub fn reshim(ts: &Toolset) -> Result<()> { Ok(()) } +#[cfg(windows)] +fn add_shim(mise_bin: &Path, symlink_path: &Path) -> Result<()> { + file::write( + symlink_path.with_extension("cmd"), + formatdoc! {r#" + @echo off + setlocal + mise x -- %* + "#}, + ) + .wrap_err_with(|| { + eyre!( + "Failed to create symlink from {} to {}", + display_path(mise_bin), + display_path(symlink_path) + ) + }) +} + +#[cfg(unix)] +fn add_shim(mise_bin: &Path, symlink_path: &Path) -> Result<()> { + file::make_symlink(mise_bin, symlink_path).wrap_err_with(|| { + eyre!( + "Failed to create symlink from {} to {}", + display_path(mise_bin), + display_path(symlink_path) + ) + })?; + Ok(()) +} + // get_shim_diffs contrasts the actual shims on disk // with the desired shims specified by the Toolset // and returns a tuple of (missing shims, extra shims) diff --git a/src/task.rs b/src/task.rs index 9e39c85dd..fb118e0ad 100644 --- a/src/task.rs +++ b/src/task.rs @@ -165,6 +165,7 @@ fn name_from_path(root: impl AsRef, path: impl AsRef) -> Result p.strip_prefix(".mise/tasks"), + p if p.starts_with("mise/tasks") => p.strip_prefix("mise/tasks"), p if p.starts_with(".config/mise/tasks") => p.strip_prefix(".config/mise/tasks"), _ => Ok(p), })?? @@ -338,6 +339,10 @@ fn config_root(config_source: &impl AsRef) -> Option<&Path> { if ancestor.ends_with(".config/mise/tasks") { return ancestor.parent()?.parent()?.parent(); } + + if ancestor.ends_with("mise/tasks") { + return ancestor.parent()?.parent(); + } } config_source.as_ref().parent() @@ -424,6 +429,7 @@ mod tests { ("/base", Some(Path::new("/"))), ("/base/.mise/tasks", Some(Path::new("/base"))), ("/base/.config/mise/tasks", Some(Path::new("/base"))), + ("/base/mise/tasks", Some(Path::new("/base"))), ]; for (src, expected) in test_cases { diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index c4699508b..1952ad296 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -13,17 +13,18 @@ use itertools::Itertools; use rayon::prelude::*; pub use builder::ToolsetBuilder; +pub use tool_request::ToolRequest; pub use tool_request_set::{ToolRequestSet, ToolRequestSetBuilder}; pub use tool_source::ToolSource; pub use tool_version::ToolVersion; pub use tool_version_list::ToolVersionList; -pub use tool_version_request::ToolRequest; +use versions::Version; use crate::backend::Backend; use crate::cli::args::BackendArg; use crate::config::settings::SettingsStatusMissingTools; use crate::config::{Config, Settings}; -use crate::env::TERM_WIDTH; +use crate::env::{PATH_KEY, TERM_WIDTH}; use crate::errors::Error; use crate::install_context::InstallContext; use crate::path_env::PathEnv; @@ -31,11 +32,11 @@ use crate::ui::multi_progress_report::MultiProgressReport; use crate::{backend, env, runtime_symlinks, shims}; mod builder; +mod tool_request; mod tool_request_set; mod tool_source; mod tool_version; mod tool_version_list; -mod tool_version_request; pub type ToolVersionOptions = BTreeMap; @@ -163,7 +164,7 @@ impl Toolset { let queue: Vec<_> = versions .into_iter() .rev() - .group_by(|v| v.backend().clone()) + .chunk_by(|v| v.backend().clone()) .into_iter() .map(|(fa, v)| (backend::get(&fa), v.collect_vec())) .collect(); @@ -230,7 +231,7 @@ impl Toolset { Err(e) => panic::resume_unwind(e), }) .collect::>>>() - .map(|x| x.into_iter().flatten().collect()) + .map(|x| x.into_iter().flatten().rev().collect()) })?; trace!("install: resolving"); if let Err(err) = self.resolve() { @@ -327,7 +328,9 @@ impl Toolset { return None; } }; - if !t.is_version_installed(&tv) || tv.version != latest { + if !t.is_version_installed(&tv) + || is_outdated_version(tv.version.as_str(), latest.as_str()) + { Some((t, tv, latest)) } else { None @@ -349,13 +352,13 @@ impl Toolset { path_env.add(p); } let mut env = self.env(config)?; - if let Some(path) = env.get("PATH") { + if let Some(path) = env.get(&*PATH_KEY) { path_env.add(PathBuf::from(path)); } for p in self.list_paths() { path_env.add(p); } - env.insert("PATH".to_string(), path_env.to_string()); + env.insert(PATH_KEY.to_string(), path_env.to_string()); Ok(env) } pub fn env(&self, config: &Config) -> Result> { @@ -385,7 +388,7 @@ impl Toolset { .rev() .collect(); if !add_paths.is_empty() { - entries.insert("PATH".to_string(), add_paths); + entries.insert(PATH_KEY.to_string(), add_paths); } entries.extend(config.env()?.clone()); Ok(entries) @@ -542,3 +545,47 @@ fn get_leaf_dependencies(requests: &[ToolRequest]) -> eyre::Result>>()?; Ok(leaves) } + +fn is_outdated_version(current: &str, latest: &str) -> bool { + let c = Version::new(current); + let l = Version::new(latest); + if c.is_some() && l.is_some() { + return c.lt(&l); + } + current != latest +} + +#[cfg(test)] +mod tests { + use crate::backend::reset; + use pretty_assertions::assert_eq; + use test_log::test; + + use super::is_outdated_version; + + #[test] + fn test_is_outdated_version() { + reset(); + + assert_eq!(is_outdated_version("1.10.0", "1.12.0"), true); + assert_eq!(is_outdated_version("1.12.0", "1.10.0"), false); + + assert_eq!( + is_outdated_version("1.10.0-SNAPSHOT", "1.12.0-SNAPSHOT"), + true + ); + assert_eq!( + is_outdated_version("1.12.0-SNAPSHOT", "1.10.0-SNAPSHOT"), + false + ); + + assert_eq!( + is_outdated_version("temurin-17.0.0", "temurin-17.0.1"), + true + ); + assert_eq!( + is_outdated_version("temurin-17.0.1", "temurin-17.0.0"), + false + ); + } +} diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_request.rs similarity index 91% rename from src/toolset/tool_version_request.rs rename to src/toolset/tool_request.rs index d7584629f..458c79112 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_request.rs @@ -25,6 +25,7 @@ pub enum ToolRequest { Ref { backend: BackendArg, ref_: String, + ref_type: String, options: ToolVersionOptions, }, Sub { @@ -39,13 +40,14 @@ pub enum ToolRequest { impl ToolRequest { pub fn new(backend: BackendArg, s: &str) -> eyre::Result { let s = match s.split_once('-') { - Some(("ref", r)) => format!("ref:{}", r), + Some((ref_type @ ("ref" | "tag" | "branch" | "rev"), r)) => format!("{ref_type}:{r}"), _ => s.to_string(), }; Ok(match s.split_once(':') { - Some(("ref", r)) => Self::Ref { + Some((ref_type @ ("ref" | "tag" | "branch" | "rev"), r)) => Self::Ref { backend, ref_: r.to_string(), + ref_type: ref_type.to_string(), options: Default::default(), }, Some(("prefix", p)) => Self::Prefix { @@ -105,7 +107,9 @@ impl ToolRequest { match self { Self::Version { version: v, .. } => v.clone(), Self::Prefix { prefix: p, .. } => format!("prefix:{p}"), - Self::Ref { ref_: r, .. } => format!("ref:{r}"), + Self::Ref { + ref_: r, ref_type, .. + } => format!("{ref_type}:{r}"), Self::Path(_, p) => format!("path:{}", p.display()), Self::Sub { sub, orig_version, .. @@ -136,9 +140,12 @@ impl ToolRequest { Self::Version { backend, version, .. } => Some(backend.installs_path.join(version)), - Self::Ref { backend, ref_, .. } => { - Some(backend.installs_path.join(format!("ref-{}", ref_))) - } + Self::Ref { + backend, + ref_, + ref_type, + .. + } => Some(backend.installs_path.join(format!("{ref_type}-{ref_}"))), Self::Sub { backend, sub, @@ -204,10 +211,13 @@ impl Display for ToolRequest { #[cfg(test)] mod tests { use super::version_sub; + use crate::backend::reset; use pretty_assertions::assert_str_eq; + use test_log::test; #[test] fn test_version_sub() { + reset(); assert_str_eq!(version_sub("18.2.3", "2"), "16"); assert_str_eq!(version_sub("18.2.3", "0.1"), "18.1"); } diff --git a/src/toolset/tool_request_set.rs b/src/toolset/tool_request_set.rs index 12957fb44..39a9b3906 100644 --- a/src/toolset/tool_request_set.rs +++ b/src/toolset/tool_request_set.rs @@ -51,13 +51,6 @@ impl ToolRequestSet { self.tools.keys().collect() } - pub fn list_current_versions(&self) -> Vec<(&BackendArg, &ToolRequest)> { - self.tools - .iter() - .map(|(fa, tvr)| (fa, tvr.last().unwrap())) - .collect() - } - pub fn add_version(&mut self, tr: ToolRequest, source: &ToolSource) { let fa = tr.backend(); if !self.tools.contains_key(fa) { diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 4979e20b1..bddb6e380 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -12,7 +12,7 @@ use crate::backend::{ABackend, Backend}; use crate::cli::args::BackendArg; use crate::config::Config; use crate::hash::hash_to_str; -use crate::toolset::{tool_version_request, ToolRequest, ToolVersionOptions}; +use crate::toolset::{tool_request, ToolRequest, ToolVersionOptions}; /// represents a single version of a tool for a particular plugin #[derive(Debug, Clone)] @@ -124,8 +124,13 @@ impl ToolVersion { let config = Config::get(); let v = config.resolve_alias(tool, v)?; match v.split_once(':') { - Some(("ref", r)) => { - return Ok(Self::resolve_ref(tool, r.to_string(), request.options())); + Some((ref_type @ ("ref" | "tag" | "branch" | "rev"), r)) => { + return Ok(Self::resolve_ref( + tool, + r.to_string(), + ref_type.to_string(), + request.options(), + )); } Some(("path", p)) => { return Self::resolve_path(tool, PathBuf::from(p)); @@ -189,7 +194,7 @@ impl ToolVersion { "latest" => tool.latest_version(None)?.unwrap(), _ => Config::get().resolve_alias(tool, v)?, }; - let v = tool_version_request::version_sub(&v, sub); + let v = tool_request::version_sub(&v, sub); Self::resolve_version(tool, request, latest_versions, &v) } @@ -203,10 +208,16 @@ impl ToolVersion { Ok(Self::new(tool, request, v.to_string())) } - fn resolve_ref(tool: &dyn Backend, ref_: String, opts: ToolVersionOptions) -> Self { + fn resolve_ref( + tool: &dyn Backend, + ref_: String, + ref_type: String, + opts: ToolVersionOptions, + ) -> Self { let request = ToolRequest::Ref { backend: tool.fa().clone(), ref_, + ref_type, options: opts.clone(), }; let version = request.version(); diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 78b44c230..e66166d4c 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -1,7 +1,7 @@ use crate::backend; use crate::cli::args::BackendArg; use crate::errors::Error; -use crate::toolset::tool_version_request::ToolRequest; +use crate::toolset::tool_request::ToolRequest; use crate::toolset::{ToolSource, ToolVersion}; /// represents several versions of a tool for a particular plugin diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 975891047..45fb0e945 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -166,10 +166,15 @@ impl SingleReport for VerboseReport { #[cfg(test)] mod tests { + use test_log::test; + + use crate::test::reset; + use super::*; #[test] fn test_progress_report() { + reset(); let pr = ProgressReport::new("foo".into()); pr.set_message("message".into()); pr.finish_with_message("message".into()); @@ -177,6 +182,7 @@ mod tests { #[test] fn test_progress_report_verbose() { + reset(); let pr = VerboseReport::new("PREFIX".to_string()); pr.set_message("message".into()); pr.finish_with_message("message".into()); @@ -184,6 +190,7 @@ mod tests { #[test] fn test_progress_report_quiet() { + reset(); let pr = QuietReport::new(); pr.set_message("message".into()); pr.finish_with_message("message".into()); diff --git a/tests/cli/backend.rs b/tests/cli/backend.rs index a579f636a..c9529a136 100644 --- a/tests/cli/backend.rs +++ b/tests/cli/backend.rs @@ -2,7 +2,7 @@ use crate::cli::prelude::*; use eyre::Result; const EXPECTED_EZA_OUTPUT: &str = "eza - A modern, maintained replacement for ls -v0.17.0 [+git] +v0.18.24 [+git] https://github.com/eza-community/eza "; @@ -12,13 +12,13 @@ https://github.com/eza-community/eza fn test_cargo_binstall() -> Result<()> { mise! { when!( - given!(args "rm", "cargo:eza@0.17.0"); + given!(args "rm", "cargo:eza@0.18.24"); should!(succeed) ), when!( given!(env_var "MISE_EXPERIMENTAL", "1"), given!(env_var "MISE_CARGO_BINSTALL", "1"), - given!(args "x", "cargo:eza@0.17.0", "--", "eza", "-v"); + given!(args "x", "cargo:eza@0.18.24", "--", "eza", "-v"); should!(output_exactly EXPECTED_EZA_OUTPUT), should!(succeed) ) @@ -31,12 +31,12 @@ fn test_cargo_binstall() -> Result<()> { fn test_cargo_local_build() -> Result<()> { mise! { when!( - given!(args "rm", "cargo:eza@0.17.0"); + given!(args "rm", "cargo:eza@0.18.24"); should!(succeed) ), when!( given!(env_var "MISE_EXPERIMENTAL", "1"), - given!(args "x", "cargo:eza@0.17.0", "--", "eza", "-v"); + given!(args "x", "cargo:eza@0.18.24", "--", "eza", "-v"); should!(output_exactly EXPECTED_EZA_OUTPUT), should!(succeed) ) diff --git a/tests/cli/global.rs b/tests/cli/global.rs index b7f1e425b..6f008b5ff 100644 --- a/tests/cli/global.rs +++ b/tests/cli/global.rs @@ -10,7 +10,7 @@ fn test_exec_change_directory() -> Result<()> { .with_home_files([CONFIGS.get(".tool-versions")]) .build()?; - let tool_verisons_path = env.home_path().join(".tool-versions"); + let tool_versions_path = env.home_path().join(".tool-versions"); // Given default settings // When `mise global node 20.0.0` is run @@ -41,7 +41,7 @@ fn test_exec_change_directory() -> Result<()> { env.mise() .unset_env("MISE_GLOBAL_CONFIG_FILE") .unset_env("MISE_CONFIG_FILE") - .env("MISE_CONFIG_FILE", &tool_verisons_path) + .env("MISE_CONFIG_FILE", &tool_versions_path) .args(["global", "node", "20.0.0"]) .run()? .stdout(predicate::str::contains("~/.tool-versions")) @@ -53,7 +53,7 @@ fn test_exec_change_directory() -> Result<()> { env.mise() .unset_env("MISE_GLOBAL_CONFIG_FILE") .unset_env("MISE_CONFIG_FILE") - .env("MISE_GLOBAL_CONFIG_FILE", tool_verisons_path) + .env("MISE_GLOBAL_CONFIG_FILE", tool_versions_path) .args(["global", "node", "20.0.0"]) .run()? .stdout(predicate::str::contains("~/.tool-versions")) diff --git a/tests/cli/install.rs b/tests/cli/install.rs index 685cc6e94..7c4a78aab 100644 --- a/tests/cli/install.rs +++ b/tests/cli/install.rs @@ -100,7 +100,7 @@ fn test_nodejs() -> Result<()> { .run()? .success(); - // When node@lts/hydrogen is insalled + // When node@lts/hydrogen is installed // Mise should succeed env.mise() .env( @@ -211,7 +211,7 @@ fn python_config_fixture() -> File { // From e2e/test_python #[test] #[ignore] -fn test_python_complie() -> Result<()> { +fn test_python_compile() -> Result<()> { mise! { given_environment!(has_exported_var "MISE_ALL_COMPILE", "1"); when!(