blob: f959fd082f1663901656537b36c83e9365f1fce4 [file] [log] [blame]
// Copyright 2022 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 project
import (
"fmt"
"path/filepath"
"strings"
spdx "github.com/spdx/tools-golang/spdx/v2_2"
"go.fuchsia.dev/fuchsia/tools/check-licenses/file"
"go.fuchsia.dev/fuchsia/tools/check-licenses/project/readme"
)
// Project struct follows the format of README.fuchsia files.
// For more info, see the following article:
//
// https://fuchsia.dev/fuchsia-src/development/source_code/third-party-metadata
type Project struct {
Root string `json:"root"`
Name string `json:"name"`
URL string
LicenseFiles []*file.File `licenseFiles`
RegularFiles []*file.File
SearchableRegularFiles []*file.File
ReadmeFile *readme.Readme
// Projects that this project depends on.
// Constructed from the GN dependency tree.
Children map[string]*Project
// SPDX fields
Package *spdx.Package "json:'package'"
SPDXID string `json:"spdxid"`
// Compliance fields.
BeingSurfaced bool
SourceCodeIncluded bool
}
// Order implements sort.Interface for []*Project based on the Root field.
type Order []*Project
func (a Order) Len() int { return len(a) }
func (a Order) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a Order) Less(i, j int) bool { return a[i].Root < a[j].Root }
// NewProject creates a Project object from a README.fuchsia file.
func NewProject(r *readme.Readme, projectRootPath string) (*Project, error) {
var err error
// Make all projectRootPath values relative to Config.FuchsiaDir.
if strings.Contains(projectRootPath, Config.FuchsiaDir) {
projectRootPath, err = filepath.Rel(Config.FuchsiaDir, projectRootPath)
if err != nil {
return nil, err
}
}
// See if we've already processed this project.
// If so, return the previously created instance.
if _, ok := AllProjects[projectRootPath]; ok {
plusVal(NumPreviousProjectRetrieved, projectRootPath)
return AllProjects[projectRootPath], nil
}
p := &Project{
Root: projectRootPath,
Name: r.Name,
URL: r.URL,
ReadmeFile: r,
LicenseFiles: make([]*file.File, 0),
RegularFiles: make([]*file.File, 0),
SearchableRegularFiles: make([]*file.File, 0),
Children: make(map[string]*Project, 0),
}
for _, l := range r.Licenses {
if l.LicenseFile == "" {
continue
}
if l.LicenseFileFormat == "" {
l.LicenseFileFormat = "Single License File"
}
path := filepath.Join(p.Root, l.LicenseFile)
f, err := file.LoadFile(path, file.FileType(l.LicenseFileFormat), r.Name)
if err != nil {
// Readmes in asset dirs may occasionally go out of sync with
// the project they describe. This is to prevent roll breakages.
if r.IsAssetDirReadme {
continue
}
return nil, fmt.Errorf("failed to load license file %s: %w\n", path, err)
}
f.SetURL(l.LicenseFileURL)
p.LicenseFiles = append(p.LicenseFiles, f)
l.LicenseFileRef = f
}
AllProjects[p.Root] = p
plusVal(NumProjects, p.Root)
return p, nil
}
func (p *Project) AddFile(f *file.File) error {
if f.FileType() != file.RegularFile {
// This could be a license file.
// Make sure this file isn't already in the list.
for _, l := range p.LicenseFiles {
if l.RelPath() == f.RelPath() {
return nil
}
}
p.LicenseFiles = append(p.LicenseFiles, f)
relPath, _ := filepath.Rel(p.Root, f.RelPath())
p.ReadmeFile.AddLicense(relPath, f)
return nil
}
p.RegularFiles = append(p.RegularFiles, f)
ext := filepath.Ext(f.RelPath())
if _, ok := file.Config.Extensions[ext]; ok {
p.SearchableRegularFiles = append(p.SearchableRegularFiles, f)
}
return nil
}
func getGitInfo(path string) (string, string, error) {
url, err := git.GetURL(ctx, path)
if err != nil {
return "", "", fmt.Errorf("Failed to get git URL for path %s: %w", path, err)
}
// Turquoise repos return "sso" urls, so convert them to
// http links that a user can view in a browser.
url = strings.ReplaceAll(url, "sso://turquoise-internal", "https://turquoise-internal.googlesource.com")
// Retrieve the hash URL for the current commit.
hash, err := git.GetCommitHash(ctx, path)
if err != nil {
return "", "", fmt.Errorf("Failed to get git commit hash for path %s: %w", path, err)
}
return url, hash, nil
}