// Copyright 2022 - offen.software // SPDX-License-Identifier: MPL-2.0 package main import ( "bytes" "fmt" "io" "os" "sync" "time" "github.com/offen/docker-volume-backup/internal/errwrap" "github.com/robfig/cron/v3" ) var noop = func() error { return nil } // remove removes the given file or directory from disk. func remove(location string) error { fi, err := os.Lstat(location) if err != nil { if os.IsNotExist(err) { return nil } return errwrap.Wrap(err, fmt.Sprintf("error checking for existence of `%s`", location)) } if fi.IsDir() { err = os.RemoveAll(location) } else { err = os.Remove(location) } if err != nil { return errwrap.Wrap(err, fmt.Sprintf("error removing `%s", location)) } return nil } // buffer takes an io.Writer and returns a wrapped version of the // writer that writes to both the original target as well as the returned buffer func buffer(w io.Writer) (io.Writer, *bytes.Buffer) { buffering := &bufferingWriter{buf: bytes.Buffer{}, writer: w} return buffering, &buffering.buf } type bufferingWriter struct { buf bytes.Buffer writer io.Writer } func (b *bufferingWriter) Write(p []byte) (n int, err error) { if n, err := b.buf.Write(p); err != nil { return n, errwrap.Wrap(err, "error writing to buffer") } return b.writer.Write(p) } type noopWriteCloser struct { io.Writer } func (noopWriteCloser) Close() error { return nil } type handledSwarmService struct { serviceID string initialReplicaCount uint64 } type concurrentSlice[T any] struct { val []T sync.Mutex } func (c *concurrentSlice[T]) append(v T) { c.Lock() defer c.Unlock() c.val = append(c.val, v) } func (c *concurrentSlice[T]) value() []T { return c.val } // checkCronSchedule detects whether the given cron expression will actually // ever be executed or not. func checkCronSchedule(expression string) (ok bool) { defer func() { if err := recover(); err != nil { ok = false } }() sched, err := cron.ParseStandard(expression) if err != nil { ok = false return } now := time.Now() sched.Next(now) // panics when the cron would never run ok = true return }