[mirror] Scalable static site server for Git forges (like GitHub Pages)
at main 3.4 kB view raw
1package git_pages 2 3import ( 4 "fmt" 5 "slices" 6 "strings" 7 8 "github.com/valyala/fasttemplate" 9) 10 11type WildcardPattern struct { 12 Domain []string 13 CloneURL *fasttemplate.Template 14 IndexRepos []*fasttemplate.Template 15 IndexBranch string 16 Authorization bool 17} 18 19func (pattern *WildcardPattern) GetHost() string { 20 parts := []string{"*"} 21 parts = append(parts, pattern.Domain...) 22 return strings.Join(parts, ".") 23} 24 25// Returns `subdomain, found` where if `found == true`, `subdomain` contains the part of `host` 26// corresponding to the * in the domain pattern. 27func (pattern *WildcardPattern) Matches(host string) (string, bool) { 28 hostParts := strings.Split(host, ".") 29 hostLen := len(hostParts) 30 patternLen := len(pattern.Domain) 31 32 // host must have at least one more part than the pattern domain 33 if hostLen <= patternLen { 34 return "", false 35 } 36 37 // break the host parts into <subdomain parts> and <domain parts> 38 mid := hostLen - patternLen 39 prefix := hostParts[:mid] 40 suffix := hostParts[mid:] 41 42 // check if the suffix matches the domain 43 if !slices.Equal(suffix, pattern.Domain) { 44 return "", false 45 } 46 47 // return all the subdomain parts 48 subdomain := strings.Join(prefix, ".") 49 return subdomain, true 50} 51 52func (pattern *WildcardPattern) ApplyTemplate(userName string, projectName string) ([]string, string) { 53 var repoURLs []string 54 var branch string 55 repoURLTemplate := pattern.CloneURL 56 if projectName == ".index" { 57 for _, indexRepoTemplate := range pattern.IndexRepos { 58 indexRepo := indexRepoTemplate.ExecuteString(map[string]any{"user": userName}) 59 repoURLs = append(repoURLs, repoURLTemplate.ExecuteString(map[string]any{ 60 "user": userName, 61 "project": indexRepo, 62 })) 63 } 64 branch = pattern.IndexBranch 65 } else { 66 repoURLs = append(repoURLs, repoURLTemplate.ExecuteString(map[string]any{ 67 "user": userName, 68 "project": projectName, 69 })) 70 branch = "pages" 71 } 72 return repoURLs, branch 73} 74 75func TranslateWildcards(configs []WildcardConfig) ([]*WildcardPattern, error) { 76 var wildcardPatterns []*WildcardPattern 77 for _, config := range configs { 78 cloneURLTemplate, err := fasttemplate.NewTemplate(config.CloneURL, "<", ">") 79 if err != nil { 80 return nil, fmt.Errorf("wildcard pattern: clone URL: %w", err) 81 } 82 83 var indexRepoTemplates []*fasttemplate.Template 84 var indexRepoBranch string = config.IndexRepoBranch 85 for _, indexRepo := range config.IndexRepos { 86 indexRepoTemplate, err := fasttemplate.NewTemplate(indexRepo, "<", ">") 87 if err != nil { 88 return nil, fmt.Errorf("wildcard pattern: index repo: %w", err) 89 } 90 indexRepoTemplates = append(indexRepoTemplates, indexRepoTemplate) 91 } 92 93 authorization := false 94 if config.Authorization != "" { 95 if slices.Contains([]string{"gogs", "gitea", "forgejo"}, config.Authorization) { 96 // Currently these are the only supported forges, and the authorization mechanism 97 // is the same for all of them. 98 authorization = true 99 } else { 100 return nil, fmt.Errorf( 101 "wildcard pattern: unknown authorization mechanism: %s", 102 config.Authorization, 103 ) 104 } 105 } 106 107 wildcardPatterns = append(wildcardPatterns, &WildcardPattern{ 108 Domain: strings.Split(config.Domain, "."), 109 CloneURL: cloneURLTemplate, 110 IndexRepos: indexRepoTemplates, 111 IndexBranch: indexRepoBranch, 112 Authorization: authorization, 113 }) 114 } 115 return wildcardPatterns, nil 116}