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