011 Project 11: Build a du Clone

011 Build a du Clone

Calculate recursive directory size and print human-readable output.

dir walk -> sum file sizes -> print per path + total

Full main.go

package main

import (
    "flag"
    "fmt"
    "io/fs"
    "os"
    "path/filepath"
)

func human(n int64) string {
    units := []string{"B", "KB", "MB", "GB", "TB"}
    v := float64(n)
    i := 0
    for v >= 1024 && i < len(units)-1 {
        v /= 1024
        i++
    }
    return fmt.Sprintf("%.1f%s", v, units[i])
}

func dirSize(root string) (int64, error) {
    var total int64
    err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
        if err != nil {
            return nil
        }
        if d.IsDir() {
            return nil
        }
        info, err := d.Info()
        if err != nil {
            return nil
        }
        total += info.Size()
        return nil
    })
    return total, err
}

func main() {
    humanFmt := flag.Bool("h", true, "human readable")
    flag.Parse()

    args := flag.Args()
    if len(args) == 0 {
        args = []string{"."}
    }

    var grand int64
    for _, p := range args {
        sz, err := dirSize(p)
        if err != nil {
            fmt.Fprintf(os.Stderr, "%s: %v\n", p, err)
            continue
        }
        grand += sz
        if *humanFmt {
            fmt.Printf("%8s  %s\n", human(sz), p)
        } else {
            fmt.Printf("%8d  %s\n", sz, p)
        }
    }

    if len(args) > 1 {
        if *humanFmt {
            fmt.Printf("%8s  total\n", human(grand))
        } else {
            fmt.Printf("%8d  total\n", grand)
        }
    }
}

Run

go run . -h /var/log /tmp

Step-by-Step Explanation

  1. Parse command-line flags and validate inputs early.
  2. Keep the core operation in a small, testable function.
  3. Process data as a stream when possible to reduce memory use.
  4. Print stable output and meaningful exit codes.
  5. Add one extension feature and test edge cases.

Code Anatomy

  • main handles flags, orchestration, and errors.
  • Worker/helper functions hold business logic.
  • Output section should be deterministic for scripting and CI usage.

Learning Goals

  • Write composable Unix-style Go tools.
  • Improve error messages and operator experience.
  • Practice iterative improvement over one clear baseline.