From 43129a1901149607b65e4c4dd831cd4a13dbfead Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Tue, 23 May 2023 06:47:35 +0000
Subject: [PATCH 001/172] add repo license check
---
go.mod | 1 +
go.sum | 2 +
modules/util/path.go | 31 +++++++-----
options/locale/locale_en-US.ini | 1 +
routers/web/repo/view.go | 85 +++++++++++++++++++++++++--------
templates/repo/sub_menu.tmpl | 11 +++++
6 files changed, 101 insertions(+), 30 deletions(-)
diff --git a/go.mod b/go.mod
index 93b8052daf86..85b75d425725 100644
--- a/go.mod
+++ b/go.mod
@@ -203,6 +203,7 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.3.3 // indirect
+ github.com/google/licensecheck v0.3.1 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
diff --git a/go.sum b/go.sum
index 8e5b728aac9d..b4911d746fa3 100644
--- a/go.sum
+++ b/go.sum
@@ -575,6 +575,8 @@ github.com/google/go-tpm v0.3.3/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51B
github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845/go.mod h1:AVfHadzbdzHo54inR2x1v640jdi1YSi3NauM2DUsxk0=
github.com/google/go-tpm-tools v0.2.0/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs=
+github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
diff --git a/modules/util/path.go b/modules/util/path.go
index 1a68bc748802..8164d91c4b9a 100644
--- a/modules/util/path.go
+++ b/modules/util/path.go
@@ -282,38 +282,47 @@ func CommonSkip(name string) bool {
return false
}
-// IsReadmeFileName reports whether name looks like a README file
+type FileType string
+
+const (
+ FileTypeReadme FileType = "readme"
+ FileTypeLicense FileType = "license"
+)
+
+// IsFileName reports whether name looks like a fileType file
// based on its name.
-func IsReadmeFileName(name string) bool {
+func IsFileName(name string, fileType FileType) bool {
name = strings.ToLower(name)
- if len(name) < 6 {
+ lenFileType := len(fileType)
+ if len(name) < lenFileType {
return false
- } else if len(name) == 6 {
- return name == "readme"
+ } else if len(name) == lenFileType {
+ return name == string(fileType)
}
- return name[:7] == "readme."
+ return name[:lenFileType+1] == string(fileType)+"."
}
-// IsReadmeFileExtension reports whether name looks like a README file
+// IsFileExtension reports whether name looks like a fileType file
// based on its name. It will look through the provided extensions and check if the file matches
// one of the extensions and provide the index in the extension list.
// If the filename is `readme.` with an unmatched extension it will match with the index equaling
// the length of the provided extension list.
// Note that the '.' should be provided in ext, e.g ".md"
-func IsReadmeFileExtension(name string, ext ...string) (int, bool) {
+func IsFileExtension(name string, fileType FileType, ext ...string) (int, bool) {
name = strings.ToLower(name)
- if len(name) < 6 || name[:6] != "readme" {
+ lenFileType := len(fileType)
+ if len(name) < lenFileType || name[:lenFileType] != string(fileType) {
return 0, false
}
for i, extension := range ext {
extension = strings.ToLower(extension)
- if name[6:] == extension {
+ if name[lenFileType:] == extension {
return i, true
}
}
- if name[6] == '.' {
+ if name[lenFileType] == '.' {
return len(ext), true
}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 80ccecbce162..72917997c0bd 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -930,6 +930,7 @@ issue_labels_helper = Select an issue label set.
license = License
license_helper = Select a license file.
license_helper_desc = A license governs what others can and can't do with your code. Not sure which one is right for your project? See Choose a license.
+multiple_licenses = Multiple Licenses
readme = README
readme_helper = Select a README file template.
readme_helper_desc = This is the place where you can write a complete description for your project.
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 2fd893f91c6d..870df8d99750 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -42,6 +42,7 @@ import (
"code.gitea.io/gitea/routers/web/feed"
issue_service "code.gitea.io/gitea/services/issue"
+ "github.com/google/licensecheck"
"github.com/nektos/act/pkg/model"
)
@@ -54,7 +55,7 @@ const (
tplMigrating base.TplName = "repo/migrate/migrating"
)
-// locate a README for a tree in one of the supported paths.
+// locate a README/LICENSE for a tree in one of the supported paths.
//
// entries is passed to reduce calls to ListEntries(), so
// this has precondition:
@@ -62,14 +63,14 @@ const (
// entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries()
//
// FIXME: There has to be a more efficient way of doing this
-func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, tryWellKnownDirs bool) (string, *git.TreeEntry, error) {
+func findFileInEntries(ctx *context.Context, fileType util.FileType, entries []*git.TreeEntry, tryWellKnownDirs bool) (string, *git.TreeEntry, error) {
// Create a list of extensions in priority order
// 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
// 2. Txt files - e.g. README.txt
// 3. No extension - e.g. README
exts := append(localizedExtensions(".md", ctx.Locale.Language()), ".txt", "") // sorted by priority
extCount := len(exts)
- readmeFiles := make([]*git.TreeEntry, extCount+1)
+ targetFiles := make([]*git.TreeEntry, extCount+1)
docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/)
for _, entry := range entries {
@@ -94,31 +95,31 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, try
}
continue
}
- if i, ok := util.IsReadmeFileExtension(entry.Name(), exts...); ok {
+ if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok {
log.Debug("Potential readme file: %s", entry.Name())
- if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].Name(), entry.Blob().Name()) {
+ if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) {
if entry.IsLink() {
target, err := entry.FollowLinks()
if err != nil && !git.IsErrBadLink(err) {
return "", nil, err
} else if target != nil && (target.IsExecutable() || target.IsRegular()) {
- readmeFiles[i] = entry
+ targetFiles[i] = entry
}
} else {
- readmeFiles[i] = entry
+ targetFiles[i] = entry
}
}
}
}
- var readmeFile *git.TreeEntry
- for _, f := range readmeFiles {
+ var targetFile *git.TreeEntry
+ for _, f := range targetFiles {
if f != nil {
- readmeFile = f
+ targetFile = f
break
}
}
- if ctx.Repo.TreePath == "" && readmeFile == nil {
+ if ctx.Repo.TreePath == "" && targetFile == nil {
for _, subTreeEntry := range docsEntries {
if subTreeEntry == nil {
continue
@@ -134,17 +135,17 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, try
return "", nil, err
}
- subfolder, readmeFile, err := findReadmeFileInEntries(ctx, childEntries, false)
+ subfolder, targetFile, err := findFileInEntries(ctx, fileType, childEntries, false)
if err != nil && !git.IsErrNotExist(err) {
return "", nil, err
}
- if readmeFile != nil {
- return path.Join(subTreeEntry.Name(), subfolder), readmeFile, nil
+ if targetFile != nil {
+ return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil
}
}
}
- return "", readmeFile, nil
+ return "", targetFile, nil
}
func renderDirectory(ctx *context.Context, treeLink string) {
@@ -158,13 +159,19 @@ func renderDirectory(ctx *context.Context, treeLink string) {
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
}
- subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true)
+ subfolder, readmeFile, err := findFileInEntries(ctx, util.FileTypeReadme, entries, true)
if err != nil {
- ctx.ServerError("findReadmeFileInEntries", err)
+ ctx.ServerError("findFileInEntries", err)
return
}
-
renderReadmeFile(ctx, subfolder, readmeFile, treeLink)
+
+ subfolder, licenseFile, err := findFileInEntries(ctx, util.FileTypeLicense, entries, false)
+ if err != nil {
+ ctx.ServerError("findFileInEntries", err)
+ return
+ }
+ renderLicenseFile(ctx, subfolder, licenseFile, treeLink)
}
// localizedExtensions prepends the provided language code with and without a
@@ -323,6 +330,46 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr
}
}
+func renderLicenseFile(ctx *context.Context, subfolder string, licenseFile *git.TreeEntry, readmeTreelink string) {
+ target := licenseFile
+ if licenseFile != nil && licenseFile.IsLink() {
+ target, _ = licenseFile.FollowLinks()
+ }
+ if target == nil {
+ // if findFile() failed and/or gave us a broken symlink (which it shouldn't)
+ // simply skip rendering the LICENSE
+ return
+ }
+
+ buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, target.Blob())
+ if err != nil {
+ ctx.ServerError("getFileReader", err)
+ return
+ }
+ defer dataRc.Close()
+
+ // TODO: if fInfo.isLFSFile?
+ if !fInfo.isTextFile {
+ return
+ }
+ if fInfo.fileSize >= setting.UI.MaxDisplayFileSize {
+ // License file is too large to calculate
+ return
+ }
+
+ rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
+
+ contentBuf := &bytes.Buffer{}
+ ctx.Data["EscapeStatus"], err = charset.EscapeControlStringReader(rd, contentBuf, ctx.Locale)
+ if err != nil {
+ log.Error("Read failed: %v", err)
+ }
+ cov := licensecheck.Scan(contentBuf.Bytes())
+ fmt.Println(cov.Match)
+ ctx.Data["MatchedLicenses"] = cov.Match
+ ctx.Data["LicenseFileName"] = licenseFile.Name()
+}
+
func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink string) {
ctx.Data["IsViewFile"] = true
ctx.Data["HideRepoInfo"] = true
@@ -430,7 +477,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
shouldRenderSource := ctx.FormString("display") == "source"
- readmeExist := util.IsReadmeFileName(blob.Name())
+ readmeExist := util.IsFileName(blob.Name(), util.FileTypeReadme)
ctx.Data["ReadmeExist"] = readmeExist
markupType := markup.Type(blob.Name())
diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl
index bfe5a20b164d..dd5891161e0d 100644
--- a/templates/repo/sub_menu.tmpl
+++ b/templates/repo/sub_menu.tmpl
@@ -19,6 +19,17 @@
{{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}}
{{svg "octicon-database"}} {{.locale.PrettyNumber (index $fileSizeFields 0)}} {{index $fileSizeFields 1}}
+ {{if .MatchedLicenses}}
+
{{svg "octicon-law"}}
- {{if eq (len .MatchedLicenses) 1}}
- {{(index .MatchedLicenses 0).ID}}
+ {{if eq (len .Licenses) 1}}
+ {{index .Licenses 0}}
{{else}}
{{.locale.Tr "repo.multiple_licenses"}}
From 973f9950d1f1c11c42fcc229220029864dfba894 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 00:32:35 +0000
Subject: [PATCH 007/172] check license change in HookPostReceive
---
models/repo/license.go | 38 -----------
modules/git/blob.go | 11 ++++
modules/git/repo_license_gogit.go | 68 -------------------
modules/git/repo_license_nogogit.go | 90 --------------------------
modules/git/repo_license_stats_test.go | 35 ----------
modules/indexer/stats/db.go | 16 +----
routers/private/hook_post_receive.go | 63 +++++++++++++++++-
7 files changed, 74 insertions(+), 247 deletions(-)
delete mode 100644 models/repo/license.go
delete mode 100644 modules/git/repo_license_gogit.go
delete mode 100644 modules/git/repo_license_nogogit.go
delete mode 100644 modules/git/repo_license_stats_test.go
diff --git a/models/repo/license.go b/models/repo/license.go
deleted file mode 100644
index d8bf4e558354..000000000000
--- a/models/repo/license.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package repo
-
-import (
- "context"
-
- "code.gitea.io/gitea/models/db"
-)
-
-// UpdateLanguageStats updates the license statistics for repository
-func UpdateLicenseStats(repo *Repository, commitID string, licenses []string) error {
- ctx, committer, err := db.TxContext(db.DefaultContext)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = UpdateLicense(ctx, repo.ID, licenses); err != nil {
- return err
- }
-
- // Update indexer status
- if err = UpdateIndexerStatus(ctx, repo, RepoIndexerTypeStats, commitID); err != nil {
- return err
- }
-
- return committer.Commit()
-}
-
-// UpdateRepoSize updates the repository size, calculating it using getDirectorySize
-func UpdateLicense(ctx context.Context, repoID int64, licenses []string) error {
- _, err := db.GetEngine(ctx).ID(repoID).Cols("licenses").NoAutoTime().Update(&Repository{
- Licenses: licenses,
- })
- return err
-}
diff --git a/modules/git/blob.go b/modules/git/blob.go
index 8864f54d1bf2..5e126bace1ae 100644
--- a/modules/git/blob.go
+++ b/modules/git/blob.go
@@ -33,6 +33,17 @@ func (b *Blob) GetBlobContent() (string, error) {
return string(buf), nil
}
+// GetBlobAll Gets the all content of the blob as bytes
+func (b *Blob) GetBlobAll() ([]byte, error) {
+ dataRc, err := b.DataAsync()
+ if err != nil {
+ return nil, err
+ }
+ buf, _ := io.ReadAll(dataRc)
+ _ = dataRc.Close()
+ return buf, nil
+}
+
// GetBlobLineCount gets line count of the blob
func (b *Blob) GetBlobLineCount() (int, error) {
reader, err := b.DataAsync()
diff --git a/modules/git/repo_license_gogit.go b/modules/git/repo_license_gogit.go
deleted file mode 100644
index a41cb99fef5e..000000000000
--- a/modules/git/repo_license_gogit.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-//go:build gogit
-
-package git
-
-import (
- "io"
-
- "github.com/go-git/go-git/v5"
- "github.com/go-git/go-git/v5/plumbing"
- "github.com/go-git/go-git/v5/plumbing/object"
- "github.com/google/licensecheck"
-)
-
-// GetLicenseStats calculates license stats for git repository at specified commit
-func (repo *Repository) GetLicenseStats(commitID string) ([]string, error) {
- r, err := git.PlainOpen(repo.Path)
- if err != nil {
- return nil, err
- }
-
- rev, err := r.ResolveRevision(plumbing.Revision(commitID))
- if err != nil {
- return nil, err
- }
-
- commit, err := r.CommitObject(*rev)
- if err != nil {
- return nil, err
- }
-
- tree, err := commit.Tree()
- if err != nil {
- return nil, err
- }
-
- var licenses []string
- // TODO: fix unnecessary check
- err = tree.Files().ForEach(func(f *object.File) error {
- if f.Size == 0 {
- return nil
- }
-
- // TODO: support ext
- if f.Name == "LICENSE" {
- r, err := f.Reader()
- if err != nil {
- return err
- }
- defer r.Close()
-
- content, err := io.ReadAll(r)
- if err != nil {
- return err
- }
-
- cov := licensecheck.Scan(content)
- for _, m := range cov.Match {
- licenses = append(licenses, m.ID)
- }
- }
- return nil
- })
-
- return licenses, nil
-}
diff --git a/modules/git/repo_license_nogogit.go b/modules/git/repo_license_nogogit.go
deleted file mode 100644
index 7bcf5ce18b06..000000000000
--- a/modules/git/repo_license_nogogit.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-//go:build !gogit
-
-package git
-
-import (
- "bytes"
- "io"
-
- "code.gitea.io/gitea/modules/log"
- "github.com/google/licensecheck"
-)
-
-// GetLicenseStats calculates language stats for git repository at specified commit
-func (repo *Repository) GetLicenseStats(commitID string) ([]string, error) {
- // We will feed the commit IDs in order into cat-file --batch, followed by blobs as necessary.
- // so let's create a batch stdin and stdout
- batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx)
- defer cancel()
-
- writeID := func(id string) error {
- _, err := batchStdinWriter.Write([]byte(id + "\n"))
- return err
- }
-
- if err := writeID(commitID); err != nil {
- return nil, err
- }
- shaBytes, typ, size, err := ReadBatchLine(batchReader)
- if typ != "commit" {
- log.Debug("Unable to get commit for: %s. Err: %v", commitID, err)
- return nil, ErrNotExist{commitID, ""}
- }
-
- sha, err := NewIDFromString(string(shaBytes))
- if err != nil {
- log.Debug("Unable to get commit for: %s. Err: %v", commitID, err)
- return nil, ErrNotExist{commitID, ""}
- }
-
- commit, err := CommitFromReader(repo, sha, io.LimitReader(batchReader, size))
- if err != nil {
- log.Debug("Unable to get commit for: %s. Err: %v", commitID, err)
- return nil, err
- }
- if _, err = batchReader.Discard(1); err != nil {
- return nil, err
- }
-
- tree := commit.Tree
-
- entries, err := tree.ListEntriesRecursiveWithSize()
- if err != nil {
- return nil, err
- }
-
- var licenses []string
- for _, f := range entries {
- if f.Size() == 0 {
- continue
- }
-
- // TODO: support ext
- if f.Name() == "LICENSE" {
- // Need to read all of them or can not get the right result from licensecheck.Scan
- if err := writeID(f.ID.String()); err != nil {
- return nil, err
- }
- _, _, size, err := ReadBatchLine(batchReader)
- if err != nil {
- log.Debug("Error reading blob: %s Err: %v", f.ID.String(), err)
- return nil, err
- }
- contentBuf := bytes.Buffer{}
- _, err = contentBuf.ReadFrom(io.LimitReader(batchReader, size))
- if err != nil {
- return nil, err
- }
- cov := licensecheck.Scan(contentBuf.Bytes())
- for _, m := range cov.Match {
- licenses = append(licenses, m.ID)
- }
- break
- }
- }
-
- return licenses, nil
-}
diff --git a/modules/git/repo_license_stats_test.go b/modules/git/repo_license_stats_test.go
deleted file mode 100644
index 67d83337c0be..000000000000
--- a/modules/git/repo_license_stats_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-//go:build !gogit
-
-package git
-
-import (
- "path/filepath"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestRepository_GetLicenseStats(t *testing.T) {
- // TODO: add the repo
- repoPath := filepath.Join(testReposDir, "license_stats_repo")
- gitRepo, err := openRepositoryWithDefaultContext(repoPath)
- if !assert.NoError(t, err) {
- t.Fatal()
- }
- defer gitRepo.Close()
-
- // TODO: add the LICENSE file
- stats, err := gitRepo.GetLicenseStats("8fee858da5796dfb37704761701bb8e800ad9ef3")
- if !assert.NoError(t, err) {
- t.Fatal()
- }
-
- // TODO: fix check
- assert.EqualValues(t, map[string]int64{
- "Python": 134,
- "Java": 112,
- }, stats)
-}
diff --git a/modules/indexer/stats/db.go b/modules/indexer/stats/db.go
index 05d6dd419af0..2a0475dea6a1 100644
--- a/modules/indexer/stats/db.go
+++ b/modules/indexer/stats/db.go
@@ -73,22 +73,8 @@ func (db *DBIndexer) Index(id int64) error {
log.Error("Unable to update language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
return err
}
- log.Debug("DBIndexer completed language stats for ID %s for default branch %s in %s. stats count: %d", commitID, repo.DefaultBranch, repo.RepoPath(), len(stats))
-
- licenses, err := gitRepo.GetLicenseStats(commitID)
- if err != nil {
- if !setting.IsInTesting {
- log.Error("Unable to get license stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
- }
- return err
- }
- err = repo_model.UpdateLicenseStats(repo, commitID, licenses)
- if err != nil {
- log.Error("Unable to update license stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
- return err
- }
- log.Debug("DBIndexer completed license stats for ID %s for default branch %s in %s. stats count: %d", commitID, repo.DefaultBranch, repo.RepoPath(), len(stats))
+ log.Debug("DBIndexer completed language stats for ID %s for default branch %s in %s. stats count: %d", commitID, repo.DefaultBranch, repo.RepoPath(), len(stats))
return nil
}
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index cfe20be106cf..c4bf8afb9642 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -20,12 +20,13 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
repo_service "code.gitea.io/gitea/services/repository"
+ "github.com/google/licensecheck"
)
// HookPostReceive updates services and users
func HookPostReceive(ctx *gitea_context.PrivateContext) {
opts := web.GetForm(ctx).(*private.HookOptions)
-
+ fmt.Println(opts)
// We don't rely on RepoAssignment here because:
// a) we don't need the git repo in this function
// b) our update function will likely change the repository in the db so we will need to refresh it
@@ -121,6 +122,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
// Now handle the pull request notification trailers
for i := range opts.OldCommitIDs {
refFullName := opts.RefFullNames[i]
+ oldCommitID := opts.OldCommitIDs[i]
newCommitID := opts.NewCommitIDs[i]
// post update for agit pull request
@@ -199,6 +201,65 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
// If our branch is the default branch of an unforked repo - there's no PR to create or refer to
if !repo.IsFork && branch == baseRepo.DefaultBranch {
+ // update license
+ gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
+ if err != nil {
+ log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err),
+ })
+ return
+ }
+ commit, err := gitRepo.GetCommit(newCommitID)
+ if err != nil {
+ log.Error("Failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err),
+ })
+ return
+ }
+ filesChanged, err := commit.GetFilesChangedSinceCommit(oldCommitID)
+ if err != nil {
+ log.Error("Failed to get changed files from %d to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to get changed files from %d to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err),
+ })
+ return
+ }
+ for _, fn := range filesChanged {
+ // support ext
+ if fn == "LICENSE" {
+ blob, err := commit.GetBlobByPath(fn)
+ if err != nil {
+ log.Error("Failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err),
+ })
+ return
+ }
+ contentBuf, err := blob.GetBlobAll()
+ if err != nil {
+ log.Error("Failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err),
+ })
+ return
+ }
+ var licenses []string
+ cov := licensecheck.Scan(contentBuf)
+ for _, m := range cov.Match {
+ licenses = append(licenses, m.ID)
+ }
+ repo.Licenses = licenses
+ if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
+ log.Error("Failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
+ Err: fmt.Sprintf("Failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err),
+ })
+ }
+ }
+ }
+
results = append(results, private.HookPostReceiveBranchResult{})
continue
}
From a876b2dc0357ebf4acda8e97cedebd06a53b050b Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 00:33:57 +0000
Subject: [PATCH 008/172] remove debug code
---
routers/private/hook_post_receive.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index c4bf8afb9642..f18f0c9fed63 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -26,7 +26,7 @@ import (
// HookPostReceive updates services and users
func HookPostReceive(ctx *gitea_context.PrivateContext) {
opts := web.GetForm(ctx).(*private.HookOptions)
- fmt.Println(opts)
+
// We don't rely on RepoAssignment here because:
// a) we don't need the git repo in this function
// b) our update function will likely change the repository in the db so we will need to refresh it
From a2ef8f68a9343969bb9b0dd869da040c0ad32b03 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 05:51:10 +0000
Subject: [PATCH 009/172] update license when create a repo
---
modules/repository/create.go | 5 +++
modules/repository/license.go | 42 ++++++++++++++++++++
routers/private/hook_post_receive.go | 59 +---------------------------
templates/repo/sub_menu.tmpl | 2 +-
4 files changed, 50 insertions(+), 58 deletions(-)
diff --git a/modules/repository/create.go b/modules/repository/create.go
index e1f0bdcdf995..7ca2fd41a49f 100644
--- a/modules/repository/create.go
+++ b/modules/repository/create.go
@@ -194,6 +194,10 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m
}
}
+ var licenses []string
+ if len(opts.License) > 0 {
+ licenses = append(licenses, opts.License)
+ }
repo := &repo_model.Repository{
OwnerID: u.ID,
Owner: u,
@@ -212,6 +216,7 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m
TrustModel: opts.TrustModel,
IsMirror: opts.IsMirror,
DefaultBranch: opts.DefaultBranch,
+ Licenses: licenses,
}
var rollbackRepo *repo_model.Repository
diff --git a/modules/repository/license.go b/modules/repository/license.go
index 5b188a041e24..7004aeb12fda 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -6,11 +6,15 @@ package repository
import (
"bufio"
"bytes"
+ "context"
"fmt"
"regexp"
"strings"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/options"
+ "github.com/google/licensecheck"
)
type licenseValues struct {
@@ -111,3 +115,41 @@ func getLicensePlaceholder(name string) *licensePlaceholder {
}
return ret
}
+
+func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, ownerName, repoName string) error {
+ gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
+ if err != nil {
+ return fmt.Errorf("failed to open repository: %s/%s Error: %v", ownerName, repoName, err)
+ }
+ commit, err := gitRepo.GetCommit(newCommitID)
+ if err != nil {
+ return fmt.Errorf("failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err)
+ }
+ filesChanged, err := commit.GetFilesChangedSinceCommit(oldCommitID)
+ if err != nil {
+ return fmt.Errorf("failed to get changed files from %s to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err)
+ }
+ for _, fn := range filesChanged {
+ // support ext
+ if fn == "LICENSE" {
+ blob, err := commit.GetBlobByPath(fn)
+ if err != nil {
+ return fmt.Errorf("failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err)
+ }
+ contentBuf, err := blob.GetBlobAll()
+ if err != nil {
+ return fmt.Errorf("failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err)
+ }
+ var licenses []string
+ cov := licensecheck.Scan(contentBuf)
+ for _, m := range cov.Match {
+ licenses = append(licenses, m.ID)
+ }
+ repo.Licenses = licenses
+ if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
+ return fmt.Errorf("failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err)
+ }
+ }
+ }
+ return nil
+}
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index f18f0c9fed63..8145e17b65e9 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -20,7 +20,6 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
repo_service "code.gitea.io/gitea/services/repository"
- "github.com/google/licensecheck"
)
// HookPostReceive updates services and users
@@ -202,64 +201,10 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
// If our branch is the default branch of an unforked repo - there's no PR to create or refer to
if !repo.IsFork && branch == baseRepo.DefaultBranch {
// update license
- gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
+ err := repo_module.UpdateRepoLicenses(ctx, repo, oldCommitID, newCommitID, ownerName, repoName)
if err != nil {
- log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err)
- ctx.JSON(http.StatusInternalServerError, private.Response{
- Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err),
- })
- return
+ ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()})
}
- commit, err := gitRepo.GetCommit(newCommitID)
- if err != nil {
- log.Error("Failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err)
- ctx.JSON(http.StatusInternalServerError, private.Response{
- Err: fmt.Sprintf("Failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err),
- })
- return
- }
- filesChanged, err := commit.GetFilesChangedSinceCommit(oldCommitID)
- if err != nil {
- log.Error("Failed to get changed files from %d to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err)
- ctx.JSON(http.StatusInternalServerError, private.Response{
- Err: fmt.Sprintf("Failed to get changed files from %d to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err),
- })
- return
- }
- for _, fn := range filesChanged {
- // support ext
- if fn == "LICENSE" {
- blob, err := commit.GetBlobByPath(fn)
- if err != nil {
- log.Error("Failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err)
- ctx.JSON(http.StatusInternalServerError, private.Response{
- Err: fmt.Sprintf("Failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err),
- })
- return
- }
- contentBuf, err := blob.GetBlobAll()
- if err != nil {
- log.Error("Failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err)
- ctx.JSON(http.StatusInternalServerError, private.Response{
- Err: fmt.Sprintf("Failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err),
- })
- return
- }
- var licenses []string
- cov := licensecheck.Scan(contentBuf)
- for _, m := range cov.Match {
- licenses = append(licenses, m.ID)
- }
- repo.Licenses = licenses
- if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
- log.Error("Failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err)
- ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
- Err: fmt.Sprintf("Failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err),
- })
- }
- }
- }
-
results = append(results, private.HookPostReceiveBranchResult{})
continue
}
diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl
index 3620d20b5026..738984ff9861 100644
--- a/templates/repo/sub_menu.tmpl
+++ b/templates/repo/sub_menu.tmpl
@@ -26,8 +26,8 @@
{{index .Licenses 0}}
{{else}}
{{.locale.Tr "repo.multiple_licenses"}}
-
{{end}}
+
{{end}}
{{end}}
From c4c6da53c71e206340648bd7b9a383b0a6c6f080 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 05:53:41 +0000
Subject: [PATCH 010/172] add todo
---
routers/private/hook_post_receive.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index 8145e17b65e9..341c4dc745e6 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -200,7 +200,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
// If our branch is the default branch of an unforked repo - there's no PR to create or refer to
if !repo.IsFork && branch == baseRepo.DefaultBranch {
- // update license
+ // TODO: check IsWiki?
err := repo_module.UpdateRepoLicenses(ctx, repo, oldCommitID, newCommitID, ownerName, repoName)
if err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()})
From 02787750511759f649b60710c27ed1bbd297d95c Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 05:58:20 +0000
Subject: [PATCH 011/172] add license to fork repo
---
services/repository/fork.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/services/repository/fork.go b/services/repository/fork.go
index fb93b10f1c31..ba26ef421135 100644
--- a/services/repository/fork.go
+++ b/services/repository/fork.go
@@ -82,6 +82,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
IsEmpty: opts.BaseRepo.IsEmpty,
IsFork: true,
ForkID: opts.BaseRepo.ID,
+ Licenses: opts.BaseRepo.Licenses,
}
oldRepoPath := opts.BaseRepo.RepoPath()
From c30bca1f3055e278f8ead99ff29ab8b51af2e33b Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 06:06:04 +0000
Subject: [PATCH 012/172] fix lint
---
modules/repository/license.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/modules/repository/license.go b/modules/repository/license.go
index 7004aeb12fda..ce0ee61dfb67 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -14,6 +14,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/options"
+
"github.com/google/licensecheck"
)
From aa91765ddca6f8bcfa3d93d46cfe990a42f2499f Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 06:40:14 +0000
Subject: [PATCH 013/172] add license to mirror repo
---
modules/repository/license.go | 51 +++++++++++++---------------
modules/repository/repo.go | 6 ++++
routers/private/hook_post_receive.go | 3 +-
3 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/modules/repository/license.go b/modules/repository/license.go
index ce0ee61dfb67..f20fc0e6f3eb 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -117,40 +117,37 @@ func getLicensePlaceholder(name string) *licensePlaceholder {
return ret
}
-func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, ownerName, repoName string) error {
+func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error {
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
if err != nil {
- return fmt.Errorf("failed to open repository: %s/%s Error: %v", ownerName, repoName, err)
+ return fmt.Errorf("OpenRepository: %w", err)
}
- commit, err := gitRepo.GetCommit(newCommitID)
+ commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch)
if err != nil {
- return fmt.Errorf("failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err)
+ return fmt.Errorf("GetBranchCommitID: %w", err)
}
- filesChanged, err := commit.GetFilesChangedSinceCommit(oldCommitID)
+ commit, err := gitRepo.GetCommit(commitID)
if err != nil {
- return fmt.Errorf("failed to get changed files from %s to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err)
+ return fmt.Errorf("GetCommit: %w", err)
}
- for _, fn := range filesChanged {
- // support ext
- if fn == "LICENSE" {
- blob, err := commit.GetBlobByPath(fn)
- if err != nil {
- return fmt.Errorf("failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err)
- }
- contentBuf, err := blob.GetBlobAll()
- if err != nil {
- return fmt.Errorf("failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err)
- }
- var licenses []string
- cov := licensecheck.Scan(contentBuf)
- for _, m := range cov.Match {
- licenses = append(licenses, m.ID)
- }
- repo.Licenses = licenses
- if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
- return fmt.Errorf("failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err)
- }
- }
+
+ blob, err := commit.GetBlobByPath("LICENSE")
+ if err != nil {
+ return fmt.Errorf("GetBlobByPath: %w", err)
+ }
+ contentBuf, err := blob.GetBlobAll()
+ if err != nil {
+ return fmt.Errorf("GetBlobByPath: %w", err)
}
+ var licenses []string
+ cov := licensecheck.Scan(contentBuf)
+ for _, m := range cov.Match {
+ licenses = append(licenses, m.ID)
+ }
+ repo.Licenses = licenses
+ if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
+ return fmt.Errorf("UpdateRepositoryCols: %v", err)
+ }
+
return nil
}
diff --git a/modules/repository/repo.go b/modules/repository/repo.go
index a1dba8fc6af0..3d5c40a6eb73 100644
--- a/modules/repository/repo.go
+++ b/modules/repository/repo.go
@@ -137,6 +137,12 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
}
defer gitRepo.Close()
+ // Update repo license
+ err = UpdateRepoLicenses(ctx, repo)
+ if err != nil {
+ return repo, fmt.Errorf("UpdateRepoLicenses: %w", err)
+ }
+
repo.IsEmpty, err = gitRepo.IsEmpty()
if err != nil {
return repo, fmt.Errorf("git.IsEmpty: %w", err)
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index 341c4dc745e6..4ff19984cf10 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -121,7 +121,6 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
// Now handle the pull request notification trailers
for i := range opts.OldCommitIDs {
refFullName := opts.RefFullNames[i]
- oldCommitID := opts.OldCommitIDs[i]
newCommitID := opts.NewCommitIDs[i]
// post update for agit pull request
@@ -201,7 +200,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
// If our branch is the default branch of an unforked repo - there's no PR to create or refer to
if !repo.IsFork && branch == baseRepo.DefaultBranch {
// TODO: check IsWiki?
- err := repo_module.UpdateRepoLicenses(ctx, repo, oldCommitID, newCommitID, ownerName, repoName)
+ err := repo_module.UpdateRepoLicenses(ctx, repo)
if err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()})
}
From 84801d5ef184d91f8a32a39e57b32c6f47b6c49a Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 07:07:27 +0000
Subject: [PATCH 014/172] move findFileInEntries to repo modules
---
modules/repository/file.go | 136 +++++++++++++++++++++++++++++
modules/repository/file_test.go | 6 ++
modules/repository/license_test.go | 4 +
modules/util/path.go | 33 +++----
routers/web/repo/view.go | 119 +------------------------
5 files changed, 161 insertions(+), 137 deletions(-)
create mode 100644 modules/repository/file.go
create mode 100644 modules/repository/file_test.go
diff --git a/modules/repository/file.go b/modules/repository/file.go
new file mode 100644
index 000000000000..14a68f62a98a
--- /dev/null
+++ b/modules/repository/file.go
@@ -0,0 +1,136 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repository
+
+import (
+ "path"
+ "strings"
+
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/util"
+)
+
+type FileType string
+
+const (
+ FileTypeReadme FileType = "readme"
+ FileTypeLicense FileType = "license"
+)
+
+// locate a README/LICENSE for a tree in one of the supported paths.
+//
+// entries is passed to reduce calls to ListEntries(), so
+// this has precondition:
+//
+// entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries()
+//
+// FIXME: There has to be a more efficient way of doing this
+func FindFileInEntries(fileType FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) {
+ // Create a list of extensions in priority order
+ // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
+ // 2. Txt files - e.g. README.txt
+ // 3. No extension - e.g. README
+ exts := append(localizedExtensions(".md", language), ".txt", "") // sorted by priority
+ extCount := len(exts)
+ targetFiles := make([]*git.TreeEntry, extCount+1)
+
+ docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/)
+ for _, entry := range entries {
+ if tryWellKnownDirs && entry.IsDir() {
+ // as a special case for the top-level repo introduction README,
+ // fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ...
+ // (note that docsEntries is ignored unless we are at the root)
+ lowerName := strings.ToLower(entry.Name())
+ switch lowerName {
+ case "docs":
+ if entry.Name() == "docs" || docsEntries[0] == nil {
+ docsEntries[0] = entry
+ }
+ case ".gitea":
+ if entry.Name() == ".gitea" || docsEntries[1] == nil {
+ docsEntries[1] = entry
+ }
+ case ".github":
+ if entry.Name() == ".github" || docsEntries[2] == nil {
+ docsEntries[2] = entry
+ }
+ }
+ continue
+ }
+ if i, ok := util.IsFileExtension(entry.Name(), string(fileType), exts...); ok {
+ log.Debug("Potential readme file: %s", entry.Name())
+ if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) {
+ if entry.IsLink() {
+ target, err := entry.FollowLinks()
+ if err != nil && !git.IsErrBadLink(err) {
+ return "", nil, err
+ } else if target != nil && (target.IsExecutable() || target.IsRegular()) {
+ targetFiles[i] = entry
+ }
+ } else {
+ targetFiles[i] = entry
+ }
+ }
+ }
+ }
+ var targetFile *git.TreeEntry
+ for _, f := range targetFiles {
+ if f != nil {
+ targetFile = f
+ break
+ }
+ }
+
+ if treePath == "" && targetFile == nil {
+ for _, subTreeEntry := range docsEntries {
+ if subTreeEntry == nil {
+ continue
+ }
+ subTree := subTreeEntry.Tree()
+ if subTree == nil {
+ // this should be impossible; if subTreeEntry exists so should this.
+ continue
+ }
+ var err error
+ childEntries, err := subTree.ListEntries()
+ if err != nil {
+ return "", nil, err
+ }
+
+ subfolder, targetFile, err := FindFileInEntries(fileType, childEntries, subTreeEntry.Name(), language, false)
+ if err != nil && !git.IsErrNotExist(err) {
+ return "", nil, err
+ }
+ if targetFile != nil {
+ return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil
+ }
+ }
+ }
+
+ return "", targetFile, nil
+}
+
+// localizedExtensions prepends the provided language code with and without a
+// regional identifier to the provided extension.
+// Note: the language code will always be lower-cased, if a region is present it must be separated with a `-`
+// Note: ext should be prefixed with a `.`
+func localizedExtensions(ext, languageCode string) (localizedExts []string) {
+ if len(languageCode) < 1 {
+ return []string{ext}
+ }
+
+ lowerLangCode := "." + strings.ToLower(languageCode)
+
+ if strings.Contains(lowerLangCode, "-") {
+ underscoreLangCode := strings.ReplaceAll(lowerLangCode, "-", "_")
+ indexOfDash := strings.Index(lowerLangCode, "-")
+ // e.g. [.zh-cn.md, .zh_cn.md, .zh.md, _zh.md, .md]
+ return []string{lowerLangCode + ext, underscoreLangCode + ext, lowerLangCode[:indexOfDash] + ext, "_" + lowerLangCode[1:indexOfDash] + ext, ext}
+ }
+
+ // e.g. [.en.md, .md]
+ return []string{lowerLangCode + ext, ext}
+}
diff --git a/modules/repository/file_test.go b/modules/repository/file_test.go
new file mode 100644
index 000000000000..4e34901ad33e
--- /dev/null
+++ b/modules/repository/file_test.go
@@ -0,0 +1,6 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repository
+
+// TODO
diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go
index 13c865693c3c..e1555a0eed32 100644
--- a/modules/repository/license_test.go
+++ b/modules/repository/license_test.go
@@ -179,3 +179,7 @@ Copyright (C) 2023 by Gitea teabot@gitea.io
})
}
}
+
+func Test_UpdateRepoLicenses(t *testing.T) {
+ // TODO
+}
diff --git a/modules/util/path.go b/modules/util/path.go
index 8164d91c4b9a..d805fb4ed557 100644
--- a/modules/util/path.go
+++ b/modules/util/path.go
@@ -282,47 +282,40 @@ func CommonSkip(name string) bool {
return false
}
-type FileType string
-
-const (
- FileTypeReadme FileType = "readme"
- FileTypeLicense FileType = "license"
-)
-
-// IsFileName reports whether name looks like a fileType file
+// IsFileName reports whether name looks like a target name file
// based on its name.
-func IsFileName(name string, fileType FileType) bool {
+func IsFileName(name string, targetName string) bool {
name = strings.ToLower(name)
- lenFileType := len(fileType)
- if len(name) < lenFileType {
+ lenTargetName := len(targetName)
+ if len(name) < lenTargetName {
return false
- } else if len(name) == lenFileType {
- return name == string(fileType)
+ } else if len(name) == lenTargetName {
+ return name == string(targetName)
}
- return name[:lenFileType+1] == string(fileType)+"."
+ return name[:lenTargetName+1] == string(targetName)+"."
}
-// IsFileExtension reports whether name looks like a fileType file
+// IsFileExtension reports whether name looks like a target name file
// based on its name. It will look through the provided extensions and check if the file matches
// one of the extensions and provide the index in the extension list.
// If the filename is `readme.` with an unmatched extension it will match with the index equaling
// the length of the provided extension list.
// Note that the '.' should be provided in ext, e.g ".md"
-func IsFileExtension(name string, fileType FileType, ext ...string) (int, bool) {
+func IsFileExtension(name, targetName string, ext ...string) (int, bool) {
name = strings.ToLower(name)
- lenFileType := len(fileType)
- if len(name) < lenFileType || name[:lenFileType] != string(fileType) {
+ lenTargetName := len(targetName)
+ if len(name) < lenTargetName || name[:lenTargetName] != string(targetName) {
return 0, false
}
for i, extension := range ext {
extension = strings.ToLower(extension)
- if name[lenFileType:] == extension {
+ if name[lenTargetName:] == extension {
return i, true
}
}
- if name[lenFileType] == '.' {
+ if name[lenTargetName] == '.' {
return len(ext), true
}
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index b9033563a86b..da78dd87df0b 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -54,99 +54,6 @@ const (
tplMigrating base.TplName = "repo/migrate/migrating"
)
-// locate a README/LICENSE for a tree in one of the supported paths.
-//
-// entries is passed to reduce calls to ListEntries(), so
-// this has precondition:
-//
-// entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries()
-//
-// FIXME: There has to be a more efficient way of doing this
-func findFileInEntries(ctx *context.Context, fileType util.FileType, entries []*git.TreeEntry, tryWellKnownDirs bool) (string, *git.TreeEntry, error) {
- // Create a list of extensions in priority order
- // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
- // 2. Txt files - e.g. README.txt
- // 3. No extension - e.g. README
- exts := append(localizedExtensions(".md", ctx.Locale.Language()), ".txt", "") // sorted by priority
- extCount := len(exts)
- targetFiles := make([]*git.TreeEntry, extCount+1)
-
- docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/)
- for _, entry := range entries {
- if tryWellKnownDirs && entry.IsDir() {
- // as a special case for the top-level repo introduction README,
- // fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ...
- // (note that docsEntries is ignored unless we are at the root)
- lowerName := strings.ToLower(entry.Name())
- switch lowerName {
- case "docs":
- if entry.Name() == "docs" || docsEntries[0] == nil {
- docsEntries[0] = entry
- }
- case ".gitea":
- if entry.Name() == ".gitea" || docsEntries[1] == nil {
- docsEntries[1] = entry
- }
- case ".github":
- if entry.Name() == ".github" || docsEntries[2] == nil {
- docsEntries[2] = entry
- }
- }
- continue
- }
- if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok {
- log.Debug("Potential readme file: %s", entry.Name())
- if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) {
- if entry.IsLink() {
- target, err := entry.FollowLinks()
- if err != nil && !git.IsErrBadLink(err) {
- return "", nil, err
- } else if target != nil && (target.IsExecutable() || target.IsRegular()) {
- targetFiles[i] = entry
- }
- } else {
- targetFiles[i] = entry
- }
- }
- }
- }
- var targetFile *git.TreeEntry
- for _, f := range targetFiles {
- if f != nil {
- targetFile = f
- break
- }
- }
-
- if ctx.Repo.TreePath == "" && targetFile == nil {
- for _, subTreeEntry := range docsEntries {
- if subTreeEntry == nil {
- continue
- }
- subTree := subTreeEntry.Tree()
- if subTree == nil {
- // this should be impossible; if subTreeEntry exists so should this.
- continue
- }
- var err error
- childEntries, err := subTree.ListEntries()
- if err != nil {
- return "", nil, err
- }
-
- subfolder, targetFile, err := findFileInEntries(ctx, fileType, childEntries, false)
- if err != nil && !git.IsErrNotExist(err) {
- return "", nil, err
- }
- if targetFile != nil {
- return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil
- }
- }
- }
-
- return "", targetFile, nil
-}
-
func renderDirectory(ctx *context.Context, treeLink string) {
entries := renderDirectoryFiles(ctx, 1*time.Second)
if ctx.Written() {
@@ -158,7 +65,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
}
- subfolder, readmeFile, err := findFileInEntries(ctx, util.FileTypeReadme, entries, true)
+ subfolder, readmeFile, err := repo_module.FindFileInEntries(repo_module.FileTypeReadme, entries, ctx.Repo.TreePath, ctx.Locale.Language(), true)
if err != nil {
ctx.ServerError("findFileInEntries", err)
return
@@ -166,28 +73,6 @@ func renderDirectory(ctx *context.Context, treeLink string) {
renderReadmeFile(ctx, subfolder, readmeFile, treeLink)
}
-// localizedExtensions prepends the provided language code with and without a
-// regional identifier to the provided extension.
-// Note: the language code will always be lower-cased, if a region is present it must be separated with a `-`
-// Note: ext should be prefixed with a `.`
-func localizedExtensions(ext, languageCode string) (localizedExts []string) {
- if len(languageCode) < 1 {
- return []string{ext}
- }
-
- lowerLangCode := "." + strings.ToLower(languageCode)
-
- if strings.Contains(lowerLangCode, "-") {
- underscoreLangCode := strings.ReplaceAll(lowerLangCode, "-", "_")
- indexOfDash := strings.Index(lowerLangCode, "-")
- // e.g. [.zh-cn.md, .zh_cn.md, .zh.md, _zh.md, .md]
- return []string{lowerLangCode + ext, underscoreLangCode + ext, lowerLangCode[:indexOfDash] + ext, "_" + lowerLangCode[1:indexOfDash] + ext, ext}
- }
-
- // e.g. [.en.md, .md]
- return []string{lowerLangCode + ext, ext}
-}
-
type fileInfo struct {
isTextFile bool
isLFSFile bool
@@ -429,7 +314,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
shouldRenderSource := ctx.FormString("display") == "source"
- readmeExist := util.IsFileName(blob.Name(), util.FileTypeReadme)
+ readmeExist := util.IsFileName(blob.Name(), string(repo_module.FileTypeReadme))
ctx.Data["ReadmeExist"] = readmeExist
markupType := markup.Type(blob.Name())
From 0421e9898272176c41d6b05f36757864f6579e2e Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 07:16:33 +0000
Subject: [PATCH 015/172] update license when sync mirror repo
---
services/mirror/mirror_pull.go | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go
index 60699294c18b..39e8d3de10cf 100644
--- a/services/mirror/mirror_pull.go
+++ b/services/mirror/mirror_pull.go
@@ -528,6 +528,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
return false
}
+ // Update License
+ if err = repo_module.UpdateRepoLicenses(ctx, m.Repo); err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to update repository 'licenses': %v", m.Repo, err)
+ return false
+ }
+
log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo)
return true
From cf028887b8b840e05ca1f23324fddd5a39f66ef5 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 07:24:57 +0000
Subject: [PATCH 016/172] support search license file
---
modules/repository/license.go | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/modules/repository/license.go b/modules/repository/license.go
index f20fc0e6f3eb..31fd69522e15 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -130,15 +130,25 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error
if err != nil {
return fmt.Errorf("GetCommit: %w", err)
}
+ entries, err := commit.ListEntries()
+ if err != nil {
+ return fmt.Errorf("ListEntries: %w", err)
+ }
- blob, err := commit.GetBlobByPath("LICENSE")
+ // Find license file
+ _, licenseFile, err := FindFileInEntries(FileTypeLicense, entries, "", "", false)
if err != nil {
- return fmt.Errorf("GetBlobByPath: %w", err)
+ return fmt.Errorf("FindFileInEntries: %w", err)
}
+
+ // Read license file content
+ blob := licenseFile.Blob()
contentBuf, err := blob.GetBlobAll()
if err != nil {
return fmt.Errorf("GetBlobByPath: %w", err)
}
+
+ // check license
var licenses []string
cov := licensecheck.Scan(contentBuf)
for _, m := range cov.Match {
From 10b2a902209a930f941f824507df13829384e9f8 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 07:34:49 +0000
Subject: [PATCH 017/172] imporve debug info
---
modules/repository/file.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/repository/file.go b/modules/repository/file.go
index 14a68f62a98a..6698602bd9f3 100644
--- a/modules/repository/file.go
+++ b/modules/repository/file.go
@@ -61,7 +61,7 @@ func FindFileInEntries(fileType FileType, entries []*git.TreeEntry, treePath, la
continue
}
if i, ok := util.IsFileExtension(entry.Name(), string(fileType), exts...); ok {
- log.Debug("Potential readme file: %s", entry.Name())
+ log.Debug("Potential %s file: %s", fileType, entry.Name())
if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) {
if entry.IsLink() {
target, err := entry.FollowLinks()
From f2857204c9c1ad284ac714180b8f5d70812be91f Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 08:19:24 +0000
Subject: [PATCH 018/172] fix test
---
modules/repository/file.go | 11 ++---------
modules/repository/license.go | 3 ++-
modules/util/path.go | 29 ++++++++++++++++++-----------
routers/web/repo/view.go | 4 ++--
4 files changed, 24 insertions(+), 23 deletions(-)
diff --git a/modules/repository/file.go b/modules/repository/file.go
index 6698602bd9f3..dc94a2c43380 100644
--- a/modules/repository/file.go
+++ b/modules/repository/file.go
@@ -13,13 +13,6 @@ import (
"code.gitea.io/gitea/modules/util"
)
-type FileType string
-
-const (
- FileTypeReadme FileType = "readme"
- FileTypeLicense FileType = "license"
-)
-
// locate a README/LICENSE for a tree in one of the supported paths.
//
// entries is passed to reduce calls to ListEntries(), so
@@ -28,7 +21,7 @@ const (
// entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries()
//
// FIXME: There has to be a more efficient way of doing this
-func FindFileInEntries(fileType FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) {
+func FindFileInEntries(fileType util.FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) {
// Create a list of extensions in priority order
// 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
// 2. Txt files - e.g. README.txt
@@ -60,7 +53,7 @@ func FindFileInEntries(fileType FileType, entries []*git.TreeEntry, treePath, la
}
continue
}
- if i, ok := util.IsFileExtension(entry.Name(), string(fileType), exts...); ok {
+ if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok {
log.Debug("Potential %s file: %s", fileType, entry.Name())
if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) {
if entry.IsLink() {
diff --git a/modules/repository/license.go b/modules/repository/license.go
index 31fd69522e15..259eb57b11ae 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -14,6 +14,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/options"
+ "code.gitea.io/gitea/modules/util"
"github.com/google/licensecheck"
)
@@ -136,7 +137,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error
}
// Find license file
- _, licenseFile, err := FindFileInEntries(FileTypeLicense, entries, "", "", false)
+ _, licenseFile, err := FindFileInEntries(util.FileTypeLicense, entries, "", "", false)
if err != nil {
return fmt.Errorf("FindFileInEntries: %w", err)
}
diff --git a/modules/util/path.go b/modules/util/path.go
index d805fb4ed557..41e45aa90217 100644
--- a/modules/util/path.go
+++ b/modules/util/path.go
@@ -282,17 +282,24 @@ func CommonSkip(name string) bool {
return false
}
+type FileType string
+
+const (
+ FileTypeReadme FileType = "readme"
+ FileTypeLicense FileType = "license"
+)
+
// IsFileName reports whether name looks like a target name file
// based on its name.
-func IsFileName(name string, targetName string) bool {
+func IsFileName(name string, fileType FileType) bool {
name = strings.ToLower(name)
- lenTargetName := len(targetName)
- if len(name) < lenTargetName {
+ lenFileType := len(fileType)
+ if len(name) < lenFileType {
return false
- } else if len(name) == lenTargetName {
- return name == string(targetName)
+ } else if len(name) == lenFileType {
+ return name == string(fileType)
}
- return name[:lenTargetName+1] == string(targetName)+"."
+ return name[:lenFileType+1] == string(fileType)+"."
}
// IsFileExtension reports whether name looks like a target name file
@@ -301,21 +308,21 @@ func IsFileName(name string, targetName string) bool {
// If the filename is `readme.` with an unmatched extension it will match with the index equaling
// the length of the provided extension list.
// Note that the '.' should be provided in ext, e.g ".md"
-func IsFileExtension(name, targetName string, ext ...string) (int, bool) {
+func IsFileExtension(name string, fileType FileType, ext ...string) (int, bool) {
name = strings.ToLower(name)
- lenTargetName := len(targetName)
- if len(name) < lenTargetName || name[:lenTargetName] != string(targetName) {
+ lenFileType := len(fileType)
+ if len(name) < lenFileType || name[:lenFileType] != string(fileType) {
return 0, false
}
for i, extension := range ext {
extension = strings.ToLower(extension)
- if name[lenTargetName:] == extension {
+ if name[lenFileType:] == extension {
return i, true
}
}
- if name[lenTargetName] == '.' {
+ if name[lenFileType] == '.' {
return len(ext), true
}
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index da78dd87df0b..c4f96439d360 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -65,7 +65,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
}
- subfolder, readmeFile, err := repo_module.FindFileInEntries(repo_module.FileTypeReadme, entries, ctx.Repo.TreePath, ctx.Locale.Language(), true)
+ subfolder, readmeFile, err := repo_module.FindFileInEntries(util.FileTypeReadme, entries, ctx.Repo.TreePath, ctx.Locale.Language(), true)
if err != nil {
ctx.ServerError("findFileInEntries", err)
return
@@ -314,7 +314,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
shouldRenderSource := ctx.FormString("display") == "source"
- readmeExist := util.IsFileName(blob.Name(), string(repo_module.FileTypeReadme))
+ readmeExist := util.IsFileName(blob.Name(), util.FileTypeReadme)
ctx.Data["ReadmeExist"] = readmeExist
markupType := markup.Type(blob.Name())
From 7eb45846fa73cae24772ec705d14f42922f27a46 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 08:29:26 +0000
Subject: [PATCH 019/172] fix test
---
modules/repository/file_test.go | 57 +++++++++++++++++++++++++++++-
routers/web/repo/view_test.go | 62 ---------------------------------
2 files changed, 56 insertions(+), 63 deletions(-)
delete mode 100644 routers/web/repo/view_test.go
diff --git a/modules/repository/file_test.go b/modules/repository/file_test.go
index 4e34901ad33e..171c9d9b74de 100644
--- a/modules/repository/file_test.go
+++ b/modules/repository/file_test.go
@@ -3,4 +3,59 @@
package repository
-// TODO
+import (
+ "reflect"
+ "testing"
+)
+
+func Test_localizedExtensions(t *testing.T) {
+ tests := []struct {
+ name string
+ ext string
+ languageCode string
+ wantLocalizedExts []string
+ }{
+ {
+ name: "empty language",
+ ext: ".md",
+ wantLocalizedExts: []string{".md"},
+ },
+ {
+ name: "No region - lowercase",
+ languageCode: "en",
+ ext: ".csv",
+ wantLocalizedExts: []string{".en.csv", ".csv"},
+ },
+ {
+ name: "No region - uppercase",
+ languageCode: "FR",
+ ext: ".txt",
+ wantLocalizedExts: []string{".fr.txt", ".txt"},
+ },
+ {
+ name: "With region - lowercase",
+ languageCode: "en-us",
+ ext: ".md",
+ wantLocalizedExts: []string{".en-us.md", ".en_us.md", ".en.md", "_en.md", ".md"},
+ },
+ {
+ name: "With region - uppercase",
+ languageCode: "en-CA",
+ ext: ".MD",
+ wantLocalizedExts: []string{".en-ca.MD", ".en_ca.MD", ".en.MD", "_en.MD", ".MD"},
+ },
+ {
+ name: "With region - all uppercase",
+ languageCode: "ZH-TW",
+ ext: ".md",
+ wantLocalizedExts: []string{".zh-tw.md", ".zh_tw.md", ".zh.md", "_zh.md", ".md"},
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if gotLocalizedExts := localizedExtensions(tt.ext, tt.languageCode); !reflect.DeepEqual(gotLocalizedExts, tt.wantLocalizedExts) {
+ t.Errorf("localizedExtensions() = %v, want %v", gotLocalizedExts, tt.wantLocalizedExts)
+ }
+ })
+ }
+}
diff --git a/routers/web/repo/view_test.go b/routers/web/repo/view_test.go
deleted file mode 100644
index 73ba118823bf..000000000000
--- a/routers/web/repo/view_test.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2017 The Gitea Authors. All rights reserved.
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package repo
-
-import (
- "reflect"
- "testing"
-)
-
-func Test_localizedExtensions(t *testing.T) {
- tests := []struct {
- name string
- ext string
- languageCode string
- wantLocalizedExts []string
- }{
- {
- name: "empty language",
- ext: ".md",
- wantLocalizedExts: []string{".md"},
- },
- {
- name: "No region - lowercase",
- languageCode: "en",
- ext: ".csv",
- wantLocalizedExts: []string{".en.csv", ".csv"},
- },
- {
- name: "No region - uppercase",
- languageCode: "FR",
- ext: ".txt",
- wantLocalizedExts: []string{".fr.txt", ".txt"},
- },
- {
- name: "With region - lowercase",
- languageCode: "en-us",
- ext: ".md",
- wantLocalizedExts: []string{".en-us.md", ".en_us.md", ".en.md", "_en.md", ".md"},
- },
- {
- name: "With region - uppercase",
- languageCode: "en-CA",
- ext: ".MD",
- wantLocalizedExts: []string{".en-ca.MD", ".en_ca.MD", ".en.MD", "_en.MD", ".MD"},
- },
- {
- name: "With region - all uppercase",
- languageCode: "ZH-TW",
- ext: ".md",
- wantLocalizedExts: []string{".zh-tw.md", ".zh_tw.md", ".zh.md", "_zh.md", ".md"},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if gotLocalizedExts := localizedExtensions(tt.ext, tt.languageCode); !reflect.DeepEqual(gotLocalizedExts, tt.wantLocalizedExts) {
- t.Errorf("localizedExtensions() = %v, want %v", gotLocalizedExts, tt.wantLocalizedExts)
- }
- })
- }
-}
From 8ba16c0c545bcff2be749f09974d2dc44d1b1b43 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 09:47:41 +0000
Subject: [PATCH 020/172] fix
---
modules/repository/license.go | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/modules/repository/license.go b/modules/repository/license.go
index 259eb57b11ae..96bffdce1bdc 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -142,22 +142,24 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error
return fmt.Errorf("FindFileInEntries: %w", err)
}
- // Read license file content
- blob := licenseFile.Blob()
- contentBuf, err := blob.GetBlobAll()
- if err != nil {
- return fmt.Errorf("GetBlobByPath: %w", err)
- }
+ if licenseFile != nil {
+ // Read license file content
+ blob := licenseFile.Blob()
+ contentBuf, err := blob.GetBlobAll()
+ if err != nil {
+ return fmt.Errorf("GetBlobByPath: %w", err)
+ }
- // check license
- var licenses []string
- cov := licensecheck.Scan(contentBuf)
- for _, m := range cov.Match {
- licenses = append(licenses, m.ID)
- }
- repo.Licenses = licenses
- if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
- return fmt.Errorf("UpdateRepositoryCols: %v", err)
+ // check license
+ var licenses []string
+ cov := licensecheck.Scan(contentBuf)
+ for _, m := range cov.Match {
+ licenses = append(licenses, m.ID)
+ }
+ repo.Licenses = licenses
+ if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
+ return fmt.Errorf("UpdateRepositoryCols: %v", err)
+ }
}
return nil
From 0637b87923a611d3b5ad29d4c1d2286657f13f63 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Thu, 25 May 2023 10:19:20 +0000
Subject: [PATCH 021/172] fix
---
modules/repository/license.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/modules/repository/license.go b/modules/repository/license.go
index 96bffdce1bdc..e92f9a745ceb 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -119,6 +119,10 @@ func getLicensePlaceholder(name string) *licensePlaceholder {
}
func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error {
+ if repo.DefaultBranch == "" {
+ return nil
+ }
+
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
if err != nil {
return fmt.Errorf("OpenRepository: %w", err)
From facd6982e24912bdb3c068297c31e583d8a93aed Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Fri, 26 May 2023 00:44:00 +0000
Subject: [PATCH 022/172] improve
---
modules/context/repo.go | 2 -
modules/repository/license.go | 83 ++++++++++++++++++++--------
modules/repository/repo.go | 2 +-
routers/private/hook_post_receive.go | 2 +-
routers/web/repo/view.go | 5 ++
services/mirror/mirror_pull.go | 2 +-
6 files changed, 67 insertions(+), 29 deletions(-)
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 9ee51b2d9ed3..ff4d2d6803ed 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -400,8 +400,6 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
ctx.Data["RepoName"] = ctx.Repo.Repository.Name
ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty
ctx.Data["Licenses"] = ctx.Repo.Repository.Licenses
- // TODO: support ext
- ctx.Data["LicenseFileName"] = "LICENSE"
}
// RepoIDAssignment returns a handler which assigns the repo to the context.
diff --git a/modules/repository/license.go b/modules/repository/license.go
index e92f9a745ceb..ceb6a600fdf7 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -118,32 +118,19 @@ func getLicensePlaceholder(name string) *licensePlaceholder {
return ret
}
-func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error {
- if repo.DefaultBranch == "" {
- return nil
- }
-
- gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
- if err != nil {
- return fmt.Errorf("OpenRepository: %w", err)
- }
- commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch)
- if err != nil {
- return fmt.Errorf("GetBranchCommitID: %w", err)
- }
- commit, err := gitRepo.GetCommit(commitID)
- if err != nil {
- return fmt.Errorf("GetCommit: %w", err)
- }
- entries, err := commit.ListEntries()
- if err != nil {
- return fmt.Errorf("ListEntries: %w", err)
+// UpdateRepoLicenses will update repository licenses col if license file exists
+func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error {
+ if gitRepo == nil {
+ var err error
+ gitRepo, err = git.OpenRepository(ctx, repo.RepoPath())
+ if err != nil {
+ return fmt.Errorf("OpenRepository: %w", err)
+ }
}
- // Find license file
- _, licenseFile, err := FindFileInEntries(util.FileTypeLicense, entries, "", "", false)
+ _, licenseFile, err := findLicenseFile(ctx, gitRepo, repo.DefaultBranch)
if err != nil {
- return fmt.Errorf("FindFileInEntries: %w", err)
+ return fmt.Errorf("findLicenseFile: %w", err)
}
if licenseFile != nil {
@@ -151,7 +138,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error
blob := licenseFile.Blob()
contentBuf, err := blob.GetBlobAll()
if err != nil {
- return fmt.Errorf("GetBlobByPath: %w", err)
+ return fmt.Errorf("GetBlobAll: %w", err)
}
// check license
@@ -168,3 +155,51 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error
return nil
}
+
+// GetLicenseFileName returns license file name in the repository if it exists
+func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) (string, error) {
+ if repo.DefaultBranch == "" {
+ return "", nil
+ }
+ if gitRepo == nil {
+ var err error
+ gitRepo, err = git.OpenRepository(ctx, repo.RepoPath())
+ if err != nil {
+ return "", fmt.Errorf("OpenRepository: %w", err)
+ }
+ }
+
+ _, licenseFile, err := findLicenseFile(ctx, gitRepo, repo.DefaultBranch)
+ if err != nil {
+ return "", fmt.Errorf("findLicenseFile: %w", err)
+ }
+
+ if licenseFile != nil {
+ return licenseFile.Name(), nil
+ }
+ return "", nil
+}
+
+// findLicenseFile returns the entry of license file in the repository if it exists
+func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) {
+ if branchName == "" {
+ return "", nil, nil
+ }
+ if gitRepo == nil {
+ return "", nil, nil
+ }
+
+ commitID, err := gitRepo.GetBranchCommitID(branchName)
+ if err != nil {
+ return "", nil, fmt.Errorf("GetBranchCommitID: %w", err)
+ }
+ commit, err := gitRepo.GetCommit(commitID)
+ if err != nil {
+ return "", nil, fmt.Errorf("GetCommit: %w", err)
+ }
+ entries, err := commit.ListEntries()
+ if err != nil {
+ return "", nil, fmt.Errorf("ListEntries: %w", err)
+ }
+ return FindFileInEntries(util.FileTypeLicense, entries, "", "", false)
+}
diff --git a/modules/repository/repo.go b/modules/repository/repo.go
index 3d5c40a6eb73..50fa5788eea5 100644
--- a/modules/repository/repo.go
+++ b/modules/repository/repo.go
@@ -138,7 +138,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
defer gitRepo.Close()
// Update repo license
- err = UpdateRepoLicenses(ctx, repo)
+ err = UpdateRepoLicenses(ctx, repo, gitRepo)
if err != nil {
return repo, fmt.Errorf("UpdateRepoLicenses: %w", err)
}
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index 4ff19984cf10..c0a0ca830f11 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -200,7 +200,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
// If our branch is the default branch of an unforked repo - there's no PR to create or refer to
if !repo.IsFork && branch == baseRepo.DefaultBranch {
// TODO: check IsWiki?
- err := repo_module.UpdateRepoLicenses(ctx, repo)
+ err := repo_module.UpdateRepoLicenses(ctx, repo, nil)
if err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()})
}
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index c4f96439d360..772056bb4837 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -870,6 +870,11 @@ func renderCode(ctx *context.Context) {
ctx.Data["TreeLink"] = treeLink
ctx.Data["TreeNames"] = treeNames
ctx.Data["BranchLink"] = branchLink
+ ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
+ if err != nil {
+ ctx.ServerError("GetLicenseFileName", err)
+ return
+ }
ctx.HTML(http.StatusOK, tplRepoHome)
}
diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go
index 39e8d3de10cf..d4724de45f29 100644
--- a/services/mirror/mirror_pull.go
+++ b/services/mirror/mirror_pull.go
@@ -529,7 +529,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
}
// Update License
- if err = repo_module.UpdateRepoLicenses(ctx, m.Repo); err != nil {
+ if err = repo_module.UpdateRepoLicenses(ctx, m.Repo, gitRepo); err != nil {
log.Error("SyncMirrors [repo: %-v]: unable to update repository 'licenses': %v", m.Repo, err)
return false
}
From af1b031c0592c651014eb21ed4eea9e235463343 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Fri, 26 May 2023 00:53:45 +0000
Subject: [PATCH 023/172] fix fork repo
---
routers/private/hook_post_receive.go | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index c0a0ca830f11..728cac86a1c9 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -197,15 +197,18 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
}
- // If our branch is the default branch of an unforked repo - there's no PR to create or refer to
- if !repo.IsFork && branch == baseRepo.DefaultBranch {
+ if branch == baseRepo.DefaultBranch {
// TODO: check IsWiki?
err := repo_module.UpdateRepoLicenses(ctx, repo, nil)
if err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()})
}
- results = append(results, private.HookPostReceiveBranchResult{})
- continue
+
+ // If our branch is the default branch of an unforked repo - there's no PR to create or refer to
+ if !repo.IsFork {
+ results = append(results, private.HookPostReceiveBranchResult{})
+ continue
+ }
}
pr, err := issues_model.GetUnmergedPullRequest(ctx, repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch, issues_model.PullRequestFlowGithub)
From 30c25ba3add3d4715b4e6e6d937441f082dc45d3 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Fri, 26 May 2023 01:00:22 +0000
Subject: [PATCH 024/172] remove check iswiki
---
routers/private/hook_post_receive.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index 728cac86a1c9..01b61ab0f0bd 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -198,7 +198,6 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
if branch == baseRepo.DefaultBranch {
- // TODO: check IsWiki?
err := repo_module.UpdateRepoLicenses(ctx, repo, nil)
if err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()})
From bc005ddc8fd9520dc3d3c7046c717eff11024f15 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Fri, 26 May 2023 02:48:05 +0000
Subject: [PATCH 025/172] fix no commitID
---
modules/repository/license.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/modules/repository/license.go b/modules/repository/license.go
index ceb6a600fdf7..725c903499ac 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -191,6 +191,9 @@ func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName st
commitID, err := gitRepo.GetBranchCommitID(branchName)
if err != nil {
+ if git.IsErrNotExist(err) {
+ return "", nil, nil
+ }
return "", nil, fmt.Errorf("GetBranchCommitID: %w", err)
}
commit, err := gitRepo.GetCommit(commitID)
From 3518a638992c79add59263fadb349e8ae7fb8c93 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Fri, 26 May 2023 02:54:57 +0000
Subject: [PATCH 026/172] fix lint
---
routers/private/hook_post_receive.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index b6034f0343ef..7d38d077398c 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -193,8 +193,8 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
}
- branch := refFullName.BranchName()
-
+ branch := refFullName.BranchName()
+
if branch == baseRepo.DefaultBranch {
err := repo_module.UpdateRepoLicenses(ctx, repo, nil)
if err != nil {
From 763f104e74befa92e4f6d3c6fa5246dfac6f515e Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Mon, 29 May 2023 04:40:05 +0000
Subject: [PATCH 027/172] improve
---
modules/repository/license.go | 61 +++++++++++++++++++----------------
1 file changed, 33 insertions(+), 28 deletions(-)
diff --git a/modules/repository/license.go b/modules/repository/license.go
index 725c903499ac..fe68aa8dcfa8 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -128,29 +128,15 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRep
}
}
- _, licenseFile, err := findLicenseFile(ctx, gitRepo, repo.DefaultBranch)
+ _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch)
if err != nil {
return fmt.Errorf("findLicenseFile: %w", err)
}
-
- if licenseFile != nil {
- // Read license file content
- blob := licenseFile.Blob()
- contentBuf, err := blob.GetBlobAll()
- if err != nil {
- return fmt.Errorf("GetBlobAll: %w", err)
- }
-
- // check license
- var licenses []string
- cov := licensecheck.Scan(contentBuf)
- for _, m := range cov.Match {
- licenses = append(licenses, m.ID)
- }
- repo.Licenses = licenses
- if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
- return fmt.Errorf("UpdateRepositoryCols: %v", err)
- }
+ if repo.Licenses, err = detectLicense(licenseFile); err != nil {
+ return fmt.Errorf("checkLicenseFile: %w", err)
+ }
+ if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
+ return fmt.Errorf("UpdateRepositoryCols: %v", err)
}
return nil
@@ -169,7 +155,7 @@ func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, gitRep
}
}
- _, licenseFile, err := findLicenseFile(ctx, gitRepo, repo.DefaultBranch)
+ _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch)
if err != nil {
return "", fmt.Errorf("findLicenseFile: %w", err)
}
@@ -181,7 +167,7 @@ func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, gitRep
}
// findLicenseFile returns the entry of license file in the repository if it exists
-func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) {
+func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) {
if branchName == "" {
return "", nil, nil
}
@@ -189,16 +175,12 @@ func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName st
return "", nil, nil
}
- commitID, err := gitRepo.GetBranchCommitID(branchName)
+ commit, err := gitRepo.GetBranchCommit(branchName)
if err != nil {
if git.IsErrNotExist(err) {
return "", nil, nil
}
- return "", nil, fmt.Errorf("GetBranchCommitID: %w", err)
- }
- commit, err := gitRepo.GetCommit(commitID)
- if err != nil {
- return "", nil, fmt.Errorf("GetCommit: %w", err)
+ return "", nil, fmt.Errorf("GetBranchCommit: %w", err)
}
entries, err := commit.ListEntries()
if err != nil {
@@ -206,3 +188,26 @@ func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName st
}
return FindFileInEntries(util.FileTypeLicense, entries, "", "", false)
}
+
+// detectLicense returns the licenses detected in the given file
+func detectLicense(file *git.TreeEntry) ([]string, error) {
+ if file == nil {
+ return nil, nil
+ }
+
+ // Read license file content
+ blob := file.Blob()
+ contentBuf, err := blob.GetBlobAll()
+ if err != nil {
+ return nil, fmt.Errorf("GetBlobAll: %w", err)
+ }
+
+ // check license
+ var licenses []string
+ cov := licensecheck.Scan(contentBuf)
+ for _, m := range cov.Match {
+ licenses = append(licenses, m.ID)
+ }
+
+ return licenses, nil
+}
From f481624e4c4f50ef418d3d25995e4417ec9253f1 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Mon, 29 May 2023 04:40:36 +0000
Subject: [PATCH 028/172] add db migration
---
models/migrations/migrations.go | 2 +
models/migrations/v1_20/v259.go | 122 ++++++++++++++++++++++++++++++++
2 files changed, 124 insertions(+)
create mode 100644 models/migrations/v1_20/v259.go
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 231c93cc74bb..9466e1df039c 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -495,6 +495,8 @@ var migrations = []Migration{
NewMigration("Add Actions Artifact table", v1_20.CreateActionArtifactTable),
// v258 -> 259
NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue),
+ // v259 -> 260
+ NewMigration("Add Repository Licenses", v1_20.AddRepositoryLicenses),
}
// GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v1_20/v259.go b/models/migrations/v1_20/v259.go
new file mode 100644
index 000000000000..d64a938ee64b
--- /dev/null
+++ b/models/migrations/v1_20/v259.go
@@ -0,0 +1,122 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_20 //nolint
+
+import (
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ repo_module "code.gitea.io/gitea/modules/repository"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
+ "github.com/google/licensecheck"
+
+ "xorm.io/builder"
+ "xorm.io/xorm"
+)
+
+// Copy paste from models/repo.go because we cannot import models package
+func repoPath(userName, repoName string) string {
+ return filepath.Join(userPath(userName), strings.ToLower(repoName)+".git")
+}
+
+func userPath(userName string) string {
+ return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
+}
+
+func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) {
+ if branchName == "" {
+ return "", nil, nil
+ }
+ if gitRepo == nil {
+ return "", nil, nil
+ }
+
+ commit, err := gitRepo.GetBranchCommit(branchName)
+ if err != nil {
+ if git.IsErrNotExist(err) {
+ return "", nil, nil
+ }
+ return "", nil, fmt.Errorf("GetBranchCommit: %w", err)
+ }
+ entries, err := commit.ListEntries()
+ if err != nil {
+ return "", nil, fmt.Errorf("ListEntries: %w", err)
+ }
+ return repo_module.FindFileInEntries(util.FileTypeLicense, entries, "", "", false)
+}
+
+func detectLicense(file *git.TreeEntry) ([]string, error) {
+ if file == nil {
+ return nil, nil
+ }
+
+ // Read license file content
+ blob := file.Blob()
+ contentBuf, err := blob.GetBlobAll()
+ if err != nil {
+ return nil, fmt.Errorf("GetBlobAll: %w", err)
+ }
+
+ // check license
+ var licenses []string
+ cov := licensecheck.Scan(contentBuf)
+ for _, m := range cov.Match {
+ licenses = append(licenses, m.ID)
+ }
+
+ return licenses, nil
+}
+
+func AddRepositoryLicenses(x *xorm.Engine) error {
+ type Repository struct {
+ ID int64 `xorm:"pk autoincr"`
+ OwnerName string
+ Name string `xorm:"INDEX NOT NULL"`
+ DefaultBranch string
+ Licenses []string `xorm:"TEXT JSON"`
+ }
+
+ if err := x.Sync(new(Repository)); err != nil {
+ return err
+ }
+
+ sess := x.NewSession()
+ defer sess.Close()
+
+ if err := sess.Begin(); err != nil {
+ return err
+ }
+
+ repos := make([]*Repository, 0)
+ if err := sess.Where(builder.IsNull{"licenses"}).Find(&repos); err != nil {
+ return err
+ }
+
+ for _, repo := range repos {
+ gitRepo, err := git.OpenRepository(git.DefaultContext, repoPath(repo.OwnerName, repo.Name))
+ if err != nil {
+ log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err)
+ return err
+ }
+ _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch)
+ if err != nil {
+ log.Error("Error whilst finding license file in [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err)
+ return err
+ }
+ repo.Licenses, err = detectLicense(licenseFile)
+ if err != nil {
+ log.Error("Error whilst detecting license from %s in [%d]%s/%s. Error: %v", licenseFile.Name(), repo.ID, repo.OwnerName, repo.Name, err)
+ return err
+ }
+ if _, err := sess.ID(repo.ID).Cols("licenses").NoAutoTime().Update(repo); err != nil {
+ log.Error("Error whilst updating [%d]%s/%s licenses column. Error: %v", repo.ID, repo.OwnerName, repo.Name, err)
+ return err
+ }
+ }
+ return sess.Commit()
+}
From 07e91bf049b7c689958b777e79b6063392163f71 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Mon, 29 May 2023 05:24:09 +0000
Subject: [PATCH 029/172] fix migration
---
models/migrations/v1_20/v259.go | 109 +++++++++++++++++++++++++++++++-
1 file changed, 107 insertions(+), 2 deletions(-)
diff --git a/models/migrations/v1_20/v259.go b/models/migrations/v1_20/v259.go
index d64a938ee64b..a20f6dc17dc3 100644
--- a/models/migrations/v1_20/v259.go
+++ b/models/migrations/v1_20/v259.go
@@ -5,12 +5,13 @@ package v1_20 //nolint
import (
"fmt"
+ "path"
"path/filepath"
"strings"
+ "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
- repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/google/licensecheck"
@@ -28,6 +29,7 @@ func userPath(userName string) string {
return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
}
+// Copy paste from modules/repository/file.go because we cannot import models package
func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) {
if branchName == "" {
return "", nil, nil
@@ -47,7 +49,110 @@ func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.T
if err != nil {
return "", nil, fmt.Errorf("ListEntries: %w", err)
}
- return repo_module.FindFileInEntries(util.FileTypeLicense, entries, "", "", false)
+ return findFileInEntries(util.FileTypeLicense, entries, "", "", false)
+}
+
+func findFileInEntries(fileType util.FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) {
+ // Create a list of extensions in priority order
+ // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md
+ // 2. Txt files - e.g. README.txt
+ // 3. No extension - e.g. README
+ exts := append(localizedExtensions(".md", language), ".txt", "") // sorted by priority
+ extCount := len(exts)
+ targetFiles := make([]*git.TreeEntry, extCount+1)
+
+ docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/)
+ for _, entry := range entries {
+ if tryWellKnownDirs && entry.IsDir() {
+ // as a special case for the top-level repo introduction README,
+ // fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ...
+ // (note that docsEntries is ignored unless we are at the root)
+ lowerName := strings.ToLower(entry.Name())
+ switch lowerName {
+ case "docs":
+ if entry.Name() == "docs" || docsEntries[0] == nil {
+ docsEntries[0] = entry
+ }
+ case ".gitea":
+ if entry.Name() == ".gitea" || docsEntries[1] == nil {
+ docsEntries[1] = entry
+ }
+ case ".github":
+ if entry.Name() == ".github" || docsEntries[2] == nil {
+ docsEntries[2] = entry
+ }
+ }
+ continue
+ }
+ if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok {
+ log.Debug("Potential %s file: %s", fileType, entry.Name())
+ if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) {
+ if entry.IsLink() {
+ target, err := entry.FollowLinks()
+ if err != nil && !git.IsErrBadLink(err) {
+ return "", nil, err
+ } else if target != nil && (target.IsExecutable() || target.IsRegular()) {
+ targetFiles[i] = entry
+ }
+ } else {
+ targetFiles[i] = entry
+ }
+ }
+ }
+ }
+ var targetFile *git.TreeEntry
+ for _, f := range targetFiles {
+ if f != nil {
+ targetFile = f
+ break
+ }
+ }
+
+ if treePath == "" && targetFile == nil {
+ for _, subTreeEntry := range docsEntries {
+ if subTreeEntry == nil {
+ continue
+ }
+ subTree := subTreeEntry.Tree()
+ if subTree == nil {
+ // this should be impossible; if subTreeEntry exists so should this.
+ continue
+ }
+ var err error
+ childEntries, err := subTree.ListEntries()
+ if err != nil {
+ return "", nil, err
+ }
+
+ subfolder, targetFile, err := findFileInEntries(fileType, childEntries, subTreeEntry.Name(), language, false)
+ if err != nil && !git.IsErrNotExist(err) {
+ return "", nil, err
+ }
+ if targetFile != nil {
+ return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil
+ }
+ }
+ }
+
+ return "", targetFile, nil
+}
+
+func localizedExtensions(ext, languageCode string) (localizedExts []string) {
+ if len(languageCode) < 1 {
+ return []string{ext}
+ }
+
+ lowerLangCode := "." + strings.ToLower(languageCode)
+
+ if strings.Contains(lowerLangCode, "-") {
+ underscoreLangCode := strings.ReplaceAll(lowerLangCode, "-", "_")
+ indexOfDash := strings.Index(lowerLangCode, "-")
+ // e.g. [.zh-cn.md, .zh_cn.md, .zh.md, _zh.md, .md]
+ return []string{lowerLangCode + ext, underscoreLangCode + ext, lowerLangCode[:indexOfDash] + ext, "_" + lowerLangCode[1:indexOfDash] + ext, ext}
+ }
+
+ // e.g. [.en.md, .md]
+ return []string{lowerLangCode + ext, ext}
}
func detectLicense(file *git.TreeEntry) ([]string, error) {
From 744a03226f9bf50b428a6e77f5eeff3fabb78ce9 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Mon, 29 May 2023 06:13:49 +0000
Subject: [PATCH 030/172] add licensecheck test
---
models/migrations/v1_20/v259.go | 4 +--
modules/repository/license.go | 20 +++++++-----
modules/repository/license_test.go | 51 ++++++++++++++++++++++++++++--
3 files changed, 63 insertions(+), 12 deletions(-)
diff --git a/models/migrations/v1_20/v259.go b/models/migrations/v1_20/v259.go
index a20f6dc17dc3..4cb95c980eda 100644
--- a/models/migrations/v1_20/v259.go
+++ b/models/migrations/v1_20/v259.go
@@ -155,7 +155,7 @@ func localizedExtensions(ext, languageCode string) (localizedExts []string) {
return []string{lowerLangCode + ext, ext}
}
-func detectLicense(file *git.TreeEntry) ([]string, error) {
+func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) {
if file == nil {
return nil, nil
}
@@ -213,7 +213,7 @@ func AddRepositoryLicenses(x *xorm.Engine) error {
log.Error("Error whilst finding license file in [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err)
return err
}
- repo.Licenses, err = detectLicense(licenseFile)
+ repo.Licenses, err = detectLicenseByEntry(licenseFile)
if err != nil {
log.Error("Error whilst detecting license from %s in [%d]%s/%s. Error: %v", licenseFile.Name(), repo.ID, repo.OwnerName, repo.Name, err)
return err
diff --git a/modules/repository/license.go b/modules/repository/license.go
index fe68aa8dcfa8..09eac2d3ef54 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -132,7 +132,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRep
if err != nil {
return fmt.Errorf("findLicenseFile: %w", err)
}
- if repo.Licenses, err = detectLicense(licenseFile); err != nil {
+ if repo.Licenses, err = detectLicenseByEntry(licenseFile); err != nil {
return fmt.Errorf("checkLicenseFile: %w", err)
}
if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil {
@@ -189,25 +189,29 @@ func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.T
return FindFileInEntries(util.FileTypeLicense, entries, "", "", false)
}
-// detectLicense returns the licenses detected in the given file
-func detectLicense(file *git.TreeEntry) ([]string, error) {
+// detectLicenseByEntry returns the licenses detected by the given tree entry
+func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) {
if file == nil {
return nil, nil
}
- // Read license file content
blob := file.Blob()
contentBuf, err := blob.GetBlobAll()
if err != nil {
return nil, fmt.Errorf("GetBlobAll: %w", err)
}
+ return detectLicense(contentBuf), nil
+}
+
+func detectLicense(buf []byte) []string {
+ if len(buf) <= 0 {
+ return nil
+ }
- // check license
var licenses []string
- cov := licensecheck.Scan(contentBuf)
+ cov := licensecheck.Scan(buf)
for _, m := range cov.Match {
licenses = append(licenses, m.ID)
}
-
- return licenses, nil
+ return licenses
}
diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go
index e1555a0eed32..a45537507a32 100644
--- a/modules/repository/license_test.go
+++ b/modules/repository/license_test.go
@@ -6,6 +6,7 @@ package repository
import (
"fmt"
"testing"
+ "time"
"github.com/stretchr/testify/assert"
)
@@ -180,6 +181,52 @@ Copyright (C) 2023 by Gitea teabot@gitea.io
}
}
-func Test_UpdateRepoLicenses(t *testing.T) {
- // TODO
+func Test_detectLicense(t *testing.T) {
+ type DetectLicenseTest struct {
+ name string
+ arg []byte
+ want []string
+ }
+
+ tests := []DetectLicenseTest{
+ {
+ name: "empty",
+ arg: []byte(""),
+ want: nil,
+ },
+ {
+ name: "no detected license",
+ arg: []byte("Copyright (c) 2023 Gitea"),
+ want: nil,
+ },
+ }
+
+ LoadRepoConfig()
+ for _, licenseName := range Licenses {
+ license, err := getLicense(licenseName, &licenseValues{
+ Owner: "Gitea",
+ Email: "teabot@gitea.io",
+ Repo: "gitea",
+ Year: time.Now().Format("2006"),
+ })
+ assert.NoError(t, err)
+
+ tests = append(tests, DetectLicenseTest{
+ name: fmt.Sprintf("auto single license test: %s", licenseName),
+ arg: license,
+ want: []string{licenseName},
+ })
+ }
+
+ tests = append(tests, DetectLicenseTest{
+ name: fmt.Sprintf("auto multiple license test: %s and %s", tests[2].want[0], tests[3].want[0]),
+ arg: append(tests[2].arg, tests[3].arg...),
+ want: []string{tests[2].want[0], tests[3].want[0]},
+ })
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, detectLicense(tt.arg), "%s", tt.arg)
+ })
+ }
}
From 93d2c7f055e28f95e059c711ccb0de614ffc37c9 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Tue, 30 May 2023 05:33:32 +0000
Subject: [PATCH 031/172] fix lint
---
modules/repository/license.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/repository/license.go b/modules/repository/license.go
index 09eac2d3ef54..bd8b1be9b370 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -204,7 +204,7 @@ func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) {
}
func detectLicense(buf []byte) []string {
- if len(buf) <= 0 {
+ if len(buf) == 0 {
return nil
}
From 92d8df7592b8cdb35ab74c4d29333882f3cfeb7d Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Wed, 31 May 2023 01:09:16 +0000
Subject: [PATCH 032/172] move the position of license
---
templates/repo/sub_menu.tmpl | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl
index 738984ff9861..09fb5d1048f0 100644
--- a/templates/repo/sub_menu.tmpl
+++ b/templates/repo/sub_menu.tmpl
@@ -14,11 +14,6 @@
- {{$fileSizeFormatted := FileSize .Repository.Size}}{{/* the formatted string is always "{val} {unit}" */}}
- {{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}}
- {{svg "octicon-database"}} {{.locale.PrettyNumber (index $fileSizeFields 0)}} {{index $fileSizeFields 1}}
-
{{if .Licenses}}
+ {{$fileSizeFormatted := FileSize .Repository.Size}}{{/* the formatted string is always "{val} {unit}" */}}
+ {{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}}
+ {{svg "octicon-database"}} {{.locale.PrettyNumber (index $fileSizeFields 0)}} {{index $fileSizeFields 1}}
+
{{end}}
From ac8442202c6883d77442704c724b43035714da28 Mon Sep 17 00:00:00 2001
From: yp05327 <576951401@qq.com>
Date: Wed, 31 May 2023 01:26:42 +0000
Subject: [PATCH 033/172] fix
---
routers/web/repo/branch.go | 6 ++++++
routers/web/repo/commit.go | 17 ++++++++++++++++-
templates/repo/sub_menu.tmpl | 2 +-
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go
index ea2c01856d45..1c54626c0f5a 100644
--- a/routers/web/repo/branch.go
+++ b/routers/web/repo/branch.go
@@ -80,6 +80,12 @@ func Branches(ctx *context.Context) {
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager
+ var err error
+ ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
+ if err != nil {
+ ctx.ServerError("GetLicenseFileName", err)
+ return
+ }
ctx.HTML(http.StatusOK, tplBranch)
}
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index e88f1139f8b7..1974abd7ab15 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -21,6 +21,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitgraph"
"code.gitea.io/gitea/modules/log"
+ repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/gitdiff"
)
@@ -85,7 +86,11 @@ func Commits(ctx *context.Context) {
pager := context.NewPagination(int(commitsCount), pageSize, page, 5)
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager
-
+ ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
+ if err != nil {
+ ctx.ServerError("GetLicenseFileName", err)
+ return
+ }
ctx.HTML(http.StatusOK, tplCommits)
}
@@ -203,6 +208,11 @@ func SearchCommits(ctx *context.Context) {
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
ctx.Data["RefName"] = ctx.Repo.RefName
+ ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
+ if err != nil {
+ ctx.ServerError("GetLicenseFileName", err)
+ return
+ }
ctx.HTML(http.StatusOK, tplCommits)
}
@@ -252,6 +262,11 @@ func FileHistory(ctx *context.Context) {
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager
+ ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo)
+ if err != nil {
+ ctx.ServerError("GetLicenseFileName", err)
+ return
+ }
ctx.HTML(http.StatusOK, tplCommits)
}
diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl
index 09fb5d1048f0..0d113e621d3c 100644
--- a/templates/repo/sub_menu.tmpl
+++ b/templates/repo/sub_menu.tmpl
@@ -16,7 +16,7 @@
{{end}}
{{if .Licenses}}