Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions docs/bootstrap/packages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mise can ensure machine-global system packages are installed via the
"brew:postgresql@17" = "latest"
"brew:ffmpeg" = "latest"
"brew-cask:firefox" = "latest"
"mas:497799835" = "latest"
```

Each entry is keyed `"manager:package"` — the manager prefix is required —
Expand Down Expand Up @@ -45,6 +46,7 @@ applied by `mise bootstrap user apply` or [`mise bootstrap`](/cli/bootstrap.html
| `pacman` | Arch, Manjaro | [pacman](/bootstrap/packages/pacman.html) |
| `brew` | macOS (arm64), Linux (x86_64/arm64) — **no Homebrew required** | [brew](/bootstrap/packages/brew.html) |
| `brew-cask` | macOS — **no Homebrew required** | [brew](/bootstrap/packages/brew.html) |
| `mas` | macOS with the `mas` CLI on `PATH` | [mas](/bootstrap/packages/mas.html) |

## Semantics

Expand All @@ -55,8 +57,9 @@ applied by `mise bootstrap user apply` or [`mise bootstrap`](/cli/bootstrap.html
- **OS-filtered** — entries for a manager that isn't available on the current
machine are not acted on, so the same config works across platforms: `apt`
entries are ignored on macOS, `dnf` entries on Ubuntu, and so on. `brew`
works on both macOS and Linux; `brew-cask` works on macOS. Status commands
still list unavailable managers so nothing is silently invisible.
works on both macOS and Linux; `brew-cask` works on macOS; `mas` works on
macOS when the `mas` CLI is on `PATH`. Status commands still list
unavailable managers so nothing is silently invisible.
- **Manual installation only** — mise never installs system packages
implicitly. `mise install` will print a one-time hint when packages are
missing, but only `mise bootstrap packages install` ever installs anything.
Expand Down Expand Up @@ -86,14 +89,15 @@ mise bootstrap packages install --yes # skip the confirmation prompt
mise bootstrap packages install --manager apt
mise bootstrap packages install --update # refresh package manager metadata first

mise bootstrap packages use apt:curl brew:jq brew-cask:firefox # add and install
mise bootstrap packages use apt:curl brew:jq brew-cask:firefox mas:497799835
mise bootstrap packages use -g brew:ffmpeg # write globally
mise bootstrap packages use apt:curl@8.5.0-2 # pin a version (brew pins via the
# formula name: brew:postgresql@17)

mise bootstrap packages upgrade # upgrade installed packages to current versions
mise bootstrap packages upgrade --manager brew
mise bootstrap packages upgrade --manager brew-cask
mise bootstrap packages upgrade --manager mas
```

`mise bootstrap packages use` is `mise use` for system packages: it writes
Expand All @@ -106,11 +110,12 @@ Mac.
`mise bootstrap packages upgrade` refreshes package manager metadata and upgrades the
configured packages that are already installed to the newest available
version — apt and dnf also honor a version pinned in config (pacman, brew,
and brew-cask [can't install pins](/bootstrap/packages/pacman.html), so
brew-cask, and mas [can't install pins](/bootstrap/packages/pacman.html), so
pinned entries are skipped with a warning). Packages that aren't installed
yet are skipped — that's `mise bootstrap packages install`'s job. For brew
this pours the formula's current bottle and replaces the old keg; for
brew-cask this installs the current cask artifact.
brew-cask this installs the current cask artifact; for mas this runs
`mas upgrade`.

`mise doctor` also reports configured system packages and warns when any are
missing.
Expand Down
71 changes: 71 additions & 0 deletions docs/bootstrap/packages/mas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# mas <Badge type="warning" text="experimental" />

Mac App Store apps via the [`mas`](https://github.com/mas-cli/mas) CLI.

```toml
[bootstrap.packages]
"brew:mas" = "latest"
"mas:497799835" = "latest" # Xcode
```

`mas` apps are part of `[bootstrap.packages]`, just like apt packages,
Homebrew formulae, and casks. The package name is the App Store app ID:
a numeric ADAM ID accepted by `mas install` and `mas upgrade`.

mise does not install `mas` implicitly. Install it yourself first, for
example with the built-in brew manager:

```toml
[bootstrap.packages]
"brew:mas" = "latest"
"mas:497799835" = "latest"
```

or with a normal mise tool if you have one configured globally:

```sh
mise use -g mas
```

## Commands

```sh
mise bootstrap packages use mas:497799835
mise bootstrap packages status
mise bootstrap packages install --manager mas
mise bootstrap packages upgrade --manager mas
```

`mise bootstrap packages install` runs `mas install <id>` for missing apps.
`mise bootstrap packages upgrade` runs `mas upgrade <id>` for installed apps.
Both commands require numeric ADAM IDs; bundle identifiers such as
`com.apple.dt.Xcode` are not valid package names.

## Caveats

`mas` is macOS-only and must be on `PATH`. On other platforms, or when the
`mas` command is missing, shared configs list the entries as skipped instead
of failing. Explicit commands such as `mise bootstrap packages install
--manager mas` still fail when `mas` is unavailable, matching the other
package managers.

Mac App Store operations may require an Apple Account signed in to the App
Store, macOS authentication, prior purchase/claiming for paid apps, and valid
Spotlight indexing. mise surfaces errors from `mas` rather than trying to
purchase or claim apps itself.

## Finding IDs

Use `mas search` or copy an App Store URL and extract the numeric ID:

```sh
mas search xcode
```

For example, Xcode's App Store URL contains `id497799835`, so the package
entry is:

```toml
[bootstrap.packages]
"mas:497799835" = "latest"
```
5 changes: 3 additions & 2 deletions docs/cli/bootstrap/packages/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ Packages in `manager:package` form; defaults to everything configured in [bootst

### `-m --manager <MANAGER>`

Only install packages for this manager, e.g. `apt`, `brew`, or `brew-cask`
Only install packages for this manager, e.g. `apt`, `brew`, `brew-cask`, or `mas`

**Choices:**

- `apt`
- `brew`
- `brew-cask`
- `dnf`
- `mas`
- `pacman`

### `-n --dry-run`
Expand All @@ -52,7 +53,7 @@ Examples:

```
mise bootstrap packages install
mise bootstrap packages install apt:curl brew:jq brew-cask:firefox
mise bootstrap packages install apt:curl brew:jq brew-cask:firefox mas:497799835
mise bootstrap packages install --dry-run
mise bootstrap packages install --manager apt --yes
```
11 changes: 7 additions & 4 deletions docs/cli/bootstrap/packages/upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ Upgrade installed bootstrap packages from `[bootstrap.packages]`
Refreshes package manager metadata and upgrades the configured packages
that are already installed: apt/dnf/pacman upgrade to the newest available
version (apt and dnf honor a version pinned in config), brew pours the
formula's current bottle and replaces the old keg, and brew-cask installs
the current cask artifact. Packages that are not installed yet are skipped
— use `mise bootstrap packages install` for those.
formula's current bottle and replaces the old keg, brew-cask installs
the current cask artifact, and mas upgrades App Store apps. Packages that
are not installed yet are skipped — use `mise bootstrap packages install`
for those.

Packages can also be given explicitly in `manager:package` form.

Expand All @@ -26,14 +27,15 @@ Packages in `manager:package` form; defaults to everything configured in [bootst

### `-m --manager <MANAGER>`

Only upgrade packages for this manager, e.g. `apt`, `brew`, or `brew-cask`
Only upgrade packages for this manager, e.g. `apt`, `brew`, `brew-cask`, or `mas`

**Choices:**

- `apt`
- `brew`
- `brew-cask`
- `dnf`
- `mas`
- `pacman`

### `-n --dry-run`
Expand All @@ -50,6 +52,7 @@ Examples:
mise bootstrap packages upgrade
mise bootstrap packages upgrade brew:postgresql@17
mise bootstrap packages upgrade --manager brew-cask
mise bootstrap packages upgrade --manager mas
mise bootstrap packages upgrade --manager apt --yes
mise bootstrap packages upgrade --dry-run
```
4 changes: 2 additions & 2 deletions docs/cli/bootstrap/packages/use.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Versions are pinned with `@`: `mise bootstrap packages use apt:curl@8.5.0-2`. Wi
`@` (or with `@latest`) no pin is written. brew formulae and casks
version through their names instead (for example `brew:postgresql@17`,
`brew-cask:temurin@17`), where `@` is part of the Homebrew name rather than
a mise version selector.
a mise version selector. mas uses numeric ADAM IDs and does not support pins.

## Arguments

Expand Down Expand Up @@ -48,7 +48,7 @@ Skip the confirmation prompt
Examples:

```
mise bootstrap packages use apt:curl brew:jq brew-cask:firefox
mise bootstrap packages use apt:curl brew:jq brew-cask:firefox mas:497799835
mise bootstrap packages use -g brew:postgresql@17
mise bootstrap packages use apt:curl@8.5.0-2
```
8 changes: 8 additions & 0 deletions e2e/cli/test_system_status
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,21 @@ cat <<EOF >mise.toml
"apt:bc" = "latest"
"brew:jq" = "latest"
"dnf:bc" = "latest"
"mas:497799835" = "latest"
"pacman:bc" = "latest"
EOF

# status renders on any platform; unavailable managers are skipped, not errors
assert_succeed "mise bootstrap packages status"
assert_contains "mise bootstrap packages status" "bc"
assert_contains "mise bootstrap packages status" "497799835"
assert_contains "mise bootstrap packages status --json" '"apt"'
assert_contains "mise bootstrap packages status --json" '"mas"'
if [[ "$(uname)" == "Darwin" ]] && command -v mas >/dev/null; then
assert_succeed "mise bootstrap packages install --manager mas --dry-run --yes"
else
assert_fail "mise bootstrap packages install --manager mas --dry-run --yes"
fi

# unknown managers warn but don't fail
cat <<EOF >mise.toml
Expand Down
6 changes: 6 additions & 0 deletions e2e/cli/test_system_use
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ assert_fail "cat mise.toml"
# version pins use @, like mise use
assert_contains "mise bootstrap packages use --dry-run apt:curl@8.5.0-2" '"apt:curl" = "8.5.0-2"'

# mas uses numeric ADAM IDs
assert_contains "mise bootstrap packages use --dry-run mas:497799835" '"mas:497799835" = "latest"'
assert_contains "mise bootstrap packages use --dry-run mas:497799835@latest" '"mas:497799835" = "latest"'
assert_fail "mise bootstrap packages use --dry-run mas:com.apple.dt.Xcode"
assert_fail "mise bootstrap packages use --dry-run mas:497799835@1"

# bad specs and unknown managers fail before anything is written
assert_fail "mise bootstrap packages use noprefix"
assert_fail "mise bootstrap packages use not-a-real-manager:pkg"
Expand Down
13 changes: 7 additions & 6 deletions man/man1/mise.1
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ only.
.PP
.TP
\fB\-m, \-\-manager\fR \fI<MANAGER>\fR
Only install packages for this manager, e.g. `apt`, `brew`, or `brew\-cask`
Only install packages for this manager, e.g. `apt`, `brew`, `brew\-cask`, or `mas`
.TP
\fB\-n, \-\-dry\-run\fR
Print the commands that would run without running them
Expand Down Expand Up @@ -971,9 +971,10 @@ Upgrade installed bootstrap packages from `[bootstrap.packages]`
Refreshes package manager metadata and upgrades the configured packages
that are already installed: apt/dnf/pacman upgrade to the newest available
version (apt and dnf honor a version pinned in config), brew pours the
formula's current bottle and replaces the old keg, and brew\-cask installs
the current cask artifact. Packages that are not installed yet are skipped
— use `mise bootstrap packages install` for those.
formula's current bottle and replaces the old keg, brew\-cask installs
the current cask artifact, and mas upgrades App Store apps. Packages that
are not installed yet are skipped — use `mise bootstrap packages install`
for those.

Packages can also be given explicitly in `manager:package` form.
.PP
Expand All @@ -983,7 +984,7 @@ Packages can also be given explicitly in `manager:package` form.
.PP
.TP
\fB\-m, \-\-manager\fR \fI<MANAGER>\fR
Only upgrade packages for this manager, e.g. `apt`, `brew`, or `brew\-cask`
Only upgrade packages for this manager, e.g. `apt`, `brew`, `brew\-cask`, or `mas`
.TP
\fB\-n, \-\-dry\-run\fR
Print the commands that would run without running them
Expand All @@ -1006,7 +1007,7 @@ Versions are pinned with `@`: `mise bootstrap packages use apt:curl@8.5.0\-2`. W
`@` (or with `@latest`) no pin is written. brew formulae and casks
version through their names instead (for example `brew:postgresql@17`,
`brew\-cask:temurin@17`), where `@` is part of the Homebrew name rather than
a mise version selector.
a mise version selector. mas uses numeric ADAM IDs and does not support pins.
.PP
\fBUsage:\fR mise bootstrap packages use [OPTIONS] <PACKAGE> ...
.PP
Expand Down
22 changes: 12 additions & 10 deletions mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -401,14 +401,14 @@ only.
Examples:

$ mise bootstrap packages install
$ mise bootstrap packages install apt:curl brew:jq brew-cask:firefox
$ mise bootstrap packages install apt:curl brew:jq brew-cask:firefox mas:497799835
$ mise bootstrap packages install --dry-run
$ mise bootstrap packages install --manager apt --yes

"""#
flag "-m --manager" help="Only install packages for this manager, e.g. `apt`, `brew`, or `brew-cask`" {
flag "-m --manager" help="Only install packages for this manager, e.g. `apt`, `brew`, `brew-cask`, or `mas`" {
arg <MANAGER> {
choices apt brew brew-cask dnf pacman
choices apt brew brew-cask dnf mas pacman
}
}
flag "-n --dry-run" help="Print the commands that would run without running them"
Expand Down Expand Up @@ -437,9 +437,10 @@ Upgrade installed bootstrap packages from `[bootstrap.packages]`
Refreshes package manager metadata and upgrades the configured packages
that are already installed: apt/dnf/pacman upgrade to the newest available
version (apt and dnf honor a version pinned in config), brew pours the
formula's current bottle and replaces the old keg, and brew-cask installs
the current cask artifact. Packages that are not installed yet are skipped
— use `mise bootstrap packages install` for those.
formula's current bottle and replaces the old keg, brew-cask installs
the current cask artifact, and mas upgrades App Store apps. Packages that
are not installed yet are skipped — use `mise bootstrap packages install`
for those.

Packages can also be given explicitly in `manager:package` form.
"""#
Expand All @@ -449,13 +450,14 @@ Examples:
$ mise bootstrap packages upgrade
$ mise bootstrap packages upgrade brew:postgresql@17
$ mise bootstrap packages upgrade --manager brew-cask
$ mise bootstrap packages upgrade --manager mas
$ mise bootstrap packages upgrade --manager apt --yes
$ mise bootstrap packages upgrade --dry-run

"""#
flag "-m --manager" help="Only upgrade packages for this manager, e.g. `apt`, `brew`, or `brew-cask`" {
flag "-m --manager" help="Only upgrade packages for this manager, e.g. `apt`, `brew`, `brew-cask`, or `mas`" {
arg <MANAGER> {
choices apt brew brew-cask dnf pacman
choices apt brew brew-cask dnf mas pacman
}
}
flag "-n --dry-run" help="Print the commands that would run without running them"
Expand All @@ -475,12 +477,12 @@ Versions are pinned with `@`: `mise bootstrap packages use apt:curl@8.5.0-2`. Wi
`@` (or with `@latest`) no pin is written. brew formulae and casks
version through their names instead (for example `brew:postgresql@17`,
`brew-cask:temurin@17`), where `@` is part of the Homebrew name rather than
a mise version selector.
a mise version selector. mas uses numeric ADAM IDs and does not support pins.
"""#
after_long_help #"""
Examples:

$ mise bootstrap packages use apt:curl brew:jq brew-cask:firefox
$ mise bootstrap packages use apt:curl brew:jq brew-cask:firefox mas:497799835
$ mise bootstrap packages use -g brew:postgresql@17
$ mise bootstrap packages use apt:curl@8.5.0-2

Expand Down
6 changes: 3 additions & 3 deletions src/cli/system/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ pub struct SystemInstall {
#[clap(value_name = "PACKAGE")]
packages: Vec<String>,

/// Only install packages for this manager, e.g. `apt`, `brew`, or `brew-cask`
#[clap(long, short, value_parser = ["apt", "brew", "brew-cask", "dnf", "pacman"])]
/// Only install packages for this manager, e.g. `apt`, `brew`, `brew-cask`, or `mas`
#[clap(long, short, value_parser = ["apt", "brew", "brew-cask", "dnf", "mas", "pacman"])]
manager: Option<String>,

/// Print the commands that would run without running them
Expand Down Expand Up @@ -195,7 +195,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!(
r#"<bold><underline>Examples:</underline></bold>

$ <bold>mise bootstrap packages install</bold>
$ <bold>mise bootstrap packages install apt:curl brew:jq brew-cask:firefox</bold>
$ <bold>mise bootstrap packages install apt:curl brew:jq brew-cask:firefox mas:497799835</bold>
$ <bold>mise bootstrap packages install --dry-run</bold>
$ <bold>mise bootstrap packages install --manager apt --yes</bold>
"#
Expand Down
Loading
Loading