Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/define target lang for generate #257

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8786cc4
refactor: move generation logic to own file and pass FS interface
tauraamui Jun 22, 2023
03f2df5
define FS interface
tauraamui Jun 22, 2023
46e3a58
tests: implement working mock FS to use for further testing
tauraamui Jun 22, 2023
11be66a
deps: update dependancies
tauraamui Jun 22, 2023
f0de0f5
fix: correct logic for mock FS, and remove unneeded pre-create of file
tauraamui Jun 22, 2023
2a19731
dep inject HTTP getter func to remove requirement for live endpoint f…
tauraamui Jun 22, 2023
1ffd768
tests: define basic assertion case for e2e existing functionality
tauraamui Jun 22, 2023
7f03589
tests: slim down static http get response bodies
tauraamui Jun 22, 2023
9cc3bb6
tests: ensure generated language dir and Go src file were created suc…
tauraamui Jun 22, 2023
c78f94c
tests: make usage of fake filesystem more clear
tauraamui Jun 22, 2023
137ced4
tests: explicitly check to ensure directory was created as directory
tauraamui Jun 22, 2023
ce7dceb
tests: define own endpoints for v1.19.14 MC language fetching
tauraamui Jun 22, 2023
fc3f7ef
feat: use flags package to pass in EN US file path
tauraamui Jun 23, 2023
ee2369e
tests: ensure that correct/expected version is fetched
tauraamui Jun 23, 2023
9cbe09d
tests: add explaination comment
tauraamui Jun 23, 2023
a2124f2
feat: download given version
tauraamui Jun 23, 2023
d1b6e3e
tests: ensure that given version is downloaded
tauraamui Jun 23, 2023
961222a
re-include generate build tags
tauraamui Jun 23, 2023
968348d
fix: include generate exclusion tag to entry point
tauraamui Jun 26, 2023
f9ff286
fix comment for assertion in test
tauraamui Jun 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 15 additions & 190 deletions data/lang/gen_lang.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,216 +5,41 @@
package main

import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
stdos "os"
"path/filepath"
"regexp"
"strings"
"sync"
"text/template"
)

// language=gohtml
var langTmpl = `// Code generated by downloader.go; DO NOT EDIT.

package {{.Name}}
{{if ne .Name "en_us"}}
import "github.com/Tnze/go-mc/chat"

func init() { chat.SetLanguage(Map) }
{{end}}
var Map = {{.LangMap | printf "%#v"}}
`
"github.com/hack-pad/hackpadfs/os"
)

//go:generate go run $GOFILE
//go:generate go fmt ./...
func main() {
if len(os.Args) == 2 {
fmt.Println("generating en-us lang")
f, err := os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer f.Close()
readLang("en_us", f)
return
} else {
fmt.Println("generating langs except en-us")
fmt.Println("WARN: You should also set the secondary argument to en-us's json file")
}

versionURL, err := assetIndexURL()
if err != nil {
panic(err)
}

resp, err := http.Get(versionURL)
if err != nil {
panic(err)
}
defer resp.Body.Close()

var list struct {
Objects map[string]struct {
Hash string `json:"hash"`
Size int64 `json:"size"`
} `json:"objects"`
}

err = json.NewDecoder(resp.Body).Decode(&list)
if err != nil {
panic(err)
}

tasks := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 16; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for i := range tasks {
v := list.Objects[i]
if strings.HasPrefix(i, "minecraft/lang/") {
name := i[len("minecraft/lang/") : len(i)-len(".json")]
lang(name, v.Hash)
}
}
}()
}
for i := range list.Objects {
tasks <- i
}
close(tasks)
wg.Wait()
}

func lang(name, hash string) {
// download language
LangURL := "https://resources.download.minecraft.net/" + hash[:2] + "/" + hash
fmt.Println(name, ":", LangURL)
resp, err := http.Get(LangURL)
if err != nil {
panic(err)
}
defer resp.Body.Close()
readLang(name, resp.Body)
}

// read one language translation
func readLang(name string, r io.Reader) {
var LangMap map[string]string
err := json.NewDecoder(r).Decode(&LangMap)
if err != nil {
panic(err)
}
trans(LangMap)

pName := strings.ReplaceAll(name, "_", "-")

// mkdir
err = os.Mkdir(pName, 0o777)
if err != nil && !os.IsExist(err) {
panic(err)
}

f, err := os.OpenFile(filepath.Join(pName, name+".go"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0o666)
fsys, err := resolveFS(string(filepath.Separator))
if err != nil {
panic(err)
}
defer f.Close()

genData := struct {
PkgName string
Name string
LangMap map[string]string
}{
PkgName: pName,
Name: name,
LangMap: LangMap,
}

tmpl := template.Must(template.New("").Parse(langTmpl))
if err := tmpl.Execute(f, genData); err != nil {
panic(err)
}
run(fsys, http.Get, stdos.Args)
}

var javaN = regexp.MustCompile(`%[0-9]\$s`)

// Java use %2$s to refer to the second arg, but Golang use %2s, so we need this
func trans(m map[string]string) {
// replace "%[0-9]\$s" with "%[0-9]s"
for i := range m {
c := m[i]
if javaN.MatchString(c) {
m[i] = javaN.ReplaceAllStringFunc(c, func(s string) string {
var index int
_, err := fmt.Sscanf(s, "%%%d$s", &index)
if err != nil {
panic(err)
}
return fmt.Sprintf("%%[%d]s", index)
})
}
}
}
func resolveFS(base string) (*os.FS, error) {
fs := os.NewFS()

func assetIndexURL() (string, error) {
// Pseudo code for get versionURL:
// $manifest = {https://piston-meta.mojang.com/mc/game/version_manifest_v2.json}
// $latest = $manifest.latest.release
// $versionURL = {$manifest.versions[where .id == $latest ].url}
// $assetIndexURL = $version.assetIndex.url
var manifest struct {
Latest struct {
Release string `json:"release"`
} `json:"latest"`
Versions []struct {
ID string `json:"id"`
URL string `json:"url"`
} `json:"versions"`
}

manifestRes, err := http.Get("https://piston-meta.mojang.com/mc/game/version_manifest_v2.json")
baseDirectory, err := fs.FromOSPath(base) // Convert to an FS path
if err != nil {
return "", fmt.Errorf("could not reach version manifest: %w", err)
}
defer manifestRes.Body.Close()

if err := json.NewDecoder(manifestRes.Body).Decode(&manifest); err != nil {
return "", fmt.Errorf("could not decode manifest JSON: %w", err)
}

var versionURL string
for _, v := range manifest.Versions {
if manifest.Latest.Release == v.ID {
versionURL = v.URL
break
}
}
if versionURL == "" {
return "", errors.New("could not determine versionURL")
}

var version struct {
AssetIndex struct {
URL string `json:"url"`
} `json:"assetIndex"`
return nil, err
}

versionRes, err := http.Get(versionURL)
baseDirFS, err := fs.Sub(baseDirectory) // Run all file system operations rooted at the current working directory
if err != nil {
return "", fmt.Errorf("could not reach versionURL: %w", err)
return nil, err
}
defer versionRes.Body.Close()

if err := json.NewDecoder(versionRes.Body).Decode(&version); err != nil {
return "", fmt.Errorf("could not decode version JSON: %w", err)
ofs, ok := baseDirFS.(*os.FS)
if !ok {
return nil, errors.New("sub FS not an OS instance FS")
}

return version.AssetIndex.URL, nil
return ofs, nil
}
Loading