github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/timeutil/gen/main.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 // This binary takes the tzdata from Go's source and extracts all 12 // timezones names from them. From there, a mapping of lowercased 13 // timezone map to the tzdata names is generated into a file. 14 package main 15 16 import ( 17 "bufio" 18 "flag" 19 "fmt" 20 "io" 21 "log" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "runtime" 26 "sort" 27 "strings" 28 29 "github.com/cockroachdb/errors" 30 ) 31 32 const header = `// Code generated by pkg/util/timeutil/gen/main.go - DO NOT EDIT. 33 // 34 // Copyright 2020 The Cockroach Authors. 35 // 36 // Use of this software is governed by the Business Source License 37 // included in the file licenses/BSL.txt. 38 // 39 // As of the Change Date specified in that file, in accordance with 40 // the Business Source License, use of this software will be governed 41 // by the Apache License, Version 2.0, included in the file 42 // licenses/APL.txt. 43 44 package timeutil 45 46 var lowercaseTimezones = map[string]string{ 47 ` 48 49 func main() { 50 var filenameFlag = flag.String("filename", "lowercase_timezones_generated.go", "filename path") 51 var zoneInfoFlag = flag.String("zoneinfo", filepath.Join(runtime.GOROOT(), "lib", "time", "zoneinfo.zip"), "path to zoneinfo.zip") 52 var crlfmtFlag = flag.String("crlfmt", "crlfmt", "crlfmt binary to use") 53 flag.Parse() 54 55 zipdataFile, err := os.Open(*zoneInfoFlag) 56 if err != nil { 57 log.Fatalf("error loading zoneinfo.zip: %+v\n", err) 58 } 59 60 zipdata, err := io.ReadAll(zipdataFile) 61 if err != nil { 62 log.Fatalf("error reading all content from zoneinfo.zip: %+v\n", err) 63 } 64 65 if err := zipdataFile.Close(); err != nil { 66 log.Fatalf("error closing zoneinfo.zip: %+v\n", err) 67 } 68 69 zones, err := loadFromTZData(string(zipdata)) 70 if err != nil { 71 log.Fatalf("error parsing tzdata: %+v", err) 72 } 73 sort.Strings(zones) 74 75 of, err := os.Create(*filenameFlag) 76 if err != nil { 77 log.Fatalf("failed to create file: %+v", err) 78 } 79 80 buf := bufio.NewWriter(of) 81 _, err = buf.WriteString(header) 82 if err != nil { 83 log.Fatalf("failed to write header: %+v", err) 84 } 85 86 for _, zone := range zones { 87 fmt.Fprintf(buf, "\t`%s`: `%s`,\n", strings.ToLower(zone), zone) 88 } 89 fmt.Fprintf(buf, "}\n") 90 91 if err := buf.Flush(); err != nil { 92 log.Fatalf("error flushing buffer: %+v", err) 93 } 94 if err := of.Close(); err != nil { 95 log.Fatalf("error closing file: %+v", err) 96 } 97 if err := exec.Command(*crlfmtFlag, "-w", "-tab", "2", *filenameFlag).Run(); err != nil { 98 log.Fatalf("failed to run crlfmt: %+v", err) 99 } 100 } 101 102 // get4s returns the little-endian 32-bit value at the start of s. 103 func get4s(s string) int { 104 if len(s) < 4 { 105 return 0 106 } 107 return int(s[0]) | int(s[1])<<8 | int(s[2])<<16 | int(s[3])<<24 108 } 109 110 // get2s returns the little-endian 16-bit value at the start of s. 111 func get2s(s string) int { 112 if len(s) < 2 { 113 return 0 114 } 115 return int(s[0]) | int(s[1])<<8 116 } 117 118 // loadFromTZData loads all zone names from a tzdata zip. 119 func loadFromTZData(z string) ([]string, error) { 120 const ( 121 zecheader = 0x06054b50 122 zcheader = 0x02014b50 123 ztailsize = 22 124 ) 125 126 idx := len(z) - ztailsize 127 n := get2s(z[idx+10:]) 128 idx = get4s(z[idx+16:]) 129 130 var ret []string 131 for i := 0; i < n; i++ { 132 // See time.loadTzinfoFromZip for zip entry layout. 133 if get4s(z[idx:]) != zcheader { 134 break 135 } 136 meth := get2s(z[idx+10:]) 137 namelen := get2s(z[idx+28:]) 138 xlen := get2s(z[idx+30:]) 139 fclen := get2s(z[idx+32:]) 140 zname := z[idx+46 : idx+46+namelen] 141 idx += 46 + namelen + xlen + fclen 142 // Ignore directories. 143 if !strings.HasSuffix(zname, "/") { 144 ret = append(ret, zname) 145 } 146 if meth != 0 { 147 return nil, errors.Newf("unsupported compression for %s in embedded tzdata", zname) 148 } 149 } 150 151 return ret, nil 152 }