andrew/purl
GitHub: andrew/purl
一个符合 PURL 规范的 Ruby 库与 CLI 工具,用于跨 37 种包生态系统解析、验证、生成 Package URL 并进行 registry URL 转换与包信息查询。
Stars: 12 | Forks: 1
# Purl - Ruby 的 Package URL 解析器
一个 Ruby 库,用于解析、验证和生成由 [PURL 规范](https://github.com/package-url/purl-spec) 定义的 Package URL (PURL)。
该库具有命名空间错误类型的全面错误处理、双向 registry URL 转换以及基于 JSON 的配置以实现跨语言兼容性。
[](https://www.ruby-lang.org/)
[](https://rubygems.org/gems/purl)
[](https://opensource.org/licenses/MIT)
**[在 RubyGems 上获取](https://rubygems.org/gems/purl)** | **[API 文档](https://rdoc.info/github/andrew/purl)**
## 相关库
- **[Vers](https://github.com/andrew/vers)** - 一个 Ruby 库,用于处理支持 VERS 规范的版本范围
## 功能
- **命令行界面** 包含 parse、validate、convert、download、generate、info、lookup 和 advisories 命令,并支持 JSON 输出
- **全面的 PURL 解析和验证** 支持 37 种包类型(32 种官方类型 + 5 种额外的生态系统)
- **更好的错误处理** 包含命名空间错误类和上下文信息
- **双向 registry URL 转换** - 从 PURL 生成 registry URL 并从 registry URL 解析 PURL
- **下载 URL 生成** 支持 18 种包生态系统(gem、npm、cargo、maven 等)
- **安全公告查询** - 从 advisories.ecosyste.ms 查询安全公告
- **包信息查询** - 从 ecosyste.ms 查询包元数据
- **针对特定类型的验证** 支持 conan、cran 和 swift 包
- **Registry URL 生成** 支持 20 种包生态系统(npm、gem、maven、pypi 等)
- **Rails 风格的路由模式** 用于 registry URL 模板
- **100% 兼容** 官方 PURL 规范测试套件(59/59 项测试通过)
- **跨语言兼容性** 采用基于 JSON 的配置
- **全面的文档** 和示例
## 安装说明
将以下行添加到您的应用程序的 Gemfile 中:
```
gem 'purl'
```
然后执行:
```
bundle install
```
或者自行安装:
```
gem install purl
```
## 命令行界面
purl gem 包含一个命令行界面,可方便地访问所有解析、验证、转换和生成功能。
### 安装说明
安装 gem 后即可自动使用 CLI:
```
gem install purl
purl --help
```
### 可用命令
```
purl parse # Parse and display PURL components
purl validate # Validate a PURL (exit code indicates success)
purl convert # Convert registry URL to PURL
purl url # Convert PURL to registry URL
purl download # Get download URL for package version
purl generate [options] # Generate PURL from components
purl info [type] # Show information about PURL types
purl lookup # Look up package information from ecosyste.ms
purl advisories # Look up security advisories from advisories.ecosyste.ms
```
### JSON 输出
所有命令均支持带有 `--json` 标志的 JSON 输出:
```
purl --json parse "pkg:gem/rails@7.0.0"
purl --json info gem
purl --json lookup "pkg:cargo/rand"
purl --json advisories "pkg:npm/lodash@4.17.19"
```
### 命令示例
#### 解析 PURL
```
$ purl parse "pkg:gem/rails@7.0.0"
Valid PURL: pkg:gem/rails@7.0.0
Components:
Type: gem
Namespace: (none)
Name: rails
Version: 7.0.0
Qualifiers: (none)
Subpath: (none)
$ purl --json parse "pkg:npm/@babel/core@7.0.0"
{
"success": true,
"purl": "pkg:npm/%40babel/core@7.0.0",
"components": {
"type": "npm",
"namespace": "@babel",
"name": "core",
"version": "7.0.0",
"qualifiers": {},
"subpath": null
}
}
```
#### 验证 PURL
```
$ purl validate "pkg:gem/rails@7.0.0"
Valid PURL
$ purl validate "invalid-purl"
Invalid PURL: PURL must start with 'pkg:'
```
#### 将 Registry URL 转换为 PURL
```
$ purl convert "https://rubygems.org/gems/rails"
pkg:gem/rails
$ purl convert "https://www.npmjs.com/package/@babel/core"
pkg:npm/@babel/core
```
#### 将 PURL 转换为 Registry URL
```
$ purl url "pkg:gem/rails@7.0.0"
https://rubygems.org/gems/rails
$ purl url "pkg:npm/@babel/core@7.0.0"
https://www.npmjs.com/package/@babel/core
$ purl --json url "pkg:gem/rails@7.0.0"
{
"success": true,
"purl": "pkg:gem/rails@7.0.0",
"registry_url": "https://rubygems.org/gems/rails",
"type": "gem"
}
```
#### 获取下载 URL
```
$ purl download "pkg:gem/rails@7.0.0"
https://rubygems.org/downloads/rails-7.0.0.gem
$ purl download "pkg:npm/@babel/core@7.20.0"
https://registry.npmjs.org/@babel/core/-/core-7.20.0.tgz
$ purl download "pkg:cargo/serde@1.0.152"
https://static.crates.io/crates/serde/serde-1.0.152.crate
$ purl --json download "pkg:maven/org.apache.commons/commons-lang3@3.12.0"
{
"success": true,
"purl": "pkg:maven/org.apache.commons/commons-lang3@3.12.0",
"download_url": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar",
"type": "maven"
}
```
#### 生成 PURL
```
$ purl generate --type gem --name rails --version 7.0.0
pkg:gem/rails@7.0.0
$ purl generate --type npm --namespace @babel --name core --version 7.0.0 --qualifiers "arch=x64,os=linux"
pkg:npm/%40babel/core@7.0.0?arch=x64&os=linux
```
#### 显示类型信息
```
$ purl info gem
Type: gem
Known: Yes
Description: RubyGems
Default registry: https://rubygems.org
Registry URL generation: Yes
Reverse parsing: Yes
Examples:
pkg:gem/ruby-advisory-db-check@0.12.4
pkg:gem/rails@7.0.4
pkg:gem/bundler@2.3.26
Registry URL patterns:
https://rubygems.org/gems/:name
https://rubygems.org/gems/:name/versions/:version
$ purl info # Shows all types
Known PURL types:
alpm
Description: Arch Linux packages
Registry support: No
Reverse parsing: No
...
Total types: 37
Registry supported: 20
```
#### 查询包信息
```
$ purl lookup "pkg:cargo/rand"
Package: rand (cargo)
Description: Random number generators and other randomness functionality.
Homepage: https://rust-random.github.io/book
Repository: https://github.com/rust-random/rand
License: MIT OR Apache-2.0
Downloads: 145,678,901
Latest Version: 0.8.5
Published: 2023-01-13T17:47:01.870Z
$ purl --json lookup "pkg:cargo/rand@0.8.5"
{
"success": true,
"purl": "pkg:cargo/rand@0.8.5",
"package": {
"name": "rand",
"ecosystem": "cargo",
"description": "Random number generators and other randomness functionality.",
"homepage": "https://rust-random.github.io/book",
"repository_url": "https://github.com/rust-random/rand",
"registry_url": "https://crates.io/crates/rand",
"licenses": "MIT OR Apache-2.0",
"latest_version": "0.8.5",
"latest_version_published_at": "2023-01-13T17:47:01.870Z",
"versions_count": 89,
"maintainers": [
{
"login": "dhardy",
"name": "Diggory Hardy"
}
]
},
"version": {
"number": "0.8.5",
"published_at": "2023-01-13T17:47:01.870Z",
"registry_url": "https://crates.io/crates/rand/0.8.5",
"downloads": 5678901,
"size": 102400
}
}
```
#### 查询安全公告
```
$ purl advisories "pkg:npm/lodash@4.17.19"
Security Advisories for pkg:npm/lodash@4.17.19
================================================================================
Advisory #1: Regular Expression Denial of Service (ReDoS) in lodash
Identifiers: GHSA-x5rq-j2xg-h7qm, CVE-2019-1010266
Severity: MODERATE
Description:
lodash prior to 4.7.11 is affected by: CWE-400: Uncontrolled Resource
Consumption. The impact is: Denial of service. The component is: Date
handler. The attack vector is: Attacker provides very long strings, which
the library attempts to match using a regular expression. The fixed version
is: 4.7.11.
Affected Packages:
Package: npm/lodash
Vulnerable: >= 4.7.0, < 4.17.11
Patched: 4.17.11
Source: github | Origin: UNSPECIFIED | Published: 2019-07-19T16:13:07.000Z
Advisory URL: https://github.com/advisories/GHSA-x5rq-j2xg-h7qm
Total advisories found: 3
$ purl --json advisories "pkg:npm/lodash@4.17.19"
{
"success": true,
"purl": "pkg:npm/lodash@4.17.19",
"advisories": [
{
"id": "MDE2OlNlY3VyaXR5QWR2aXNvcnlHSFNBLXg1cnEtajJ4Zy1oN3Ft",
"title": "Regular Expression Denial of Service (ReDoS) in lodash",
"description": "lodash prior to 4.7.11 is affected by...",
"severity": "MODERATE",
"url": "https://github.com/advisories/GHSA-x5rq-j2xg-h7qm",
"published_at": "2019-07-19T16:13:07.000Z",
"affected_packages": [
{
"ecosystem": "npm",
"name": "lodash",
"vulnerable_version_range": ">= 4.7.0, < 4.17.11",
"first_patched_version": "4.17.11"
}
],
"identifiers": ["GHSA-x5rq-j2xg-h7qm", "CVE-2019-1010266"]
}
],
"count": 3
}
```
### 生成选项
`generate` 命令支持所有 PURL 组件:
```
purl generate --help
Usage: purl generate [options]
--type TYPE Package type (required)
--name NAME Package name (required)
--namespace NAMESPACE Package namespace
--version VERSION Package version
--qualifiers QUALIFIERS Qualifiers as key=value,key2=value2
--subpath SUBPATH Package subpath
-h, --help Show this help
```
### 退出代码
CLI 使用标准退出代码:
- `0` - 成功
- `1` - 错误(无效的 PURL、不支持的操作等)
这使得 CLI 适合在脚本和 CI/CD pipeline 中使用:
```
if purl validate "pkg:gem/rails@7.0.0"; then
echo "Valid PURL"
else
echo "Invalid PURL"
exit 1
fi
```
## 库的用法
### 基础 PURL 解析
```
require 'purl'
# 解析 PURL 字符串
purl = Purl.parse("pkg:gem/rails@7.0.0")
puts purl.type # => "gem"
puts purl.name # => "rails"
puts purl.version # => "7.0.0"
puts purl.namespace # => nil
# 使用 namespace 和 qualifiers 进行解析
purl = Purl.parse("pkg:npm/@babel/core@7.0.0?arch=x86_64")
puts purl.type # => "npm"
puts purl.namespace # => "@babel"
puts purl.name # => "core"
puts purl.version # => "7.0.0"
puts purl.qualifiers # => {"arch" => "x86_64"}
```
### 创建 PURL
```
# 创建 PURL 对象
purl = Purl::PackageURL.new(
type: "maven",
namespace: "org.apache.commons",
name: "commons-lang3",
version: "3.12.0"
)
puts purl.to_s # => "pkg:maven/org.apache.commons/commons-lang3@3.12.0"
```
### 修改 PURL 对象
PURL 对象在设计上是不变的,但您可以使用 `with` 方法创建带有修改属性的新对象:
```
# 创建原始 PURL
original = Purl::PackageURL.new(
type: "npm",
namespace: "@babel",
name: "core",
version: "7.20.0",
qualifiers: { "arch" => "x64" }
)
# 创建更新了 version 的新 PURL
updated = original.with(version: "7.21.0")
puts updated.to_s # => "pkg:npm/@babel/core@7.21.0?arch=x64"
# 更新 qualifiers
with_new_qualifiers = original.with(
qualifiers: { "arch" => "arm64", "os" => "linux" }
)
puts with_new_qualifiers.to_s # => "pkg:npm/@babel/core@7.20.0?arch=arm64&os=linux"
# 一次更新多个属性
fully_updated = original.with(
version: "8.0.0",
qualifiers: { "dev" => "true" },
subpath: "lib/index.js"
)
puts fully_updated.to_s # => "pkg:npm/@babel/core@8.0.0#lib/index.js?dev=true"
# 原始对象保持不变
puts original.to_s # => "pkg:npm/@babel/core@7.20.0?arch=x64"
```
### Registry URL 生成
```
# 从 PURLs 生成 registry URLs
purl = Purl.parse("pkg:gem/rails@7.0.0")
puts purl.registry_url # => "https://rubygems.org/gems/rails"
puts purl.registry_url_with_version # => "https://rubygems.org/gems/rails/versions/7.0.0"
# 检查是否支持 registry URL 生成
puts purl.supports_registry_url? # => true
# 带 scoped packages 的 NPM
purl = Purl.parse("pkg:npm/@babel/core@7.0.0")
puts purl.registry_url # => "https://www.npmjs.com/package/@babel/core"
```
### 下载 URL 生成
为包构件生成直接下载 URL:
```
# 从 PURLs 生成 download URLs
purl = Purl.parse("pkg:gem/rails@7.0.0")
puts purl.download_url # => "https://rubygems.org/downloads/rails-7.0.0.gem"
# 检查是否支持 download URL 生成
puts purl.supports_download_url? # => true
# 带 scoped packages 的 NPM
purl = Purl.parse("pkg:npm/@babel/core@7.20.0")
puts purl.download_url # => "https://registry.npmjs.org/@babel/core/-/core-7.20.0.tgz"
# Maven packages
purl = Purl.parse("pkg:maven/org.apache.commons/commons-lang3@3.12.0")
puts purl.download_url # => "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar"
# 通过 repository_url qualifier 的自定义 registry
purl = Purl.parse("pkg:npm/lodash@4.17.21?repository_url=https://npm.mycompany.com")
puts purl.download_url # => "https://npm.mycompany.com/lodash/-/lodash-4.17.21.tgz"
# 通过参数指定自定义 registry
purl = Purl.parse("pkg:gem/rails@7.0.0")
puts purl.download_url(base_url: "https://gems.internal.com/downloads")
# => "https://gems.internal.com/downloads/rails-7.0.0.gem"
# 获取支持的类型列表
puts Purl.download_supported_types
# => ["bioconductor", "bitbucket", "cargo", "clojars", "cran", "elm", "gem",
# "github", "gitlab", "golang", "hackage", "hex", "luarocks", "maven",
# "npm", "nuget", "pub", "swift"]
```
### ecosyste.ms API URL
为 packages.ecosyste.ms 服务生成 API URL:
```
# 获取 package type 的 ecosyste.ms registry 名称
purl = Purl.parse("pkg:gem/rake@13.3.1")
purl.ecosystems_registry # => "rubygems.org"
# 生成 API URLs
purl.ecosystems_api_url # => "https://packages.ecosyste.ms/api/v1/registries/rubygems.org/packages/rake/versions/13.3.1"
purl.ecosystems_package_api_url # => "https://packages.ecosyste.ms/api/v1/registries/rubygems.org/packages/rake"
purl.ecosystems_version_api_url # => "https://packages.ecosyste.ms/api/v1/registries/rubygems.org/packages/rake/versions/13.3.1"
# 适用于带 namespace 的 packages
purl = Purl.parse("pkg:npm/@babel/core@7.20.0")
purl.ecosystems_registry # => "npmjs.org"
purl.ecosystems_api_url # => "https://packages.ecosyste.ms/api/v1/registries/npmjs.org/packages/%40babel%2Fcore/versions/7.20.0"
# 没有 version 时,返回 package URL
purl = Purl.parse("pkg:cargo/serde")
purl.ecosystems_api_url # => "https://packages.ecosyste.ms/api/v1/registries/crates.io/packages/serde"
```
### 反向解析:Registry URL 到 PURL
```
# 将 registry URLs 解析回 PURLs
purl = Purl.from_registry_url("https://rubygems.org/gems/rails/versions/7.0.0")
puts purl.to_s # => "pkg:gem/rails@7.0.0"
# 适用于各种 registries
purl = Purl.from_registry_url("https://www.npmjs.com/package/@babel/core")
puts purl.to_s # => "pkg:npm/@babel/core"
purl = Purl.from_registry_url("https://pypi.org/project/django/4.0.0/")
puts purl.to_s # => "pkg:pypi/django@4.0.0"
```
### 自定义 Registry 域名
您可以解析来自自定义域名的 registry URL,或为私有 registry 生成 URL:
```
# 从自定义域名解析(指定 type 以辅助解析)
purl = Purl.from_registry_url("https://npm.company.com/package/@babel/core", type: "npm")
puts purl.to_s # => "pkg:npm/@babel/core"
# 为自定义 registries 生成 URLs
purl = Purl.parse("pkg:gem/rails@7.0.0")
custom_url = purl.registry_url(base_url: "https://gems.internal.com/gems")
puts custom_url # => "https://gems.internal.com/gems/rails"
# 带有特定版本的 URLs
with_version = purl.registry_url_with_version(base_url: "https://gems.internal.com/gems")
puts with_version # => "https://gems.internal.com/gems/rails/versions/7.0.0"
# 适用于所有支持的 package 类型
composer_purl = Purl.parse("pkg:composer/symfony/console@5.4.0")
private_composer = composer_purl.registry_url(base_url: "https://packagist.company.com/packages")
puts private_composer # => "https://packagist.company.com/packages/symfony/console"
```
### 路由模式
```
# 获取 package type 的 route patterns(Rails 风格)
patterns = Purl::RegistryURL.route_patterns_for("gem")
# => ["https://rubygems.org/gems/:name", "https://rubygems.org/gems/:name/versions/:version"]
# 获取所有 route patterns
all_patterns = Purl::RegistryURL.all_route_patterns
puts all_patterns["npm"]
# => ["https://www.npmjs.com/package/:namespace/:name", "https://www.npmjs.com/package/:name", ...]
```
### 使用 Qualifiers
Qualifiers 是键值对,用于提供有关包的额外元数据:
```
# 创建带 qualifiers 的 PURL
purl = Purl::PackageURL.new(
type: "apk",
name: "curl",
version: "7.83.0-r0",
qualifiers: {
"distro" => "alpine-3.16",
"arch" => "x86_64",
"repository_url" => "https://dl-cdn.alpinelinux.org"
}
)
puts purl.to_s # => "pkg:apk/curl@7.83.0-r0?arch=x86_64&distro=alpine-3.16&repository_url=https://dl-cdn.alpinelinux.org"
# 访问 qualifiers
puts purl.qualifiers["distro"] # => "alpine-3.16"
puts purl.qualifiers["arch"] # => "x86_64"
# 解析带 qualifiers 的 PURL
parsed = Purl.parse("pkg:rpm/httpd@2.4.53?distro=fedora-36&arch=x86_64")
puts parsed.qualifiers # => {"distro" => "fedora-36", "arch" => "x86_64"}
# 向现有 PURL 添加 qualifiers
with_qualifiers = purl.with(qualifiers: purl.qualifiers.merge("signed" => "true"))
```
### 包类型信息
```
# 获取所有已知的 PURL 类型
puts Purl.known_types.length # => 37
puts Purl.known_types.include?("gem") # => true
# 检查类型支持
puts Purl.known_type?("gem") # => true
puts Purl.registry_supported_types # => ["cargo", "gem", "maven", "npm", ...]
puts Purl.reverse_parsing_supported_types # => ["bioconductor", "cargo", "clojars", ...]
puts Purl.download_supported_types # => ["cargo", "gem", "maven", "npm", ...]
# 获取某种类型的默认 registry
puts Purl.default_registry("gem") # => "https://rubygems.org"
puts Purl.default_registry("npm") # => "https://registry.npmjs.org"
puts Purl.default_registry("golang") # => nil (no default)
# 获取某种类型的官方示例
puts Purl.type_examples("gem") # => ["pkg:gem/rails@7.0.4", "pkg:gem/bundler@2.3.26", ...]
puts Purl.type_examples("npm") # => ["pkg:npm/lodash@4.17.21", "pkg:npm/@babel/core@7.20.0", ...]
puts Purl.type_examples("unknown") # => []
# 获取详细的类型信息
info = Purl.type_info("gem")
puts info[:known] # => true
puts info[:description] # => "RubyGems"
puts info[:default_registry] # => "https://rubygems.org"
puts info[:examples] # => ["pkg:gem/rails@7.0.4", ...]
puts info[:registry_url_generation] # => true
puts info[:reverse_parsing] # => true
puts info[:download_url_generation] # => true
puts info[:route_patterns] # => ["https://rubygems.org/gems/:name", ...]
```
### 安全公告查询
使用 advisories.ecosyste.ms API 查询包的安全公告:
```
# 查找 package 的 advisories
purl = Purl.parse("pkg:npm/lodash@4.17.19")
advisories = purl.advisories
# 显示 advisory 信息
advisories.each do |advisory|
puts "Title: #{advisory[:title]}"
puts "Severity: #{advisory[:severity]}"
puts "Description: #{advisory[:description]}"
puts "URL: #{advisory[:url]}"
# Show affected packages
advisory[:affected_packages].each do |pkg|
puts " Package: #{pkg[:ecosystem]}/#{pkg[:name]}"
puts " Vulnerable: #{pkg[:vulnerable_version_range]}"
puts " Patched: #{pkg[:first_patched_version]}" if pkg[:first_patched_version]
end
# Show identifiers (CVE, GHSA, etc.)
puts "Identifiers: #{advisory[:identifiers].join(', ')}"
puts
end
# 查找 package 任意版本的 advisories
purl = Purl.parse("pkg:npm/lodash")
all_advisories = purl.advisories
# 使用自定义 user agent 和 timeout
advisories = purl.advisories(user_agent: "my-app/1.0", timeout: 5)
```
### 错误处理
```
# 带有 context 的详细错误类型
begin
Purl.parse("invalid-purl")
rescue Purl::InvalidSchemeError => e
puts "Scheme error: #{e.message}"
rescue Purl::ParseError => e
puts "Parse error: #{e.message}"
puts "Component: #{e.component}"
puts "Value: #{e.value}"
end
# 特定类型的 validation 错误
begin
Purl::PackageURL.new(type: "swift", name: "Alamofire") # Swift requires namespace
rescue Purl::ValidationError => e
puts e.message # => "Swift PURLs require a namespace to be unambiguous"
end
```
### 支持的包类型
该库支持 37 种包类型(32 种官方类型 + 5 种额外的生态系统):
**Registry URL 生成(20 种):**
- `bioconductor` (R/Bioconductor) - bioconductor.org
- `cargo` (Rust) - crates.io
- `clojars` (Clojure) - clojars.org
- `cocoapods` (iOS) - cocoapods.org
- `composer` (PHP) - packagist.org
- `conda` (Python) - anaconda.org
- `cpan` (Perl) - metacpan.org
- `deno` (Deno) - deno.land/x
- `elm` (Elm) - package.elm-lang.org
- `gem` (Ruby) - rubygems.org
- `golang` (Go) - pkg.go.dev
- `hackage` (Haskell) - hackage.haskell.org
- `hex` (Elixir) - hex.pm
- `homebrew` (macOS) - formulae.brew.sh
- `maven` (Java) - mvnrepository.com
- `npm` (Node.js) - npmjs.com
- `nuget` (.NET) - nuget.org
- `pub` (Dart) - pub.dev
- `pypi` (Python) - pypi.org
- `swift` (Swift) - swiftpackageindex.com
**反向解析(20 种):**
- `bioconductor`, `cargo`, `clojars`, `cocoapods`, `composer`, `conda`, `cpan`, `deno`, `elm`, `gem`, `golang`, `hackage`, `hex`, `homebrew`, `maven`, `npm`, `nuget`, `pub`, `pypi`, `swift`
**下载 URL 生成(18 种):**
- `bioconductor` - bioconductor.org/packages/release/bioc/src/contrib
- `bitbucket` - bitbucket.org 归档下载
- `cargo` - static.crates.io/crates
- `clojars` - repo.clojars.org(Maven 风格)
- `cran` - cran.r-project.org/src/contrib
- `elm` - GitHub 归档下载
- `gem` - rubygems.org/downloads
- `github` - GitHub 归档下载
- `gitlab` - GitLab 归档下载
- `golang` - proxy.golang.org
- `hackage` - hackage.haskell.org/package
- `hex` - repo.hex.pm/tarballs
- `luarocks` - luarocks.org/manifests
- `maven` - repo.maven.apache.org/maven2
- `npm` - registry.npmjs.org
- `nuget` - api.nuget.org/v3-flatcontainer
- `pub` - pub.dev/packages
- `swift` - GitHub/GitLab/Bitbucket(派生自 namespace)
**所有 37 种支持的类型:**
`alpm`, `apk`, `bioconductor`, `bitbucket`, `bitnami`, `cargo`, `clojars`, `cocoapods`, `composer`, `conan`, `conda`, `cpan`, `cran`, `deb`, `deno`, `docker`, `elm`, `gem`, `generic`, `github`, `golang`, `hackage`, `hex`, `homebrew`, `huggingface`, `luarocks`, `maven`, `mlflow`, `npm`, `nuget`, `oci`, `pub`, `pypi`, `qpkg`, `rpm`, `swid`, `swift`
## 规范合规性
- **100% 兼容** 官方 PURL 规范测试套件(59/59 项测试通过)
- **支持所有 32 种官方包类型** 以及 5 种额外的生态系统类型
- **针对特定类型的验证** 支持 conan、cran、swift、cpan 和 mlflow 包
- **妥善的错误处理** 用于处理应被拒绝的无效 PURL
## JSON 配置
包类型和 registry 模式存储在 `purl-types.json` 中,以便于贡献和实现跨语言兼容性:
```
{
"version": "1.0.0",
"description": "PURL types and registry URL patterns for package ecosystems",
"source": "https://github.com/package-url/purl-spec/blob/main/PURL-TYPES.rst",
"last_updated": "2025-07-24",
"types": {
"gem": {
"description": "RubyGems",
"default_registry": "https://rubygems.org",
"registry_config": {
"path_template": "/gems/:name",
"version_path_template": "/gems/:name/versions/:version",
"reverse_regex": "/gems/([^/?#]+)(?:/versions/([^/?#]+))?",
"components": {
"namespace": false,
"version_in_url": true,
"version_path": "/versions/"
}
}
}
}
}
```
**关键配置改进:**
- **与域名无关的模式**:不带硬编码域名的 `path_template` 支持自定义 registry
- **灵活的 URL 生成**:将 `default_registry` + `path_template` 组合适用于任何域名
- **更整洁的 JSON**:减少重复并简化维护
- **跨 registry 兼容性**:相同的 URL 结构适用于公共和私有 registry
## JSON Schema 验证
该库包含用于验证和文档的 JSON schema:
- **`schemas/purl-types.schema.json`** - PURL 类型配置文件的 schema
- **`schemas/test-suite-data.schema.json`** - 官方测试套件数据的 schema
这些 schema 提供:
- **结构验证** - 确保 JSON 文件符合预期格式
- **文档** - 带有描述的自我记录配置
- **IDE 支持** - 在编辑器中启用自动补全和验证
- **CI/CD 集成** - 在自动化 pipeline 中验证配置
根据对应的 schema 验证 JSON 文件:
```
rake spec:validate_schemas
```
## 开发
检出仓库后,运行 `bin/setup` 安装依赖项。然后:
```
# 运行测试
rake test
# 运行 specification compliance 测试
rake spec:compliance
# 从官方 PURL spec 更新测试用例
rake spec:update
# 显示类型信息
rake spec:types
# 根据官方 specification 验证类型
rake spec:verify_types
```
### 针对官方规范进行测试
该库包含官方 [purl-spec](https://github.com/package-url/purl-spec) 仓库作为 git submodule 用于测试和验证:
```
# 初始化 submodule(仅首次)
git submodule update --init --recursive
# 将 submodule 更新到最新的 spec
git submodule update --remote purl-spec
```
测试使用 submodule 中的文件来:
- **Schema 验证**:根据 `purl-spec/schemas/` 中的官方 schema 验证我们的 `purl-types.json`
- **类型合规性**:确保我们支持的类型与 `purl-spec/types/` 中的官方类型相匹配
- **测试数据**:从 `purl-spec/tests/` 访问官方测试用例和示例
该 submodule 会通过 Dependabot 每周自动更新,确保测试与最新的规范更改保持同步。当 submodule 更新时,您可以审查并合并 PR 以采用新的规范要求。
### Rake 任务
- `rake spec:update` - 从官方 PURL 规范仓库获取最新测试用例
- `rake spec:compliance` - 针对官方测试套件运行合规性测试
- `rake spec:types` - 显示所有 PURL 类型及其支持情况的信息
- `rake spec:verify_types` - 根据官方规范验证我们的类型列表
- `rake spec:validate_schemas` - 根据 schema 验证 JSON 文件
- `rake spec:debug` - 显示失败测试用例的详细信息
## 资金支持
如果您觉得这个项目有用,请考虑支持它的开发:
- [GitHub Sponsors](https://github.com/sponsors/andrew)
- [Ko-fi](https://ko-fi.com/andrewnez)
- [Buy Me a Coffee](https://www.buymeacoffee.com/andrewnez)
您的支持有助于为整个 Ruby 社区维护和改进此库。
## 贡献
欢迎在 GitHub 上提交 Bug 报告和 Pull Request。本项目旨在成为一个安全、欢迎的协作空间,并期望贡献者遵守[贡献者公约](http://contributor-covenant.org)的行为准则。
1. Fork 它
2. 创建您的功能分支 (`git checkout -b my-new-feature`)
3. 进行更改
4. 为您的更改添加测试
5. 确保所有测试通过 (`rake test`)
6. 提交您的更改 (`git commit -am 'Add some feature'`)
7. 推送到分支 (`git push origin my-new-feature`)
8. 创建新的 Pull Request
### 添加新的包类型
要添加对新包类型的支持:
1. 使用新的类型配置更新 `purl-types.json`
2. 如果适用,添加 registry URL 模式
3. 如果需要,在 `lib/purl/package_url.rb` 中添加特定于类型的验证规则
4. 为新功能添加测试
## 许可证
该 gem 作为开源软件提供,基于 [MIT 许可证](https://opensource.org/licenses/MIT) 的条款发布。
## 更新日志
请查看 [CHANGELOG.md](CHANGELOG.md) 获取详细的更改和发布历史。
## 行为准则
期望所有在 Purl 项目代码库、问题跟踪系统、聊天室和邮件列表中进行互动的人员都能遵守[贡献者公约行为准则CODE_OF_CONDUCT.md)。
标签:Homebrew安装, PURL规范, Ruby, 依赖解析, 动态分析, 包管理, 库, 应急响应, 文档结构分析, 知识库