main.go (6423B)
1 package main 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "os" 8 "path/filepath" 9 "regexp" 10 "strings" 11 12 "github.com/gohugoio/hugo/common/hexec" 13 14 "github.com/gohugoio/hugo/common/hugio" 15 16 "github.com/spf13/afero" 17 ) 18 19 func main() { 20 // The current is built with 41a82aa9c3 text/template/parse: allow space after continue or break 21 fmt.Println("Forking ...") 22 defer fmt.Println("Done ...") 23 24 cleanFork() 25 26 htmlRoot := filepath.Join(forkRoot, "htmltemplate") 27 28 for _, pkg := range goPackages { 29 copyGoPackage(pkg.dstPkg, pkg.srcPkg) 30 } 31 32 for _, pkg := range goPackages { 33 doWithGoFiles(pkg.dstPkg, pkg.rewriter, pkg.replacer) 34 } 35 36 goimports(htmlRoot) 37 gofmt(forkRoot) 38 } 39 40 const ( 41 // TODO(bep) 42 goSource = "/Users/bep/dev/go/misc/go/src" 43 forkRoot = "../../tpl/internal/go_templates" 44 ) 45 46 type goPackage struct { 47 srcPkg string 48 dstPkg string 49 replacer func(name, content string) string 50 rewriter func(name string) 51 } 52 53 var ( 54 textTemplateReplacers = strings.NewReplacer( 55 `"text/template/`, `"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/`, 56 `"internal/fmtsort"`, `"github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"`, 57 `"internal/testenv"`, `"github.com/gohugoio/hugo/tpl/internal/go_templates/testenv"`, 58 "TestLinkerGC", "_TestLinkerGC", 59 // Rename types and function that we want to overload. 60 "type state struct", "type stateOld struct", 61 "func (s *state) evalFunction", "func (s *state) evalFunctionOld", 62 "func (s *state) evalField(", "func (s *state) evalFieldOld(", 63 "func (s *state) evalCall(", "func (s *state) evalCallOld(", 64 "func isTrue(val reflect.Value) (truth, ok bool) {", "func isTrueOld(val reflect.Value) (truth, ok bool) {", 65 ) 66 67 testEnvReplacers = strings.NewReplacer( 68 `"internal/cfg"`, `"github.com/gohugoio/hugo/tpl/internal/go_templates/cfg"`, 69 ) 70 71 htmlTemplateReplacers = strings.NewReplacer( 72 `. "html/template"`, `. "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate"`, 73 `"html/template"`, `template "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate"`, 74 "\"text/template\"\n", "template \"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate\"\n", 75 `"html/template"`, `htmltemplate "html/template"`, 76 `"fmt"`, `htmltemplate "html/template"`, 77 `t.Skip("this test currently fails with -race; see issue #39807")`, `// t.Skip("this test currently fails with -race; see issue #39807")`, 78 ) 79 ) 80 81 func commonReplace(name, content string) string { 82 if strings.HasSuffix(name, "_test.go") { 83 content = strings.Replace(content, "package template\n", `// +build go1.13,!windows 84 85 package template 86 `, 1) 87 content = strings.Replace(content, "package template_test\n", `// +build go1.13 88 89 package template_test 90 `, 1) 91 92 content = strings.Replace(content, "package parse\n", `// +build go1.13 93 94 package parse 95 `, 1) 96 97 } 98 99 return content 100 } 101 102 var goPackages = []goPackage{ 103 { 104 srcPkg: "text/template", dstPkg: "texttemplate", 105 replacer: func(name, content string) string { return textTemplateReplacers.Replace(commonReplace(name, content)) }, 106 }, 107 { 108 srcPkg: "html/template", dstPkg: "htmltemplate", replacer: func(name, content string) string { 109 if strings.HasSuffix(name, "content.go") { 110 // Remove template.HTML types. We need to use the Go types. 111 content = removeAll(`(?s)// Strings of content.*?\)\n`, content) 112 } 113 114 content = commonReplace(name, content) 115 116 return htmlTemplateReplacers.Replace(content) 117 }, 118 rewriter: func(name string) { 119 for _, s := range []string{"CSS", "HTML", "HTMLAttr", "JS", "JSStr", "URL", "Srcset"} { 120 rewrite(name, fmt.Sprintf("%s -> htmltemplate.%s", s, s)) 121 } 122 rewrite(name, `"text/template/parse" -> "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"`) 123 }, 124 }, 125 {srcPkg: "internal/fmtsort", dstPkg: "fmtsort", rewriter: func(name string) { 126 rewrite(name, `"internal/fmtsort" -> "github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"`) 127 }}, 128 { 129 srcPkg: "internal/testenv", dstPkg: "testenv", 130 replacer: func(name, content string) string { return testEnvReplacers.Replace(content) }, rewriter: func(name string) { 131 rewrite(name, `"internal/testenv" -> "github.com/gohugoio/hugo/tpl/internal/go_templates/testenv"`) 132 }, 133 }, 134 {srcPkg: "internal/cfg", dstPkg: "cfg", rewriter: func(name string) { 135 rewrite(name, `"internal/cfg" -> "github.com/gohugoio/hugo/tpl/internal/go_templates/cfg"`) 136 }}, 137 } 138 139 var fs = afero.NewOsFs() 140 141 // Removes all non-Hugo files in the go_templates folder. 142 func cleanFork() { 143 must(filepath.Walk(filepath.Join(forkRoot), func(path string, info os.FileInfo, err error) error { 144 if !info.IsDir() && len(path) > 10 && !strings.Contains(path, "hugo") { 145 must(fs.Remove(path)) 146 } 147 return nil 148 })) 149 } 150 151 func must(err error, what ...string) { 152 if err != nil { 153 log.Fatal(what, " ERROR: ", err) 154 } 155 } 156 157 func copyGoPackage(dst, src string) { 158 from := filepath.Join(goSource, src) 159 to := filepath.Join(forkRoot, dst) 160 fmt.Println("Copy", from, "to", to) 161 must(hugio.CopyDir(fs, from, to, func(s string) bool { return true })) 162 } 163 164 func doWithGoFiles(dir string, 165 rewrite func(name string), 166 transform func(name, in string) string) { 167 if rewrite == nil && transform == nil { 168 return 169 } 170 must(filepath.Walk(filepath.Join(forkRoot, dir), func(path string, info os.FileInfo, err error) error { 171 if info.IsDir() { 172 return nil 173 } 174 175 if !strings.HasSuffix(path, ".go") || strings.Contains(path, "hugo_") { 176 return nil 177 } 178 179 fmt.Println("Handle", path) 180 181 if rewrite != nil { 182 rewrite(path) 183 } 184 185 if transform == nil { 186 return nil 187 } 188 189 data, err := ioutil.ReadFile(path) 190 must(err) 191 f, err := os.Create(path) 192 must(err) 193 defer f.Close() 194 _, err = f.WriteString(transform(path, string(data))) 195 must(err) 196 197 return nil 198 })) 199 } 200 201 func removeAll(expression, content string) string { 202 re := regexp.MustCompile(expression) 203 return re.ReplaceAllString(content, "") 204 } 205 206 func rewrite(filename, rule string) { 207 cmf, _ := hexec.SafeCommand("gofmt", "-w", "-r", rule, filename) 208 out, err := cmf.CombinedOutput() 209 if err != nil { 210 log.Fatal("gofmt failed:", string(out)) 211 } 212 } 213 214 func goimports(dir string) { 215 cmf, _ := hexec.SafeCommand("goimports", "-w", dir) 216 out, err := cmf.CombinedOutput() 217 if err != nil { 218 log.Fatal("goimports failed:", string(out)) 219 } 220 } 221 222 func gofmt(dir string) { 223 cmf, _ := hexec.SafeCommand("gofmt", "-w", dir) 224 out, err := cmf.CombinedOutput() 225 if err != nil { 226 log.Fatal("gofmt failed:", string(out)) 227 } 228 }