summaryrefslogtreecommitdiff
path: root/main.go
blob: 9cb32f21f3217ec12757f82502e266ccf71d00e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main

import (
	"bufio"
	"crypto/sha256"
	"fmt"
	"io/fs"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"time"
)

type metadata struct {
	size, mtime, mode int64
	// sum               [sha256.Size]byte
	sum []byte
}

type metamap map[string]metadata

func getIndex(root string, mm metamap) (index string, err error) {
	filesystem := os.DirFS(root)
	err = fs.WalkDir(filesystem, ".", func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		info, err := d.Info()
		if err != nil {
			return err
		}
		if info.IsDir() {
			if d.Name() == ".bb" {
				return fs.SkipDir
			}
			return nil
		}

		b, err := os.ReadFile(path)
		if err != nil {
			return err
		}

		// md := metadata{info.Size(), info.ModTime().Unix(), int64(info.Mode()), sha256.Sum256(b)}
		a := sha256.Sum256(b)
		md := metadata{info.Size(), info.ModTime().Unix(), int64(info.Mode()), a[:]}

		log.Println(path, md, mm[path])

		index += fmt.Sprintf("%s %d %d %o %x\n", url.PathEscape(path), md.size, md.mtime, md.mode, md.sum)
		return nil
	})
	return index, err
}

func readIndex(path string) (md metamap, err error) {
	f, err := os.Open(path)
	if err != nil {
		return md, err
	}
	defer f.Close()
	md = metamap{}
	scan := bufio.NewScanner(f)
	for scan.Scan() {
		var p string
		var d metadata
		n, err := fmt.Sscanf(scan.Text(), "%s %d %d %o %64x", &p, &d.size, &d.mtime, &d.mode, &d.sum)
		if err != nil || n != 5 {
			return md, err
		}
		path, err := url.PathUnescape(p)
		if err != nil {
			return md, err
		}
		md[path] = d
	}
	if err := scan.Err(); err != nil {
		return md, err
	}
	return md, nil
}

func initBB(root string) (current, previous string, err error) {
	if err = os.MkdirAll(filepath.Join(root, ".bb", "data"), 0o750); err != nil {
		return "", "", err
	}
	prevs, _ := fs.Glob(os.DirFS(root), filepath.Join(".bb", "index-*"))
	if len(prevs) > 0 {
		previous = prevs[len(prevs)-1]
	}
	now := time.Now()
	y, m, d := now.Date()
	h, mn, s := now.Clock()
	current = filepath.Join(root, ".bb", fmt.Sprintf("index-%d-%02d%02d-%02d%02d%02d", y, m, d, h, mn, s))
	return current, previous, nil
}

func main() {
	log.SetFlags(log.Lshortfile)
	wd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	index, oldindex, err := initBB(wd)
	if err != nil {
		log.Fatal(err)
	}

	md := metamap{}
	if oldindex != "" {
		if md, err = readIndex(oldindex); err != nil {
			log.Fatal(err)
		}
	}
	data, err := getIndex(wd, md)
	if err != nil {
		log.Fatal(err)
	}
	err = os.WriteFile(index, []byte(data), 0o644)
	if err != nil {
		log.Fatal(err)
	}
}