Metadata-Version: 2.5
Name: tclake-cli
Version: 0.0.4
Summary: Command-line tool for Tencent Cloud TCLake
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# tclake-cli

腾讯云 TCLake 命令行工具。通过 `tccatalog` 云 API 查询 Lakehouse / Volume 元数据，并借助 [rclone](https://rclone.org) 在本地与 Volume 之间收发文件。

- 元数据查询只依赖 Python 标准库（Python ≥ 3.8），没有第三方运行时依赖。
- 文件传输（`volume list` 列卷内文件、`volume cp`）需要本机安装 rclone。
- 临时 COS 密钥会在过期前自动刷新，长时间传输不会中断；中断后重跑同一条命令即可从断点继续。

## 目录

- [功能一览](#功能一览)
- [安装](#安装)
- [快速开始](#快速开始)
- [配置与凭证](#配置与凭证)
- [全局参数](#全局参数)
- [路径规则](#路径规则)
- [命令详解](#命令详解)
- [输出格式](#输出格式)
- [退出码](#退出码)
- [常见问题](#常见问题)
- [安全说明](#安全说明)

## 功能一览

| 命令 | 作用 | 依赖 |
| --- | --- | --- |
| `tclake init` | 写入 SecretId / SecretKey / 地域 / 云 API 域名 | — |
| `tclake lakehouse list [路径]` | 列出 lakehouse catalog、schema、table | 云 API |
| `tclake lakehouse describe <路径>` | 查看 catalog / schema / table 详情（含列信息） | 云 API |
| `tclake volume list [路径]` | 列出 volume catalog、schema、volume；路径到 volume 及以下时列出卷内文件 | 云 API；卷内文件需 rclone |
| `tclake volume describe <路径>` | 查看 catalog / schema / volume 详情（含 `StorageLocation`） | 云 API |
| `tclake volume credentials <c.s.v>` | 获取 volume 的临时 COS 密钥 | 云 API |
| `tclake volume cp <源> <目标>` | 本地 ⇄ volume 拷贝文件或目录，自动刷新临时密钥 | rclone |

## 安装

### 安装 tclake-cli

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

安装后即可使用 `tclake` 命令；如果提示找不到命令，请把 pip 的用户 bin 目录（通常是 `~/.local/bin`）加入 `PATH`。

### 安装 rclone（文件传输需要）

| 平台 | 命令 |
| --- | --- |
| macOS（推荐） | `brew install rclone` |
| Linux / macOS | `curl https://rclone.org/install.sh \| sudo bash` |
| 其他 | <https://rclone.org/downloads/> |

建议使用 **rclone ≥ 1.68**：这些版本支持「不重启 rclone 刷新凭证」（见 [凭证刷新](#凭证刷新---refresh)）。更老的版本也能用，会自动退回「重启 rclone」方式。检查版本：

```bash
rclone version
```

未安装 rclone 时，`volume cp` 和卷内 `volume list` 会直接报错并提示安装命令（退出码 2），不会发出任何云 API 请求。

## 快速开始

```bash
# 1. 配置密钥（交互输入，不回显）
tclake init

# 2. 查询元数据
tclake lakehouse list                         # lakehouse catalog
tclake lakehouse list sales.db1               # sales.db1 下的表
tclake lakehouse describe sales.db1.orders    # 表详情和列

tclake volume list                            # volume catalog
tclake volume list volc.db1                   # volc.db1 下的 volume
tclake volume describe volc.db1.raw           # volume 详情

# 3. 文件操作（需 rclone）
tclake volume list volc.db1.raw               # 卷根目录下的文件
tclake volume cp ./data volc.db1.raw          # 上传
tclake volume cp volc.db1.raw/2026 ./out      # 下载
```

## 配置与凭证

### tclake init

```bash
tclake init                                   # 交互式
tclake init --profile prod                    # 写入名为 prod 的配置档
tclake init --secret-id AKIDxxxx --secret-key xxxx --region ap-shanghai   # 非交互，适合脚本/CI
```

| 参数 | 说明 |
| --- | --- |
| `--secret-id` | 腾讯云 SecretId；不给则交互输入（不回显，已有值只显示掩码，回车保留） |
| `--secret-key` | 腾讯云 SecretKey；不给则交互输入（不回显） |
| `--region` | 地域，如 `ap-guangzhou`、`ap-shanghai`；[地域列表](https://cloud.tencent.com/document/buy-guide/240/3637) |
| `--endpoint` | 云 API 域名，默认 `tccatalog.<region>.tencentcloudapi.com`，测试环境才需要改 |

`--secret-id`、`--secret-key`、`--region` 三者都给出时不再提问；只给一部分时，缺的项继续交互输入。

### 配置文件

```text
~/.tclake/config          # [profile] region、endpoint
~/.tclake/credentials     # [profile] secret_id、secret_key、token（可选）
```

两个文件权限 `0600`，目录 `0700`。凭证文件已存在且权限宽于 `0600` 时，`init` 拒绝写入并提示 `chmod 600`。设置环境变量 `TCLAKE_HOME` 可以把 `~/.tclake` 换到其他目录。

只有 endpoint 与地域默认域名不同时才写入 `config`，所以之后用 `--region` 切换地域时，域名会跟着变。

### 生效优先级

从高到低：

1. 命令行 `--region` / `--endpoint`（只覆盖地域和域名）
2. 环境变量
3. `--profile` 指定的配置档（默认 `default`）

| 环境变量 | 说明 |
| --- | --- |
| `TENCENTCLOUD_SECRET_ID` / `TENCENTCLOUD_SECRET_KEY` | 永久密钥 |
| `TENCENTCLOUD_TOKEN` | 可选，STS 临时密钥的 token（会以 `X-TC-Token` 头参与请求） |
| `TENCENTCLOUD_REGION` | 地域 |
| `TENCENTCLOUD_ENDPOINT` | 云 API 域名 |

这些变量名与 TCLake 文件系统客户端一致，同一台机器上可以共用一套密钥。找不到 SecretId / SecretKey 时，命令提示先执行 `tclake init`，退出码 2，不会弹出交互。

## 全局参数

全局参数写在 `tclake` 和子命令之间，例如 `tclake --profile prod volume list`。

| 参数 | 说明 |
| --- | --- |
| `--profile NAME` | 使用的配置档，默认 `default` |
| `--region REGION` | 覆盖地域；同时决定默认的云 API 域名和 COS 域名 |
| `--endpoint HOST` | 覆盖云 API 域名（测试环境） |
| `--output table\|json` | 输出格式，默认 `table`；`list` / `describe` / `credentials` 后也可写 `-o json` |
| `--name-pattern PATTERN` | `list` 的名称过滤，写在 `tclake` 后或 `list` 子命令后均可。catalog / schema / table / volume 名称用 SQL LIKE 语法（`%` 任意多个字符，`_` 单个字符），卷内文件用 glob（`*`） |
| `--type TYPE` | 只对不带路径的 `list` 生效，覆盖默认 catalog 类型过滤，可重复；写在 `tclake` 后或 `list` 后均可 |
| `--debug` | 向 stderr 打印 Action、RequestId、耗时、rclone 命令行（不含密钥） |
| `--version` | 打印版本 |

## 路径规则

catalog、schema、table / volume 之间用 `.` 分隔，名称本身不能包含 `.`。**路径的段数决定查询的是哪一级**，命令里不需要写 `catalog`、`schema` 之类的字面量：

| 段数 | 示例 | `list` 列出 | `describe` 查看 |
| --- | --- | --- | --- |
| 0 | （空） | catalog | — |
| 1 | `sales` | schema | catalog |
| 2 | `sales.db1` | table / volume | schema |
| 3 | `sales.db1.orders` | 卷内文件（仅 volume） | table / volume |

volume 路径后面可以用 `/` 接卷内子路径：`volc.db1.raw/2026/10/a.csv`。子路径里的多余 `/` 会被规范化，`.` 和 `..` 会被拒绝，避免越出卷的存储前缀。

## 命令详解

### lakehouse list / describe

```bash
tclake lakehouse list                         # 列出 lakehouse catalog（默认 Types=[LAKEHOUSE]）
tclake lakehouse list --type DLC              # 列出 DLC 类型 catalog
tclake lakehouse list sales                   # sales 下的 schema
tclake lakehouse list sales.db1               # sales.db1 下的表
tclake --name-pattern 'order%' lakehouse list sales.db1   # 名称过滤（SQL LIKE）
tclake lakehouse list sales.db1 --name-pattern 'order%'   # 同上，过滤器放在子命令后也可以

tclake lakehouse describe sales               # catalog：Name, Type, Provider, Comment
tclake lakehouse describe sales.db1           # schema：Name, Comment
tclake lakehouse describe sales.db1.orders    # table：Name, TableType, TableFormat, Comment + 列 + 属性
```

`--type` 取值是管控面的 catalog 类型：`LAKEHOUSE`、`VOLUME`、`MODEL`、`DLC`、`TCC-HIVE` 等。

### volume list

```bash
tclake volume list                            # volume catalog（默认 Types=[VOLUME]）
tclake volume list volc                       # volc 下的 schema
tclake volume list volc.db1                   # volc.db1 下的 volume
tclake volume list volc.db1 --name-pattern 'raw%'        # SQL LIKE

# 以下列卷内文件，需 rclone
tclake volume list volc.db1.raw               # 卷根目录（只列一层）
tclake volume list volc.db1.raw/2026 -R       # 递归列出 2026/ 下所有文件
tclake volume list volc.db1.raw -R --name-pattern '*.csv'   # 卷内文件用 glob
tclake volume list volc.db1.raw -o json
```

| 参数 | 说明 |
| --- | --- |
| `path` | 见 [路径规则](#路径规则)；三段及以上时列卷内文件 |
| `-R, --recursive` | 递归列出，只对卷内路径有效 |
| `--name-pattern PATTERN` | 前两级传给云 API，SQL LIKE 语法（`raw%`）；卷内文件作为 rclone `--include` 的 glob（`*.csv`，匹配相对路径） |
| `--cos-endpoint HOST` | 覆盖 COS 域名，默认 `cos.<region>.myqcloud.com` |
| `-o, --output` | `table` 或 `json` |

卷内文件的表格输出：

```text
NAME          SIZE      MODIFIED
2026/         -
a.csv         2.5 KiB   2026-10-20 13:22:32
```

目录以 `/` 结尾；`MODIFIED` 是对象在 COS 上的最后修改时间，按本地时区显示。`-o json` 输出 `{"StorageLocation": "...", "Files": [...]}`，`Files` 是 `rclone lsjson` 的原始条目（`Path`、`Size`、`ModTime`、`IsDir` 等）。

### volume describe

```bash
tclake volume describe volc                   # catalog
tclake volume describe volc.db1               # schema
tclake volume describe volc.db1.raw           # volume：Name, Type, StorageLocation, Comment + 属性
```

`StorageLocation`（如 `cosn://bucket/prefix`）就是该 volume 在 COS 上的实际位置。

### volume credentials

```bash
tclake volume credentials volc.db1.raw
tclake volume credentials volc.db1.raw -o json | jq -r '.Credentials[0].ExpireTimeInMs'
```

输出该 volume 的临时 COS 密钥（`AccessKeyId`、`SecretAccessKey`、`SessionToken` 全部明文，以及 `ExpireTimeInMs`，有效期约 12 小时），同时往 stderr 打印一行提醒。密钥是要交给 rclone / SDK 使用的，所以不做掩码；请勿重定向保存。

| 参数 | 说明 |
| --- | --- |
| `--credential-process` | 按 AWS `credential_process` 格式输出 JSON，供 `volume cp` 内部使用（见 [凭证刷新](#凭证刷新---refresh)） |
| `--margin SECONDS` | 搭配 `--credential-process`：把上报的 `Expiration` 提前多少秒，默认 600 |

### volume cp

在本地和 volume 之间拷贝文件或目录。**源和目标中必须恰好有一个是 volume 路径**，方向由此判断：

```bash
# 上传
tclake volume cp ./data volc.db1.raw                    # ./data 目录的内容 -> 卷根目录
tclake volume cp ./a.csv volc.db1.raw/2026/10           # 单文件 -> 卷内 2026/10/a.csv
tclake volume cp ./data volc.db1.raw/backup -t 32       # 32 个文件并行

# 下载
tclake volume cp volc.db1.raw ./out                     # 整个卷 -> ./out
tclake volume cp volc.db1.raw/2026 ./out                # 卷内 2026/ 的内容 -> ./out
tclake volume cp volc.db1.raw/2026/10/a.csv ./out       # 单文件 -> ./out/a.csv

# 透传 rclone 参数（-- 之后原样交给 rclone copy）
tclake volume cp ./data volc.db1.raw -- --dry-run       # 只演练，不传
tclake volume cp ./data volc.db1.raw -- --bwlimit 50M --exclude '*.tmp'

# 指定配置档 / 地域
tclake --profile prod --region ap-shanghai volume cp ./data volc.db1.raw
```

| 参数 | 默认 | 说明 |
| --- | --- | --- |
| `src` | — | 本地文件/目录，或 `<catalog>.<schema>.<volume>[/<path>]` |
| `dst` | — | 本地目录，或 `<catalog>.<schema>.<volume>[/<path>]` |
| `-t, --transfers N` | 16 | 并行传输的文件数（rclone `--transfers`） |
| `--refresh MODE` | `auto` | 凭证刷新方式：`auto` / `process` / `restart`，见下文 |
| `--margin SECONDS` | 600 | 在临时密钥过期前多少秒刷新 |
| `--max-retry N` | 5 | rclone 连续失败、或获取凭证连续失败多少次后放弃 |
| `--cos-endpoint HOST` | `cos.<region>.myqcloud.com` | 覆盖 COS 域名（例如 bucket 不在 `--region` 地域，或走内网域名） |
| `-- ...` | — | 之后的所有参数原样透传给 `rclone copy` |

stdout 是终端时自动加上 rclone 的 `--progress` 显示进度；重定向到文件或管道时不加。

#### 拷贝语义

- 采用 `rclone copy` 语义：**目标一律视为目录**。拷贝目录时拷的是目录*内容*；拷贝单个文件时，文件放进目标目录，保留原文件名（暂不支持改名）。
- 只新增或覆盖，不会删除目标端多出来的文件。
- 目标端已存在、且大小和修改时间都相同的文件会被跳过。

#### 本地路径与 volume 路径的区分

`data.tar.gz` 这类文件名也是三段点分，判断规则如下：

1. 以 `/`、`.`、`~` 开头的一定是本地路径；
2. 本地存在的路径按本地处理（所以 `data.tar.gz` 仍然是文件）；
3. 其余形如 `a.b.c[/...]` 的按 volume 路径处理。

下载到一个尚不存在、名字又像 `a.b.c` 的本地目录时，请写成 `./a.b.c`。两边都是 volume 时报错（暂不支持 volume 之间直接拷贝）。

#### 凭证刷新（`--refresh`）

volume 的临时 COS 密钥有效期约 12 小时。为了让长时间传输不中断，有两种刷新方式：

| 模式 | 原理 | 要求 | 特点 |
| --- | --- | --- | --- |
| `process` | rclone 用 `env_auth` 读取一个临时生成的 AWS 配置，里面配置了 `credential_process = <python> -m tclake_cli ... volume credentials <c.s.v> --credential-process`。rclone 内置的 AWS SDK 在上报的过期时间（真实过期时间减 `--margin`）到达前，会自动重新执行这条命令换取新密钥 | rclone ≥ 1.68 | rclone 全程不重启，传输中的文件不会被打断，单个文件的传输时长也不受密钥有效期限制 |
| `restart` | rclone 用静态密钥运行；到「过期时间减 `--margin`」时，tclake 先发 SIGINT 停掉 rclone（30 秒后仍未退出则 SIGTERM，再 30 秒后 SIGKILL），重新获取密钥后再启动 rclone | 任意版本 | 已传完的文件会跳过，只重传当时正在传输的文件；单个文件必须在约 11 小时 50 分钟内传完 |
| `auto`（默认） | rclone ≥ 1.68 时用 `process`，否则用 `restart` | — | — |

开始传输时，日志会打印实际使用的模式，例如 `credential refresh: process`。`--refresh process` 遇到老版本 rclone 时直接报错，提示升级 rclone 或改用 `restart`。

`process` 模式说明：

- 启动 rclone 前先在 tclake 进程里取一次密钥，提前暴露权限、配置问题；
- 生成的 AWS 配置放在临时目录（`0700` / `0600`），只包含命令行、不含任何密钥，传输结束后删除；
- rclone 子进程环境里的 `AWS_*` 凭证变量会被清掉，避免本机已有的 AWS 配置抢先生效；
- `credential_process` 子进程本身就是一次普通的 tclake 调用，会按 `--profile`、`--region`、`--endpoint`、环境变量、`~/.tclake` 的同样规则解析永久密钥。

#### 失败重试与断点续传

- rclone 以下列退出码结束时不重试，tclake 直接以退出码 4 结束：2（参数错误）、3/4（目录/文件不存在）、7（致命错误）、8/10（超出传输量/时长限制）、9（没有文件需要传输）。
- 其他非 0 退出码：重新获取密钥后重启 rclone；连续失败 `--max-retry` 次后放弃（退出码 4）。`restart` 模式下按计划轮换密钥不计入失败次数。
- 获取密钥失败（网络、云 API 错误）每 10 秒重试一次，最多 `--max-retry` 次。
- Ctrl-C：先停掉 rclone 再退出（退出码 130）。**重跑同一条命令即可续传**，已传完的文件会被跳过。
- 续传以文件为单位：中断时正在传输的文件会从头重传，不支持单个文件的分片续传。

## 输出格式

- 成功结果输出到 stdout，提示和错误输出到 stderr，因此 stdout 可以放心接管道。
- `table`：等宽对齐表格（默认）。
- `json`：完整的云 API `Response` 对象（含 `RequestId`），缩进格式化。

```bash
tclake lakehouse list -o json | jq -r '.CatalogNames[].Name'
tclake lakehouse list sales.db1 -o json | jq -r '.TableNames[].Name'
tclake lakehouse describe sales.db1.orders -o json | jq '.Table.Columns[] | {Name, Type, Comment}'
tclake volume describe volc.db1.raw -o json | jq -r '.Volume.StorageLocation'
tclake volume list volc.db1.raw -R -o json | jq -r '.Files[] | select(.IsDir | not) | .Path'
```

## 退出码

| 退出码 | 含义 |
| --- | --- |
| 0 | 成功 |
| 1 | 云 API 业务错误（stderr 打印 Code、Message、RequestId） |
| 2 | 本地参数、路径或配置错误，或未安装 rclone；不会发出请求 |
| 3 | 网络错误或超时 |
| 4 | rclone 传输失败（不可重试的退出码，或重试次数用完） |
| 130 | 被 Ctrl-C 中断 |

## 常见问题

**提示 `rclone not found on PATH`**
按 [安装 rclone](#安装-rclone文件传输需要) 安装。macOS 用 `brew install rclone`。

**想先看看会传哪些文件**
加 `-- --dry-run`。

**bucket 和 `--region` 不在同一地域，或要走内网**
用 `--cos-endpoint` 指定 COS 域名，例如 `--cos-endpoint cos.ap-beijing.myqcloud.com`。

**百万级小文件重跑太慢**
重跑时 rclone 要逐个比较目标端文件。可以透传 `-- --size-only`（只比较大小）或 `-- --fast-list` 减少请求数。

**单个文件很大（数 TB）**
使用 `--refresh process`（rclone ≥ 1.68），它没有单文件时长限制。`restart` 模式下，单个文件必须在一个密钥周期内传完。

**中断后 COS 上残留未完成的分片**
rclone 收到 SIGINT 时会尽量清理。仍有残留时，建议给 bucket 配置「清理未完成分片上传」的生命周期规则。

**想看 tclake 实际执行的 rclone 命令**
加全局参数 `--debug`，会打印 rclone 命令行和 `credential_process` 命令（都不包含密钥）。

## 安全说明

- 永久密钥只存在 `~/.tclake/credentials`（`0600`）或环境变量中，`--help`、错误信息、`--debug` 日志都不会回显 SecretKey。
- 临时密钥通过环境变量或 `credential_process` 管道交给 rclone，不会出现在 rclone 的命令行参数里（`ps` 看不到），日志里只打印 AccessKeyId 的前 8 位。
- `restart` 模式下，rclone 子进程的环境里会去掉 `TENCENTCLOUD_SECRET_ID/KEY/TOKEN`；`process` 模式需要保留它们，因为 `credential_process` 子进程要用它们获取新密钥。
- tclake 不会替你执行 rclone 安装脚本（需要 sudo），只提示安装命令。
- `volume credentials` 会明文输出临时密钥，请勿保存到文件或与永久密钥放在一起。
