| @@ -11,6 +11,7 @@ import ( |
| 11 | "strconv" |
11 | "strconv" |
| 12 | "strings" |
12 | "strings" |
| 13 | |
13 | |
| |
14 | "gitbay.org/gitbay/internal/backuplock" |
| 14 | "gitbay.org/gitbay/internal/gitutil" |
15 | "gitbay.org/gitbay/internal/gitutil" |
| 15 | "gitbay.org/gitbay/internal/policy" |
16 | "gitbay.org/gitbay/internal/policy" |
| 16 | "gitbay.org/gitbay/internal/protocol" |
17 | "gitbay.org/gitbay/internal/protocol" |
| @@ -513,6 +514,11 @@ func runRepoTransfer(c *Ctx, args []string) int { |
| 513 | if _, err := os.Stat(newDir); err == nil { |
514 | if _, err := os.Stat(newDir); err == nil { |
| 514 | return c.fail(protocol.ExitFailure, "repository directory already exists at %s/%s", newOwner, repo.Name) |
515 | return c.fail(protocol.ExitFailure, "repository directory already exists at %s/%s", newOwner, repo.Name) |
| 515 | } |
516 | } |
| |
517 | release, lockCode := holdOffBackup(c) |
| |
518 | if lockCode >= 0 { |
| |
519 | return lockCode |
| |
520 | } |
| |
521 | defer release() |
| 516 | // The directory moves before the record changes: a move that fails |
522 | // The directory moves before the record changes: a move that fails |
| 517 | // leaves nothing to undo, whereas the record's change into an org |
523 | // leaves nothing to undo, whereas the record's change into an org |
| 518 | // folds labels and milestones into the org's rows, which a revert |
524 | // folds labels and milestones into the org's rows, which a revert |
| @@ -557,6 +563,11 @@ func runRepoRename(c *Ctx, args []string) int { |
| 557 | if _, err := os.Stat(newDir); err == nil { |
563 | if _, err := os.Stat(newDir); err == nil { |
| 558 | return c.fail(protocol.ExitFailure, "repository directory already exists at %s/%s", repo.OwnerName, newName) |
564 | return c.fail(protocol.ExitFailure, "repository directory already exists at %s/%s", repo.OwnerName, newName) |
| 559 | } |
565 | } |
| |
566 | release, lockCode := holdOffBackup(c) |
| |
567 | if lockCode >= 0 { |
| |
568 | return lockCode |
| |
569 | } |
| |
570 | defer release() |
| 560 | if err := c.Store.RenameRepo(repo.ID, newName); err != nil { |
571 | if err := c.Store.RenameRepo(repo.ID, newName); err != nil { |
| 561 | return c.failErr(err) |
572 | return c.failErr(err) |
| 562 | } |
573 | } |
| @@ -609,6 +620,11 @@ func runRepoDelete(c *Ctx, args []string) int { |
| 609 | // webhooks; an instance that needs to hear about it wants the audit log |
620 | // webhooks; an instance that needs to hear about it wants the audit log |
| 610 | // (#112). |
621 | // (#112). |
| 611 | func deleteRepo(c *Ctx, repo store.Repo) int { |
622 | func deleteRepo(c *Ctx, repo store.Repo) int { |
| |
623 | release, lockCode := holdOffBackup(c) |
| |
624 | if lockCode >= 0 { |
| |
625 | return lockCode |
| |
626 | } |
| |
627 | defer release() |
| 612 | // Open MRs sourced from this repo keep working (targets own the |
628 | // Open MRs sourced from this repo keep working (targets own the |
| 613 | // objects) but must show that the source is gone. |
629 | // objects) but must show that the source is gone. |
| 614 | if err := c.Store.MarkSourceGoneForRepo(repo.ID); err != nil { |
630 | if err := c.Store.MarkSourceGoneForRepo(repo.ID); err != nil { |
| @@ -625,6 +641,18 @@ func deleteRepo(c *Ctx, repo store.Repo) int { |
| 625 | }) |
641 | }) |
| 626 | } |
642 | } |
| 627 | |
643 | |
| |
644 | // holdOffBackup keeps a full backup from starting while a repository |
| |
645 | // directory moves or goes, and refuses while one runs: the backup's |
| |
646 | // database snapshot names every repository its walk then archives |
| |
647 | // (#259). The caller defers the returned release. |
| |
648 | func holdOffBackup(c *Ctx) (func(), int) { |
| |
649 | release, err := backuplock.TryShared(c.Cfg.Server.Root) |
| |
650 | if err != nil { |
| |
651 | return nil, c.fail(protocol.ExitFailure, "%v", err) |
| |
652 | } |
| |
653 | return release, -1 |
| |
654 | } |
| |
655 | |
| 628 | func runAccessGrant(c *Ctx, args []string) int { |
656 | func runAccessGrant(c *Ctx, args []string) int { |
| 629 | if len(args) != 3 || !slices.Contains([]string{"read", "write", "admin"}, args[2]) { |
657 | if len(args) != 3 || !slices.Contains([]string{"read", "write", "admin"}, args[2]) { |
| 630 | return c.usage() |
658 | return c.usage() |