blob: 7618504b6fbf23115f2a12ffc920bf2c8f8e51e0 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package checklicenses
import (
"context"
"errors"
"fmt"
"log"
"os"
"path/filepath"
"runtime/trace"
"sort"
"sync"
)
// Licenses is an object that facilitates operations on each License object in bulk.
type Licenses struct {
licenses []*License
notices []*License
sync.RWMutex
}
// NewLicenses returns a Licenses object with each license pattern loaded from
// the .lic folder location specified in the config file.
func NewLicenses(ctx context.Context, config *Config) (*Licenses, error) {
defer trace.StartRegion(ctx, "NewLicenses").End()
l := &Licenses{}
err := filepath.Walk(config.LicensePatternDir,
func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
license, err := NewLicense(path, config)
if err != nil {
return err
}
l.licenses = append(l.licenses, license)
return nil
})
if err != nil {
return nil, err
}
if len(l.licenses) == 0 {
return nil, errors.New("no licenses")
}
sort.Sort(licenseByPattern(l.licenses))
return l, nil
}
func (l *Licenses) GetFilesWithProhibitedLicenses() []string {
var filesWithProhibitedLicenses []string
set := map[string]bool{}
for _, license := range l.licenses {
if license.ValidType {
continue
}
for _, match := range license.matches {
for _, path := range match.Files {
if !contains(license.AllowedDirs, path) {
log.Printf("Prohibited: %q in %q\n", license.Category, path)
if _, found := set[path]; !found {
set[path] = true
filesWithProhibitedLicenses = append(filesWithProhibitedLicenses, path)
}
}
}
}
}
sort.Strings(filesWithProhibitedLicenses)
return filesWithProhibitedLicenses
}
func (l *Licenses) GetFilesWithBadLicenseUsage() []string {
var filesWithBadLicenseUsage []string
set := map[string]bool{}
for _, license := range l.licenses {
if len(license.BadLicenseUsage) > 0 {
for _, path := range license.BadLicenseUsage {
log.Printf("Not allowlisted: %q in %q\n", license.Category, path)
if _, found := set[path]; !found {
set[path] = true
filesWithBadLicenseUsage = append(filesWithBadLicenseUsage, path)
}
}
}
}
sort.Strings(filesWithBadLicenseUsage)
return filesWithBadLicenseUsage
}
func (l *Licenses) MatchSingleLicenseFile(data []byte, path string, metrics *Metrics, ft *FileTree) {
for _, license := range l.licenses {
if ok, match := license.Search(data, path); ok {
metrics.increment("num_single_license_file_match")
ft.Lock()
ft.SingleLicenseFiles[path] = append(ft.SingleLicenseFiles[path], license)
ft.LicenseMatches[path] = append(ft.LicenseMatches[path], match)
ft.Unlock()
}
}
}
func (l *Licenses) MatchNoticeFile(data []byte, path string, metrics *Metrics, ft *FileTree) {
custom := NewCustomLicense(path)
l.Lock()
l.notices = append(l.notices, custom)
l.Unlock()
if ok, match := custom.Search(data, path); ok {
metrics.increment("num_single_license_file_match")
ft.Lock()
ft.SingleLicenseFiles[path] = append(ft.SingleLicenseFiles[path], custom)
ft.LicenseMatches[path] = append(ft.LicenseMatches[path], match)
ft.Unlock()
} else {
fmt.Printf("Error: failed to match custom license text '%v'\n", path)
}
}
// MatchFile returns true if any License matches input data
// along with the license that matched. It returns false and nil
// if there were no matches.
func (l *Licenses) MatchFile(data []byte, path string, metrics *Metrics) (bool, *License, *Match) {
for _, license := range l.licenses {
if ok, match := license.Search(data, path); ok {
metrics.increment("num_licensed")
return true, license, match
}
}
return false, nil, nil
}