Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions internal/cargo/cargo.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,26 @@ func init() {
// cargoTomlParser parses Cargo.toml files.
type cargoTomlParser struct{}

// inheritableString decodes a Cargo [package] field that may be a literal
// string or the workspace-inheritance table form {workspace = true}. The
// inherited value is not resolvable from a single file, so the table form
// yields the zero value instead of failing the whole decode.
type inheritableString string

func (s *inheritableString) UnmarshalTOML(v any) error {
if str, ok := v.(string); ok {
*s = inheritableString(str)
}
return nil
Comment on lines +28 to +32
}

func (p *cargoTomlParser) Parse(filename string, content []byte) (*core.Result, error) {
var cargo struct {
Package struct {
Name string `toml:"name"`
Version string `toml:"version"`
License string `toml:"license"`
LicenseFile string `toml:"license-file"`
Name string `toml:"name"`
Version inheritableString `toml:"version"`
License inheritableString `toml:"license"`
LicenseFile inheritableString `toml:"license-file"`
} `toml:"package"`
Dependencies map[string]any `toml:"dependencies"`
DevDependencies map[string]any `toml:"dev-dependencies"`
Expand Down Expand Up @@ -72,13 +85,13 @@ func (p *cargoTomlParser) Parse(filename string, content []byte) (*core.Result,

var licenses []string
if cargo.Package.License != "" {
licenses = []string{cargo.Package.License}
licenses = []string{string(cargo.Package.License)}
}
return &core.Result{
Name: pkgName,
Version: cargo.Package.Version,
Version: string(cargo.Package.Version),
Licenses: licenses,
LicenseFile: cargo.Package.LicenseFile,
LicenseFile: string(cargo.Package.LicenseFile),
Dependencies: filtered,
Declarations: declarations,
}, nil
Expand Down
54 changes: 54 additions & 0 deletions internal/cargo/cargo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,60 @@ anyhow = "=1.0.0"
}
}

func TestCargoTomlWorkspaceInheritedPackageFields(t *testing.T) {
content := []byte(`[package]
name = "member"
version.workspace = true
license.workspace = true
license-file = { workspace = true }
edition.workspace = true

[dependencies]
serde = "1.0"
`)

parser := &cargoTomlParser{}
result, err := parser.Parse("Cargo.toml", content)
if err != nil {
t.Fatalf("Parse failed: %v", err)
}
if result.Name != "member" {
t.Errorf("Name = %q, want %q", result.Name, "member")
}
if result.Version != "" {
t.Errorf("Version = %q, want empty for workspace-inherited", result.Version)
}
if result.Licenses != nil {
t.Errorf("Licenses = %v, want nil for workspace-inherited", result.Licenses)
}
if result.LicenseFile != "" {
t.Errorf("LicenseFile = %q, want empty for workspace-inherited", result.LicenseFile)
}
if len(result.Dependencies) != 1 || result.Dependencies[0].Name != "serde" {
t.Fatalf("Dependencies = %+v, want [serde]", result.Dependencies)
}

literal := []byte(`[package]
name = "root"
version = "1.2.3"
license = "MIT OR Apache-2.0"
license-file = "COPYING"
`)
result, err = parser.Parse("Cargo.toml", literal)
if err != nil {
t.Fatalf("Parse literal failed: %v", err)
}
if result.Version != "1.2.3" {
t.Errorf("literal Version = %q, want %q", result.Version, "1.2.3")
}
if len(result.Licenses) != 1 || result.Licenses[0] != "MIT OR Apache-2.0" {
t.Errorf("literal Licenses = %v, want [MIT OR Apache-2.0]", result.Licenses)
}
if result.LicenseFile != "COPYING" {
t.Errorf("literal LicenseFile = %q, want %q", result.LicenseFile, "COPYING")
}
}

func TestCargoLock(t *testing.T) {
content, err := os.ReadFile("../../testdata/cargo/Cargo.lock")
if err != nil {
Expand Down