OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / gen.go
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // +build ignore
6
7 // gen runs go generate on Unicode- and CLDR-related package in the text
8 // repositories, taking into account dependencies and versions.
9 package main
10
11 import (
12         "bytes"
13         "flag"
14         "fmt"
15         "go/build"
16         "go/format"
17         "io/ioutil"
18         "os"
19         "os/exec"
20         "path"
21         "path/filepath"
22         "regexp"
23         "runtime"
24         "strings"
25         "sync"
26         "unicode"
27
28         "golang.org/x/text/internal/gen"
29 )
30
31 var (
32         verbose     = flag.Bool("v", false, "verbose output")
33         force       = flag.Bool("force", false, "ignore failing dependencies")
34         doCore      = flag.Bool("core", false, "force an update to core")
35         excludeList = flag.String("exclude", "",
36                 "comma-separated list of packages to exclude")
37
38         // The user can specify a selection of packages to build on the command line.
39         args []string
40 )
41
42 func exclude(pkg string) bool {
43         if len(args) > 0 {
44                 return !contains(args, pkg)
45         }
46         return contains(strings.Split(*excludeList, ","), pkg)
47 }
48
49 // TODO:
50 // - Better version handling.
51 // - Generate tables for the core unicode package?
52 // - Add generation for encodings. This requires some retooling here and there.
53 // - Running repo-wide "long" tests.
54
55 var vprintf = fmt.Printf
56
57 func main() {
58         gen.Init()
59         args = flag.Args()
60         if !*verbose {
61                 // Set vprintf to a no-op.
62                 vprintf = func(string, ...interface{}) (int, error) { return 0, nil }
63         }
64
65         // TODO: create temporary cache directory to load files and create and set
66         // a "cache" option if the user did not specify the UNICODE_DIR environment
67         // variable. This will prevent duplicate downloads and also will enable long
68         // tests, which really need to be run after each generated package.
69
70         updateCore := *doCore
71         if gen.UnicodeVersion() != unicode.Version {
72                 fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n",
73                         gen.UnicodeVersion(),
74                         unicode.Version)
75                 // TODO: use collate to compare. Simple comparison will work, though,
76                 // until Unicode reaches version 10. To avoid circular dependencies, we
77                 // could use the NumericWeighter without using package collate using a
78                 // trivial Weighter implementation.
79                 if gen.UnicodeVersion() < unicode.Version && !*force {
80                         os.Exit(2)
81                 }
82                 updateCore = true
83         }
84
85         var unicode = &dependency{}
86         if updateCore {
87                 fmt.Printf("Updating core to version %s...\n", gen.UnicodeVersion())
88                 unicode = generate("unicode")
89
90                 // Test some users of the unicode packages, especially the ones that
91                 // keep a mirrored table. These may need to be corrected by hand.
92                 generate("regexp", unicode)
93                 generate("strconv", unicode) // mimics Unicode table
94                 generate("strings", unicode)
95                 generate("testing", unicode) // mimics Unicode table
96         }
97
98         var (
99                 cldr       = generate("./unicode/cldr", unicode)
100                 language   = generate("./language", cldr)
101                 internal   = generate("./internal", unicode, language)
102                 norm       = generate("./unicode/norm", unicode)
103                 rangetable = generate("./unicode/rangetable", unicode)
104                 cases      = generate("./cases", unicode, norm, language, rangetable)
105                 width      = generate("./width", unicode)
106                 bidi       = generate("./unicode/bidi", unicode, norm, rangetable)
107                 mib        = generate("./encoding/internal/identifier", unicode)
108                 _          = generate("./encoding/htmlindex", unicode, language, mib)
109                 _          = generate("./encoding/ianaindex", unicode, language, mib)
110                 _          = generate("./secure/precis", unicode, norm, rangetable, cases, width, bidi)
111                 _          = generate("./currency", unicode, cldr, language, internal)
112                 _          = generate("./internal/number", unicode, cldr, language, internal)
113                 _          = generate("./feature/plural", unicode, cldr, language, internal)
114                 _          = generate("./internal/export/idna", unicode, bidi, norm)
115                 _          = generate("./language/display", unicode, cldr, language, internal)
116                 _          = generate("./collate", unicode, norm, cldr, language, rangetable)
117                 _          = generate("./search", unicode, norm, cldr, language, rangetable)
118         )
119         all.Wait()
120
121         // Copy exported packages to the destination golang.org repo.
122         copyExported("golang.org/x/net/idna")
123
124         if updateCore {
125                 copyVendored()
126         }
127
128         if hasErrors {
129                 fmt.Println("FAIL")
130                 os.Exit(1)
131         }
132         vprintf("SUCCESS\n")
133 }
134
135 var (
136         all       sync.WaitGroup
137         hasErrors bool
138 )
139
140 type dependency struct {
141         sync.WaitGroup
142         hasErrors bool
143 }
144
145 func generate(pkg string, deps ...*dependency) *dependency {
146         var wg dependency
147         if exclude(pkg) {
148                 return &wg
149         }
150         wg.Add(1)
151         all.Add(1)
152         go func() {
153                 defer wg.Done()
154                 defer all.Done()
155                 // Wait for dependencies to finish.
156                 for _, d := range deps {
157                         d.Wait()
158                         if d.hasErrors && !*force {
159                                 fmt.Printf("--- ABORT: %s\n", pkg)
160                                 wg.hasErrors = true
161                                 return
162                         }
163                 }
164                 vprintf("=== GENERATE %s\n", pkg)
165                 args := []string{"generate"}
166                 if *verbose {
167                         args = append(args, "-v")
168                 }
169                 args = append(args, pkg)
170                 cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
171                 w := &bytes.Buffer{}
172                 cmd.Stderr = w
173                 cmd.Stdout = w
174                 if err := cmd.Run(); err != nil {
175                         fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(w), err)
176                         hasErrors = true
177                         wg.hasErrors = true
178                         return
179                 }
180
181                 vprintf("=== TEST %s\n", pkg)
182                 args[0] = "test"
183                 cmd = exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
184                 wt := &bytes.Buffer{}
185                 cmd.Stderr = wt
186                 cmd.Stdout = wt
187                 if err := cmd.Run(); err != nil {
188                         fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(wt), err)
189                         hasErrors = true
190                         wg.hasErrors = true
191                         return
192                 }
193                 vprintf("--- SUCCESS: %s\n\t%v\n", pkg, indent(w))
194                 fmt.Print(wt.String())
195         }()
196         return &wg
197 }
198
199 // copyExported copies a package in x/text/internal/export to the
200 // destination repository.
201 func copyExported(p string) {
202         copyPackage(
203                 filepath.Join("internal", "export", path.Base(p)),
204                 filepath.Join("..", filepath.FromSlash(p[len("golang.org/x"):])),
205                 "golang.org/x/text/internal/export/"+path.Base(p),
206                 p)
207 }
208
209 // copyVendored copies packages used by Go core into the vendored directory.
210 func copyVendored() {
211         root := filepath.Join(build.Default.GOROOT, filepath.FromSlash("src/vendor/golang_org/x"))
212
213         err := filepath.Walk(root, func(dir string, info os.FileInfo, err error) error {
214                 if err != nil || !info.IsDir() || root == dir {
215                         return err
216                 }
217                 src := dir[len(root)+1:]
218                 const slash = string(filepath.Separator)
219                 if c := strings.Split(src, slash); c[0] == "text" {
220                         // Copy a text repo package from its normal location.
221                         src = strings.Join(c[1:], slash)
222                 } else {
223                         // Copy the vendored package if it exists in the export directory.
224                         src = filepath.Join("internal", "export", filepath.Base(src))
225                 }
226                 copyPackage(src, dir, "golang.org", "golang_org")
227                 return nil
228         })
229         if err != nil {
230                 fmt.Printf("Seeding directory %s has failed %v:", root, err)
231                 os.Exit(1)
232         }
233 }
234
235 // goGenRE is used to remove go:generate lines.
236 var goGenRE = regexp.MustCompile("//go:generate[^\n]*\n")
237
238 // copyPackage copies relevant files from a directory in x/text to the
239 // destination package directory. The destination package is assumed to have
240 // the same name. For each copied file go:generate lines are removed and
241 // and package comments are rewritten to the new path.
242 func copyPackage(dirSrc, dirDst, search, replace string) {
243         err := filepath.Walk(dirSrc, func(file string, info os.FileInfo, err error) error {
244                 base := filepath.Base(file)
245                 if err != nil || info.IsDir() ||
246                         !strings.HasSuffix(base, ".go") ||
247                         strings.HasSuffix(base, "_test.go") && !strings.HasPrefix(base, "example") ||
248                         // Don't process subdirectories.
249                         filepath.Dir(file) != dirSrc {
250                         return nil
251                 }
252                 b, err := ioutil.ReadFile(file)
253                 if err != nil || bytes.Contains(b, []byte("\n// +build ignore")) {
254                         return err
255                 }
256                 // Fix paths.
257                 b = bytes.Replace(b, []byte(search), []byte(replace), -1)
258                 // Remove go:generate lines.
259                 b = goGenRE.ReplaceAllLiteral(b, nil)
260                 comment := "// Code generated by running \"go generate\" in golang.org/x/text. DO NOT EDIT.\n\n"
261                 if *doCore {
262                         comment = "// Code generated by running \"go run gen.go -core\" in golang.org/x/text. DO NOT EDIT.\n\n"
263                 }
264                 if !bytes.HasPrefix(b, []byte(comment)) {
265                         b = append([]byte(comment), b...)
266                 }
267                 if b, err = format.Source(b); err != nil {
268                         fmt.Println("Failed to format file:", err)
269                         os.Exit(1)
270                 }
271                 file = filepath.Join(dirDst, base)
272                 vprintf("=== COPY %s\n", file)
273                 return ioutil.WriteFile(file, b, 0666)
274         })
275         if err != nil {
276                 fmt.Println("Copying exported files failed:", err)
277                 os.Exit(1)
278         }
279 }
280
281 func contains(a []string, s string) bool {
282         for _, e := range a {
283                 if s == e {
284                         return true
285                 }
286         }
287         return false
288 }
289
290 func indent(b *bytes.Buffer) string {
291         return strings.Replace(strings.TrimSpace(b.String()), "\n", "\n\t", -1)
292 }