Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
72d6b538f7
|
|||
48dd30fb94
|
|||
b7c5756f11
|
|||
2070a432a5
|
56
cmdext/builder.go
Normal file
56
cmdext/builder.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package cmdext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommandRunner struct {
|
||||||
|
program string
|
||||||
|
args []string
|
||||||
|
timeout *time.Duration
|
||||||
|
env []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Runner(program string) *CommandRunner {
|
||||||
|
return &CommandRunner{
|
||||||
|
program: program,
|
||||||
|
args: make([]string, 0),
|
||||||
|
timeout: nil,
|
||||||
|
env: make([]string, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Arg(arg string) *CommandRunner {
|
||||||
|
r.args = append(r.args, arg)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Args(arg []string) *CommandRunner {
|
||||||
|
r.args = append(r.args, arg...)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Timeout(timeout time.Duration) *CommandRunner {
|
||||||
|
r.timeout = &timeout
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Env(key, value string) *CommandRunner {
|
||||||
|
r.env = append(r.env, fmt.Sprintf("%s=%s", key, value))
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) RawEnv(env string) *CommandRunner {
|
||||||
|
r.env = append(r.env, env)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Envs(env []string) *CommandRunner {
|
||||||
|
r.env = append(r.env, env...)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *CommandRunner) Run() (CommandResult, error) {
|
||||||
|
return run(*r)
|
||||||
|
}
|
@@ -14,9 +14,10 @@ type CommandResult struct {
|
|||||||
CommandTimedOut bool
|
CommandTimedOut bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunCommand(program string, args []string, timeout *time.Duration) (CommandResult, error) {
|
func run(opt CommandRunner) (CommandResult, error) {
|
||||||
|
cmd := exec.Command(opt.program, opt.args...)
|
||||||
|
|
||||||
cmd := exec.Command(program, args...)
|
cmd.Env = append(cmd.Env, opt.env...)
|
||||||
|
|
||||||
stdoutPipe, err := cmd.StdoutPipe()
|
stdoutPipe, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -75,11 +76,14 @@ func RunCommand(program string, args []string, timeout *time.Duration) (CommandR
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if timeout != nil {
|
var timeoutChan <-chan time.Time = make(chan time.Time, 1)
|
||||||
|
if opt.timeout != nil {
|
||||||
|
timeoutChan = time.After(*opt.timeout)
|
||||||
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|
||||||
case <-time.After(*timeout):
|
case <-timeoutChan:
|
||||||
_ = cmd.Process.Kill()
|
_ = cmd.Process.Kill()
|
||||||
return CommandResult{
|
return CommandResult{
|
||||||
StdOut: stdout,
|
StdOut: stdout,
|
||||||
@@ -109,34 +113,5 @@ func RunCommand(program string, args []string, timeout *time.Duration) (CommandR
|
|||||||
CommandTimedOut: false,
|
CommandTimedOut: false,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
select {
|
|
||||||
|
|
||||||
case err := <-errch:
|
|
||||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
|
||||||
return CommandResult{
|
|
||||||
StdOut: stdout,
|
|
||||||
StdErr: stderr,
|
|
||||||
StdCombined: stdcombined,
|
|
||||||
ExitCode: exiterr.ExitCode(),
|
|
||||||
CommandTimedOut: false,
|
|
||||||
}, nil
|
|
||||||
} else if err != nil {
|
|
||||||
return CommandResult{}, err
|
|
||||||
} else {
|
|
||||||
return CommandResult{
|
|
||||||
StdOut: stdout,
|
|
||||||
StdErr: stderr,
|
|
||||||
StdCombined: stdcombined,
|
|
||||||
ExitCode: 0,
|
|
||||||
CommandTimedOut: false,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
cmdext/helper.go
Normal file
12
cmdext/helper.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package cmdext
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func RunCommand(program string, args []string, timeout *time.Duration) (CommandResult, error) {
|
||||||
|
b := Runner(program)
|
||||||
|
b = b.Args(args)
|
||||||
|
if timeout != nil {
|
||||||
|
b = b.Timeout(*timeout)
|
||||||
|
}
|
||||||
|
return b.Run()
|
||||||
|
}
|
182
rfctime/rfc3339.go
Normal file
182
rfctime/rfc3339.go
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
package rfctime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RFC3339Time time.Time
|
||||||
|
|
||||||
|
func (t RFC3339Time) Time() time.Time {
|
||||||
|
return time.Time(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) MarshalBinary() ([]byte, error) {
|
||||||
|
return (time.Time)(t).MarshalBinary()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339Time) UnmarshalBinary(data []byte) error {
|
||||||
|
return (*time.Time)(t).UnmarshalBinary(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) GobEncode() ([]byte, error) {
|
||||||
|
return (time.Time)(t).GobEncode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339Time) GobDecode(data []byte) error {
|
||||||
|
return (*time.Time)(t).GobDecode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339Time) UnmarshalJSON(data []byte) error {
|
||||||
|
str := ""
|
||||||
|
if err := json.Unmarshal(data, &str); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t0, err := time.Parse(t.FormatStr(), str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = RFC3339Time(t0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) MarshalJSON() ([]byte, error) {
|
||||||
|
str := t.Time().Format(t.FormatStr())
|
||||||
|
return json.Marshal(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) MarshalText() ([]byte, error) {
|
||||||
|
b := make([]byte, 0, len(t.FormatStr()))
|
||||||
|
return t.Time().AppendFormat(b, t.FormatStr()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RFC3339Time) UnmarshalText(data []byte) error {
|
||||||
|
var err error
|
||||||
|
v, err := time.Parse(t.FormatStr(), string(data))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tt := RFC3339Time(v)
|
||||||
|
*t = tt
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Serialize() string {
|
||||||
|
return t.Time().Format(t.FormatStr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) FormatStr() string {
|
||||||
|
return time.RFC3339
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) After(u RFCTime) bool {
|
||||||
|
return t.Time().After(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Before(u RFCTime) bool {
|
||||||
|
return t.Time().Before(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Equal(u RFCTime) bool {
|
||||||
|
return t.Time().Equal(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) IsZero() bool {
|
||||||
|
return t.Time().IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Date() (year int, month time.Month, day int) {
|
||||||
|
return t.Time().Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Year() int {
|
||||||
|
return t.Time().Year()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Month() time.Month {
|
||||||
|
return t.Time().Month()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Day() int {
|
||||||
|
return t.Time().Day()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Weekday() time.Weekday {
|
||||||
|
return t.Time().Weekday()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) ISOWeek() (year, week int) {
|
||||||
|
return t.Time().ISOWeek()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Clock() (hour, min, sec int) {
|
||||||
|
return t.Time().Clock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Hour() int {
|
||||||
|
return t.Time().Hour()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Minute() int {
|
||||||
|
return t.Time().Minute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Second() int {
|
||||||
|
return t.Time().Second()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Nanosecond() int {
|
||||||
|
return t.Time().Nanosecond()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) YearDay() int {
|
||||||
|
return t.Time().YearDay()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Add(d time.Duration) RFC3339Time {
|
||||||
|
return RFC3339Time(t.Time().Add(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Sub(u RFCTime) time.Duration {
|
||||||
|
return t.Time().Sub(u.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) AddDate(years int, months int, days int) RFC3339Time {
|
||||||
|
return RFC3339Time(t.Time().AddDate(years, months, days))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Unix() int64 {
|
||||||
|
return t.Time().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) UnixMilli() int64 {
|
||||||
|
return t.Time().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) UnixMicro() int64 {
|
||||||
|
return t.Time().UnixMicro()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) UnixNano() int64 {
|
||||||
|
return t.Time().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) Format(layout string) string {
|
||||||
|
return t.Time().Format(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) GoString() string {
|
||||||
|
return t.Time().GoString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RFC3339Time) String() string {
|
||||||
|
return t.Time().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRFC3339(t time.Time) RFC3339Time {
|
||||||
|
return RFC3339Time(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NowRFC3339() RFC3339Time {
|
||||||
|
return RFC3339Time(time.Now())
|
||||||
|
}
|
@@ -2,58 +2,50 @@ package syncext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync/atomic"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AtomicBool struct {
|
type AtomicBool struct {
|
||||||
v int32
|
v bool
|
||||||
waiter chan bool // unbuffered
|
listener map[string]chan bool
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAtomicBool(value bool) *AtomicBool {
|
func NewAtomicBool(value bool) *AtomicBool {
|
||||||
if value {
|
return &AtomicBool{
|
||||||
return &AtomicBool{v: 1, waiter: make(chan bool)}
|
v: value,
|
||||||
} else {
|
listener: make(map[string]chan bool),
|
||||||
return &AtomicBool{v: 0, waiter: make(chan bool)}
|
lock: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AtomicBool) Get() bool {
|
func (a *AtomicBool) Get() bool {
|
||||||
return atomic.LoadInt32(&a.v) == 1
|
a.lock.Lock()
|
||||||
|
defer a.lock.Unlock()
|
||||||
|
return a.v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AtomicBool) Set(value bool) {
|
func (a *AtomicBool) Set(value bool) {
|
||||||
if value {
|
a.lock.Lock()
|
||||||
atomic.StoreInt32(&a.v, 1)
|
defer a.lock.Unlock()
|
||||||
} else {
|
|
||||||
atomic.StoreInt32(&a.v, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
a.v = value
|
||||||
|
|
||||||
|
for k, v := range a.listener {
|
||||||
select {
|
select {
|
||||||
case a.waiter <- value:
|
case v <- value:
|
||||||
// message sent
|
// message sent
|
||||||
default:
|
default:
|
||||||
// no receiver on channel
|
// no receiver on channel
|
||||||
|
delete(a.listener, k)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AtomicBool) Wait(waitFor bool) {
|
func (a *AtomicBool) Wait(waitFor bool) {
|
||||||
if a.Get() == waitFor {
|
_ = a.WaitWithContext(context.Background(), waitFor)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
if v, ok := ReadChannelWithTimeout(a.waiter, 128*time.Millisecond); ok {
|
|
||||||
if v == waitFor {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if a.Get() == waitFor {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AtomicBool) WaitWithTimeout(timeout time.Duration, waitFor bool) error {
|
func (a *AtomicBool) WaitWithTimeout(timeout time.Duration, waitFor bool) error {
|
||||||
@@ -71,12 +63,25 @@ func (a *AtomicBool) WaitWithContext(ctx context.Context, waitFor bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uuid, _ := langext.NewHexUUID()
|
||||||
|
|
||||||
|
waitchan := make(chan bool)
|
||||||
|
|
||||||
|
a.lock.Lock()
|
||||||
|
a.listener[uuid] = waitchan
|
||||||
|
a.lock.Unlock()
|
||||||
|
defer func() {
|
||||||
|
a.lock.Lock()
|
||||||
|
delete(a.listener, uuid)
|
||||||
|
a.lock.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
timeOut := 128 * time.Millisecond
|
timeOut := 1024 * time.Millisecond
|
||||||
|
|
||||||
if dl, ok := ctx.Deadline(); ok {
|
if dl, ok := ctx.Deadline(); ok {
|
||||||
timeOutMax := dl.Sub(time.Now())
|
timeOutMax := dl.Sub(time.Now())
|
||||||
@@ -87,7 +92,7 @@ func (a *AtomicBool) WaitWithContext(ctx context.Context, waitFor bool) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := ReadChannelWithTimeout(a.waiter, timeOut); ok {
|
if v, ok := ReadChannelWithTimeout(waitchan, timeOut); ok {
|
||||||
if v == waitFor {
|
if v == waitFor {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user