refactor(errorsx): auto-generate syscall errors mapping (#429)
* refactor(errorsx): auto-generate syscall errors mapping Part of https://github.com/ooni/probe/issues/1505 * fix: generate independently of the platform
This commit is contained in:
parent
b13c7bf8fb
commit
3747598b4a
37
internal/errorsx/errno.go
Normal file
37
internal/errorsx/errno.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
|
// Generated: 2021-07-02 15:15:17.997258 +0200 CEST m=+0.110031584
|
||||||
|
|
||||||
|
package errorsx
|
||||||
|
|
||||||
|
//go:generate go run ./generator/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// toSyscallErr converts a syscall error to the
|
||||||
|
// proper OONI error. Returns the OONI error string
|
||||||
|
// on success, an empty string otherwise.
|
||||||
|
func toSyscallErr(err error) string {
|
||||||
|
// filter out system errors: necessary to detect all windows errors
|
||||||
|
// https://github.com/ooni/probe/issues/1526 describes the problem
|
||||||
|
// of mapping localized windows errors.
|
||||||
|
var errno syscall.Errno
|
||||||
|
if !errors.As(err, &errno) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch errno {
|
||||||
|
case ECANCELED:
|
||||||
|
return FailureInterrupted
|
||||||
|
case ECONNREFUSED:
|
||||||
|
return FailureConnectionRefused
|
||||||
|
case ECONNRESET:
|
||||||
|
return FailureConnectionReset
|
||||||
|
case EHOSTUNREACH:
|
||||||
|
return FailureHostUnreachable
|
||||||
|
case ETIMEDOUT:
|
||||||
|
return FailureGenericTimeoutError
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
|
// Generated: 2021-07-02 15:15:17.887594 +0200 CEST m=+0.000365001
|
||||||
|
|
||||||
package errorsx
|
package errorsx
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
|
// Generated: 2021-07-02 15:15:17.971155 +0200 CEST m=+0.083928418
|
||||||
|
|
||||||
package errorsx
|
package errorsx
|
||||||
|
|
||||||
import "golang.org/x/sys/windows"
|
import "golang.org/x/sys/windows"
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/ooni/probe-cli/v3/internal/scrubber"
|
"github.com/ooni/probe-cli/v3/internal/scrubber"
|
||||||
)
|
)
|
||||||
|
@ -112,24 +111,10 @@ func toFailureString(err error) string {
|
||||||
return errwrapper.Error() // we've already wrapped it
|
return errwrapper.Error() // we've already wrapped it
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter out system errors: necessary to detect all windows errors
|
if failure := toSyscallErr(err); failure != "" {
|
||||||
// https://github.com/ooni/probe/issues/1526 describes the problem of mapping localized windows errors
|
return failure
|
||||||
var errno syscall.Errno
|
|
||||||
if errors.As(err, &errno) {
|
|
||||||
switch errno {
|
|
||||||
case ECANCELED:
|
|
||||||
return FailureInterrupted
|
|
||||||
case ECONNRESET:
|
|
||||||
return FailureConnectionReset
|
|
||||||
case ECONNREFUSED:
|
|
||||||
return FailureConnectionRefused
|
|
||||||
case EHOSTUNREACH:
|
|
||||||
return FailureHostUnreachable
|
|
||||||
case ETIMEDOUT:
|
|
||||||
return FailureGenericTimeoutError
|
|
||||||
// TODO(kelmenhorst): find out if we need more system errors here
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, context.Canceled) {
|
if errors.Is(err, context.Canceled) {
|
||||||
return FailureInterrupted
|
return FailureInterrupted
|
||||||
}
|
}
|
||||||
|
|
175
internal/errorsx/generator/main.go
Normal file
175
internal/errorsx/generator/main.go
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
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()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user