diff options
Diffstat (limited to 'internal/service/service.go')
-rw-r--r-- | internal/service/service.go | 84 |
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 } |