package main import ( "errors" "fmt" "io/fs" "os" "path/filepath" "strconv" "strings" ) func readQuota(root string) int64 { b, err := os.ReadFile(filepath.Join(root, "quota")) if err != nil { return 0 } n, _ := parseSize(strings.TrimSpace(string(b))) return n } func parseSize(s string) (int64, error) { s = strings.ToUpper(strings.TrimSpace(s)) mult := int64(1) switch { case strings.HasSuffix(s, "G"): mult, s = 1<<30, strings.TrimSuffix(s, "G") case strings.HasSuffix(s, "M"): mult, s = 1<<20, strings.TrimSuffix(s, "M") case strings.HasSuffix(s, "K"): mult, s = 1<<10, strings.TrimSuffix(s, "K") } n, err := strconv.ParseInt(s, 10, 64) if err != nil || n < 0 { return 0, errors.New("size must be a number with an optional K, M or G suffix") } return n * mult, nil } func usage(dir string) int64 { var total int64 filepath.WalkDir(dir, func(p string, d fs.DirEntry, err error) error { if err == nil && !d.IsDir() { if info, err := d.Info(); err == nil { total += info.Size() } } return nil }) return total } func overQuota(root string, owner string) (bool, int64, int64) { quota := readQuota(root) if quota == 0 { return false, 0, 0 } used := usage(filepath.Join(root, "repos", owner)) return used >= quota, used, quota } func quotaMessage(used, quota int64) string { return fmt.Sprintf("disk quota exceeded, %s used of %s", humanSize(used), humanSize(quota)) }