This commit is contained in:
Diego Fernando Carrión 2021-08-29 18:27:05 +02:00
parent c71519707f
commit 6a233fb76c
7 changed files with 543 additions and 0 deletions

25
LICENSE Normal file
View File

@ -0,0 +1,25 @@
X11 License (X11)
Copyright (c) 2018 Diego Fernando Carrión
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Except as contained in this notice, the name(s) of the above copyright holders
shall not be used in advertising or otherwise to promote the sale, use or other
dealings in this Software without prior written authorization.

70
assert/assert.go Normal file
View File

@ -0,0 +1,70 @@
package assert
import (
"fmt"
"os"
"runtime"
eval "github.com/novalagung/go-eek"
"gitlab.com/CRThaze/cworthy/exits"
)
type EvalVar eval.Var
type EvalVal eval.ExecVar
const (
stdAssertFailureFmt = "%s%s%s:%d %s%sAssertion `%s` failed.\n"
)
var (
AssertFailureFmt = stdAssertFailureFmt
AssertionStream = os.Stderr
)
func assertFailBase(frmt, assertion, file string, line int, function string) {
fmt.Fprintf(AssertionStream, frmt, file, line, function, assertion)
exits.Abort()
}
func assertFail(frmt, expr string) {
if pc, file, line, ok := runtime.Caller(2); ok {
frames := runtime.CallersFrames([]uintptr{pc})
firstFrame, _ := frames.Next()
assertFailBase(frmt, expr, file, line, firstFrame.Function)
}
}
func Assert(exprResult bool) {
if exprResult {
return
}
assertFail(AssertFailureFmt, "")
}
func AssertEval(expr string, vals EvalVal, vars ...EvalVar) {
defer func() {
if paniced := recover(); paniced != nil {
assertFail("Assertion paniced", expr)
}
}()
obj := eval.New("Assertion Eval", expr)
for _, v := range vars {
obj.DefineVariable(v)
}
obj.PrepareEvaluation(expr)
if err := obj.Build(); err != nil {
assertFail("Assertion cannot build", expr)
}
resultItf, err := obj.Evaluate(vals)
if err != nil {
assertFail("Assertion could not be evaluated", expr)
}
if result, ok := resultItf.(bool); !ok {
panic("Invalid assertion")
} else if result {
return
}
assertFail(AssertFailureFmt, expr)
}

384
errno/err.go Normal file
View File

@ -0,0 +1,384 @@
package errgo
type ErrorT uint16
const (
NULL ErrorT = iota
/****************
* Posix Errors *
****************/
// Argument list too long.
E2BIG
// Permission denied.
EACCES
// Address in use.
EADDRINUSE
// Address not available.
EADDRNOTAVAIL
// Address family not supported.
EAFNOSUPPORT
// Resource unavailable, try again.
EAGAIN
// Connection already in progress.
EALREADY
// Bad file descriptor.
EBADF
// Bad message.
EBADMSG
// Device or resource busy.
EBUSY
// Operation canceled.
ECANCELED
// No child processes.
ECHILD
// Connection aborted.
ECONNABORTED
// Connection refused.
ECONNREFUSED
// Connection reset.
ECONNRESET
// Resource deadlock would occur.
EDEADLK
// Destination address required.
EDESTADDRREQ
// Mathematics argument out of domain of function.
EDOM
// Reserved.
EDQUOT
// File exists.
EEXIST
// Bad address.
EFAULT
// File too large.
EFBIG
// Host is unreachable.
EHOSTUNREACH
// Identifier removed.
EIDRM
// Illegal byte sequence.
EILSEQ
// Operation in progress.
EINPROGRESS
// Interrupted function.
EINTR
// Invalid argument.
EINVAL
// I/O error.
EIO
// Socket is connected.
EISCONN
// Is a directory.
EISDIR
// Too many levels of symbolic links.
ELOOP
// File descriptor value too large.
EMFILE
// Too many links.
EMLINK
// Message too large.
EMSGSIZE
// Reserved.
EMULTIHOP
// Filename too long.
ENAMETOOLONG
// Network is down.
ENETDOWN
// Connection aborted by network.
ENETRESET
// Network unreachable.
ENETUNREACH
// Too many files open in system.
ENFILE
// No buffer space available.
ENOBUFS
// No message is available on the STREAM head read queue.
ENODATA
// No such device.
ENODEV
// No such file or directory.
ENOENT
// Executable file format error.
ENOEXEC
// No locks available.
ENOLCK
// Reserved.
ENOLINK
// Not enough space.
ENOMEM
// No message of the desired type.
ENOMSG
// Protocol not available.
ENOPROTOOPT
// No space left on device.
ENOSPC
// No STREAM resources.
ENOSR
// Not a STREAM.
ENOSTR
// Functionality not supported.
ENOSYS
// The socket is not connected.
ENOTCONN
// Not a directory or a symbolic link to a directory.
ENOTDIR
// Directory not empty.
ENOTEMPTY
// State not recoverable.
ENOTRECOVERABLE
// Not a socket.
ENOTSOCK
// Not supported.
ENOTSUP
// Inappropriate I/O control operation.
ENOTTY
// No such device or address.
ENXIO
// Operation not supported on socket.
EOPNOTSUPP
// Value too large to be stored in data type.
EOVERFLOW
// Previous owner died.
EOWNERDEAD
// Operation not permitted.
EPERM
// Broken pipe.
EPIPE
// Protocol error.
EPROTO
// Protocol not supported.
EPROTONOSUPPORT
// Protocol wrong type for socket.
EPROTOTYPE
// Result too large.
ERANGE
// Read-only file system.
EROFS
// Invalid seek.
ESPIPE
// No such process.
ESRCH
// Reserved.
ESTALE
// Stream ioctl() timeout.
ETIME
// Connection timed out.
ETIMEDOUT
// Text file busy.
ETXTBSY
// Operation would block.
EWOULDBLOCK
// Cross-device link.
EXDEV
/*************************
* ErrGo Specific Errors *
*************************/
// Generic error.
EOTHER ErrorT = 16384 + iota
// ID is already in use.
EIDINUSE
// Already set.
EALREADYSET
// Not found.
ENOTFOUND
)
var errorTable = map[ErrorT]string{
/****************
* Posix Errors *
****************/
E2BIG: "Argument list too long",
EACCES: "Permission denied",
EADDRINUSE: "Address in use",
EADDRNOTAVAIL: "Address not available",
EAFNOSUPPORT: "Address family not supported",
EAGAIN: "Resource unavailable, try again",
EALREADY: "Connection already in progress",
EBADF: "Bad file descriptor",
EBADMSG: "Bad message",
EBUSY: "Device or resource busy",
ECANCELED: "Operation canceled",
ECHILD: "No child processes",
ECONNABORTED: "Connection aborted",
ECONNREFUSED: "Connection refused",
ECONNRESET: "Connection reset",
EDEADLK: "Resource deadlock would occur",
EDESTADDRREQ: "Destination address required",
EDOM: "Mathematics argument out of domain of function",
EDQUOT: "Reserved",
EEXIST: "File exists",
EFAULT: "Bad address",
EFBIG: "File too large",
EHOSTUNREACH: "Host is unreachable",
EIDRM: "Identifier removed",
EILSEQ: "Illegal byte sequence",
EINPROGRESS: "Operation in progress",
EINTR: "Interrupted function",
EINVAL: "Invalid argument",
EIO: "I/O error",
EISCONN: "Socket is connected",
EISDIR: "Is a directory",
ELOOP: "Too many levels of symbolic links",
EMFILE: "File descriptor value too large",
EMLINK: "Too many links",
EMSGSIZE: "Message too large",
EMULTIHOP: "Reserved",
ENAMETOOLONG: "Filename too long",
ENETDOWN: "Network is down",
ENETRESET: "Connection aborted by network",
ENETUNREACH: "Network unreachable",
ENFILE: "Too many files open in system",
ENOBUFS: "No buffer space available",
ENODATA: "No message is available on the STREAM head read queue",
ENODEV: "No such device",
ENOENT: "No such file or directory",
ENOEXEC: "Executable file format error",
ENOLCK: "No locks available",
ENOLINK: "Reserved",
ENOMEM: "Not enough space",
ENOMSG: "No message of the desired type",
ENOPROTOOPT: "Protocol not available",
ENOSPC: "No space left on device",
ENOSR: "No STREAM resources",
ENOSTR: "Not a STREAM",
ENOSYS: "Functionality not supported",
ENOTCONN: "The socket is not connected",
ENOTDIR: "Not a directory or a symbolic link to a directory",
ENOTEMPTY: "Directory not empty",
ENOTRECOVERABLE: "State not recoverable",
ENOTSOCK: "Not a socket",
ENOTSUP: "Not supported",
ENOTTY: "Inappropriate I/O control operation",
ENXIO: "No such device or address",
EOPNOTSUPP: "Operation not supported on socket",
EOVERFLOW: "Value too large to be stored in data type",
EOWNERDEAD: "Previous owner died",
EPERM: "Operation not permitted",
EPIPE: "Broken pipe",
EPROTO: "Protocol error",
EPROTONOSUPPORT: "Protocol not supported",
EPROTOTYPE: "Protocol wrong type for socket",
ERANGE: "Result too large",
EROFS: "Read-only file system",
ESPIPE: "Invalid seek",
ESRCH: "No such process",
ESTALE: "Reserved",
ETIME: "Stream ioctl() timeout",
ETIMEDOUT: "Connection timed out",
ETXTBSY: "Text file busy",
EWOULDBLOCK: "Operation would block",
EXDEV: "Cross-device link",
/*************************
* ErrGo Specific Errors *
*************************/
EOTHER: "Generic error",
EIDINUSE: "ID is already in use",
EALREADYSET: "Already set",
ENOTFOUND: "Not found",
}
const userErrorIDSpaceStart = uint16(1) << 15
var highestUserErrorID uint16 = userErrorIDSpaceStart
// Error is required to satisfy the Go error interface.
func (err ErrorT) Error() string {
return errorTable[err]
}
// RegisterMsg allows you to set the error message on manually created ErrorT's.
func (err ErrorT) RegisterMsg(msg string) error {
if _, nok := errorTable[err]; nok {
return EALREADYSET
}
return nil
}
// MustRegisterMsg is identical to RegisterMsg but will panic on errors.
func (err ErrorT) MustRegisterMsg(msg string) {
if e := err.RegisterMsg(msg); e != nil {
panic(e)
}
}
// ID is shorthand for uint16(err), when err is an ErrorT.
func (err ErrorT) ID() uint16 {
return uint16(err)
}
// NewErrorT is a factory for ErrorT.
// In the event that an invalid id is provided it will return an empty ErrorT in the first value
// and one of the following in the second:
// EINVAL When the id provided is not >32767
// EIDINUSE When the ID is already in use.
func NewErrorT(id uint16, msg string) (ErrorT, error) {
if id < userErrorIDSpaceStart {
return ErrorT(0), EINVAL
}
err := ErrorT(id)
if _, nok := errorTable[err]; nok {
return ErrorT(0), EIDINUSE
}
err.MustRegisterMsg(msg)
return err, nil
}
// MustNewErrorT is identical to NewErrorT but will panic on errors.
func MustNewErrorT(id uint16, msg string) ErrorT {
err, e := NewErrorT(id, msg)
if e != nil {
panic(e)
}
return err
}
// NewNextErrorT is a factory for ErrorT which attempt to auto assign an ID >32767 and <65536.
// In the event that 32768 errors have already been created in this way, it will return an empty
// ErrorT in the first value and EOVERFLOW in the second.
func NewNextErrorT(msg string) (ErrorT, error) {
if highestUserErrorID == ^uint16(0) {
return ErrorT(0), EOVERFLOW
}
id := highestUserErrorID
highestUserErrorID++
err := ErrorT(id)
err.MustRegisterMsg(msg)
return err, nil
}
// MustNewNextErrorT is identical to NewNextErrorT but will panic on errors.
func MustNewNextErrorT(msg string) ErrorT {
err, e := NewNextErrorT(msg)
if e != nil {
panic(e)
}
return err
}
// Lookup takes an id and attempts to find an ErrorT which matches it.
func Lookup(id uint16) (err ErrorT, msg string, e error) {
for err, msg := range errorTable {
if uint16(err) == id {
return err, msg, nil
}
}
return ErrorT(0), "", ENOTFOUND
}
// Assert will perform a type assertion on a given error to ErrorT.
func Assert(e error) (ErrorT, error) {
err, ok := e.(ErrorT)
if !ok {
return ErrorT(0), EINVAL
}
return err, nil
}
// MustAssert is identical to Assert but will panic on errors.
func MustAssert(e error) ErrorT {
err, e := Assert(e)
if e != nil {
panic(e)
}
return err
}

14
exits/abort.go Normal file
View File

@ -0,0 +1,14 @@
package exits
import (
"os"
"syscall"
)
func Abort() {
proc, err := os.FindProcess(os.Getpid())
if err != nil {
panic(err)
}
proc.Signal(syscall.SIGABRT)
}

30
exits/exits.go Normal file
View File

@ -0,0 +1,30 @@
package exits
import (
"gitlab.com/CRThaze/cworthy/errno"
)
type ErrorT errno.ErrorT
const (
EX_OK = 0 // successful termination
EX__BASE = 64 // base value for error messages
EX_USAGE = 64 // command line usage error
EX_DATAERR = 65 // data format error
EX_NOINPUT = 66 // cannot open input
EX_NOUSER = 67 // addressee unknown
EX_NOHOST = 68 // host name unknown
EX_UNAVAILABLE = 69 // service unavailable
EX_SOFTWARE = 70 // internal software error
EX_OSERR = 71 // system error (e.g., can't fork)
EX_OSFILE = 72 // critical OS file missing
EX_CANTCREAT = 73 // can't create (user) output file
EX_IOERR = 74 // input/output error
EX_TEMPFAIL = 75 // temp failure; user is invited to retry
EX_PROTOCOL = 76 // remote error in protocol
EX_NOPERM = 77 // permission denied
EX_CONFIG = 78 // configuration error
EX__MAX = 78 // maximum listed value
EX_ABORT = 134
)

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module gitlab.com/CRThaze/cworthy
go 1.17
require github.com/novalagung/go-eek v1.0.1

15
go.sum Normal file
View File

@ -0,0 +1,15 @@
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/novalagung/go-eek v1.0.1 h1:0KCCoccqz8Jp5ru6QynOp5F4b01rDrc7iHSSry08jG4=
github.com/novalagung/go-eek v1.0.1/go.mod h1:Q9MQtLRP21rO5/7UmIJUr5URe1ysI+K/wM3zYJCxPxo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=