Metadata-Version: 2.4
Name: mpy-cli
Version: 2.0.0
Summary: MicroPython interactive deployment CLI based on mpremote
License-Expression: GPL-3.0-only
Project-URL: Homepage, https://github.com/LanternCX/mpy-cli
Project-URL: Repository, https://github.com/LanternCX/mpy-cli
Project-URL: Issues, https://github.com/LanternCX/mpy-cli/issues
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mpremote>=1.24.0
Requires-Dist: questionary>=2.0.1
Requires-Dist: rich>=13.7.0
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
Provides-Extra: dev
Requires-Dist: pyright>=1.1.407; extra == "dev"
Requires-Dist: pytest>=7.4.0; extra == "dev"
Dynamic: license-file

# mpy-cli

`mpy-cli` 是一个面向 MicroPython 的交互式部署工具，用于将本地代码上传到 MicroPython 端。

支持能力：

- 增量部署（基于 `git diff` 文件集，仅上传修改部分）
- 全量部署（清空设备文件根目录后重刷）
- `.mpyignore` 忽略规则，类似 `.gitignore`
- 萌新以及跨平台友好的交互式命令行操作

---

## Quick Start

如果你是第一次使用本项目，可以遵循以下步骤。

阅读完本章之后，建议继续阅读 [在其他项目中安装为命令行工具](#install)

### 0) 环境要求

- Python 版本：`>= 3.10`（推荐 `3.11`）
- 已安装 `uv`（推荐）
- 已安装 Git
- 开发机可访问 MicroPython 设备串口

可先检查工具版本：

```bash
uv --version
python3 --version
```

### 1) 克隆仓库

```bash
git clone https://github.com/LanternCX/mpy-cli.git
cd mpy-cli
```

### 2) 安装依赖

推荐使用 `uv`：

```bash
uv sync --extra dev
```

也可以使用 Python 自带虚拟环境：

```bash
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -e ".[dev]"
```

### 3) 运行测试

使用 `uv`：

```bash
uv run pytest -q
```

使用已激活的虚拟环境：

```bash
python3 -m pytest -q
```

### 4) 运行 LSP 检查

使用 `uv`：

```bash
uv run pyright
```

使用已激活的虚拟环境：

```bash
pyright
```

### 5) 初始化项目

使用 `uv`：

```bash
uv run mpy-cli init
```

`init` 会进入交互式配置向导（可扫描设备端口并选择），无需手动编辑配置文件。

如果已经激活 `.venv`，也可以直接使用 `mpy-cli`。

在 `plan/deploy` 交互模式下，如果未提供 `--port`，会自动扫描可用端口并提示选择。

初始化后会生成：

- `.mpy-cli.toml`
- `.mpyignore`
- `.mpy-cli/`（运行目录）

详细参数参见[CLI 参数总览](#cli-params)

### 6) 后续重配（可选）

如果你后续想修改端口、同步模式、运行目录、设备上传目录等配置，直接执行：

```bash
mpy-cli config
```

详细参数参见[CLI 参数总览](#cli-params)

### 7) 计划部署

如果你还不确定当前有哪些可连接的 MicroPython 设备，可以先执行：

```bash
mpy-cli list
```

该命令会扫描串口并探测可访问的 MicroPython 设备，输出所有可用设备的端口与基础信息。

预览部署操作，防止程序产生意料之外的行为

```bash
mpy-cli plan
```

详细参数参见[CLI 参数总览](#cli-params)

### 8) 部署到 MicroPython 端

预览部署操作，防止程序产生意料之外的行为

```bash
mpy-cli deploy
```

详细参数参见[CLI 参数总览](#cli-params)

如果后续想要进行无交互式的部署，可以执行

```bash
mpy-cli deploy --no-interactive --yes
```

---

<span id="install"></span>
## 在其他项目中安装为命令行工具

推荐直接从 PyPI 安装：

```bash
python3 -m pip install mpy-cli
```

也可以使用 `uv` 安装为独立命令行工具：

```bash
uv tool install mpy-cli
```

从源码安装时，推荐使用目标项目自己的虚拟环境：

- `TARGET_PROJECT_PATH`: 你要安装并使用 mpy-cli 的目标项目目录
- `SOURCE_MPY_CLI_PATH`: 本地 mpy-cli 源码仓库路径（作为安装源）

```bash
cd <TARGET_PROJECT_PATH>
uv venv
source .venv/bin/activate

# 从源码安装 mpy-cli
uv pip install <SOURCE_MPY_CLI_PATH>
```

也可以使用 Python 自带虚拟环境：

```bash
cd <TARGET_PROJECT_PATH>
python3 -m venv .venv
source .venv/bin/activate

# 从源码安装 mpy-cli
python3 -m pip install <SOURCE_MPY_CLI_PATH>
```

安装后可直接在该项目环境中使用：

```bash
mpy-cli -h
mpy-cli init
mpy-cli config
mpy-cli list
mpy-cli plan
mpy-cli deploy
mpy-cli upload
mpy-cli run
mpy-cli delete
mpy-cli tree
```

源码安装说明：

- 上面是“普通安装”（固定当前代码版本）。
- 如果你希望 `mpy-cli` 代码改动后立即生效，可改用可编辑安装：

```bash
uv pip install -e <SOURCE_MPY_CLI_PATH>
```

或：

```bash
python3 -m pip install -e <SOURCE_MPY_CLI_PATH>
```

---

<span id="cli-params"></span>
## CLI 参数总览

下面列出当前可用命令和参数，便于查阅。

### `mpy-cli init`

```bash
mpy-cli init [-f] [--force] [-n] [--no-interactive]
```

- `-f`/`--force`：覆盖已有 `.mpy-cli.toml` 和 `.mpyignore`。
- `-n`/`--no-interactive`：跳过初始化后的交互配置向导。

### `mpy-cli config`

```bash
mpy-cli config
```

- 无额外参数。
- 进入交互式配置向导，更新 `.mpy-cli.toml`。

常用配置项说明：

- `source_dir`：本地源码根目录。`plan/deploy` 计算远端路径时以该目录为根，不保留 `source_dir` 前缀。
- `.mpyignore`：规则匹配对象为“相对 `source_dir` 的路径”。
- 当 `source_dir = "src"` 时，本地 `src/main.py` 对应远端 `:main.py`。
- 若历史 `.mpyignore` 规则包含 `src/...` 前缀，需迁移为相对 `source_dir` 的写法。
- `device_upload_dir`：设备端上传目录前缀，留空表示设备根目录。
- 当 `device_upload_dir = "apps/demo"` 时，本地 `main.py` 会上传到设备 `:apps/demo/main.py`。
- `full` 模式会清空该上传目录，而不是整机设备根目录。
- `compile_mpy`：默认是否启用主机侧 `mpy-cross` 交叉编译上传，默认 `false`。
- `keep_py`：当 `compile_mpy = true` 时，哪些相对 `source_dir` 的路径继续保留源码上传，使用逗号分隔在向导中填写。
- `mpy_cross_binary`：`mpy-cross` 命令名，默认 `mpy-cross`。
- `mpy_emit_policy`：默认最高 emitter 策略，支持 `bytecode`、`native`、`viper`，默认 `bytecode`；`native` 会按 `native`、`bytecode` 顺序尝试，`viper` 会按 `viper`、`native`、`bytecode` 顺序尝试。
- `mpy_cross_arch`：`native` / `viper` 使用的目标架构，留空表示不传 `-march`。

### `mpy-cli plan`

```bash
mpy-cli plan [-m {incremental,full}] [--mode {incremental,full}] [-b BASE] [--base BASE] [-p PORT] [--port PORT] [-c {on,off}] [--compile-mpy {on,off}] [-k PATH] [--keep-py PATH] [--emit-policy {bytecode,native,viper}] [--mpy-cross-arch ARCH] [-n] [--no-interactive] [-y] [--yes]
```

- `-m`/`--mode`：指定同步模式（`incremental` 或 `full`）。
- `-b`/`--base`：仅在 `incremental` 模式生效，指定 Git 基准提交；增量集合按“该基准提交 vs 当前工作区”计算。
- `-p`/`--port`：指定设备端口（如 `/dev/ttyACM0` 或 `COM3`）。
- `-c`/`--compile-mpy`：设置本次是否启用主机侧 `mpy-cross` 交叉编译，取值 `on` 或 `off`；不传时回退到配置文件中的 `compile_mpy`。
- `-k`/`--keep-py`：声明本次继续保留源码上传的相对 `source_dir` 路径，可重复传入；只有在 `compile_mpy = on` 时生效。
- `--emit-policy`：设置本次 `mpy-cross` 默认最高 emitter 策略，取值 `bytecode`、`native` 或 `viper`；不传时回退到配置文件中的 `mpy_emit_policy`。
- `--mpy-cross-arch`：设置本次 `native` / `viper` 的 `-march` 目标架构；不传时回退到配置文件中的 `mpy_cross_arch`。
- `-n`/`--no-interactive`：禁用交互提问。
- `-y`/`--yes`：保留参数；在 `plan` 中不会触发写入确认流程。

当开启 `compile_mpy` 后，`plan` 展示的是板端最终会出现的 `.py` / `.mpy` 文件以及兼容性清理动作，而不是本地源码原样列表。

### `mpy-cli list`

```bash
mpy-cli list [-w N] [--workers N] [-t SECONDS] [--probe-timeout SECONDS] [-s MODE] [--scan-mode MODE] [-r] [--reset]
```

- `-w`/`--workers`：并发探测线程数，默认 `8`；当扫描到很多端口时可提升返回速度。
- `-t`/`--probe-timeout`：单端口探测超时秒数，默认 `1.0`；慢端口超时后会被跳过，不阻塞全部结果。
- `-s`/`--scan-mode`：端口探测策略，支持 `known-first`、`known-only`、`full-only`，默认 `known-first`。
- `-r`/`--reset`：先清空之前的扫描记录，再立即执行当前这次 `list`。
- 默认会先读取运行时数据库里“上一次扫描成功过”的端口，仅对“成功缓存端口与当前 `mpremote connect list` 交集”做探测；若没有发现设备，再回退到当前可用端口全量探测。
- 该策略兼容 macOS / Linux / Windows：是否“当前可用”以本次 `mpremote connect list` 结果为准，因此 `COM3` 这类 Windows 端口同样可用。
- 自动扫描串口，并对选中的端口进行受控并发探测，返回所有可访问的 MicroPython 设备。
- 若存在 `.mpy-cli.toml`，会优先使用其中的 `mpremote_binary` 配置；否则默认使用 `mpremote`。

推荐用法：

```bash
mpy-cli list
```

当本机串口很多、默认探测较慢时，可按需调高并发并缩短超时：

```bash
mpy-cli list -w 12 -t 1.0
```

如果你想直接忽略缓存、每次都对当前端口全量探测：

```bash
mpy-cli list -s full-only
```

如果你想先清空之前的扫描记录，再做一次全新的 list：

```bash
mpy-cli list -r
```

输出会包含当前探测到的所有可用 MicroPython 设备，例如端口、实现版本、平台与机型信息。

### `mpy-cli deploy`

```bash
mpy-cli deploy [-m {incremental,full}] [--mode {incremental,full}] [-b BASE] [--base BASE] [-p PORT] [--port PORT] [-c {on,off}] [--compile-mpy {on,off}] [-k PATH] [--keep-py PATH] [--emit-policy {bytecode,native,viper}] [--mpy-cross-arch ARCH] [-n] [--no-interactive] [-y] [--yes]
```

- `-m`/`--mode`：指定同步模式（`incremental` 或 `full`）。
- `-b`/`--base`：仅在 `incremental` 模式生效，指定 Git 基准提交；未提供时默认对比 `HEAD` 与当前工作区。
- `-p`/`--port`：指定设备端口。
- `-c`/`--compile-mpy`：设置本次是否启用主机侧 `mpy-cross` 交叉编译，取值 `on` 或 `off`；不传时回退到配置文件中的 `compile_mpy`。
- `-k`/`--keep-py`：声明本次继续保留源码上传的相对 `source_dir` 路径，可重复传入；只有在 `compile_mpy = on` 时生效。
- `--emit-policy`：设置本次 `mpy-cross` 默认最高 emitter 策略，取值 `bytecode`、`native` 或 `viper`；不传时回退到配置文件中的 `mpy_emit_policy`。
- `--mpy-cross-arch`：设置本次 `native` / `viper` 的 `-march` 目标架构；不传时回退到配置文件中的 `mpy_cross_arch`。
- `-n`/`--no-interactive`：禁用交互提问。
- `-y`/`--yes`：跳过执行前确认（包括全量模式二次确认）。

当开启 `compile_mpy` 后，普通 Python 模块会先在主机侧通过 `mpy-cross` 转成 `.mpy` 再上传到板端；被 `keep_py` 命中的路径继续保留源码上传。`native` 策略会先尝试 `native`，失败后回退到普通编译；`viper` 策略会先尝试 `viper`，失败后依次回退到 `native` 和普通编译。源码中的 `@micropython.native` / `@micropython.viper` 由 `mpy-cross` 处理。整个过程不建立目录级缓存，只在单文件上传过程中短暂生成临时 `.mpy` 产物。

推荐用法：

```bash
mpy-cli deploy -n -y
```

进行 `config` 之后直接无交互烧入

如果你希望只保留入口文件源码，其余模块交叉编译后上传：

```bash
mpy-cli deploy -c on -k main.py -n -y
```

如果你希望优先尝试 `viper` / `native`，并在失败时自动回退到普通编译：

```bash
mpy-cli deploy -c on --emit-policy viper --mpy-cross-arch armv7emsp -n -y
```

### `mpy-cli upload`

```bash
mpy-cli upload [-l LOCAL] [--local LOCAL] [-r REMOTE] [--remote REMOTE] [-p PORT] [--port PORT] [-n] [--no-interactive] [-y] [--yes]
```

- `-l`/`--local`：本地文件路径（如 `seekfree_demo/E01_demo.py`）。
- `-r`/`--remote`：设备目标路径；不传时交互模式默认优先使用“相对 `source_dir` 路径”，若本地文件不在 `source_dir` 下则回退为本地输入路径，可手动修改。
- `-p`/`--port`：指定设备端口。
- `-n`/`--no-interactive`：禁用交互提问；此时需显式提供 `--local` 和 `--remote`。
- `-y`/`--yes`：跳过执行前确认。

推荐用法：

```bash
mpy-cli upload -l <LOCAL>
```

填写字段 `LOCAL` 指定本地文件路径之后交互式确认远程路径

### `mpy-cli run`

```bash
mpy-cli run [-f PATH] [--path PATH] [-p PORT] [--port PORT] [-n] [--no-interactive] [-y] [--yes]
```

- `-f`/`--path`：设备目标文件路径，语义为相对 `device_upload_dir`。
- `-p`/`--port`：指定设备端口。
- `-n`/`--no-interactive`：禁用交互提问；此时需显式提供 `--path`。
- `-y`/`--yes`：跳过执行前确认。

推荐用法：

```bash
mpy-cli run -f main.py
```

若配置 `device_upload_dir = "apps/demo"`，则会执行 `:apps/demo/main.py`。

### `mpy-cli delete`

```bash
mpy-cli delete [-f PATH] [--path PATH] [-p PORT] [--port PORT] [-n] [--no-interactive] [-y] [--yes]
```

- `-f`/`--path`：设备目标路径，语义为相对 `device_upload_dir`，可为文件或目录。
- `-p`/`--port`：指定设备端口。
- `-n`/`--no-interactive`：禁用交互提问；此时需显式提供 `--path`。
- `-y`/`--yes`：跳过执行前确认。

推荐用法：

```bash
mpy-cli delete -f obsolete.py
```

若配置 `device_upload_dir = "apps/demo"`，则会删除 `:apps/demo/obsolete.py`。
当 `--path` 指向目录时，默认递归删除整个目录。

### `mpy-cli tree`

```bash
mpy-cli tree [-a PATH] [--path PATH] [-p PORT] [--port PORT] [-n] [--no-interactive]
```

- `-a`/`--path`：设备目标目录路径，语义为相对 `device_upload_dir`；不传时默认读取 `device_upload_dir` 根目录。
- `-p`/`--port`：指定设备端口。
- `-n`/`--no-interactive`：禁用交互提问；此时需通过 `--port` 或配置文件提供端口。

推荐用法：

```bash
mpy-cli tree -a .
```

若配置 `device_upload_dir = "apps/demo"`，则默认读取 `:apps/demo`；例如 `--path services` 会读取 `:apps/demo/services`。

---

## 常见问题

### 1) `mpremote` 找不到

```bash
uv pip install mpremote
```

或：

```bash
python3 -m pip install mpremote
```

### 2) 串口连接失败或者烧录报错

- 检查串口号（如 `/dev/ttyACM0`、`COM3`）
- 关闭占用串口的软件（如 Thonny）

### 3) 我不确定会同步哪些文件

先执行 `mpy-cli plan ...` 查看计划，再执行 `deploy`。

### 4) 我不知道串口号

参见 Thonny 中的设备串口号（圆括号内的内容）。

### 5) 为什么选择 mpy-cli？

搭配 stubs，例如在智能车竞赛中使用我的项目[micropython-smartcar-stubs](https://github.com/LanternCX/micropython-smartcar-stubs)。

可以实现完全无 thonny 开发 MicroPython 项目。

---

## Contribute

开发与规范说明：`docs/developer-guide.md`

本仓库采用 GPL-3.0 协议开源。

如果你将本仓库代码或其中的部分实现用于竞赛、课程项目、科研展示或商业实践，并因此获得奖项、奖金或其他收益，欢迎开源你的相关代码、注明本项目来源，或通过 Star、Issue、PR 等方式参与社区共建。
