blob: 41c03a819fdb6a2707726ea8d5177fe7e2d6d41b [file] [log] [blame]
// Copyright 2019 The Go 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 frontend
import (
"bytes"
"context"
"sort"
"strconv"
"github.com/google/safehtml"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/licenses"
)
// License contains information used for a single license section.
type License struct {
*licenses.License
Anchor safehtml.Identifier
Source string
}
// LicensesDetails contains license information for a package or module.
type LicensesDetails struct {
Licenses []License
}
// LicenseMetadata contains license metadata that is used in the package
// header.
type LicenseMetadata struct {
Type string
Anchor safehtml.Identifier
}
// fetchLicensesDetails fetches license data for the package version specified by
// path and version from the database and returns a LicensesDetails.
func fetchLicensesDetails(ctx context.Context, ds internal.DataSource, um *internal.UnitMeta) (*LicensesDetails, error) {
u, err := ds.GetUnit(ctx, um, internal.WithLicenses, internal.BuildContext{})
if err != nil {
return nil, err
}
return &LicensesDetails{Licenses: transformLicenses(um.ModulePath, um.Version, u.LicenseContents)}, nil
}
// transformLicenses transforms licenses.License into a License
// by adding an anchor field.
func transformLicenses(modulePath, requestedVersion string, dbLicenses []*licenses.License) []License {
licenses := make([]License, len(dbLicenses))
var filePaths []string
for _, l := range dbLicenses {
filePaths = append(filePaths, l.FilePath)
}
anchors := licenseAnchors(filePaths)
for i, l := range dbLicenses {
l.Contents = bytes.ReplaceAll(l.Contents, []byte("\r"), nil)
licenses[i] = License{
Anchor: anchors[i],
License: l,
Source: fileSource(modulePath, requestedVersion, l.FilePath),
}
}
return licenses
}
// transformLicenseMetadata transforms licenses.Metadata into a LicenseMetadata
// by adding an anchor field.
func transformLicenseMetadata(dbLicenses []*licenses.Metadata) []LicenseMetadata {
var mds []LicenseMetadata
var filePaths []string
for _, l := range dbLicenses {
filePaths = append(filePaths, l.FilePath)
}
anchors := licenseAnchors(filePaths)
for i, l := range dbLicenses {
anchor := anchors[i]
for _, typ := range l.Types {
mds = append(mds, LicenseMetadata{
Type: typ,
Anchor: anchor,
})
}
}
return mds
}
// licenseAnchors returns anchors (HTML identifiers) for all the paths, in the
// same order. If the paths are unique, it ensures that the resulting anchors
// are unique. The argument is modified.
func licenseAnchors(paths []string) []safehtml.Identifier {
// Remember the original index of each path.
index := map[string]int{}
for i, p := range paths {
index[p] = i
}
// Pick a canonical order for the paths, so we assign the same anchors
// the same set of paths regardless of the order they're given to use.
sort.Strings(paths)
ids := make([]safehtml.Identifier, len(paths))
for i, p := range paths {
ids[index[p]] = safehtml.IdentifierFromConstantPrefix("lic", strconv.Itoa(i))
}
return ids
}