gitea源码

generate.go 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package main
  4. import (
  5. "bytes"
  6. "flag"
  7. "fmt"
  8. "go/format"
  9. "os"
  10. "sort"
  11. "text/template"
  12. "unicode"
  13. "code.gitea.io/gitea/modules/json"
  14. "golang.org/x/text/unicode/rangetable"
  15. )
  16. // ambiguous.json provides a one to one mapping of ambiguous characters to other characters
  17. // See https://github.com/hediet/vscode-unicode-data/blob/main/out/ambiguous.json
  18. type AmbiguousTable struct {
  19. Confusable []rune
  20. With []rune
  21. Locale string
  22. RangeTable *unicode.RangeTable
  23. }
  24. type RunePair struct {
  25. Confusable rune
  26. With rune
  27. }
  28. var verbose bool
  29. func main() {
  30. flag.Usage = func() {
  31. fmt.Fprintf(os.Stderr, `%s: Generate AmbiguousCharacter
  32. Usage: %[1]s [-v] [-o output.go] ambiguous.json
  33. `, os.Args[0])
  34. flag.PrintDefaults()
  35. }
  36. output := ""
  37. flag.BoolVar(&verbose, "v", false, "verbose output")
  38. flag.StringVar(&output, "o", "ambiguous_gen.go", "file to output to")
  39. flag.Parse()
  40. input := flag.Arg(0)
  41. if input == "" {
  42. input = "ambiguous.json"
  43. }
  44. bs, err := os.ReadFile(input)
  45. if err != nil {
  46. fatalf("Unable to read: %s Err: %v", input, err)
  47. }
  48. var unwrapped string
  49. if err := json.Unmarshal(bs, &unwrapped); err != nil {
  50. fatalf("Unable to unwrap content in: %s Err: %v", input, err)
  51. }
  52. fromJSON := map[string][]uint32{}
  53. if err := json.Unmarshal([]byte(unwrapped), &fromJSON); err != nil {
  54. fatalf("Unable to unmarshal content in: %s Err: %v", input, err)
  55. }
  56. tables := make([]*AmbiguousTable, 0, len(fromJSON))
  57. for locale, chars := range fromJSON {
  58. table := &AmbiguousTable{Locale: locale}
  59. table.Confusable = make([]rune, 0, len(chars)/2)
  60. table.With = make([]rune, 0, len(chars)/2)
  61. pairs := make([]RunePair, len(chars)/2)
  62. for i := 0; i < len(chars); i += 2 {
  63. pairs[i/2].Confusable, pairs[i/2].With = rune(chars[i]), rune(chars[i+1])
  64. }
  65. sort.Slice(pairs, func(i, j int) bool {
  66. return pairs[i].Confusable < pairs[j].Confusable
  67. })
  68. for _, pair := range pairs {
  69. table.Confusable = append(table.Confusable, pair.Confusable)
  70. table.With = append(table.With, pair.With)
  71. }
  72. table.RangeTable = rangetable.New(table.Confusable...)
  73. tables = append(tables, table)
  74. }
  75. sort.Slice(tables, func(i, j int) bool {
  76. return tables[i].Locale < tables[j].Locale
  77. })
  78. data := map[string]any{
  79. "Tables": tables,
  80. }
  81. if err := runTemplate(generatorTemplate, output, &data); err != nil {
  82. fatalf("Unable to run template: %v", err)
  83. }
  84. }
  85. func runTemplate(t *template.Template, filename string, data any) error {
  86. buf := bytes.NewBuffer(nil)
  87. if err := t.Execute(buf, data); err != nil {
  88. return fmt.Errorf("unable to execute template: %w", err)
  89. }
  90. bs, err := format.Source(buf.Bytes())
  91. if err != nil {
  92. verbosef("Bad source:\n%s", buf.String())
  93. return fmt.Errorf("unable to format source: %w", err)
  94. }
  95. old, err := os.ReadFile(filename)
  96. if err != nil && !os.IsNotExist(err) {
  97. return fmt.Errorf("failed to read old file %s because %w", filename, err)
  98. } else if err == nil {
  99. if bytes.Equal(bs, old) {
  100. // files are the same don't rewrite it.
  101. return nil
  102. }
  103. }
  104. file, err := os.Create(filename)
  105. if err != nil {
  106. return fmt.Errorf("failed to create file %s because %w", filename, err)
  107. }
  108. defer file.Close()
  109. _, err = file.Write(bs)
  110. if err != nil {
  111. return fmt.Errorf("unable to write generated source: %w", err)
  112. }
  113. return nil
  114. }
  115. var generatorTemplate = template.Must(template.New("ambiguousTemplate").Parse(`// This file is generated by modules/charset/ambiguous/generate.go DO NOT EDIT
  116. // Copyright 2022 The Gitea Authors. All rights reserved.
  117. // SPDX-License-Identifier: MIT
  118. package charset
  119. import "unicode"
  120. // This file is generated from https://github.com/hediet/vscode-unicode-data/blob/main/out/ambiguous.json
  121. // AmbiguousTable matches a confusable rune with its partner for the Locale
  122. type AmbiguousTable struct {
  123. Confusable []rune
  124. With []rune
  125. Locale string
  126. RangeTable *unicode.RangeTable
  127. }
  128. // AmbiguousCharacters provides a map by locale name to the confusable characters in that locale
  129. var AmbiguousCharacters = map[string]*AmbiguousTable{
  130. {{range .Tables}}{{printf "%q:" .Locale}} {
  131. Confusable: []rune{ {{range .Confusable}}{{.}},{{end}} },
  132. With: []rune{ {{range .With}}{{.}},{{end}} },
  133. Locale: {{printf "%q" .Locale}},
  134. RangeTable: &unicode.RangeTable{
  135. R16: []unicode.Range16{
  136. {{range .RangeTable.R16 }} {Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}},
  137. {{end}} },
  138. R32: []unicode.Range32{
  139. {{range .RangeTable.R32}} {Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}},
  140. {{end}} },
  141. LatinOffset: {{.RangeTable.LatinOffset}},
  142. },
  143. },
  144. {{end}}
  145. }
  146. `))
  147. func logf(format string, args ...any) {
  148. fmt.Fprintf(os.Stderr, format+"\n", args...)
  149. }
  150. func verbosef(format string, args ...any) {
  151. if verbose {
  152. logf(format, args...)
  153. }
  154. }
  155. func fatalf(format string, args ...any) {
  156. logf("fatal: "+format+"\n", args...)
  157. os.Exit(1)
  158. }