Files
zeekayandHanzo Dev aa87442fdd Record upstream authorship centrally in NOTICE instead of in every file header
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the
Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in
NOTICE, alongside LICENSE. The header lint accepts any copyright line above the
SPDX line, so it no longer demands an upstream one.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 17:50:35 -07:00

114 lines
2.8 KiB
Go

// Copyright 2026 Hanzo AI, Inc. All rights reserved.
// SPDX-License-Identifier: MIT
package repository
import (
"bufio"
"bytes"
"fmt"
"regexp"
"strings"
"github.com/hanzoai/git/modules/options"
)
type LicenseValues struct {
Owner string
Email string
Repo string
Year string
}
func GetLicense(name string, values *LicenseValues) ([]byte, error) {
data, err := options.License(name)
if err != nil {
return nil, fmt.Errorf("GetLicense[%s]: %w", name, err)
}
return fillLicensePlaceholder(name, values, data), nil
}
func fillLicensePlaceholder(name string, values *LicenseValues, origin []byte) []byte {
placeholder := getLicensePlaceholder(name)
scanner := bufio.NewScanner(bytes.NewReader(origin))
output := bytes.NewBuffer(nil)
for scanner.Scan() {
line := scanner.Text()
if placeholder.MatchLine == nil || placeholder.MatchLine.MatchString(line) {
for _, v := range placeholder.Owner {
line = strings.ReplaceAll(line, v, values.Owner)
}
for _, v := range placeholder.Email {
line = strings.ReplaceAll(line, v, values.Email)
}
for _, v := range placeholder.Repo {
line = strings.ReplaceAll(line, v, values.Repo)
}
for _, v := range placeholder.Year {
line = strings.ReplaceAll(line, v, values.Year)
}
}
output.WriteString(line + "\n")
}
return output.Bytes()
}
type licensePlaceholder struct {
Owner []string
Email []string
Repo []string
Year []string
MatchLine *regexp.Regexp
}
func getLicensePlaceholder(name string) *licensePlaceholder {
// Some universal placeholders.
// If you want to add a new one, make sure you have check it by `grep -r 'NEW_WORD' options/license` and all of them are placeholders.
ret := &licensePlaceholder{
Owner: []string{
"<name of author>",
"<owner>",
"[NAME]",
"[name of copyright owner]",
"[name of copyright holder]",
"<COPYRIGHT HOLDERS>",
"<copyright holders>",
"<AUTHOR>",
"<author's name or designee>",
"[one or more legally recognised persons or entities offering the Work under the terms and conditions of this Licence]",
},
Email: []string{
"[EMAIL]",
},
Repo: []string{
"<program>",
"<one line to give the program's name and a brief idea of what it does.>",
},
Year: []string{
"<year>",
"[YEAR]",
"{YEAR}",
"[yyyy]",
"[Year]",
"[year]",
},
}
// Some special placeholders for specific licenses.
// It's unsafe to apply them to all licenses.
switch name {
case "0BSD":
return &licensePlaceholder{
Owner: []string{"AUTHOR"},
Email: []string{"EMAIL"},
Year: []string{"YEAR"},
MatchLine: regexp.MustCompile(`Copyright \(C\) YEAR by AUTHOR EMAIL`), // there is another AUTHOR in the file, but it's not a placeholder
}
// Other special placeholders can be added here.
}
return ret
}