| // 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 file |
| |
| import ( |
| "bytes" |
| "crypto/sha1" |
| "encoding/base64" |
| |
| "go.fuchsia.dev/fuchsia/tools/check-licenses/file/notice" |
| ) |
| |
| // FileData holds the text information (and some metadata) for a given file. |
| // |
| // Many NOTICE files will include several license texts in it. |
| // FileData represents one of those segments. It also maintains a line number |
| // that points to the location of this license text in the original NOTICE file, |
| // making it easier to find this license text again later. |
| type FileData struct { |
| FilePath string |
| LibraryName string |
| LineNumber int |
| Data []byte |
| LicenseType string |
| |
| hash string |
| } |
| |
| // Order implements sort.Interface for []*FileData based on the FilePath field. |
| type OrderFileData []*FileData |
| |
| func (a OrderFileData) Len() int { return len(a) } |
| func (a OrderFileData) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
| func (a OrderFileData) Less(i, j int) bool { |
| if a[i].FilePath < a[j].FilePath { |
| return true |
| } |
| if a[i].FilePath > a[j].FilePath { |
| return false |
| } |
| return a[i].LineNumber < a[j].LineNumber |
| } |
| |
| func NewFileData(path string, content []byte, filetype FileType) ([]*FileData, error) { |
| data := make([]*FileData, 0) |
| |
| // The "LicenseFormat" field of each file is set at the project level |
| // (in README.fuchsia files) and it affects how they are analyzed here. |
| switch filetype { |
| |
| // Default: File.LicenseFormat == Any |
| // This is most likely a regular source file in the repository. |
| // May or may not have copyright information. |
| case Any: |
| data = append(data, &FileData{ |
| FilePath: path, |
| LineNumber: 0, |
| Data: bytes.TrimSpace(content), |
| }) |
| |
| // File.LicenseFormat == CopyrightHeader |
| // All source files belonging to "The Fuchsia Authors" (fuchsia.git) |
| // must contain Copyright header information. |
| case CopyrightHeader: |
| data = append(data, &FileData{ |
| FilePath: path, |
| LineNumber: 0, |
| Data: bytes.TrimSpace(content), |
| }) |
| |
| // File.LicenseFormat == SingleLicense |
| // Regular LICENSE files that contain text for a single license. |
| case SingleLicense: |
| data = append(data, &FileData{ |
| FilePath: path, |
| LineNumber: 0, |
| Data: bytes.TrimSpace(content), |
| }) |
| |
| // File.LicenseFormat == MultiLicense* |
| // NOTICE files that contain text for multiple licenses. |
| // See the files in the /notice subdirectory for more info. |
| case MultiLicenseChromium: |
| ndata, err := notice.ParseChromium(path, content) |
| if err != nil { |
| return nil, err |
| } |
| for _, d := range ndata { |
| data = append(data, &FileData{ |
| FilePath: path, |
| LineNumber: d.LineNumber, |
| LibraryName: d.LibraryName, |
| Data: bytes.TrimSpace(d.LicenseText), |
| }) |
| } |
| case MultiLicenseFlutter: |
| ndata, err := notice.ParseFlutter(path, content) |
| if err != nil { |
| return nil, err |
| } |
| for _, d := range ndata { |
| data = append(data, &FileData{ |
| FilePath: path, |
| LineNumber: d.LineNumber, |
| LibraryName: d.LibraryName, |
| Data: bytes.TrimSpace(d.LicenseText), |
| }) |
| } |
| case MultiLicenseAndroid: |
| ndata, err := notice.ParseAndroid(path, content) |
| if err != nil { |
| return nil, err |
| } |
| for _, d := range ndata { |
| data = append(data, &FileData{ |
| FilePath: path, |
| LineNumber: d.LineNumber, |
| LibraryName: d.LibraryName, |
| Data: bytes.TrimSpace(d.LicenseText), |
| }) |
| } |
| case MultiLicenseGoogle: |
| ndata, err := notice.ParseGoogle(path, content) |
| if err != nil { |
| return nil, err |
| } |
| for _, d := range ndata { |
| data = append(data, &FileData{ |
| FilePath: path, |
| LineNumber: d.LineNumber, |
| LibraryName: d.LibraryName, |
| Data: bytes.TrimSpace(d.LicenseText), |
| }) |
| } |
| } |
| |
| for _, d := range data { |
| for _, r := range Config.Replacements { |
| d.Data = bytes.ReplaceAll(d.Data, []byte(r.Replace), []byte(r.With)) |
| } |
| } |
| return data, nil |
| } |
| |
| func (fd *FileData) SetData(data []byte) { |
| fd.Data = data |
| fd.hash = "" |
| fd.Hash() |
| } |
| |
| // Hash the content of this filedata object, to help detect duplicate texts |
| // and help reduce the final NOTICE filesize. |
| func (fd *FileData) Hash() string { |
| if len(fd.hash) > 0 { |
| return fd.hash |
| } |
| |
| hasher := sha1.New() |
| hasher.Write(bytes.TrimSpace(fd.Data)) |
| fd.hash = base64.URLEncoding.EncodeToString(hasher.Sum(nil)) |
| return fd.hash |
| } |