mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Refactor git attributes (#29356)
This commit is contained in:
		
							
								
								
									
										35
									
								
								modules/git/attribute.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								modules/git/attribute.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // Copyright 2024 The Gitea Authors. All rights reserved. | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| package git | ||||
|  | ||||
| import ( | ||||
| 	"code.gitea.io/gitea/modules/optional" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	AttributeLinguistVendored      = "linguist-vendored" | ||||
| 	AttributeLinguistGenerated     = "linguist-generated" | ||||
| 	AttributeLinguistDocumentation = "linguist-documentation" | ||||
| 	AttributeLinguistDetectable    = "linguist-detectable" | ||||
| 	AttributeLinguistLanguage      = "linguist-language" | ||||
| 	AttributeGitlabLanguage        = "gitlab-language" | ||||
| ) | ||||
|  | ||||
| // true if "set"/"true", false if "unset"/"false", none otherwise | ||||
| func AttributeToBool(attr map[string]string, name string) optional.Option[bool] { | ||||
| 	switch attr[name] { | ||||
| 	case "set", "true": | ||||
| 		return optional.Some(true) | ||||
| 	case "unset", "false": | ||||
| 		return optional.Some(false) | ||||
| 	} | ||||
| 	return optional.None[bool]() | ||||
| } | ||||
|  | ||||
| func AttributeToString(attr map[string]string, name string) optional.Option[string] { | ||||
| 	if value, has := attr[name]; has && value != "unspecified" { | ||||
| 		return optional.Some(value) | ||||
| 	} | ||||
| 	return optional.None[string]() | ||||
| } | ||||
| @@ -11,7 +11,6 @@ import ( | ||||
| 	"os" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/optional" | ||||
| ) | ||||
|  | ||||
| // CheckAttributeOpts represents the possible options to CheckAttribute | ||||
| @@ -292,10 +291,17 @@ func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeRe | ||||
| 	} | ||||
|  | ||||
| 	checker := &CheckAttributeReader{ | ||||
| 		Attributes: []string{"linguist-vendored", "linguist-generated", "linguist-language", "gitlab-language", "linguist-documentation", "linguist-detectable"}, | ||||
| 		Repo:       repo, | ||||
| 		IndexFile:  indexFilename, | ||||
| 		WorkTree:   worktree, | ||||
| 		Attributes: []string{ | ||||
| 			AttributeLinguistVendored, | ||||
| 			AttributeLinguistGenerated, | ||||
| 			AttributeLinguistDocumentation, | ||||
| 			AttributeLinguistDetectable, | ||||
| 			AttributeLinguistLanguage, | ||||
| 			AttributeGitlabLanguage, | ||||
| 		}, | ||||
| 		Repo:      repo, | ||||
| 		IndexFile: indexFilename, | ||||
| 		WorkTree:  worktree, | ||||
| 	} | ||||
| 	ctx, cancel := context.WithCancel(repo.Ctx) | ||||
| 	if err := checker.Init(ctx); err != nil { | ||||
| @@ -317,23 +323,3 @@ func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeRe | ||||
|  | ||||
| 	return checker, deferable | ||||
| } | ||||
|  | ||||
| // true if "set"/"true", false if "unset"/"false", none otherwise | ||||
| func attributeToBool(attr map[string]string, name string) optional.Option[bool] { | ||||
| 	if value, has := attr[name]; has && value != "unspecified" { | ||||
| 		switch value { | ||||
| 		case "set", "true": | ||||
| 			return optional.Some(true) | ||||
| 		case "unset", "false": | ||||
| 			return optional.Some(false) | ||||
| 		} | ||||
| 	} | ||||
| 	return optional.None[bool]() | ||||
| } | ||||
|  | ||||
| func attributeToString(attr map[string]string, name string) optional.Option[string] { | ||||
| 	if value, has := attr[name]; has && value != "unspecified" { | ||||
| 		return optional.Some(value) | ||||
| 	} | ||||
| 	return optional.None[string]() | ||||
| } | ||||
|   | ||||
| @@ -24,7 +24,7 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) { | ||||
| 	select { | ||||
| 	case attr := <-wr.ReadAttribute(): | ||||
| 		assert.Equal(t, ".gitignore\"\n", attr.Filename) | ||||
| 		assert.Equal(t, "linguist-vendored", attr.Attribute) | ||||
| 		assert.Equal(t, AttributeLinguistVendored, attr.Attribute) | ||||
| 		assert.Equal(t, "unspecified", attr.Value) | ||||
| 	case <-time.After(100 * time.Millisecond): | ||||
| 		assert.FailNow(t, "took too long to read an attribute from the list") | ||||
| @@ -38,7 +38,7 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) { | ||||
| 	select { | ||||
| 	case attr := <-wr.ReadAttribute(): | ||||
| 		assert.Equal(t, ".gitignore\"\n", attr.Filename) | ||||
| 		assert.Equal(t, "linguist-vendored", attr.Attribute) | ||||
| 		assert.Equal(t, AttributeLinguistVendored, attr.Attribute) | ||||
| 		assert.Equal(t, "unspecified", attr.Value) | ||||
| 	case <-time.After(100 * time.Millisecond): | ||||
| 		assert.FailNow(t, "took too long to read an attribute from the list") | ||||
| @@ -77,21 +77,21 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) { | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.EqualValues(t, attributeTriple{ | ||||
| 		Filename:  "shouldbe.vendor", | ||||
| 		Attribute: "linguist-vendored", | ||||
| 		Attribute: AttributeLinguistVendored, | ||||
| 		Value:     "set", | ||||
| 	}, attr) | ||||
| 	attr = <-wr.ReadAttribute() | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.EqualValues(t, attributeTriple{ | ||||
| 		Filename:  "shouldbe.vendor", | ||||
| 		Attribute: "linguist-generated", | ||||
| 		Attribute: AttributeLinguistGenerated, | ||||
| 		Value:     "unspecified", | ||||
| 	}, attr) | ||||
| 	attr = <-wr.ReadAttribute() | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.EqualValues(t, attributeTriple{ | ||||
| 		Filename:  "shouldbe.vendor", | ||||
| 		Attribute: "linguist-language", | ||||
| 		Attribute: AttributeLinguistLanguage, | ||||
| 		Value:     "unspecified", | ||||
| 	}, attr) | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,8 @@ package git | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/optional" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -46,3 +48,20 @@ func mergeLanguageStats(stats map[string]int64) map[string]int64 { | ||||
| 	} | ||||
| 	return res | ||||
| } | ||||
|  | ||||
| func TryReadLanguageAttribute(attrs map[string]string) optional.Option[string] { | ||||
| 	language := AttributeToString(attrs, AttributeLinguistLanguage) | ||||
| 	if language.Value() == "" { | ||||
| 		language = AttributeToString(attrs, AttributeGitlabLanguage) | ||||
| 		if language.Has() { | ||||
| 			raw := language.Value() | ||||
| 			// gitlab-language may have additional parameters after the language | ||||
| 			// ignore them and just use the main language | ||||
| 			// https://docs.gitlab.com/ee/user/project/highlighting.html#override-syntax-highlighting-for-a-file-type | ||||
| 			if idx := strings.IndexByte(raw, '?'); idx >= 0 { | ||||
| 				language = optional.Some(raw[:idx]) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return language | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,6 @@ package git | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"strings" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/analyze" | ||||
| 	"code.gitea.io/gitea/modules/optional" | ||||
| @@ -66,36 +65,27 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err | ||||
| 		if checker != nil { | ||||
| 			attrs, err := checker.CheckPath(f.Name) | ||||
| 			if err == nil { | ||||
| 				isVendored = attributeToBool(attrs, "linguist-vendored") | ||||
| 				isVendored = AttributeToBool(attrs, AttributeLinguistVendored) | ||||
| 				if isVendored.ValueOrDefault(false) { | ||||
| 					return nil | ||||
| 				} | ||||
|  | ||||
| 				isGenerated = attributeToBool(attrs, "linguist-generated") | ||||
| 				isGenerated = AttributeToBool(attrs, AttributeLinguistGenerated) | ||||
| 				if isGenerated.ValueOrDefault(false) { | ||||
| 					return nil | ||||
| 				} | ||||
|  | ||||
| 				isDocumentation = attributeToBool(attrs, "linguist-documentation") | ||||
| 				isDocumentation = AttributeToBool(attrs, AttributeLinguistDocumentation) | ||||
| 				if isDocumentation.ValueOrDefault(false) { | ||||
| 					return nil | ||||
| 				} | ||||
|  | ||||
| 				isDetectable = attributeToBool(attrs, "linguist-detectable") | ||||
| 				isDetectable = AttributeToBool(attrs, AttributeLinguistDetectable) | ||||
| 				if !isDetectable.ValueOrDefault(true) { | ||||
| 					return nil | ||||
| 				} | ||||
|  | ||||
| 				hasLanguage := attributeToString(attrs, "linguist-language") | ||||
| 				if hasLanguage.Value() == "" { | ||||
| 					hasLanguage = attributeToString(attrs, "gitlab-language") | ||||
| 					if hasLanguage.Has() { | ||||
| 						language := hasLanguage.Value() | ||||
| 						if idx := strings.IndexByte(language, '?'); idx >= 0 { | ||||
| 							hasLanguage = optional.Some(language[:idx]) | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				hasLanguage := TryReadLanguageAttribute(attrs) | ||||
| 				if hasLanguage.Value() != "" { | ||||
| 					language := hasLanguage.Value() | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,6 @@ package git | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"strings" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/analyze" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| @@ -97,36 +96,27 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err | ||||
| 		if checker != nil { | ||||
| 			attrs, err := checker.CheckPath(f.Name()) | ||||
| 			if err == nil { | ||||
| 				isVendored = attributeToBool(attrs, "linguist-vendored") | ||||
| 				isVendored = AttributeToBool(attrs, AttributeLinguistVendored) | ||||
| 				if isVendored.ValueOrDefault(false) { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				isGenerated = attributeToBool(attrs, "linguist-generated") | ||||
| 				isGenerated = AttributeToBool(attrs, AttributeLinguistGenerated) | ||||
| 				if isGenerated.ValueOrDefault(false) { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				isDocumentation = attributeToBool(attrs, "linguist-documentation") | ||||
| 				isDocumentation = AttributeToBool(attrs, AttributeLinguistDocumentation) | ||||
| 				if isDocumentation.ValueOrDefault(false) { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				isDetectable = attributeToBool(attrs, "linguist-detectable") | ||||
| 				isDetectable = AttributeToBool(attrs, AttributeLinguistDetectable) | ||||
| 				if !isDetectable.ValueOrDefault(true) { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				hasLanguage := attributeToString(attrs, "linguist-language") | ||||
| 				if hasLanguage.Value() == "" { | ||||
| 					hasLanguage = attributeToString(attrs, "gitlab-language") | ||||
| 					if hasLanguage.Has() { | ||||
| 						language := hasLanguage.Value() | ||||
| 						if idx := strings.IndexByte(language, '?'); idx >= 0 { | ||||
| 							hasLanguage = optional.Some(language[:idx]) | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				hasLanguage := TryReadLanguageAttribute(attrs) | ||||
| 				if hasLanguage.Value() != "" { | ||||
| 					language := hasLanguage.Value() | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user