blob: 716d764ae69dce871b77551b62162319c526453a [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"
"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 _, found := set[path]; !found && !contains(license.AllowedDirs, path) {
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 {
if _, found := set[path]; !found {
set[path] = true
filesWithBadLicenseUsage = append(filesWithBadLicenseUsage, path)
}
}
}
}
sort.Strings(filesWithBadLicenseUsage)
return filesWithBadLicenseUsage
}
func CheckLicenseAllowList(license *License, path string) bool {
var licenseAllowed = true
if len(license.AllowedDirs) > 0 && !contains(license.AllowedDirs, path) {
license.BadLicenseUsage = append(license.BadLicenseUsage, path)
licenseAllowed = false
}
return licenseAllowed
}
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 && CheckLicenseAllowList(license, path) {
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 && CheckLicenseAllowList(license, path) {
metrics.increment("num_licensed")
return true, license, match
}
}
return false, nil, nil
}