text/gen.go

223 строки
6.0 KiB
Go
Исходник Обычный вид История

// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// gen runs go generate on Unicode- and CLDR-related package in the text
// repositories, taking into account dependencies and versions.
package main
import (
"bytes"
"flag"
"fmt"
"go/build"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"sync"
"unicode"
"golang.org/x/text/internal/gen"
)
var (
verbose = flag.Bool("v", false, "verbose output")
force = flag.Bool("force", false, "ignore failing dependencies")
doCore = flag.Bool("core", false, "force an update to core")
excludeList = flag.String("exclude", "",
"comma-separated list of packages to exclude")
// The user can specify a selection of packages to build on the command line.
args []string
)
func exclude(pkg string) bool {
if len(args) > 0 {
return !contains(args, pkg)
}
return contains(strings.Split(*excludeList, ","), pkg)
}
// TODO:
// - Better version handling.
// - Generate tables for the core unicode package?
// - Add generation for encodings. This requires some retooling here and there.
// - Running repo-wide "long" tests.
var vprintf = fmt.Printf
func main() {
gen.Init()
args = flag.Args()
if !*verbose {
// Set vprintf to a no-op.
vprintf = func(string, ...interface{}) (int, error) { return 0, nil }
}
// TODO: create temporary cache directory to load files and create and set
// a "cache" option if the user did not specify the UNICODE_DIR environment
// variable. This will prevent duplicate downloads and also will enable long
// tests, which really need to be run after each generated package.
updateCore := *doCore
if gen.UnicodeVersion() != unicode.Version {
fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n",
gen.UnicodeVersion(),
unicode.Version)
// TODO: use collate to compare. Simple comparison will work, though,
// until Unicode reaches version 10. To avoid circular dependencies, we
// could use the NumericWeighter without using package collate using a
// trivial Weighter implementation.
if gen.UnicodeVersion() < unicode.Version && !*force {
os.Exit(2)
}
updateCore = true
}
var unicode = &dependency{}
if updateCore {
fmt.Printf("Updating core to version %s...\n", gen.UnicodeVersion())
unicode = generate("unicode")
// Test some users of the unicode packages, especially the ones that
// keep a mirrored table. These may need to be corrected by hand.
generate("regexp", unicode)
generate("strconv", unicode) // mimics Unicode table
generate("strings", unicode)
generate("testing", unicode) // mimics Unicode table
}
var (
cldr = generate("./unicode/cldr", unicode)
language = generate("./language", cldr)
internal = generate("./internal", unicode, language)
norm = generate("./unicode/norm", unicode)
rangetable = generate("./unicode/rangetable", unicode)
cases = generate("./cases", unicode, norm, language, rangetable)
width = generate("./width", unicode)
bidi = generate("./unicode/bidi", unicode, norm, rangetable)
_ = generate("./secure/precis", unicode, norm, rangetable, cases, width, bidi)
_ = generate("./encoding/htmlindex", unicode, language)
_ = generate("./currency", unicode, cldr, language, internal)
_ = generate("./internal/number", unicode, cldr, language, internal)
_ = generate("./language/display", unicode, cldr, language, internal)
_ = generate("./collate", unicode, norm, cldr, language, rangetable)
_ = generate("./search", unicode, norm, cldr, language, rangetable)
)
if updateCore {
copyVendored()
generate("vendor/golang_org/x/net/idna", unicode, norm, width, cases)
}
all.Wait()
if hasErrors {
fmt.Println("FAIL")
os.Exit(1)
}
vprintf("SUCCESS\n")
}
var (
all sync.WaitGroup
hasErrors bool
)
type dependency struct {
sync.WaitGroup
hasErrors bool
}
func generate(pkg string, deps ...*dependency) *dependency {
var wg dependency
if exclude(pkg) {
return &wg
}
wg.Add(1)
all.Add(1)
go func() {
defer wg.Done()
defer all.Done()
// Wait for dependencies to finish.
for _, d := range deps {
d.Wait()
if d.hasErrors && !*force {
fmt.Printf("--- ABORT: %s\n", pkg)
wg.hasErrors = true
return
}
}
vprintf("=== GENERATE %s\n", pkg)
args := []string{"generate"}
if *verbose {
args = append(args, "-v")
}
args = append(args, pkg)
cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
w := &bytes.Buffer{}
cmd.Stderr = w
cmd.Stdout = w
if err := cmd.Run(); err != nil {
fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(w), err)
hasErrors = true
wg.hasErrors = true
return
}
vprintf("=== TEST %s\n", pkg)
args[0] = "test"
cmd = exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
wt := &bytes.Buffer{}
cmd.Stderr = wt
cmd.Stdout = wt
if err := cmd.Run(); err != nil {
fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(wt), err)
hasErrors = true
wg.hasErrors = true
return
}
vprintf("--- SUCCESS: %s\n\t%v\n", pkg, indent(w))
fmt.Print(wt.String())
}()
return &wg
}
func copyVendored() {
// Copy the vendored files. Some more may need to be copied in by hand.
dir := filepath.Join(build.Default.GOROOT, "src/vendor/golang_org/x/text")
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
b, err := ioutil.ReadFile(path[len(dir)+1:])
if err != nil {
return err
}
vprintf("=== COPY %s\n", path)
b = bytes.Replace(b, []byte("golang.org"), []byte("golang_org"), -1)
return ioutil.WriteFile(path, b, 0666)
})
if err != nil {
fmt.Println("Copying vendored files failed:", err)
os.Exit(1)
}
}
func contains(a []string, s string) bool {
for _, e := range a {
if s == e {
return true
}
}
return false
}
func indent(b *bytes.Buffer) string {
return strings.Replace(strings.TrimSpace(b.String()), "\n", "\n\t", -1)
}