1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
// Package generator downloads an updated version of the PSL list and compiles it into go code.
//
// It is meant to be used by maintainers in conjunction with the go generate tool
// to update the list.
package generator
import (
"bytes"
"context"
"fmt"
"go/format"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"text/template"
"time"
"github.com/google/go-github/v50/github"
"github.com/weppos/publicsuffix-go/publicsuffix"
)
const (
list = `// This file is automatically generated
// Run "go run cmd/gen/gen.go" to update the list.
package publicsuffix
const ListVersion = "PSL version {{.VersionSHA}} ({{.VersionDate}})"
func DefaultRules() [{{len .Rules}}]Rule {
return r
}
var r = [{{len .Rules}}]Rule{
{{range $r := .Rules}} \
{ {{$r.Type}}, "{{$r.Value}}", {{$r.Length}}, {{$r.Private}} },
{{end}}
}
func init() {
for i := range r {
DefaultList.AddRule(&r[i])
}
}
`
)
var (
listTmpl = template.Must(template.New("list").Parse(cont(list)))
)
// https://github.com/golang/go/issues/9969
// Requires go1.6
func cont(s string) string {
return strings.Replace(s, "\\\n", "", -1)
}
func extractHeadInfo() (sha string, datetime github.Timestamp) {
client := github.NewClient(nil)
commits, _, err := client.Repositories.ListCommits(context.Background(), "publicsuffix", "list", nil)
if err != nil {
log.Fatal(err)
}
lastCommit := commits[0]
return lastCommit.GetSHA(), lastCommit.GetCommit().GetCommitter().GetDate()
}
// Generator represents a generator.
type Generator struct {
Verbose bool
}
// NewGenerator creates a Generator with default settings.
func NewGenerator() *Generator {
g := &Generator{
Verbose: false,
}
return g
}
// Write ...
func (g *Generator) Write(filename string) error {
content, err := g.generate()
if err != nil {
return err
}
g.log("Writing %v...\n", filename)
return ioutil.WriteFile(filename, content, 0644)
}
// Print ...
func (g *Generator) Print() error {
content, err := g.generate()
if err != nil {
return err
}
_, err = os.Stdout.Write(content)
return err
}
// Generate downloads an updated version of the PSL list and compiles it into go code.
func (g *Generator) generate() ([]byte, error) {
g.log("Fetching PSL version...\n")
sha, datetime := extractHeadInfo()
g.log("Downloading PSL %s...\n", sha[:6])
resp, err := http.Get(fmt.Sprintf("https://raw.githubusercontent.com/publicsuffix/list/%s/public_suffix_list.dat", sha))
if err != nil {
return nil, err
}
defer resp.Body.Close()
list := publicsuffix.NewList()
rules, err := list.Load(resp.Body, nil)
if err != nil {
return nil, err
}
data := struct {
VersionSHA string
VersionDate string
Rules []publicsuffix.Rule
}{
sha[:6],
datetime.Format(time.ANSIC),
rules,
}
g.log("Parsing PSL...\n")
buf := new(bytes.Buffer)
err = listTmpl.Execute(buf, &data)
if err != nil {
return nil, err
}
return format.Source(buf.Bytes())
}
func (g *Generator) log(format string, v ...interface{}) {
if !g.Verbose {
return
}
log.Printf(format, v...)
}
func (g *Generator) fatal(message string) {
if !g.Verbose {
fmt.Println(message)
os.Exit(1)
}
log.Fatal(message)
}
|