-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocument.go
More file actions
111 lines (103 loc) · 3.73 KB
/
Copy pathdocument.go
File metadata and controls
111 lines (103 loc) · 3.73 KB
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
package codegraph
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"io/fs"
"sort"
"strings"
"github.com/compforge/codegraph/internal/analysis"
)
// Document is one source unit or opaque gitlink supplied for graph construction.
// It may come from
// a filesystem, a Git revision, or memory; it need not exist on disk.
// Path is a slash-separated, snapshot-relative logical path (fs.ValidPath).
// It supplies identity, language detection, relative-import context, and source
// locations. Content is the complete source at that path, with offsets from zero;
// a gitlink instead supplies its pinned commit and has no source locations.
// Snapshot identity belongs to Graph. Each input is represented by a DocumentKind
// node whose ID matches this document.
// +spec=`The same logical path identifies the same source unit across input batches`
type Document struct {
Path string
Content []byte
// Gitlink is the full pinned Git commit ID for an opaque submodule entry.
// Set it only for Git mode 160000; Content must be empty. The caller reads
// Git metadata. CodeGraph neither opens the checkout nor loads its symbols.
Gitlink string
}
// Identifiable has a stable identity within one Graph snapshot.
type Identifiable interface {
ID() string
}
// ID is the Document node identity for this source document.
func (d Document) ID() string { return DocumentID(d.Path) }
// AddDocuments admits an explicit batch and starts background graph construction.
// The batch is validated before any document is admitted. It returns after
// submission; callers can use GetDocument or FindAsync for early facts, and
// Wait to wait for complete graph publication. Input bytes are copied.
func (g *Graph) AddDocuments(ctx context.Context, documents ...Document) error {
_, err := g.enqueueDocuments(ctx, documents...)
return err
}
func (d Document) validate() error {
if !fs.ValidPath(d.Path) {
return fmt.Errorf("invalid source path %q", d.Path)
}
if d.Gitlink == "" {
return nil
}
if d.Path == "." {
return fmt.Errorf("gitlink must name an entry within the snapshot")
}
if len(d.Content) != 0 {
return fmt.Errorf("gitlink %s cannot also contain source bytes", d.Path)
}
if len(d.Gitlink) != 40 && len(d.Gitlink) != 64 {
return fmt.Errorf("gitlink %s requires a full commit object ID", d.Path)
}
if _, err := hex.DecodeString(d.Gitlink); err != nil {
return fmt.Errorf("gitlink %s: invalid commit object ID", d.Path)
}
return nil
}
func (d Document) same(other Document) bool {
return d.Gitlink == other.Gitlink && bytes.Equal(d.Content, other.Content)
}
func (d Document) matches(f analysis.Facts) bool {
return d.Gitlink == f.Gitlink && bytes.Equal(d.Content, f.Source)
}
func (d Document) size() int64 { return int64(len(d.Content) + len(d.Gitlink)) }
func (d Document) digest() [32]byte {
// Include the material type/version so a source or a different gitlink at
// the same path can never reuse an extraction from another snapshot.
h := sha256.New()
h.Write([]byte(d.Gitlink))
h.Write([]byte{0})
h.Write(d.Content)
var sum [32]byte
copy(sum[:], h.Sum(nil))
return sum
}
// A gitlink contributes one entry to the parent snapshot. Descendant materials
// belong to a different repository snapshot and cannot share that boundary.
func validateDocumentBoundaries(documents map[string]Document) error {
names := make([]string, 0, len(documents))
for p := range documents {
names = append(names, p)
}
sort.Strings(names)
for p, d := range documents {
if d.Gitlink == "" {
continue
}
prefix := p + "/"
i := sort.SearchStrings(names, prefix)
if i < len(names) && strings.HasPrefix(names[i], prefix) {
return fmt.Errorf("gitlink %s is an opaque boundary; document %s belongs to its child snapshot", p, names[i])
}
}
return nil
}