aboutsummaryrefslogtreecommitdiff
path: root/internal/service/service.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/service/service.go')
-rw-r--r--internal/service/service.go84
1 files changed, 81 insertions, 3 deletions
diff --git a/internal/service/service.go b/internal/service/service.go
index c5235f2..577a4b4 100644
--- a/internal/service/service.go
+++ b/internal/service/service.go
@@ -1,9 +1,12 @@
package service
import (
+ "bytes"
"errors"
"fmt"
"os"
+ "os/exec"
+ "path"
"strconv"
"strings"
"sync"
@@ -103,21 +106,82 @@ func (s *Service) scheduled(yield func(*mirrorRecord) bool) {
}
}
+func runBash(runDir string, commands string) error {
+ cmd := exec.Command("bash", "-c", commands)
+ cmd.Dir = runDir
+
+ var stdErr bytes.Buffer
+ cmd.Stderr = &stdErr
+
+ err := cmd.Run()
+ if err != nil {
+ return errors.New(stdErr.String())
+ }
+
+ return nil
+}
+
func (s *Service) Mirror(arg *Mirror) error {
if arg.From.Path == "" || arg.To.Path == "" || arg.Method == "" {
return fmt.Errorf("badly formatted mirror '%s'", arg.String())
}
+ if arg.To.Scheme != "" {
+ return fmt.Errorf("unsupported destination URL scheme '%s'", arg.To.Scheme)
+ }
+
+ cfgStagingMethod := s.cfg.StagingMethod
+ if arg.StagingMethod != "" {
+ cfgStagingMethod = arg.StagingMethod
+ }
+
+ cfgStagingPath := s.cfg.StagingPath
+ if arg.StagingPath != "" {
+ cfgStagingPath = arg.StagingPath
+ }
+
+ var downloadPath string
var err error
+ switch cfgStagingMethod {
+ case StagingMethodNone:
+ downloadPath = arg.To.Path
+ case StagingMethodTemporary:
+ tempPath, err := os.MkdirTemp("", "mirror.")
+ if err != nil {
+ return err
+ }
+ defer os.RemoveAll(tempPath)
+
+ downloadPath = tempPath
+ case StagingMethodPersistent:
+ downloadPath = path.Join(cfgStagingPath, arg.To.URL.Path)
+ default:
+ return fmt.Errorf("unknown staging method '%s'", cfgStagingMethod)
+ }
+
+ err = os.MkdirAll(downloadPath, 0755)
+ if err != nil {
+ return fmt.Errorf("creating directory '%s' for downloaded contents: %w", downloadPath, err)
+ }
+ err = os.MkdirAll(arg.To.URL.Path, 0755)
+ if err != nil {
+ return fmt.Errorf("creating directory '%s' for downloaded contents: %w", downloadPath, err)
+ }
+
+ err = Rsync(internal.MustURL(downloadPath), arg.To)
+ if err != nil {
+ return fmt.Errorf("copying current mirror data for staging to '%s': %w", downloadPath, err)
+ }
+
switch arg.Method {
case "git":
- err = MirrorGit(arg.To, arg.From, arg.Description)
+ err = MirrorGit(internal.MustURL(downloadPath), arg.From, arg.Description)
case "github-assets":
client := github.NewClient()
- err = client.MirrorAssets(arg.To, arg.From)
+ err = client.MirrorAssets(internal.MustURL(downloadPath), arg.From)
case "rsync":
- err = Rsync(arg.To, arg.From)
+ err = Rsync(internal.MustURL(downloadPath), arg.From)
default:
err = fmt.Errorf("unknown method '%s'", arg.Method)
}
@@ -126,6 +190,20 @@ func (s *Service) Mirror(arg *Mirror) error {
return fmt.Errorf("could not clone from '%s': %w", arg.From, err)
}
+ if s.cfg.Verify != "" {
+ err = runBash(downloadPath, s.cfg.Verify)
+ if err != nil {
+ return fmt.Errorf("verification failed: %w", err)
+ }
+ }
+
+ if downloadPath != arg.To.String() {
+ err = Rsync(arg.To, internal.MustURL(downloadPath))
+ if err != nil {
+ return fmt.Errorf("committing staged mirror data: %w", err)
+ }
+ }
+
return nil
}