-
Notifications
You must be signed in to change notification settings - Fork 25
/
list.go
130 lines (120 loc) · 3.38 KB
/
list.go
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
125
126
127
128
129
130
package main
import (
"bufio"
"bytes"
"io/ioutil"
"path/filepath"
"strings"
shell "github.com/ipfs/go-ipfs-api"
"github.com/pkg/errors"
)
func listInfoRefs(forPush bool) error {
refsCat, err := ipfsShell.Cat(filepath.Join(ipfsRepoPath, "info", "refs"))
if err != nil {
return errors.Wrapf(err, "failed to cat info/refs from %s", ipfsRepoPath)
}
s := bufio.NewScanner(refsCat)
for s.Scan() {
hashRef := strings.Split(s.Text(), "\t")
if len(hashRef) != 2 {
return errors.Errorf("processing info/refs: what is this: %v", hashRef)
}
ref2hash[hashRef[1]] = hashRef[0]
}
if err := s.Err(); err != nil {
return errors.Wrapf(err, "ipfs.Cat(info/refs) scanner error")
}
return nil
}
func listHeadRef() (string, error) {
headCat, err := ipfsShell.Cat(filepath.Join(ipfsRepoPath, "HEAD"))
if err != nil {
return "", errors.Wrapf(err, "failed to cat HEAD from %s", ipfsRepoPath)
}
head, err := ioutil.ReadAll(headCat)
if err != nil {
return "", errors.Wrapf(err, "failed to readAll HEAD from %s", ipfsRepoPath)
}
if !bytes.HasPrefix(head, []byte("ref: ")) {
return "", errors.Errorf("illegal HEAD file from %s: %q", ipfsRepoPath, head)
}
headRef := string(bytes.TrimSpace(head[5:]))
headHash, ok := ref2hash[headRef]
if !ok {
// use first hash in map?..
return "", errors.Errorf("unknown HEAD reference %q", headRef)
}
return headHash, headCat.Close()
}
func listIterateRefs(forPush bool) error {
refsDir := filepath.Join(ipfsRepoPath, "refs")
return Walk(refsDir, func(p string, info *shell.LsLink, err error) error {
if err != nil {
return errors.Wrapf(err, "walk(%s) failed", p)
}
log.Log("event", "debug", "name", info.Name, "msg", "iterateRefs: walked to", "p", p)
if info.Type == 2 {
rc, err := ipfsShell.Cat(p)
if err != nil {
return errors.Wrapf(err, "walk(%s) cat ref failed", p)
}
data, err := ioutil.ReadAll(rc)
if err != nil {
return errors.Wrapf(err, "walk(%s) readAll failed", p)
}
if err := rc.Close(); err != nil {
return errors.Wrapf(err, "walk(%s) cat close failed", p)
}
sha1 := strings.TrimSpace(string(data))
refName := strings.TrimPrefix(p, ipfsRepoPath+"/")
ref2hash[refName] = sha1
log.Log("event", "debug", "refMap", ref2hash, "msg", "ref2hash map updated")
}
return nil
})
}
// semi-todo make shell implement http.FileSystem
// then we can reuse filepath.Walk and make a lot of other stuff simpler
var SkipDir = errors.Errorf("walk: skipping")
type WalkFunc func(path string, info *shell.LsLink, err error) error
func walk(path string, info *shell.LsLink, walkFn WalkFunc) error {
err := walkFn(path, info, nil)
if err != nil {
if info.Type == 1 && err == SkipDir {
return nil
}
return err
}
if info.Type != 1 {
return nil
}
list, err := ipfsShell.List(path)
if err != nil {
log.Log("msg", "walk list failed", "err", err)
return walkFn(path, info, err)
}
for _, lnk := range list {
fname := filepath.Join(path, lnk.Name)
err = walk(fname, lnk, walkFn)
if err != nil {
if lnk.Type != 1 || err != SkipDir {
return err
}
}
}
return nil
}
func Walk(root string, walkFn WalkFunc) error {
list, err := ipfsShell.List(root)
if err != nil {
log.Log("msg", "walk root failed", "err", err)
return walkFn(root, nil, err)
}
for _, l := range list {
fname := filepath.Join(root, l.Name)
if err := walk(fname, l, walkFn); err != nil {
return err
}
}
return nil
}