77 lines
1.6 KiB
Go
77 lines
1.6 KiB
Go
package daemon
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
|
)
|
|
|
|
// until keeps trying fn until it returns nil, returning true. If the context is
|
|
// canceled then until returns false.
|
|
func until(
|
|
ctx context.Context,
|
|
logger *mlog.Logger,
|
|
descr string,
|
|
fn func(context.Context) error,
|
|
) bool {
|
|
for {
|
|
logger.Info(ctx, descr)
|
|
err := fn(ctx)
|
|
if err == nil {
|
|
return true
|
|
} else if ctxErr := ctx.Err(); ctxErr != nil {
|
|
return false
|
|
}
|
|
|
|
logger.Warn(ctx, descr+" failed, retrying in one second", err)
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
}
|
|
|
|
func randStr(l int) string {
|
|
b := make([]byte, l)
|
|
if _, err := rand.Read(b); err != nil {
|
|
panic(err)
|
|
}
|
|
return hex.EncodeToString(b)
|
|
}
|
|
|
|
// mkDir is like os.Mkdir but it returns better error messages. If the directory
|
|
// already exists then nil is returned.
|
|
func mkDir(path string) error {
|
|
{
|
|
parentPath := filepath.Dir(path)
|
|
parentInfo, err := os.Stat(parentPath)
|
|
if err != nil {
|
|
return fmt.Errorf("checking fs node of parent %q: %w", parentPath, err)
|
|
} else if !parentInfo.IsDir() {
|
|
return fmt.Errorf("%q is not a directory", parentPath)
|
|
}
|
|
}
|
|
|
|
info, err := os.Stat(path)
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
// fine
|
|
} else if err != nil {
|
|
return fmt.Errorf("checking fs node: %w", err)
|
|
} else if !info.IsDir() {
|
|
return fmt.Errorf("exists but is not a directory")
|
|
} else {
|
|
return nil
|
|
}
|
|
|
|
if err := os.Mkdir(path, 0700); err != nil {
|
|
return fmt.Errorf("creating directory: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|