Metadata-Version: 2.4
Name: shellus-acr-sync
Version: 0.2.1
Summary: Sync local Docker images to private registries with reversible image names
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: pyyaml>=6.0
Description-Content-Type: text/markdown

# ACR Sync

`acr-sync` 是一个 Docker 镜像同步 CLI。它按 YAML 清单把本地镜像推送到一个或多个私有镜像仓库，并可在目标机器拉取后恢复为原始镜像名。

适合把零散依赖镜像同步到 ACR、CCR 或其他兼容 Docker Registry 的仓库，用于跨机器迁移、离线部署前准备、国内外镜像源切换等场景。

## 特性

- **清单驱动**：`push`、`pull`、`plan`、`export` 只处理 `images.sync` 中的镜像。
- **多远端配置**：通过 `default` 选择默认远端，也可用 `--remote` 临时切换。
- **共享镜像清单**：多组远端共用同一份 `images.sync` / `images.exclude`。
- **可逆命名**：远端仓库名通过十六进制编码保存原始 repository，可无损恢复。
- **显式发现**：`detect` 可扫描运行中容器或本机镜像，并按需写回配置。
- **安全配置**：支持 `password_file`，避免把密码写入配置文件。

## 安装

```bash
python3 -m pip install -e .
```

未安装时可直接运行：

```bash
PYTHONPATH=src python3 -m acr_sync --help
```

## 快速开始

复制示例配置：

```bash
mkdir -p ~/.acr-sync
cp config.example.yaml ~/.acr-sync/config.yaml
```

编辑 `~/.acr-sync/config.yaml` 后预览同步计划：

```bash
acr-sync plan
```

推送镜像：

```bash
acr-sync push
```

在目标机器拉取并恢复原始镜像名：

```bash
acr-sync pull
```

> `acr-sync` 默认从 `~/.acr-sync/config.yaml` 读取配置。该文件通常包含账号或密码，不应放进 Git 仓库。

## 配置

```yaml
default: tencent

registries:
  tencent:
    registry: ccr.ccs.tencentyun.com
    namespace: your-namespace
    repository_name_max_length:
    auth:
      username: your-account@example.com
      password: ""
      password_file: ""
      skip_login: false

paths:
  export_dir: .

behavior:
  keep_remote_tag: false
  encoding_prefix: r-

images:
  sync:
    - redis:latest
    - shellus/nginx:latest

  exclude:
    - postgres:15
```

### 远端仓库

`registries` 可配置多组远端：

```yaml
default: tencent

registries:
  tencent:
    registry: ccr.ccs.tencentyun.com
    namespace: your-namespace
    auth:
      username: your-account
      password_file: /path/to/password

  aliyun:
    registry: registry.cn-hangzhou.aliyuncs.com
    namespace: your-namespace
    repository_name_max_length: 64
    auth:
      username: your-account
      password_file: /path/to/password
```

切换默认远端：

```yaml
default: aliyun
```

单次命令临时切换远端：

```bash
acr-sync --remote aliyun plan
acr-sync --remote aliyun push
acr-sync --remote tencent pull
```

> 旧版顶层 `registry` / `namespace` 配置不再支持。

### 配置字段

| 字段 | 说明 |
|------|------|
| `default` | 默认远端名称，必须存在于 `registries` |
| `registries.<name>.registry` | 镜像仓库地址，不包含协议前缀 |
| `registries.<name>.namespace` | 镜像仓库命名空间 |
| `registries.<name>.repository_name_max_length` | 远端仓库名最大长度；超限时使用可逆短编码 |
| `registries.<name>.auth.username` | `docker login` 用户名 |
| `registries.<name>.auth.password` | `docker login` 密码 |
| `registries.<name>.auth.password_file` | 密码文件路径，优先于 `password` |
| `registries.<name>.auth.skip_login` | 跳过内置 `docker login` |
| `paths.export_dir` | `export` 默认导出目录 |
| `behavior.keep_remote_tag` | 推送或拉取后保留远端长标签 |
| `behavior.encoding_prefix` | 远端仓库名前缀，默认 `r-` |
| `images.sync` | 需要同步的镜像清单 |
| `images.exclude` | `detect` 时排除的镜像清单 |

## 命令

### 预览

```bash
acr-sync plan
acr-sync plan --check-local
acr-sync --remote aliyun plan
```

### 推送

```bash
acr-sync --dry-run push
acr-sync push
acr-sync push redis:latest
acr-sync push --allow-unlisted redis:latest
acr-sync push --ignore-missing
```

### 拉取

```bash
acr-sync --dry-run pull
acr-sync pull
acr-sync pull shellus/nginx:latest
acr-sync pull --allow-unlisted redis:latest
```

### 发现镜像

```bash
acr-sync detect
acr-sync detect --all
acr-sync detect --write
acr-sync detect --all --write
```

### 导出镜像

```bash
acr-sync export
acr-sync export -o /path/to/output
```

### 编解码

```bash
acr-sync encode shellus/nginx
acr-sync decode 7368656c6c75732f6e67696e78
```

## 命名规则

远端镜像名格式：

```text
<registry>/<namespace>/<encoding_prefix><hex(repository)>:<tag>
```

示例：

```text
shellus/nginx:latest
-> ccr.ccs.tencentyun.com/your-namespace/r-7368656c6c75732f6e67696e78:latest
```

拉取时会按配置中的原始镜像名重新打标签。

若远端配置了 `repository_name_max_length` 且十六进制仓库名超出限制，会自动改用 `b-` 开头的 Base32 可逆短编码。

## 开发

运行测试：

```bash
PYTHONPATH=src python3 -m unittest discover -v
```

查看 CLI：

```bash
PYTHONPATH=src python3 -m acr_sync --help
```
