• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package results contains the result type returned by the classifier backend.
16// Placing the type into a separate module allows us to swap out backends and
17// still use the same datatype.
18package results
19
20import (
21	"bufio"
22	"fmt"
23	"os"
24	"sort"
25)
26
27// LicenseType is the assumed type of the unknown license.
28type LicenseType struct {
29	Filename   string
30	Name       string
31	MatchType  string
32	Variant    string
33	Confidence float64
34	StartLine  int
35	EndLine    int
36}
37
38// LicenseTypes is a list of LicenseType objects.
39type LicenseTypes []*LicenseType
40
41func (lt LicenseTypes) Len() int      { return len(lt) }
42func (lt LicenseTypes) Swap(i, j int) { lt[i], lt[j] = lt[j], lt[i] }
43func (lt LicenseTypes) Less(i, j int) bool {
44	if lt[i].Confidence > lt[j].Confidence {
45		return true
46	}
47	if lt[i].Confidence < lt[j].Confidence {
48		return false
49	}
50	if lt[i].Filename < lt[j].Filename {
51		return true
52	}
53	if lt[i].Filename > lt[j].Filename {
54		return false
55	}
56	return lt[i].EndLine < lt[j].EndLine
57}
58
59// Classification is the license classification for a segment of a file.
60type Classification struct {
61	Name       string
62	Confidence float64
63	StartLine  int
64	EndLine    int
65	Text       string `json:",omitempty"`
66}
67
68// Classifications contains all license classifications for a file
69type Classifications []*Classification
70
71// FileClassifications contains the license classifications for a particular file.
72type FileClassifications struct {
73	Filepath        string
74	Classifications Classifications
75}
76
77// JSONResult is the format for the jr JSON file
78type JSONResult []*FileClassifications
79
80func (jr JSONResult) Len() int           { return len(jr) }
81func (jr JSONResult) Swap(i, j int)      { jr[i], jr[j] = jr[j], jr[i] }
82func (jr JSONResult) Less(i, j int) bool { return jr[i].Filepath < jr[j].Filepath }
83
84// readFileLines will read a specified range of lines of a file
85func readFileLines(filename string, startLine, endLine int) (string, error) {
86	f, err := os.Open(filename)
87	if err != nil {
88		return "", err
89	}
90	defer f.Close()
91
92	scanner := bufio.NewScanner(f)
93	lines := ""
94	i := 0
95	for scanner.Scan() {
96		i++ // lines are 1-indexed
97		if i < startLine {
98			continue
99		} else if i > endLine {
100			break
101		}
102		lines += scanner.Text() + "\n"
103	}
104	if i < endLine {
105		return "", fmt.Errorf(
106			"line %d was the last line read from file %s, but endLine was set to %d", i, filename, endLine)
107	}
108	return lines, nil
109}
110
111// NewJSONResult creates a new JSONResult object from a LicenseTypes object.
112func NewJSONResult(licenses LicenseTypes, includeText bool) (JSONResult, error) {
113	fMap := map[string]*FileClassifications{}
114	for _, l := range licenses {
115		currF, ok := fMap[l.Filename]
116		if !ok {
117			currF = &FileClassifications{Filepath: l.Filename}
118			fMap[l.Filename] = currF
119		}
120		c := &Classification{
121			Name:       l.Name,
122			Confidence: l.Confidence,
123			StartLine:  l.StartLine,
124			EndLine:    l.EndLine,
125		}
126		if includeText {
127			text, err := readFileLines(l.Filename, l.StartLine, l.EndLine)
128			if err != nil {
129				return nil, err
130			}
131			c.Text = text
132		}
133		currF.Classifications = append(currF.Classifications, c)
134	}
135
136	jr := JSONResult{}
137	for _, fc := range fMap {
138		jr = append(jr, fc)
139	}
140	sort.Sort(jr)
141	return jr, nil
142}
143