ooni-probe-cli/internal/errorsx/generator/main.go

176 lines
4.1 KiB
Go
Raw Normal View History

package main
import (
"fmt"
"log"
"os"
"time"
"golang.org/x/sys/execabs"
)
// ErrorSpec specifies the error we care about.
type ErrorSpec struct {
// Errno is the error name as an errno value (e.g., ECONNREFUSED).
Errno string
// Failure is the error name according to OONI (e.g., FailureConnectionRefused).
Failure string
}
// TODO(kelmenhorst): find out if we need more system errors here. Currently
// the code does not generate any mapping if Failure is empty.
// Specs contains all the error specs.
var Specs = []ErrorSpec{{
Errno: "ECANCELED",
Failure: "Interrupted",
}, {
Errno: "ECONNREFUSED",
Failure: "ConnectionRefused",
}, {
Errno: "ECONNRESET",
Failure: "ConnectionReset",
}, {
Errno: "EHOSTUNREACH",
Failure: "HostUnreachable",
}, {
Errno: "ETIMEDOUT",
Failure: "GenericTimeoutError",
}, {
Errno: "EAFNOSUPPORT",
}, {
Errno: "EADDRINUSE",
}, {
Errno: "EADDRNOTAVAIL",
}, {
Errno: "EISCONN",
}, {
Errno: "EFAULT",
}, {
Errno: "EBADF",
}, {
Errno: "ECONNABORTED",
}, {
Errno: "EALREADY",
}, {
Errno: "EDESTADDRREQ",
}, {
Errno: "EINTR",
}, {
Errno: "EINVAL",
}, {
Errno: "EMSGSIZE",
}, {
Errno: "ENETDOWN",
}, {
Errno: "ENETRESET",
}, {
Errno: "ENETUNREACH",
}, {
Errno: "ENOBUFS",
}, {
Errno: "ENOPROTOOPT",
}, {
Errno: "ENOTSOCK",
}, {
Errno: "ENOTCONN",
}, {
Errno: "EWOULDBLOCK",
}, {
Errno: "EACCES",
}, {
Errno: "EPROTONOSUPPORT",
}, {
Errno: "EPROTOTYPE",
}}
func fileCreate(filename string) *os.File {
filep, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
return filep
}
func fileWrite(filep *os.File, content string) {
if _, err := filep.WriteString(content); err != nil {
log.Fatal(err)
}
}
func fileClose(filep *os.File) {
if err := filep.Close(); err != nil {
log.Fatal(err)
}
}
func filePrintf(filep *os.File, format string, v ...interface{}) {
fileWrite(filep, fmt.Sprintf(format, v...))
}
func gofmt(filename string) {
cmd := execabs.Command("go", "fmt", filename)
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
func writeSystemSpecificFile(kind string) {
filename := "errno_" + kind + ".go"
filep := fileCreate(filename)
fileWrite(filep, "// Code generated by go generate; DO NOT EDIT.\n")
filePrintf(filep, "// Generated: %+v\n\n", time.Now())
fileWrite(filep, "package errorsx\n\n")
filePrintf(filep, "import \"golang.org/x/sys/%s\"\n\n", kind)
fileWrite(filep, "const (\n")
for _, spec := range Specs {
filePrintf(filep, "\t%s = %s.%s\n", spec.Errno, kind, spec.Errno)
}
fileWrite(filep, ")\n\n")
fileClose(filep)
gofmt(filename)
}
func writeGenericFile() {
filename := "errno.go"
filep := fileCreate(filename)
fileWrite(filep, "// Code generated by go generate; DO NOT EDIT.\n")
filePrintf(filep, "// Generated: %+v\n\n", time.Now())
fileWrite(filep, "package errorsx\n\n")
fileWrite(filep, "//go:generate go run ./generator/\n\n")
fileWrite(filep, "import (\n")
fileWrite(filep, "\t\"errors\"\n")
fileWrite(filep, "\t\"syscall\"\n")
fileWrite(filep, ")\n\n")
fileWrite(filep, "// toSyscallErr converts a syscall error to the\n")
fileWrite(filep, "// proper OONI error. Returns the OONI error string\n")
fileWrite(filep, "// on success, an empty string otherwise.\n")
fileWrite(filep, "func toSyscallErr(err error) string {\n")
fileWrite(filep, "\t// filter out system errors: necessary to detect all windows errors\n")
fileWrite(filep, "\t// https://github.com/ooni/probe/issues/1526 describes the problem\n")
fileWrite(filep, "\t// of mapping localized windows errors.\n")
fileWrite(filep, "\tvar errno syscall.Errno\n")
fileWrite(filep, "\tif !errors.As(err, &errno) {\n")
fileWrite(filep, "\t\treturn \"\"\n")
fileWrite(filep, "\t}\n")
fileWrite(filep, "\tswitch errno {\n")
for _, spec := range Specs {
if spec.Failure != "" {
filePrintf(filep, "\tcase %s:\n", spec.Errno)
filePrintf(filep, "\t\treturn Failure%s\n", spec.Failure)
}
}
fileWrite(filep, "\t}\n")
fileWrite(filep, "\treturn \"\"\n")
fileWrite(filep, "}\n\n")
fileClose(filep)
gofmt(filename)
}
func main() {
writeSystemSpecificFile("unix")
writeSystemSpecificFile("windows")
writeGenericFile()
}