diff --git a/build.sh b/build.sh
index 643d5b4d4..5ea6c7fc3 100755
--- a/build.sh
+++ b/build.sh
@@ -23,6 +23,7 @@ case "${1:-default}" in
prerelease)
script authors
+ script copyrights
build weblate
pushd man ; ./refresh.sh ; popd
git add -A gui man AUTHORS
diff --git a/gui/default/syncthing/core/aboutModalView.html b/gui/default/syncthing/core/aboutModalView.html
index e95a20348..8e82ba32f 100644
--- a/gui/default/syncthing/core/aboutModalView.html
+++ b/gui/default/syncthing/core/aboutModalView.html
@@ -38,45 +38,94 @@ Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Tomasz Wilczyński, Al
Syncthing includes the following software or portions thereof:
- - Bootstrap, Copyright © 2011-2016 Twitter, Inc.
+ - Bootstrap, Copyright © 2011-2016 Twitter, Inc.
- AngularJS, Copyright © 2010-2014, 2016 Google, Inc.
- - Date Range Picker, Copyright © 2012-2018 Dan Grossman.
+ - Date Range Picker, Copyright © 2012-2018 Dan Grossman.
- JQuery Fancytree Plugin, Copyright © 2008-2018 Martin Wendt.
+ - Font AwesomeCopyright © 2024 Fonticons, Inc.
- Fork Awesome, Copyright © 2018 Dave Gandy & Fork Awesome.
- - jQuery JavaScript Library, Copyright © jQuery Foundation and other contributors.
- - moment.js, Copyright © JS Foundation and other contributors.
+ - HumanDuration.js, Copyright © 2013-2024 Evan Hahn, portions copyright © 2024 Ross Smith II.
+ - jQuery JavaScript Library, Copyright © jQuery Foundation and other contributors.
+ - leaflet.js, Copyright © 2010-2025 Volodymyr Agafonkin, Copyright © 2010-2011 CloudMade.
+ - moment.js, Copyright © JS Foundation and other contributors.
+ - The Go Programming Language, Copyright © 2009 The Go Authors.
- Prometheus, Copyright © 2012-2015 The Prometheus Authors.
- - AudriusButkevicius/go-nat-pmp, Copyright © 2013 John Howard Palevich.
- AudriusButkevicius/recli, Copyright © 2019 Audrius Butkevicius.
+ - Azure/azure-sdk-for-go, Copyright © Microsoft Corporation.
+ - Azure/go-ntlmssp, Copyright © 2016 Microsoft.
+ - alecthomas/kong, Copyright © 2018 Alec Thomas.
+ - aws/aws-sdk-go, Copyright © 2015 Amazon.com, Inc. or its affiliates, Copyright 2014-2015 Stripe, Inc.
- beorn7/perks, Copyright © 2013 Blake Mizerany.
- - pierrec/lz4, Copyright © 2015 Pierre Curto.
- - calmh/du, Public domain.
+ - calmh/incontainer, Copyright © 2022 calmh.
- calmh/xdr, Copyright © 2014 Jakob Borg.
+ - ccding/go-stun, Copyright © 2016 Cong Ding.
+ - cenkalti/backoff, Copyright © 2014 Cenk Altı.
+ - certifi/gocertifi, Copyright © 2025, the certifi/gocertifi authors.
+ - cespare/xxhash, Copyright © 2016 Caleb Spare.
- chmduquesne/rollinghash, Copyright © 2015 Christophe-Marie Duquesne.
+ - cpuguy83/go-md2man, Copyright © 2014 Brian Goff.
- d4l3k/messagediff, Copyright © 2015 Tristan Rice.
+ - davecgh/go-spew, Copyright © 2012-2016 Dave Collins .
+ - ebitengine/purego, Copyright © 2022 The Ebitengine Authors.
+ - fsnotify/fsnotify, Copyright © 2012 The Go Authors.
+ - getsentry/raven-go, Copyright © 2013 Apollic Software, LLC.
+ - go-asn1-ber/asn1-ber, Copyright © 2011-2015 Michael Mitton (mmitton@gmail.com).
+ - go-ldap/ldap, Copyright © 2011-2015 Michael Mitton (mmitton@gmail.com).
+ - go-ole/go-ole, Copyright © 2013-2017 Yasuhiro Matsumoto, .
+ - go-task/slim-sprig, Copyright © 2013-2020 Masterminds.
+ - go.uber.org/automaxprocs, Copyright © 2017 Uber Technologies, Inc.
+ - go.uber.org/mock, Copyright © 2010-2022 Google LLC.
- gobwas/glob, Copyright © 2016 Sergey Kamardin.
- - golang/groupcache, Copyright © 2013 Google Inc.
- - golang/protobuf, Copyright © 2010 The Go Authors.
+ - gofrs/flock, Copyright © 2018-2025, The Gofrs.
- golang/snappy, Copyright © 2011 The Snappy-Go Authors.
+ - google.golang.org/protobuf, Copyright © 2018 The Go Authors.
+ - google/pprof, Copyright © 2016 Google Inc.
+ - google/uuid, Copyright © 2009,2014 Google Inc.
+ - gopkg.in/yaml.v3, Copyright © 2006-2010 Kirill Simonov.
+ - greatroar/blobloom, Copyright © 2020-2024 the Blobloom authors.
+ - hashicorp/errwrap, Copyright © 2014 HashiCorp, Inc.
+ - hashicorp/go-multierror, Copyright © 2014 HashiCorp, Inc.
+ - hashicorp/golang-lru, Copyright © 2014 HashiCorp, Inc.
- jackpal/gateway, Copyright © 2010 Jack Palevich.
+ - jackpal/go-nat-pmp, Copyright 2013 John Howard Palevich.
+ - jmespath/go-jmespath, Copyright © 2015 James Saryerwinnie.
+ - julienschmidt/httprouter, Copyright © 2013, Julien Schmidt.
- kballard/go-shellquote, Copyright © 2014 Kevin Ballard.
- - mattn/go-isatty, Copyright © Yasuhiro MATSUMOTO.
- - matttproud/golang_protobuf_extensions, Copyright © 2012 Matt T. Proud.
+ - klauspost/compress, Copyright © 2012 The Go Authors.
+ - lufia/plan9stats, Copyright © 2019, KADOTA, Kyohei.
+ - maruel/panicparse, Copyright 2015 Marc-Antoine Ruel.
+ - maxbrunsfeld/counterfeiter, Copyright © 2014 maxbrunsfeld.
+ - maxmind/geoipupdate, Copyright © 2018-2024 by MaxMind, Inc.
+ - miscreant/miscreant.go, Copyright © 2017-2019 The Miscreant Developers.
+ - munnerz/goautoneg, Copyright © 2011, Open Knowledge Foundation Ltd.
+ - nxadm/tail, Copyright © 2014 ActiveState.
+ - onsi/ginkgo, Copyright © 2013-2014 Onsi Fakhouri.
- oschwald/geoip2-golang, Copyright © 2015, Gregory J. Oschwald.
- oschwald/maxminddb-golang, Copyright © 2015, Gregory J. Oschwald.
- - petermattis/goid, Copyright © 2015-2016 Peter Mattis.
+ - pierrec/lz4, Copyright © 2015 Pierre Curto.
- pkg/errors, Copyright © 2015, Dave Cheney.
+ - pmezard/go-difflib, Copyright © 2013, Patrick Mezard.
+ - posener/complete, Copyright © 2017 Eyal Posener.
+ - power-devops/perfstat, Copyright © 2020 Power DevOps.
+ - puzpuzpuz/xsync, Copyright © 2025, the puzpuzpuz/xsync authors.
+ - quic-go/quic-go, Copyright © 2016 the quic-go authors & Google, Inc.
+ - rabbitmq/amqp091-go, Copyright © 2021 VMware, Inc. or its affiliates.
- rcrowley/go-metrics, Copyright © 2012 Richard Crowley.
- - sasha-s/go-deadlock, Copyright © 2016 sasha-s.
+ - riywo/loginshell, Copyright © 2019 Ryosuke IWANAGA.
+ - russross/blackfriday, Copyright © 2011 Russ Ross.
+ - shirou/gopsutil, Copyright © 2014, WAKAYAMA Shirou.
+ - sigs.k8s.io/yaml, Copyright © 2014 Sam Ghods.
+ - stretchr/objx, Copyright © 2014 Stretchr, Inc.
+ - stretchr/testify, Copyright © 2012-2020 Mat Ryer, Tyler Bunnell and contributors.
- syncthing/notify, Copyright © 2014-2015 The Notify Authors.
- syndtr/goleveldb, Copyright © 2012 Suryandaru Triandana.
- thejerf/suture, Copyright © 2014-2015 Barracuda Networks, Inc.
- - urfave/cli, Copyright © 2016 Jeremy Saenz & Contributors.
+ - tklauser/go-sysconf, Copyright © 2018-2022, Tobias Klauser.
+ - tklauser/numcpus, Copyright © 2018-2024 Tobias Klauser.
+ - urfave/cli, Copyright © 2016 Jeremy Saenz & Contributors.
- vitrun/qart, Copyright © 2010-2011 The Go Authors.
- - gopkg.in/asn1-ber.v1, Copyright © 2011-2015 Michael Mitton, portions Copyright © 2015-2016 go-asn1-ber Authors.
- - gopkg.in/ldap.v2, Copyright © 2011-2015 Michael Mitton, portions Copyright © 2015-2016 go-ldap Authors.
- - The Go Programming Language, Copyright © 2009 The Go Authors.
- - Font Awesome by Dave Gandy - http://fontawesome.io
+ - willabides/kongplete, Copyright © 2020 WillAbides.
+ - yusufpapurcu/wmi, Copyright © 2013 Stack Exchange.
diff --git a/script/copyrights.go b/script/copyrights.go
new file mode 100644
index 000000000..f192893c2
--- /dev/null
+++ b/script/copyrights.go
@@ -0,0 +1,489 @@
+// Copyright (C) 2025 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+//go:build ignore
+// +build ignore
+
+// Updates the list of software copyrights in aboutModalView.html based on the
+// output of `go mod graph`.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "os/exec"
+ "regexp"
+ "slices"
+ "strconv"
+ "strings"
+ "time"
+
+ "golang.org/x/net/html"
+)
+
+var copyrightMap = map[string]string{
+ // https://github.com/aws/aws-sdk-go/blob/main/NOTICE.txt#L2
+ "aws/aws-sdk-go": "Copyright © 2015 Amazon.com, Inc. or its affiliates, Copyright 2014-2015 Stripe, Inc",
+ // https://github.com/ccding/go-stun/blob/master/main.go#L1
+ "ccding/go-stun": "Copyright © 2016 Cong Ding",
+ // https://github.com/search?q=repo%3Acertifi%2Fgocertifi%20copyright&type=code
+ // "certifi/gocertifi": "No copyrights found",
+ // https://github.com/search?q=repo%3Aebitengine%2Fpurego%20copyright&type=code
+ "ebitengine/purego": "Copyright © 2022 The Ebitengine Authors",
+ // https://github.com/search?q=repo%3Agoogle%2Fpprof%20copyright&type=code
+ "google/pprof": "Copyright © 2016 Google Inc",
+ // https://github.com/greatroar/blobloom/blob/master/README.md?plain=1#L74
+ "greatroar/blobloom": "Copyright © 2020-2024 the Blobloom authors",
+ // https://github.com/jmespath/go-jmespath/blob/master/NOTICE#L2
+ "jmespath/go-jmespath": "Copyright © 2015 James Saryerwinnie",
+ // https://github.com/maxmind/geoipupdate/blob/main/README.md?plain=1#L140
+ "maxmind/geoipupdate": "Copyright © 2018-2024 by MaxMind, Inc",
+ // https://github.com/search?q=repo%3Apuzpuzpuz%2Fxsync%20copyright&type=code
+ // "puzpuzpuz/xsync": "No copyrights found",
+ // https://github.com/search?q=repo%3Atklauser%2Fnumcpus%20copyright&type=code
+ "tklauser/numcpus": "Copyright © 2018-2024 Tobias Klauser",
+ // https://github.com/search?q=repo%3Auber-go%2Fmock%20copyright&type=code
+ "go.uber.org/mock": "Copyright © 2010-2022 Google LLC",
+}
+
+var urlMap = map[string]string{
+ "fontawesome.io": "https://github.com/FortAwesome/Font-Awesome",
+ "go.uber.org/automaxprocs": "https://github.com/uber-go/automaxprocs",
+ "go.uber.org/mock": "https://github.com/uber-go/mock",
+ "google.golang.org/protobuf": "https://github.com/protocolbuffers/protobuf-go",
+ "gopkg.in/yaml.v2": "", // ignore, as gopkg.in/yaml.v3 supersedes
+ "gopkg.in/yaml.v3": "https://github.com/go-yaml/yaml",
+ "sigs.k8s.io/yaml": "https://github.com/kubernetes-sigs/yaml",
+}
+
+const htmlFile = "gui/default/syncthing/core/aboutModalView.html"
+
+type Type int
+
+const (
+ // TypeJS defines non-Go copyright notices
+ TypeJS Type = iota
+ // TypeKeep defines Go copyright notices for packages that are still used.
+ TypeKeep
+ // TypeToss defines Go copyright notices for packages that are no longer used.
+ TypeToss
+ // TypeNew defines Go copyright notices for new packages found via `go mod graph`.
+ TypeNew
+)
+
+type CopyrightNotice struct {
+ Type Type
+ Name string
+ HTML string
+ Module string
+ URL string
+ Copyright string
+ RepoURL string
+ RepoCopyrights []string
+}
+
+var copyrightRe = regexp.MustCompile(`(?s)id="copyright-notices">(.+?)`)
+
+func main() {
+ bs := readAll(htmlFile)
+ matches := copyrightRe.FindStringSubmatch(string(bs))
+
+ if len(matches) <= 1 {
+ log.Fatal("Cannot find id copyright-notices in ", htmlFile)
+ }
+
+ modules := getModules()
+
+ notices := parseCopyrightNotices(matches[1])
+ old := len(notices)
+
+ // match up modules to notices
+ matched := map[string]bool{}
+ removes := 0
+ for i, notice := range notices {
+ if notice.Type == TypeJS {
+ continue
+ }
+ found := ""
+ for _, module := range modules {
+ if strings.Contains(module, notice.Name) {
+ found = module
+
+ break
+ }
+ }
+ if found != "" {
+ matched[found] = true
+ notices[i].Module = found
+
+ continue
+ }
+ removes++
+ fmt.Printf("Removing: %-40s %-55s %s\n", notice.Name, notice.URL, notice.Copyright)
+ notices[i].Type = TypeToss
+ }
+
+ // add new modules to notices
+ adds := 0
+ for _, module := range modules {
+ _, ok := matched[module]
+ if ok {
+ continue
+ }
+
+ adds++
+ notice := CopyrightNotice{}
+ notice.Name = module
+ if strings.HasPrefix(notice.Name, "github.com/") {
+ notice.Name = strings.ReplaceAll(notice.Name, "github.com/", "")
+ }
+ notice.Type = TypeNew
+
+ url, ok := urlMap[module]
+ if ok {
+ notice.URL = url
+ notice.RepoURL = url
+ } else {
+ notice.URL = "https://" + module
+ notice.RepoURL = "https://" + module
+ }
+ notices = append(notices, notice)
+ }
+
+ if removes == 0 && adds == 0 {
+ // authors.go is quiet, so let's be quiet too.
+ // fmt.Printf("No changes detected in %d modules and %d notices\n", len(modules), len(notices))
+ os.Exit(0)
+ }
+
+ // get copyrights via Github API for new modules
+ notfound := 0
+ for i, n := range notices {
+ if n.Type != TypeNew {
+ continue
+ }
+ copyright, ok := copyrightMap[n.Name]
+ if ok {
+ notices[i].Copyright = copyright
+
+ continue
+ }
+ notices[i].Copyright = defaultCopyright(n)
+
+ if strings.Contains(n.URL, "github.com/") {
+ notices[i].RepoURL = notices[i].URL
+ owner, repo := parseGitHubURL(n.URL)
+ licenseText := getLicenseText(owner, repo)
+ notices[i].RepoCopyrights = extractCopyrights(licenseText, n)
+
+ if len(notices[i].RepoCopyrights) > 0 {
+ notices[i].Copyright = notices[i].RepoCopyrights[0]
+ }
+
+ notices[i].HTML = fmt.Sprintf("%s, %s.", n.URL, n.Name, notices[i].Copyright)
+ if len(notices[i].RepoCopyrights) > 0 {
+ continue
+ }
+ }
+ fmt.Printf("Copyright not found: %-30s : using %q\n", n.Name, notices[i].Copyright)
+ notfound++
+ }
+
+ replacements := write(notices, bs)
+ fmt.Printf("Removed: %3d\n", removes)
+ fmt.Printf("Added: %3d\n", adds)
+ fmt.Printf("Copyrights not found: %3d\n", notfound)
+ fmt.Printf("Old package count: %3d\n", old)
+ fmt.Printf("New package count: %3d\n", replacements)
+}
+
+func write(notices []CopyrightNotice, bs []byte) int {
+ keys := make([]string, 0, len(notices))
+
+ noticeMap := make(map[string]CopyrightNotice, 0)
+
+ for _, n := range notices {
+ if n.Type != TypeKeep && n.Type != TypeNew {
+ continue
+ }
+ if n.Type == TypeNew {
+ fmt.Printf("Adding: %-40s %-55s %s\n", n.Name, n.URL, n.Copyright)
+ }
+ keys = append(keys, n.Name)
+ noticeMap[n.Name] = n
+ }
+
+ slices.Sort(keys)
+
+ indent := " "
+ replacements := []string{}
+ for _, n := range notices {
+ if n.Type != TypeJS {
+ continue
+ }
+ replacements = append(replacements, indent+n.HTML)
+ }
+
+ for _, k := range keys {
+ n := noticeMap[k]
+ line := fmt.Sprintf("%s%s, %s.", indent, n.URL, n.Name, n.Copyright)
+ replacements = append(replacements, line)
+ }
+ replacement := strings.Join(replacements, "\n")
+
+ bs = copyrightRe.ReplaceAll(bs, []byte("id=\"copyright-notices\">\n"+replacement+"\n "))
+ writeFile(htmlFile, string(bs))
+
+ return len(replacements)
+}
+
+func readAll(path string) []byte {
+ fd, err := os.Open(path)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer fd.Close()
+
+ bs, err := io.ReadAll(fd)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ return bs
+}
+
+func writeFile(path string, data string) {
+ err := os.WriteFile(path, []byte(data), 0o644)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func getModules() []string {
+ cmd := exec.Command("go", "mod", "graph")
+ output, err := cmd.Output()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ seen := make(map[string]struct{})
+ scanner := bufio.NewScanner(bytes.NewReader(output))
+
+ for scanner.Scan() {
+ line := scanner.Text()
+ fields := strings.Fields(line)
+ if len(fields) == 0 {
+ continue
+ }
+
+ if !strings.HasPrefix(fields[0], "github.com/syncthing/syncthing") {
+ continue
+ }
+
+ // Get left-hand side of dependency pair (before '@')
+ mod := strings.SplitN(fields[1], "@", 2)[0]
+
+ // Keep only first 3 path components
+ parts := strings.Split(mod, "/")
+ if len(parts) == 1 {
+ continue
+ }
+ short := strings.Join(parts[:min(len(parts), 3)], "/")
+
+ if strings.HasPrefix(short, "golang.org/x") ||
+ strings.HasPrefix(short, "github.com/prometheus") ||
+ short == "go" {
+
+ continue
+ }
+
+ seen[short] = struct{}{}
+ }
+
+ adds := make([]string, 0)
+ for k := range seen {
+ adds = append(adds, k)
+ }
+
+ slices.Sort(adds)
+
+ return adds
+}
+
+func parseCopyrightNotices(input string) []CopyrightNotice {
+ doc, err := html.Parse(strings.NewReader(""))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var notices []CopyrightNotice
+
+ typ := TypeJS
+
+ var f func(*html.Node)
+ f = func(n *html.Node) {
+ if n.Type == html.ElementNode && n.Data == "li" {
+ var notice CopyrightNotice
+ var aFound bool
+
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ if c.Type == html.ElementNode && c.Data == "a" {
+ aFound = true
+ for _, attr := range c.Attr {
+ if attr.Key == "href" {
+ notice.URL = attr.Val
+ }
+ }
+ if c.FirstChild != nil && c.FirstChild.Type == html.TextNode {
+ notice.Name = strings.TrimSpace(c.FirstChild.Data)
+ }
+ } else if c.Type == html.TextNode && aFound {
+ // Anything after is considered the copyright
+ notice.Copyright = strings.TrimSpace(html.UnescapeString(c.Data))
+ notice.Copyright = strings.Trim(notice.Copyright, "., ")
+ }
+ if typ == TypeJS && strings.Contains(notice.URL, "AudriusButkevicius") {
+ typ = TypeKeep
+ }
+ notice.Type = typ
+ var buf strings.Builder
+ _ = html.Render(&buf, n)
+ notice.HTML = buf.String()
+ }
+
+ notice.Copyright = strings.ReplaceAll(notice.Copyright, "©", "©")
+ notice.HTML = strings.ReplaceAll(notice.HTML, "©", "©")
+ notices = append(notices, notice)
+ }
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ f(c)
+ }
+ }
+
+ f(doc)
+
+ return notices
+}
+
+func parseGitHubURL(u string) (string, string) {
+ parsed, err := url.Parse(u)
+ if err != nil {
+ log.Fatal(err)
+ }
+ parts := strings.Split(strings.Trim(parsed.Path, "/"), "/")
+ if len(parts) < 2 {
+ log.Fatal(fmt.Errorf("invalid GitHub URL: %q", parsed.Path))
+ }
+
+ return parts[0], parts[1]
+}
+
+func getLicenseText(owner, repo string) string {
+ url := fmt.Sprintf("https://api.github.com/repos/%s/%s/license", owner, repo)
+ req, _ := http.NewRequest("GET", url, nil)
+ req.Header.Set("Accept", "application/vnd.github.v3+json")
+
+ if token := os.Getenv("GITHUB_TOKEN"); token != "" {
+ req.Header.Set("Authorization", "Bearer "+token)
+ }
+
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer resp.Body.Close()
+
+ var result struct {
+ Content string `json:"content"`
+ Encoding string `json:"encoding"`
+ }
+ body, _ := io.ReadAll(resp.Body)
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if result.Encoding != "base64" {
+ log.Fatal(fmt.Sprintf("unexpected encoding: %s", result.Encoding))
+ }
+
+ decoded, err := base64.StdEncoding.DecodeString(result.Content)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ return string(decoded)
+}
+
+func extractCopyrights(license string, notice CopyrightNotice) []string {
+ lines := strings.Split(license, "\n")
+
+ re := regexp.MustCompile(`(?i)^\s*(copyright\s*(?:©|\(c\)|©|19|20).*)$`)
+
+ copyrights := []string{}
+
+ for _, line := range lines {
+ if matches := re.FindStringSubmatch(strings.TrimSpace(line)); len(matches) == 2 {
+ copyright := strings.TrimSpace(matches[1])
+ re := regexp.MustCompile(`(?i)all rights reserved`)
+ copyright = re.ReplaceAllString(copyright, "")
+ copyright = strings.ReplaceAll(copyright, "©", "©")
+ copyright = strings.ReplaceAll(copyright, "(C)", "©")
+ copyright = strings.ReplaceAll(copyright, "(c)", "©")
+ copyright = strings.Trim(copyright, "., ")
+ copyrights = append(copyrights, copyright)
+ }
+ }
+
+ if len(copyrights) > 0 {
+ return copyrights
+ }
+
+ return []string{}
+}
+
+func defaultCopyright(n CopyrightNotice) string {
+ year := time.Now().Format("2006")
+
+ return fmt.Sprintf("Copyright © %v, the %s authors", year, n.Name)
+}
+
+func writeNotices(path string, notices []CopyrightNotice) {
+ s := ""
+ for i, n := range notices {
+ s += "# : " + strconv.Itoa(i) + "\n" + n.String()
+ }
+ writeFile(path, s)
+}
+
+func (n CopyrightNotice) String() string {
+ return fmt.Sprintf("Type : %v\nHTML : %v\nName : %v\nModule : %v\nURL : %v\nCopyright: %v\nRepoURL : %v\nRepoCopys: %v\n\n",
+ n.Type, n.HTML, n.Name, n.Module, n.URL, n.Copyright, n.RepoURL, strings.Join(n.RepoCopyrights, ","))
+}
+
+func (t Type) String() string {
+ switch t {
+ case TypeJS:
+ return "TypeJS"
+ case TypeKeep:
+ return "TypeKeep"
+ case TypeToss:
+ return "TypeToss"
+ case TypeNew:
+ return "TypeNew"
+ default:
+ return "unknown"
+ }
+}