cmd/gitbayd/maint.go
80 lines · 2093 bytes
1package main
2
3import (
4 "fmt"
5 "os"
6 "os/exec"
7
8 "github.com/spf13/cobra"
9
10 "gitbay.org/gitbay/internal/config"
11 "gitbay.org/gitbay/internal/control"
12 "gitbay.org/gitbay/internal/gitutil"
13 "gitbay.org/gitbay/internal/store"
14)
15
16func gcCmd() *cobra.Command {
17 var repoPath string
18 var aggressive bool
19 cmd := &cobra.Command{
20 Use: "gc",
21 Short: "repack and prune repositories (git gc)",
22 RunE: func(cmd *cobra.Command, args []string) error {
23 cfg, err := config.Load(configPath)
24 if err != nil {
25 return err
26 }
27 st, err := openStore(cfg)
28 if err != nil {
29 return err
30 }
31 defer st.Close()
32
33 var repos []store.Repo
34 if repoPath != "" {
35 r, err := st.RepoByPath(repoPath)
36 if err != nil {
37 return fmt.Errorf("no repository %q", repoPath)
38 }
39 repos = []store.Repo{r}
40 } else if repos, err = st.ListAllRepos(); err != nil {
41 return err
42 }
43
44 var before, after int64
45 for _, r := range repos {
46 dir := control.RepoDir(cfg.Server.Root, r.OwnerName, r.Name)
47 b := gitutil.DirSize(dir)
48 gcArgs := []string{"-C", dir, "gc", "--quiet"}
49 if aggressive {
50 gcArgs = append(gcArgs, "--aggressive")
51 }
52 if out, err := exec.Command("git", gcArgs...).CombinedOutput(); err != nil {
53 fmt.Fprintf(os.Stderr, "%s: gc failed: %v\n%s", r.Path(), err, out)
54 continue
55 }
56 a := gitutil.DirSize(dir)
57 before, after = before+b, after+a
58 fmt.Printf("%s\t%s -> %s\n", r.Path(), human(b), human(a))
59 }
60 fmt.Printf("total\t%s -> %s (freed %s)\n", human(before), human(after), human(before-after))
61 return nil
62 },
63 }
64 cmd.Flags().StringVar(&repoPath, "repo", "", "one repository (owner/name) instead of all")
65 cmd.Flags().BoolVar(&aggressive, "aggressive", false, "more thorough repack (slow; rarely needed)")
66 return cmd
67}
68
69func human(b int64) string {
70 switch {
71 case b >= 1<<30:
72 return fmt.Sprintf("%.1f GiB", float64(b)/(1<<30))
73 case b >= 1<<20:
74 return fmt.Sprintf("%.1f MiB", float64(b)/(1<<20))
75 case b >= 1<<10:
76 return fmt.Sprintf("%.1f KiB", float64(b)/(1<<10))
77 default:
78 return fmt.Sprintf("%d B", b)
79 }
80}