github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/text/internal/gen/gen.go (about) 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 // Package gen contains common code for the various code generation tools in the 6 // text repository. Its usage ensures consistency between tools. 7 // 8 // This package defines command line flags that are common to most generation 9 // tools. The flags allow for specifying specific Unicode and CLDR versions 10 // in the public Unicode data repository (http://www.unicode.org/Public). 11 // 12 // A local Unicode data mirror can be set through the flag -local or the 13 // environment variable UNICODE_DIR. The former takes precedence. The local 14 // directory should follow the same structure as the public repository. 15 // 16 // IANA data can also optionally be mirrored by putting it in the iana directory 17 // rooted at the top of the local mirror. Beware, though, that IANA data is not 18 // versioned. So it is up to the developer to use the right version. 19 package gen // import "golang.org/x/text/internal/gen" 20 21 import ( 22 "bytes" 23 "flag" 24 "fmt" 25 "go/format" 26 "io" 27 "io/ioutil" 28 "log" 29 "net/http" 30 "os" 31 "path" 32 "path/filepath" 33 "unicode" 34 35 "golang.org/x/text/unicode/cldr" 36 ) 37 38 var ( 39 url = flag.String("url", 40 "http://www.unicode.org/Public", 41 "URL of Unicode database directory") 42 iana = flag.String("iana", 43 "http://www.iana.org", 44 "URL of the IANA repository") 45 unicodeVersion = flag.String("unicode", 46 getEnv("UNICODE_VERSION", unicode.Version), 47 "unicode version to use") 48 cldrVersion = flag.String("cldr", 49 getEnv("CLDR_VERSION", cldr.Version), 50 "cldr version to use") 51 // Allow an environment variable to specify the local directory. 52 // go generate doesn't allow specifying arguments; this is a useful 53 // alternative to specifying a local mirror. 54 localDir = flag.String("local", 55 os.Getenv("UNICODE_DIR"), 56 "directory containing local data files; for debugging only.") 57 ) 58 59 func getEnv(name, def string) string { 60 if v := os.Getenv(name); v != "" { 61 return v 62 } 63 return def 64 } 65 66 // Init performs common initialization for a gen command. It parses the flags 67 // and sets up the standard logging parameters. 68 func Init() { 69 log.SetPrefix("") 70 log.SetFlags(log.Lshortfile) 71 flag.Parse() 72 } 73 74 const header = `// This file was generated by go generate; DO NOT EDIT 75 76 package %s 77 78 ` 79 80 // UnicodeVersion reports the requested Unicode version. 81 func UnicodeVersion() string { 82 return *unicodeVersion 83 } 84 85 // UnicodeVersion reports the requested CLDR version. 86 func CLDRVersion() string { 87 return *cldrVersion 88 } 89 90 // IsLocal reports whether the user specified a local directory. 91 func IsLocal() bool { 92 return *localDir != "" 93 } 94 95 // OpenUCDFile opens the requested UCD file. The file is specified relative to 96 // the public Unicode root directory. It will call log.Fatal if there are any 97 // errors. 98 func OpenUCDFile(file string) io.ReadCloser { 99 return openUnicode(path.Join(*unicodeVersion, "ucd", file)) 100 } 101 102 // OpenCLDRCoreZip opens the CLDR core zip file. It will call log.Fatal if there 103 // are any errors. 104 func OpenCLDRCoreZip() io.ReadCloser { 105 return OpenUnicodeFile("cldr", *cldrVersion, "core.zip") 106 } 107 108 // OpenUnicodeFile opens the requested file of the requested category from the 109 // root of the Unicode data archive. The file is specified relative to the 110 // public Unicode root directory. If version is "", it will use the default 111 // Unicode version. It will call log.Fatal if there are any errors. 112 func OpenUnicodeFile(category, version, file string) io.ReadCloser { 113 if version == "" { 114 version = UnicodeVersion() 115 } 116 return openUnicode(path.Join(category, version, file)) 117 } 118 119 // OpenIANAFile opens the requested IANA file. The file is specified relative 120 // to the IANA root, which is typically either http://www.iana.org or the 121 // iana directory in the local mirror. It will call log.Fatal if there are any 122 // errors. 123 func OpenIANAFile(path string) io.ReadCloser { 124 return Open(*iana, "iana", path) 125 } 126 127 // Open opens subdir/path if a local directory is specified and the file exists, 128 // where subdir is a directory relative to the local root, or fetches it from 129 // urlRoot/path otherwise. It will call log.Fatal if there are any errors. 130 func Open(urlRoot, subdir, path string) io.ReadCloser { 131 if *localDir != "" { 132 path = filepath.FromSlash(path) 133 if f, err := os.Open(filepath.Join(*localDir, subdir, path)); err == nil { 134 return f 135 } 136 } 137 return get(urlRoot, path) 138 } 139 140 func openUnicode(path string) io.ReadCloser { 141 if *localDir != "" { 142 path = filepath.FromSlash(path) 143 f, err := os.Open(filepath.Join(*localDir, path)) 144 if err != nil { 145 log.Fatal(err) 146 } 147 return f 148 } 149 return get(*url, path) 150 } 151 152 func get(root, path string) io.ReadCloser { 153 url := root + "/" + path 154 fmt.Printf("Fetching %s...", url) 155 defer fmt.Println(" done.") 156 resp, err := http.Get(url) 157 if err != nil { 158 log.Fatalf("HTTP GET: %v", err) 159 } 160 if resp.StatusCode != 200 { 161 log.Fatalf("Bad GET status for %q: %q", url, resp.Status) 162 } 163 return resp.Body 164 } 165 166 // TODO: use Write*Version in all applicable packages. 167 168 // WriteUnicodeVersion writes a constant for the Unicode version from which the 169 // tables are generated. 170 func WriteUnicodeVersion(w io.Writer) { 171 fmt.Fprintf(w, "// UnicodeVersion is the Unicode version from which the tables in this package are derived.\n") 172 fmt.Fprintf(w, "const UnicodeVersion = %q\n\n", UnicodeVersion()) 173 } 174 175 // WriteCLDRVersion writes a constant for the CLDR version from which the 176 // tables are generated. 177 func WriteCLDRVersion(w io.Writer) { 178 fmt.Fprintf(w, "// CLDRVersion is the CLDR version from which the tables in this package are derived.\n") 179 fmt.Fprintf(w, "const CLDRVersion = %q\n\n", CLDRVersion()) 180 } 181 182 // WriteGoFile prepends a standard file comment and package statement to the 183 // given bytes, applies gofmt, and writes them to a file with the given name. 184 // It will call log.Fatal if there are any errors. 185 func WriteGoFile(filename, pkg string, b []byte) { 186 w, err := os.Create(filename) 187 if err != nil { 188 log.Fatalf("Could not create file %s: %v", filename, err) 189 } 190 defer w.Close() 191 if _, err = WriteGo(w, pkg, b); err != nil { 192 log.Fatalf("Error writing file %s: %v", filename, err) 193 } 194 } 195 196 // WriteGo prepends a standard file comment and package statement to the given 197 // bytes, applies gofmt, and writes them to w. 198 func WriteGo(w io.Writer, pkg string, b []byte) (n int, err error) { 199 src := []byte(fmt.Sprintf(header, pkg)) 200 src = append(src, b...) 201 formatted, err := format.Source(src) 202 if err != nil { 203 // Print the generated code even in case of an error so that the 204 // returned error can be meaningfully interpreted. 205 n, _ = w.Write(src) 206 return n, err 207 } 208 return w.Write(formatted) 209 } 210 211 // Repackage rewrites a Go file from belonging to package main to belonging to 212 // the given package. 213 func Repackage(inFile, outFile, pkg string) { 214 src, err := ioutil.ReadFile(inFile) 215 if err != nil { 216 log.Fatalf("reading %s: %v", inFile, err) 217 } 218 const toDelete = "package main\n\n" 219 i := bytes.Index(src, []byte(toDelete)) 220 if i < 0 { 221 log.Fatalf("Could not find %q in %s.", toDelete, inFile) 222 } 223 w := &bytes.Buffer{} 224 w.Write(src[i+len(toDelete):]) 225 WriteGoFile(outFile, pkg, w.Bytes()) 226 }