Skip to main content

svnpypi - Serverless SVN Python Package Manager

svnpypi 是一个面向内部局域网、无法或不想部署通用 HTTP 包服务器场景的小型 CLI 适配工具。它复用现有 SVN 权限体系,通过 svnsvn+sshhttps 完成 Python 内部包的上传、列出、下载和安装。

核心理念: 不新增服务端,不接管认证,不重新实现依赖解析;SVN 负责权限和审计,svnpypi 只做最小必要的包分发适配。


目录


背景与限制

在很多内网或对安全有高要求的环境中,我们通常:

  1. 不允许在公网部署/上传代码;
  2. 不愿意为了几十个内部的 .whl 去费时费力维护一个包含鉴权(Auth)、SSL、反向代理的独立中心化 PyPI/Devpi 服务器。
  3. 但公司通常已经有了成熟的组织架构权限体系映射在现有的 SVN 仓库上。

所以我们需要一种 “依靠 SVN 命令行客户端做认证代理,下载包后再喂给本地 pip 的方案,svnpypi 应运而生。


核心机制

svnpypi 的工作流程分为两个阶段:

  1. 发布阶段 (Upload):在开发者机器上读取构建好的 dist/* 文件,识别包名并作为普通 SVN Asset 使用 sparse checkout 查验并建立 svn commit 提交到预先指定的 SVN 路径下供他人使用。
    • 上传新制品时会维护包目录下的 SHA256SUMS 清单。
  2. 下载阶段 (Install):在其他开发者或部署机器上,使用同一套 CLI 读取该 SVN 目录中的文件,它将:
    • 使用终端原生的 svn list 列出所有版本供决策。
    • 在同一版本存在多个制品时,使用 packaging.tags.sys_tags() 按当前解释器的完整兼容标签选择 wheel;无兼容 wheel 时回落到 sdist。
    • 使用终端原生的 svn cat 将选定发行版流式写入 /tmp/ 系统缓冲,避免大文件一次性进入内存。
    • 若包目录存在 SHA256SUMS 且包含目标文件条目,会在安装前校验 SHA256。
    • 脱离 SVN 后自动代理唤起原生的 pip install /tmp/...whl
    • 清理所有缓冲。

安装

依赖于您的内网环境中同样获取了代码库,使用:

git clone <your-repo>/svnpypi
cd svnpypi

# 安装到您的 Python 环境中
pip install .

开发验证

仓库提供 GitHub Actions CI,覆盖 Linux 的 Python 3.9/3.12/3.14、Windows 的 Python 3.12,并运行真实本地 SVN 集成测试(工具可用时)。本地可执行:

python -m ruff check src tests scripts
python -m mypy src scripts
python -m pytest -q
python -m build

发布到 PyPI

仓库提供跨平台发布脚本。它默认只运行质量检查、构建 wheel/sdist 并执行 twine check,不会自动上传:

python -m pip install -e ".[dev,release]"
python scripts/release_pypi.py

先向 TestPyPI 试传:

python scripts/release_pypi.py --upload --repository testpypi

正式发布要求工作区干净、完成全部检查、当前提交带有已推送到 origin 的 annotated v0.1.5(或 0.1.5)标签,并显式确认版本:

python scripts/release_pypi.py --upload --repository pypi --confirm-version 0.1.5

令牌配置、TestPyPI 安装验证、正式发布清单和 CI Trusted Publishing 建议见 docs/svnpypi/pypi-release.md


进阶文档

如果你需要面向团队/公司落地的长期治理方案(命名规范、环境分层、发布策略、CI、跨仓库部署等),请直接阅读按包拆分后的文档:

  • docs/README.md
  • docs/svnpypi/README.md
  • docs/svnpypi/command-reference.md
  • docs/svnpypi/stable-usage-guide.md
  • docs/svnpypi/deployment-readiness.md
  • docs/svnpypi/pypi-release.md
  • docs/svnpypi/platform-verification-matrix.md
  • docs/svnpypi/migration-guide.md
  • docs/pysvnlite/README.md

认证前置与跨环境登录

svnpypi 本身不处理认证参数(例如 --username/--password),它只复用当前系统上的 svn 客户端认证状态。

建议在每台机器首次使用前先做一次认证预热(必须非交互成功):

svn --non-interactive list <repo-url>

如果你是账号密码模式,先在受信终端执行一次交互式命令,让 SVN 按本机策略缓存凭据;随后再验证非交互访问:

svn list <repo-url>
svn --non-interactive list <repo-url>

不要把密码放在命令行参数中,避免泄漏到 shell 历史、进程列表或 CI 日志。

常见环境建议

  1. Linux/macOS + ssh key

    • 先确保 ssh-agent 中已经加载密钥(ssh-add -l 可检查)。
    • 再执行一次 svn --non-interactive list svn+ssh://... 做预热。
  2. Windows + PPK (PuTTY/Pageant/plink)

    • 推荐先在 Pageant 中加载 .ppk
    • 建议通过 SVN_SSH 指定 plink(或在 Subversion tunnels 里配置)。
    • 示例(PowerShell):
$env:SVN_SSH = '"C:\Program Files\PuTTY\plink.exe" -batch -load your_saved_session'
svn --non-interactive list svn+ssh://svn.company.com/python-packages/release
  1. CI 环境
    • 在流水线里先做一条 svn --non-interactive list/info 预检,再执行 svnpypi 命令。

推荐的工作目录结构

为了方便管理并利用 SVN 本身的特性处理“版本环境”,我们建议您将 SVN 仓库开辟特定子目录承接 Python 包:

svn+ssh://svn.yourcompany.com/python-packages/
├── release/                     <-- 稳定版本仓库(严格权限:运维小组长才能合并)
│   ├── my-internal-tool/        <-- svnpypi 自动生成
│   │   ├── my_internal_tool-1.0.0-py3-none-any.whl
│   │   └── my_internal_tool-1.1.0-py3-none-any.whl
│   └── another-library/         <-- svnpypi 自动生成
│       └── ...
└── test/                        <-- 测试/研发版本仓库(较松权限:允许所有后端开发者无损上传测试迭代)
    ├── my-internal-tool/
    │   └── my_internal_tool-1.2.0.dev1-py3-none-any.whl
    └── ...

命令指南

1. 上传包 (upload)

当您在本地开发完毕并执行了 python -m build 生成了构建物(.whl.tar.gz),您可以将其推送到远程:

# 先推送所有生成物到测试仓库频道
svnpypi upload dist/* --repo-url svn+ssh://svn.company.com/python-packages/test

上传会同步维护包目录下的 SHA256SUMS 文件,供安装前校验使用。 dist/* 等通配符由 svnpypi 自身展开,因此在 PowerShell 和 POSIX shell 中行为一致。只接受标准 wheel / sdist 文件,未匹配路径和无效制品会返回非零退出码。

如果多人同时上传同一包目录,svnpypi 会在常见 out-of-date / already exists 场景下重新查询远端并有限重试。同名远端制品只有在 SHA256 相同时才会跳过;内容不同会失败并要求提升版本。 上传准备和暂存期间会再次核对本地制品 SHA256;若构建产物正在被其他进程改写,上传会失败并要求使用稳定制品重试。

2. 列出所有的包与版本 (list)

想查看团队里都有哪些可共享组件可以安装在自己电脑上的?获取一次组件树!

svnpypi list --repo-url svn+ssh://svn.company.com/python-packages/release

输出示例:

📦 SVN Package Registry
└── pysvnlite
    ├── 0.1.1 (pysvnlite-0.1.1-py3-none-any.whl)
    ├── 0.1.0 (pysvnlite-0.1.0-py3-none-any.whl)
    └── ... and 2 more

3. 安装包到本地 (install)

这是最重要的命令。它无缝替换您常用的 pip install 但支持 svn+ssh:// 的文件读取:

# 临时探索时可安装 SVN 目录中的最高版本
svnpypi install pysvnlite --repo-url svn+ssh://svn.company.com/python-packages/release

# 稳定环境建议限定下载和安装特定版本
svnpypi install pysvnlite --version 0.1.0 --repo-url svn+ssh://svn.company.com/python-packages/release

# 限定版本范围,自动选择范围内最高可用版本
svnpypi install pysvnlite --specifier ">=0.1,<1.0" --repo-url svn+ssh://svn.company.com/python-packages/release

# 甚至向后传递任意的原生 pip 配置命令到最终触发时
svnpypi install pysvnlite --repo-url svn+ssh://svn.company.com/python-packages/release --pip-args --no-cache-dir --upgrade

# 安装成功后写出可复现记录
svnpypi install pysvnlite --version 0.1.0 --repo-url svn+ssh://svn.company.com/python-packages/release --record .svnpypi/install-record.json

# 部署环境要求制品必须存在 SHA256SUMS 条目
svnpypi install pysvnlite --version 0.1.0 --repo-url svn+ssh://svn.company.com/python-packages/release --require-hash

--record 会写出 JSON,包含包名、版本、文件名、仓库 URL、制品 URL、SHA256SUMS URL、实际 SHA256、期望 SHA256 以及是否完成 hash 校验。即使仓库里尚无对应 SHA256SUMS 条目,也会记录本次下载制品的实际 SHA256。 记录通过同目录临时文件和原子替换写入;写入失败不会截断已有记录。

4. 诊断环境 (doctor)

首次接入或 CI 排障时,可以先检查本机 svn、当前 Python 环境的 pip、以及仓库读取权限:

svnpypi doctor --repo-url svn+ssh://svn.company.com/python-packages/release

如需验证写权限,可显式启用临时目录创建/删除探针:

svnpypi doctor --repo-url svn+ssh://svn.company.com/python-packages/release --check-write

JSON 输出

listuploadinstalldoctorsync 均支持 --json,便于 CI 或脚本解析:

svnpypi list --repo-url svn+ssh://svn.company.com/python-packages/release --json
svnpypi doctor --repo-url svn+ssh://svn.company.com/python-packages/release --json

5. 同步项目内部依赖 (sync)

如果项目的 pyproject.toml 配置了 [tool.svnpypi],可以直接安装其中的内部依赖:

[tool.svnpypi]
repo_release = "svn+ssh://svn.company.com/python-packages/release"
internal_dependencies = [
    "company-core-lib==1.8.2",
    "company-auth-sdk>=3.4,<4.0",
]

执行同步:

svnpypi sync --channel release

预览将执行的安装命令:

svnpypi sync --channel release --dry-run

默认仓库地址

所有需要仓库地址的命令都可以省略 --repo-url,改用环境变量 SVNPYPI_REPO_URL

export SVNPYPI_REPO_URL=svn+ssh://svn.company.com/python-packages/release
svnpypi list
svnpypi install pysvnlite --specifier ">=0.1,<1.0"

PowerShell 示例:

$env:SVNPYPI_REPO_URL = "svn+ssh://svn.company.com/python-packages/release"
svnpypi doctor

兼容性说明(语言与操作系统)

  • Python:包元数据保持 >=3.9 兼容;Python 3.9/3.10 会安装 tomli,3.11+ 使用标准库 tomllib。Python 3.9 已结束官方维护,生产部署建议使用仍受支持的 Python 3.12 至 3.14。
  • 语言环境list/install 主要依赖 svn --xml 输出解析,基本不受终端语言(中文/日文/英文)影响。
  • 提交回显upload 会解析 svn commit 的文本输出以显示 revision;当前已兼容多语言关键字并做了回退逻辑。
  • 可预期边界:若遇到极少见本地化文案导致 revision 无法提取,提交本身仍然成功,只是无法显示 revision 数字。
  • 操作系统:核心行为依赖系统 svnpip;本地 file:// SVN 已在 Windows 验证,CI 配置覆盖 Linux/Windows。svn+ssh、HTTPS 证书和 key agent 仍需在实际部署网络中验收。

原理与安全

svnpypi 不接收或保存密码、公钥和证书配置,所有认证由系统 svn 客户端完成。不要把密码嵌入仓库 URL;应使用 SVN 凭据缓存、SSH agent 或部署机凭据。CLI 输出和安装记录会对 URL userinfo 做脱敏,但这只是误配置防护,不是推荐的认证方式。

SHA256SUMS 用于发现传输损坏和意外内容变化,不等同于数字签名。拥有制品与 manifest 写权限的账号可以同时修改两者,因此发布可信度最终依赖 SVN ACL、提交审计、传输安全和发布账号保护。

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

svnpypi-0.1.5.tar.gz (33.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

svnpypi-0.1.5-py3-none-any.whl (39.6 kB view details)

Uploaded Python 3

File details

Details for the file svnpypi-0.1.5.tar.gz.

File metadata

  • Download URL: svnpypi-0.1.5.tar.gz
  • Upload date:
  • Size: 33.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.4

File hashes

Hashes for svnpypi-0.1.5.tar.gz
Algorithm Hash digest
SHA256 f046636f55ec1df28dfbb70f0799a808471ef5031f8196abb10a51dd26873d2b
MD5 c79d0fb088f82bba41c6bb8d4741081a
BLAKE2b-256 8667c018db47b29cf08da49f84c6fa250c1d02347a2f52afbcf9c96a0a0ef1df

See more details on using hashes here.

File details

Details for the file svnpypi-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: svnpypi-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 39.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.4

File hashes

Hashes for svnpypi-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 dd5a13da8224d4610ae5f780812d577c902c500b692b8666d86bb2128572d20e
MD5 bae12f2c9d7861fed8253f59733752bb
BLAKE2b-256 0b62864f0ca70e711dbc04858886602622660e3951d60931abc42f113c7f7dd3

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.7

2 files

0.1.6

2 files

This release

0.1.5 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page