xref: /aosp_15_r20/external/spdx-tools/licensediff/licensediff.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1// Package licensediff is used to generate a "diff" between the concluded
2// licenses in two SPDX Packages, using the filename as the match point.
3// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
4package licensediff
5
6import (
7	"github.com/spdx/tools-golang/spdx/v2_1"
8	"github.com/spdx/tools-golang/spdx/v2_2"
9	"github.com/spdx/tools-golang/spdx/v2_3"
10)
11
12// LicensePair is a result set where we are talking about two license strings,
13// potentially differing, for a single filename between two SPDX Packages.
14type LicensePair struct {
15	First  string
16	Second string
17}
18
19// MakePairs2_1 essentially just consolidates all files and LicenseConcluded
20// strings into a single data structure.
21func MakePairs2_1(p1 *v2_1.Package, p2 *v2_1.Package) (map[string]LicensePair, error) {
22	pairs := map[string]LicensePair{}
23
24	// first, go through and add all files/licenses from p1
25	for _, f := range p1.Files {
26		pair := LicensePair{First: f.LicenseConcluded, Second: ""}
27		pairs[f.FileName] = pair
28	}
29
30	// now, go through all files/licenses from p2. If already
31	// present, add as .second; if not, create new pair
32	for _, f := range p2.Files {
33		firstLic := ""
34		existingPair, ok := pairs[f.FileName]
35		if ok {
36			// already present; update it
37			firstLic = existingPair.First
38		}
39		// now, update what's there, either way
40		pair := LicensePair{First: firstLic, Second: f.LicenseConcluded}
41		pairs[f.FileName] = pair
42	}
43
44	return pairs, nil
45}
46
47// MakePairs2_2 essentially just consolidates all files and LicenseConcluded
48// strings into a single data structure.
49func MakePairs2_2(p1 *v2_2.Package, p2 *v2_2.Package) (map[string]LicensePair, error) {
50	pairs := map[string]LicensePair{}
51
52	// first, go through and add all files/licenses from p1
53	for _, f := range p1.Files {
54		pair := LicensePair{First: f.LicenseConcluded, Second: ""}
55		pairs[f.FileName] = pair
56	}
57
58	// now, go through all files/licenses from p2. If already
59	// present, add as .second; if not, create new pair
60	for _, f := range p2.Files {
61		firstLic := ""
62		existingPair, ok := pairs[f.FileName]
63		if ok {
64			// already present; update it
65			firstLic = existingPair.First
66		}
67		// now, update what's there, either way
68		pair := LicensePair{First: firstLic, Second: f.LicenseConcluded}
69		pairs[f.FileName] = pair
70	}
71
72	return pairs, nil
73}
74
75// MakePairs2_3 essentially just consolidates all files and LicenseConcluded
76// strings into a single data structure.
77func MakePairs2_3(p1 *v2_3.Package, p2 *v2_3.Package) (map[string]LicensePair, error) {
78	pairs := map[string]LicensePair{}
79
80	// first, go through and add all files/licenses from p1
81	for _, f := range p1.Files {
82		pair := LicensePair{First: f.LicenseConcluded, Second: ""}
83		pairs[f.FileName] = pair
84	}
85
86	// now, go through all files/licenses from p2. If already
87	// present, add as .second; if not, create new pair
88	for _, f := range p2.Files {
89		firstLic := ""
90		existingPair, ok := pairs[f.FileName]
91		if ok {
92			// already present; update it
93			firstLic = existingPair.First
94		}
95		// now, update what's there, either way
96		pair := LicensePair{First: firstLic, Second: f.LicenseConcluded}
97		pairs[f.FileName] = pair
98	}
99
100	return pairs, nil
101}
102
103// LicenseDiff is a structured version of the output of MakePairs. It is
104// meant to make it easier to find and report on, e.g., just the files that
105// have different licenses, or those that are in just one scan.
106type LicenseDiff struct {
107	InBothChanged map[string]LicensePair
108	InBothSame    map[string]string
109	InFirstOnly   map[string]string
110	InSecondOnly  map[string]string
111}
112
113// MakeResults creates a more structured set of results from the output
114// of MakePairs.
115func MakeResults(pairs map[string]LicensePair) (*LicenseDiff, error) {
116	diff := &LicenseDiff{
117		InBothChanged: map[string]LicensePair{},
118		InBothSame:    map[string]string{},
119		InFirstOnly:   map[string]string{},
120		InSecondOnly:  map[string]string{},
121	}
122
123	// walk through pairs and allocate them where they belong
124	for filename, pair := range pairs {
125		if pair.First == pair.Second {
126			diff.InBothSame[filename] = pair.First
127		} else {
128			if pair.First == "" {
129				diff.InSecondOnly[filename] = pair.Second
130			} else if pair.Second == "" {
131				diff.InFirstOnly[filename] = pair.First
132			} else {
133				diff.InBothChanged[filename] = pair
134			}
135		}
136	}
137
138	return diff, nil
139}
140