Exclude vendor dirs from git CRLF normalization (#10911)
* Exclude vendor dirs from git CRLF normalization Should get rid of a few warnings like at the end of `lint-backend` like https://drone.gitea.io/go-gitea/gitea/23117/1/4 * make vendor Co-authored-by: John Olheiser <john.olheiser@gmail.com> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>tokarchuk/v1.17
parent
8d99ee2773
commit
848502d04c
@ -1,35 +1,35 @@ |
|||||||
package commitgraph |
package commitgraph |
||||||
|
|
||||||
import ( |
import ( |
||||||
"time" |
"time" |
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing" |
"github.com/go-git/go-git/v5/plumbing" |
||||||
) |
) |
||||||
|
|
||||||
// CommitData is a reduced representation of Commit as presented in the commit graph
|
// CommitData is a reduced representation of Commit as presented in the commit graph
|
||||||
// file. It is merely useful as an optimization for walking the commit graphs.
|
// file. It is merely useful as an optimization for walking the commit graphs.
|
||||||
type CommitData struct { |
type CommitData struct { |
||||||
// TreeHash is the hash of the root tree of the commit.
|
// TreeHash is the hash of the root tree of the commit.
|
||||||
TreeHash plumbing.Hash |
TreeHash plumbing.Hash |
||||||
// ParentIndexes are the indexes of the parent commits of the commit.
|
// ParentIndexes are the indexes of the parent commits of the commit.
|
||||||
ParentIndexes []int |
ParentIndexes []int |
||||||
// ParentHashes are the hashes of the parent commits of the commit.
|
// ParentHashes are the hashes of the parent commits of the commit.
|
||||||
ParentHashes []plumbing.Hash |
ParentHashes []plumbing.Hash |
||||||
// Generation number is the pre-computed generation in the commit graph
|
// Generation number is the pre-computed generation in the commit graph
|
||||||
// or zero if not available
|
// or zero if not available
|
||||||
Generation int |
Generation int |
||||||
// When is the timestamp of the commit.
|
// When is the timestamp of the commit.
|
||||||
When time.Time |
When time.Time |
||||||
} |
} |
||||||
|
|
||||||
// Index represents a representation of commit graph that allows indexed
|
// Index represents a representation of commit graph that allows indexed
|
||||||
// access to the nodes using commit object hash
|
// access to the nodes using commit object hash
|
||||||
type Index interface { |
type Index interface { |
||||||
// GetIndexByHash gets the index in the commit graph from commit hash, if available
|
// GetIndexByHash gets the index in the commit graph from commit hash, if available
|
||||||
GetIndexByHash(h plumbing.Hash) (int, error) |
GetIndexByHash(h plumbing.Hash) (int, error) |
||||||
// GetNodeByIndex gets the commit node from the commit graph using index
|
// GetNodeByIndex gets the commit node from the commit graph using index
|
||||||
// obtained from child node, if available
|
// obtained from child node, if available
|
||||||
GetCommitDataByIndex(i int) (*CommitData, error) |
GetCommitDataByIndex(i int) (*CommitData, error) |
||||||
// Hashes returns all the hashes that are available in the index
|
// Hashes returns all the hashes that are available in the index
|
||||||
Hashes() []plumbing.Hash |
Hashes() []plumbing.Hash |
||||||
} |
} |
||||||
|
@ -1,188 +1,188 @@ |
|||||||
package commitgraph |
package commitgraph |
||||||
|
|
||||||
import ( |
import ( |
||||||
"crypto/sha1" |
"crypto/sha1" |
||||||
"hash" |
"hash" |
||||||
"io" |
"io" |
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing" |
"github.com/go-git/go-git/v5/plumbing" |
||||||
"github.com/go-git/go-git/v5/utils/binary" |
"github.com/go-git/go-git/v5/utils/binary" |
||||||
) |
) |
||||||
|
|
||||||
// Encoder writes MemoryIndex structs to an output stream.
|
// Encoder writes MemoryIndex structs to an output stream.
|
||||||
type Encoder struct { |
type Encoder struct { |
||||||
io.Writer |
io.Writer |
||||||
hash hash.Hash |
hash hash.Hash |
||||||
} |
} |
||||||
|
|
||||||
// NewEncoder returns a new stream encoder that writes to w.
|
// NewEncoder returns a new stream encoder that writes to w.
|
||||||
func NewEncoder(w io.Writer) *Encoder { |
func NewEncoder(w io.Writer) *Encoder { |
||||||
h := sha1.New() |
h := sha1.New() |
||||||
mw := io.MultiWriter(w, h) |
mw := io.MultiWriter(w, h) |
||||||
return &Encoder{mw, h} |
return &Encoder{mw, h} |
||||||
} |
} |
||||||
|
|
||||||
// Encode writes an index into the commit-graph file
|
// Encode writes an index into the commit-graph file
|
||||||
func (e *Encoder) Encode(idx Index) error { |
func (e *Encoder) Encode(idx Index) error { |
||||||
// Get all the hashes in the input index
|
// Get all the hashes in the input index
|
||||||
hashes := idx.Hashes() |
hashes := idx.Hashes() |
||||||
|
|
||||||
// Sort the inout and prepare helper structures we'll need for encoding
|
// Sort the inout and prepare helper structures we'll need for encoding
|
||||||
hashToIndex, fanout, extraEdgesCount := e.prepare(idx, hashes) |
hashToIndex, fanout, extraEdgesCount := e.prepare(idx, hashes) |
||||||
|
|
||||||
chunkSignatures := [][]byte{oidFanoutSignature, oidLookupSignature, commitDataSignature} |
chunkSignatures := [][]byte{oidFanoutSignature, oidLookupSignature, commitDataSignature} |
||||||
chunkSizes := []uint64{4 * 256, uint64(len(hashes)) * 20, uint64(len(hashes)) * 36} |
chunkSizes := []uint64{4 * 256, uint64(len(hashes)) * 20, uint64(len(hashes)) * 36} |
||||||
if extraEdgesCount > 0 { |
if extraEdgesCount > 0 { |
||||||
chunkSignatures = append(chunkSignatures, extraEdgeListSignature) |
chunkSignatures = append(chunkSignatures, extraEdgeListSignature) |
||||||
chunkSizes = append(chunkSizes, uint64(extraEdgesCount)*4) |
chunkSizes = append(chunkSizes, uint64(extraEdgesCount)*4) |
||||||
} |
} |
||||||
|
|
||||||
if err := e.encodeFileHeader(len(chunkSignatures)); err != nil { |
if err := e.encodeFileHeader(len(chunkSignatures)); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
if err := e.encodeChunkHeaders(chunkSignatures, chunkSizes); err != nil { |
if err := e.encodeChunkHeaders(chunkSignatures, chunkSizes); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
if err := e.encodeFanout(fanout); err != nil { |
if err := e.encodeFanout(fanout); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
if err := e.encodeOidLookup(hashes); err != nil { |
if err := e.encodeOidLookup(hashes); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
if extraEdges, err := e.encodeCommitData(hashes, hashToIndex, idx); err == nil { |
if extraEdges, err := e.encodeCommitData(hashes, hashToIndex, idx); err == nil { |
||||||
if err = e.encodeExtraEdges(extraEdges); err != nil { |
if err = e.encodeExtraEdges(extraEdges); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
} else { |
} else { |
||||||
return err |
return err |
||||||
} |
} |
||||||
|
|
||||||
return e.encodeChecksum() |
return e.encodeChecksum() |
||||||
} |
} |
||||||
|
|
||||||
func (e *Encoder) prepare(idx Index, hashes []plumbing.Hash) (hashToIndex map[plumbing.Hash]uint32, fanout []uint32, extraEdgesCount uint32) { |
func (e *Encoder) prepare(idx Index, hashes []plumbing.Hash) (hashToIndex map[plumbing.Hash]uint32, fanout []uint32, extraEdgesCount uint32) { |
||||||
// Sort the hashes and build our index
|
// Sort the hashes and build our index
|
||||||
plumbing.HashesSort(hashes) |
plumbing.HashesSort(hashes) |
||||||
hashToIndex = make(map[plumbing.Hash]uint32) |
hashToIndex = make(map[plumbing.Hash]uint32) |
||||||
fanout = make([]uint32, 256) |
fanout = make([]uint32, 256) |
||||||
for i, hash := range hashes { |
for i, hash := range hashes { |
||||||
hashToIndex[hash] = uint32(i) |
hashToIndex[hash] = uint32(i) |
||||||
fanout[hash[0]]++ |
fanout[hash[0]]++ |
||||||
} |
} |
||||||
|
|
||||||
// Convert the fanout to cumulative values
|
// Convert the fanout to cumulative values
|
||||||
for i := 1; i <= 0xff; i++ { |
for i := 1; i <= 0xff; i++ { |
||||||
fanout[i] += fanout[i-1] |
fanout[i] += fanout[i-1] |
||||||
} |
} |
||||||
|
|
||||||
// Find out if we will need extra edge table
|
// Find out if we will need extra edge table
|
||||||
for i := 0; i < len(hashes); i++ { |
for i := 0; i < len(hashes); i++ { |
||||||
v, _ := idx.GetCommitDataByIndex(i) |
v, _ := idx.GetCommitDataByIndex(i) |
||||||
if len(v.ParentHashes) > 2 { |
if len(v.ParentHashes) > 2 { |
||||||
extraEdgesCount += uint32(len(v.ParentHashes) - 1) |
extraEdgesCount += uint32(len(v.ParentHashes) - 1) |
||||||
break |
break |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
func (e *Encoder) encodeFileHeader(chunkCount int) (err error) { |
func (e *Encoder) encodeFileHeader(chunkCount int) (err error) { |
||||||
if _, err = e.Write(commitFileSignature); err == nil { |
if _, err = e.Write(commitFileSignature); err == nil { |
||||||
_, err = e.Write([]byte{1, 1, byte(chunkCount), 0}) |
_, err = e.Write([]byte{1, 1, byte(chunkCount), 0}) |
||||||
} |
} |
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
func (e *Encoder) encodeChunkHeaders(chunkSignatures [][]byte, chunkSizes []uint64) (err error) { |
func (e *Encoder) encodeChunkHeaders(chunkSignatures [][]byte, chunkSizes []uint64) (err error) { |
||||||
// 8 bytes of file header, 12 bytes for each chunk header and 12 byte for terminator
|
// 8 bytes of file header, 12 bytes for each chunk header and 12 byte for terminator
|
||||||
offset := uint64(8 + len(chunkSignatures)*12 + 12) |
offset := uint64(8 + len(chunkSignatures)*12 + 12) |
||||||
for i, signature := range chunkSignatures { |
for i, signature := range chunkSignatures { |
||||||
if _, err = e.Write(signature); err == nil { |
if _, err = e.Write(signature); err == nil { |
||||||
err = binary.WriteUint64(e, offset) |
err = binary.WriteUint64(e, offset) |
||||||
} |
} |
||||||
if err != nil { |
if err != nil { |
||||||
return |
return |
||||||
} |
} |
||||||
offset += chunkSizes[i] |
offset += chunkSizes[i] |
||||||
} |
} |
||||||
if _, err = e.Write(lastSignature); err == nil { |
if _, err = e.Write(lastSignature); err == nil { |
||||||
err = binary.WriteUint64(e, offset) |
err = binary.WriteUint64(e, offset) |
||||||
} |
} |
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
func (e *Encoder) encodeFanout(fanout []uint32) (err error) { |
func (e *Encoder) encodeFanout(fanout []uint32) (err error) { |
||||||
for i := 0; i <= 0xff; i++ { |
for i := 0; i <= 0xff; i++ { |
||||||
if err = binary.WriteUint32(e, fanout[i]); err != nil { |
if err = binary.WriteUint32(e, fanout[i]); err != nil { |
||||||
return |
return |
||||||
} |
} |
||||||
} |
} |
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
func (e *Encoder) encodeOidLookup(hashes []plumbing.Hash) (err error) { |
func (e *Encoder) encodeOidLookup(hashes []plumbing.Hash) (err error) { |
||||||
for _, hash := range hashes { |
for _, hash := range hashes { |
||||||
if _, err = e.Write(hash[:]); err != nil { |
if _, err = e.Write(hash[:]); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
} |
} |
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
func (e *Encoder) encodeCommitData(hashes []plumbing.Hash, hashToIndex map[plumbing.Hash]uint32, idx Index) (extraEdges []uint32, err error) { |
func (e *Encoder) encodeCommitData(hashes []plumbing.Hash, hashToIndex map[plumbing.Hash]uint32, idx Index) (extraEdges []uint32, err error) { |
||||||
for _, hash := range hashes { |
for _, hash := range hashes { |
||||||
origIndex, _ := idx.GetIndexByHash(hash) |
origIndex, _ := idx.GetIndexByHash(hash) |
||||||
commitData, _ := idx.GetCommitDataByIndex(origIndex) |
commitData, _ := idx.GetCommitDataByIndex(origIndex) |
||||||
if _, err = e.Write(commitData.TreeHash[:]); err != nil { |
if _, err = e.Write(commitData.TreeHash[:]); err != nil { |
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
var parent1, parent2 uint32 |
var parent1, parent2 uint32 |
||||||
if len(commitData.ParentHashes) == 0 { |
if len(commitData.ParentHashes) == 0 { |
||||||
parent1 = parentNone |
parent1 = parentNone |
||||||
parent2 = parentNone |
parent2 = parentNone |
||||||
} else if len(commitData.ParentHashes) == 1 { |
} else if len(commitData.ParentHashes) == 1 { |
||||||
parent1 = hashToIndex[commitData.ParentHashes[0]] |
parent1 = hashToIndex[commitData.ParentHashes[0]] |
||||||
parent2 = parentNone |
parent2 = parentNone |
||||||
} else if len(commitData.ParentHashes) == 2 { |
} else if len(commitData.ParentHashes) == 2 { |
||||||
parent1 = hashToIndex[commitData.ParentHashes[0]] |
parent1 = hashToIndex[commitData.ParentHashes[0]] |
||||||
parent2 = hashToIndex[commitData.ParentHashes[1]] |
parent2 = hashToIndex[commitData.ParentHashes[1]] |
||||||
} else if len(commitData.ParentHashes) > 2 { |
} else if len(commitData.ParentHashes) > 2 { |
||||||
parent1 = hashToIndex[commitData.ParentHashes[0]] |
parent1 = hashToIndex[commitData.ParentHashes[0]] |
||||||
parent2 = uint32(len(extraEdges)) | parentOctopusUsed |
parent2 = uint32(len(extraEdges)) | parentOctopusUsed |
||||||
for _, parentHash := range commitData.ParentHashes[1:] { |
for _, parentHash := range commitData.ParentHashes[1:] { |
||||||
extraEdges = append(extraEdges, hashToIndex[parentHash]) |
extraEdges = append(extraEdges, hashToIndex[parentHash]) |
||||||
} |
} |
||||||
extraEdges[len(extraEdges)-1] |= parentLast |
extraEdges[len(extraEdges)-1] |= parentLast |
||||||
} |
} |
||||||
|
|
||||||
if err = binary.WriteUint32(e, parent1); err == nil { |
if err = binary.WriteUint32(e, parent1); err == nil { |
||||||
err = binary.WriteUint32(e, parent2) |
err = binary.WriteUint32(e, parent2) |
||||||
} |
} |
||||||
if err != nil { |
if err != nil { |
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
unixTime := uint64(commitData.When.Unix()) |
unixTime := uint64(commitData.When.Unix()) |
||||||
unixTime |= uint64(commitData.Generation) << 34 |
unixTime |= uint64(commitData.Generation) << 34 |
||||||
if err = binary.WriteUint64(e, unixTime); err != nil { |
if err = binary.WriteUint64(e, unixTime); err != nil { |
||||||
return |
return |
||||||
} |
} |
||||||
} |
} |
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
func (e *Encoder) encodeExtraEdges(extraEdges []uint32) (err error) { |
func (e *Encoder) encodeExtraEdges(extraEdges []uint32) (err error) { |
||||||
for _, parent := range extraEdges { |
for _, parent := range extraEdges { |
||||||
if err = binary.WriteUint32(e, parent); err != nil { |
if err = binary.WriteUint32(e, parent); err != nil { |
||||||
return |
return |
||||||
} |
} |
||||||
} |
} |
||||||
return |
return |
||||||
} |
} |
||||||
|
|
||||||
func (e *Encoder) encodeChecksum() error { |
func (e *Encoder) encodeChecksum() error { |
||||||
_, err := e.Write(e.hash.Sum(nil)[:20]) |
_, err := e.Write(e.hash.Sum(nil)[:20]) |
||||||
return err |
return err |
||||||
} |
} |
||||||
|
@ -1,259 +1,259 @@ |
|||||||
package commitgraph |
package commitgraph |
||||||
|
|
||||||
import ( |
import ( |
||||||
"bytes" |
"bytes" |
||||||
encbin "encoding/binary" |
encbin "encoding/binary" |
||||||
"errors" |
"errors" |
||||||
"io" |
"io" |
||||||
"time" |
"time" |
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing" |
"github.com/go-git/go-git/v5/plumbing" |
||||||
"github.com/go-git/go-git/v5/utils/binary" |
"github.com/go-git/go-git/v5/utils/binary" |
||||||
) |
) |
||||||
|
|
||||||
var ( |
var ( |
||||||
// ErrUnsupportedVersion is returned by OpenFileIndex when the commit graph
|
// ErrUnsupportedVersion is returned by OpenFileIndex when the commit graph
|
||||||
// file version is not supported.
|
// file version is not supported.
|
||||||
ErrUnsupportedVersion = errors.New("Unsupported version") |
ErrUnsupportedVersion = errors.New("Unsupported version") |
||||||
// ErrUnsupportedHash is returned by OpenFileIndex when the commit graph
|
// ErrUnsupportedHash is returned by OpenFileIndex when the commit graph
|
||||||
// hash function is not supported. Currently only SHA-1 is defined and
|
// hash function is not supported. Currently only SHA-1 is defined and
|
||||||
// supported
|
// supported
|
||||||
ErrUnsupportedHash = errors.New("Unsupported hash algorithm") |
ErrUnsupportedHash = errors.New("Unsupported hash algorithm") |
||||||
// ErrMalformedCommitGraphFile is returned by OpenFileIndex when the commit
|
// ErrMalformedCommitGraphFile is returned by OpenFileIndex when the commit
|
||||||
// graph file is corrupted.
|
// graph file is corrupted.
|
||||||
ErrMalformedCommitGraphFile = errors.New("Malformed commit graph file") |
ErrMalformedCommitGraphFile = errors.New("Malformed commit graph file") |
||||||
|
|
||||||
commitFileSignature = []byte{'C', 'G', 'P', 'H'} |
commitFileSignature = []byte{'C', 'G', 'P', 'H'} |
||||||
oidFanoutSignature = []byte{'O', 'I', 'D', 'F'} |
oidFanoutSignature = []byte{'O', 'I', 'D', 'F'} |
||||||
oidLookupSignature = []byte{'O', 'I', 'D', 'L'} |
oidLookupSignature = []byte{'O', 'I', 'D', 'L'} |
||||||
commitDataSignature = []byte{'C', 'D', 'A', 'T'} |
commitDataSignature = []byte{'C', 'D', 'A', 'T'} |
||||||
extraEdgeListSignature = []byte{'E', 'D', 'G', 'E'} |
extraEdgeListSignature = []byte{'E', 'D', 'G', 'E'} |
||||||
lastSignature = []byte{0, 0, 0, 0} |
lastSignature = []byte{0, 0, 0, 0} |
||||||
|
|
||||||
parentNone = uint32(0x70000000) |
parentNone = uint32(0x70000000) |
||||||
parentOctopusUsed = uint32(0x80000000) |
parentOctopusUsed = uint32(0x80000000) |
||||||
parentOctopusMask = uint32(0x7fffffff) |
parentOctopusMask = uint32(0x7fffffff) |
||||||
parentLast = uint32(0x80000000) |
parentLast = uint32(0x80000000) |
||||||
) |
) |
||||||
|
|
||||||
type fileIndex struct { |
type fileIndex struct { |
||||||
reader io.ReaderAt |
reader io.ReaderAt |
||||||
fanout [256]int |
fanout [256]int |
||||||
oidFanoutOffset int64 |
oidFanoutOffset int64 |
||||||
oidLookupOffset int64 |
oidLookupOffset int64 |
||||||
commitDataOffset int64 |
commitDataOffset int64 |
||||||
extraEdgeListOffset int64 |
extraEdgeListOffset int64 |
||||||
} |
} |
||||||
|
|
||||||
// OpenFileIndex opens a serialized commit graph file in the format described at
|
// OpenFileIndex opens a serialized commit graph file in the format described at
|
||||||
// https://github.com/git/git/blob/master/Documentation/technical/commit-graph-format.txt
|
// https://github.com/git/git/blob/master/Documentation/technical/commit-graph-format.txt
|
||||||
func OpenFileIndex(reader io.ReaderAt) (Index, error) { |
func OpenFileIndex(reader io.ReaderAt) (Index, error) { |
||||||
fi := &fileIndex{reader: reader} |
fi := &fileIndex{reader: reader} |
||||||
|
|
||||||
if err := fi.verifyFileHeader(); err != nil { |
if err := fi.verifyFileHeader(); err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
if err := fi.readChunkHeaders(); err != nil { |
if err := fi.readChunkHeaders(); err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
if err := fi.readFanout(); err != nil { |
if err := fi.readFanout(); err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
|
|
||||||
return fi, nil |
return fi, nil |
||||||
} |
} |
||||||
|
|
||||||
func (fi *fileIndex) verifyFileHeader() error { |
func (fi *fileIndex) verifyFileHeader() error { |
||||||
// Verify file signature
|
// Verify file signature
|
||||||
var signature = make([]byte, 4) |
var signature = make([]byte, 4) |
||||||
if _, err := fi.reader.ReadAt(signature, 0); err != nil { |
if _, err := fi.reader.ReadAt(signature, 0); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
if !bytes.Equal(signature, commitFileSignature) { |
if !bytes.Equal(signature, commitFileSignature) { |
||||||
return ErrMalformedCommitGraphFile |
return ErrMalformedCommitGraphFile |
||||||
} |
} |
||||||
|
|
||||||
// Read and verify the file header
|
// Read and verify the file header
|
||||||
var header = make([]byte, 4) |
var header = make([]byte, 4) |
||||||
if _, err := fi.reader.ReadAt(header, 4); err != nil { |
if _, err := fi.reader.ReadAt(header, 4); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
if header[0] != 1 { |
if header[0] != 1 { |
||||||
return ErrUnsupportedVersion |
return ErrUnsupportedVersion |
||||||
} |
} |
||||||
if header[1] != 1 { |
if header[1] != 1 { |
||||||
return ErrUnsupportedHash |
return ErrUnsupportedHash |
||||||
} |
} |
||||||
|
|
||||||
return nil |
return nil |
||||||
} |
} |
||||||
|
|
||||||
func (fi *fileIndex) readChunkHeaders() error { |
func (fi *fileIndex) readChunkHeaders() error { |
||||||
var chunkID = make([]byte, 4) |
var chunkID = make([]byte, 4) |
||||||
for i := 0; ; i++ { |
for i := 0; ; i++ { |
||||||
chunkHeader := io.NewSectionReader(fi.reader, 8+(int64(i)*12), 12) |
chunkHeader := io.NewSectionReader(fi.reader, 8+(int64(i)*12), 12) |
||||||
if _, err := io.ReadAtLeast(chunkHeader, chunkID, 4); err != nil { |
if _, err := io.ReadAtLeast(chunkHeader, chunkID, 4); err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
chunkOffset, err := binary.ReadUint64(chunkHeader) |
chunkOffset, err := binary.ReadUint64(chunkHeader) |
||||||
if err != nil { |
if err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
|
|
||||||
if bytes.Equal(chunkID, oidFanoutSignature) { |
if bytes.Equal(chunkID, oidFanoutSignature) { |
||||||
fi.oidFanoutOffset = int64(chunkOffset) |
fi.oidFanoutOffset = int64(chunkOffset) |
||||||
} else if bytes.Equal(chunkID, oidLookupSignature) { |
} else if bytes.Equal(chunkID, oidLookupSignature) { |
||||||
fi.oidLookupOffset = int64(chunkOffset) |
fi.oidLookupOffset = int64(chunkOffset) |
||||||
} else if bytes.Equal(chunkID, commitDataSignature) { |
} else if bytes.Equal(chunkID, commitDataSignature) { |
||||||
fi.commitDataOffset = int64(chunkOffset) |
fi.commitDataOffset = int64(chunkOffset) |
||||||
} else if bytes.Equal(chunkID, extraEdgeListSignature) { |
} else if bytes.Equal(chunkID, extraEdgeListSignature) { |
||||||
fi.extraEdgeListOffset = int64(chunkOffset) |
fi.extraEdgeListOffset = int64(chunkOffset) |
||||||
} else if bytes.Equal(chunkID, lastSignature) { |
} else if bytes.Equal(chunkID, lastSignature) { |
||||||
break |
break |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
if fi.oidFanoutOffset <= 0 || fi.oidLookupOffset <= 0 || fi.commitDataOffset <= 0 { |
if fi.oidFanoutOffset <= 0 || fi.oidLookupOffset <= 0 || fi.commitDataOffset <= 0 { |
||||||
return ErrMalformedCommitGraphFile |
return ErrMalformedCommitGraphFile |
||||||
} |
} |
||||||
|
|
||||||
return nil |
return nil |
||||||
} |
} |
||||||
|
|
||||||
func (fi *fileIndex) readFanout() error { |
func (fi *fileIndex) readFanout() error { |
||||||
fanoutReader := io.NewSectionReader(fi.reader, fi.oidFanoutOffset, 256*4) |
fanoutReader := io.NewSectionReader(fi.reader, fi.oidFanoutOffset, 256*4) |
||||||
for i := 0; i < 256; i++ { |
for i := 0; i < 256; i++ { |
||||||
fanoutValue, err := binary.ReadUint32(fanoutReader) |
fanoutValue, err := binary.ReadUint32(fanoutReader) |
||||||
if err != nil { |
if err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
if fanoutValue > 0x7fffffff { |
if fanoutValue > 0x7fffffff { |
||||||
return ErrMalformedCommitGraphFile |
return ErrMalformedCommitGraphFile |
||||||
} |
} |
||||||
fi.fanout[i] = int(fanoutValue) |
fi.fanout[i] = int(fanoutValue) |
||||||
} |
} |
||||||
return nil |
return nil |
||||||
} |
} |
||||||
|
|
||||||
func (fi *fileIndex) GetIndexByHash(h plumbing.Hash) (int, error) { |
func (fi *fileIndex) GetIndexByHash(h plumbing.Hash) (int, error) { |
||||||
var oid plumbing.Hash |
var oid plumbing.Hash |
||||||
|
|
||||||
// Find the hash in the oid lookup table
|
// Find the hash in the oid lookup table
|
||||||
var low int |
var low int |
||||||
if h[0] == 0 { |
if h[0] == 0 { |
||||||
low = 0 |
low = 0 |
||||||
} else { |
} else { |
||||||
low = fi.fanout[h[0]-1] |
low = fi.fanout[h[0]-1] |
||||||
} |
} |
||||||
high := fi.fanout[h[0]] |
high := fi.fanout[h[0]] |
||||||
for low < high { |
for low < high { |
||||||
mid := (low + high) >> 1 |
mid := (low + high) >> 1 |
||||||
offset := fi.oidLookupOffset + int64(mid)*20 |
offset := fi.oidLookupOffset + int64(mid)*20 |
||||||
if _, err := fi.reader.ReadAt(oid[:], offset); err != nil { |
if _, err := fi.reader.ReadAt(oid[:], offset); err != nil { |
||||||
return 0, err |
return 0, err |
||||||
} |
} |
||||||
cmp := bytes.Compare(h[:], oid[:]) |
cmp := bytes.Compare(h[:], oid[:]) |
||||||
if cmp < 0 { |
if cmp < 0 { |
||||||
high = mid |
high = mid |
||||||
} else if cmp == 0 { |
} else if cmp == 0 { |
||||||
return mid, nil |
return mid, nil |
||||||
} else { |
} else { |
||||||
low = mid + 1 |
low = mid + 1 |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return 0, plumbing.ErrObjectNotFound |
return 0, plumbing.ErrObjectNotFound |
||||||
} |
} |
||||||
|
|
||||||
func (fi *fileIndex) GetCommitDataByIndex(idx int) (*CommitData, error) { |
func (fi *fileIndex) GetCommitDataByIndex(idx int) (*CommitData, error) { |
||||||
if idx >= fi.fanout[0xff] { |
if idx >= fi.fanout[0xff] { |
||||||
return nil, plumbing.ErrObjectNotFound |
return nil, plumbing.ErrObjectNotFound |
||||||
} |
} |
||||||
|
|
||||||
offset := fi.commitDataOffset + int64(idx)*36 |
offset := fi.commitDataOffset + int64(idx)*36 |
||||||
commitDataReader := io.NewSectionReader(fi.reader, offset, 36) |
commitDataReader := io.NewSectionReader(fi.reader, offset, 36) |
||||||
|
|
||||||
treeHash, err := binary.ReadHash(commitDataReader) |
treeHash, err := binary.ReadHash(commitDataReader) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
parent1, err := binary.ReadUint32(commitDataReader) |
parent1, err := binary.ReadUint32(commitDataReader) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
parent2, err := binary.ReadUint32(commitDataReader) |
parent2, err := binary.ReadUint32(commitDataReader) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
genAndTime, err := binary.ReadUint64(commitDataReader) |
genAndTime, err := binary.ReadUint64(commitDataReader) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
|
|
||||||
var parentIndexes []int |
var parentIndexes []int |
||||||
if parent2&parentOctopusUsed == parentOctopusUsed { |
if parent2&parentOctopusUsed == parentOctopusUsed { |
||||||
// Octopus merge
|
// Octopus merge
|
||||||
parentIndexes = []int{int(parent1 & parentOctopusMask)} |
parentIndexes = []int{int(parent1 & parentOctopusMask)} |
||||||
offset := fi.extraEdgeListOffset + 4*int64(parent2&parentOctopusMask) |
offset := fi.extraEdgeListOffset + 4*int64(parent2&parentOctopusMask) |
||||||
buf := make([]byte, 4) |
buf := make([]byte, 4) |
||||||
for { |
for { |
||||||
_, err := fi.reader.ReadAt(buf, offset) |
_, err := fi.reader.ReadAt(buf, offset) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
|
|
||||||
parent := encbin.BigEndian.Uint32(buf) |
parent := encbin.BigEndian.Uint32(buf) |
||||||
offset += 4 |
offset += 4 |
||||||
parentIndexes = append(parentIndexes, int(parent&parentOctopusMask)) |
parentIndexes = append(parentIndexes, int(parent&parentOctopusMask)) |
||||||
if parent&parentLast == parentLast { |
if parent&parentLast == parentLast { |
||||||
break |
break |
||||||
} |
} |
||||||
} |
} |
||||||
} else if parent2 != parentNone { |
} else if parent2 != parentNone { |
||||||
parentIndexes = []int{int(parent1 & parentOctopusMask), int(parent2 & parentOctopusMask)} |
parentIndexes = []int{int(parent1 & parentOctopusMask), int(parent2 & parentOctopusMask)} |
||||||
} else if parent1 != parentNone { |
} else if parent1 != parentNone { |
||||||
parentIndexes = []int{int(parent1 & parentOctopusMask)} |
parentIndexes = []int{int(parent1 & parentOctopusMask)} |
||||||
} |
} |
||||||
|
|
||||||
parentHashes, err := fi.getHashesFromIndexes(parentIndexes) |
parentHashes, err := fi.getHashesFromIndexes(parentIndexes) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
|
|
||||||
return &CommitData{ |
return &CommitData{ |
||||||
TreeHash: treeHash, |
TreeHash: treeHash, |
||||||
ParentIndexes: parentIndexes, |
ParentIndexes: parentIndexes, |
||||||
ParentHashes: parentHashes, |
ParentHashes: parentHashes, |
||||||
Generation: int(genAndTime >> 34), |
Generation: int(genAndTime >> 34), |
||||||
When: time.Unix(int64(genAndTime&0x3FFFFFFFF), 0), |
When: time.Unix(int64(genAndTime&0x3FFFFFFFF), 0), |
||||||
}, nil |
}, nil |
||||||
} |
} |
||||||
|
|
||||||
func (fi *fileIndex) getHashesFromIndexes(indexes []int) ([]plumbing.Hash, error) { |
func (fi *fileIndex) getHashesFromIndexes(indexes []int) ([]plumbing.Hash, error) { |
||||||
hashes := make([]plumbing.Hash, len(indexes)) |
hashes := make([]plumbing.Hash, len(indexes)) |
||||||
|
|
||||||
for i, idx := range indexes { |
for i, idx := range indexes { |
||||||
if idx >= fi.fanout[0xff] { |
if idx >= fi.fanout[0xff] { |
||||||
return nil, ErrMalformedCommitGraphFile |
return nil, ErrMalformedCommitGraphFile |
||||||
} |
} |
||||||
|
|
||||||
offset := fi.oidLookupOffset + int64(idx)*20 |
offset := fi.oidLookupOffset + int64(idx)*20 |
||||||
if _, err := fi.reader.ReadAt(hashes[i][:], offset); err != nil { |
if _, err := fi.reader.ReadAt(hashes[i][:], offset); err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return hashes, nil |
return hashes, nil |
||||||
} |
} |
||||||
|
|
||||||
// Hashes returns all the hashes that are available in the index
|
// Hashes returns all the hashes that are available in the index
|
||||||
func (fi *fileIndex) Hashes() []plumbing.Hash { |
func (fi *fileIndex) Hashes() []plumbing.Hash { |
||||||
hashes := make([]plumbing.Hash, fi.fanout[0xff]) |
hashes := make([]plumbing.Hash, fi.fanout[0xff]) |
||||||
for i := 0; i < fi.fanout[0xff]; i++ { |
for i := 0; i < fi.fanout[0xff]; i++ { |
||||||
offset := fi.oidLookupOffset + int64(i)*20 |
offset := fi.oidLookupOffset + int64(i)*20 |
||||||
if n, err := fi.reader.ReadAt(hashes[i][:], offset); err != nil || n < 20 { |
if n, err := fi.reader.ReadAt(hashes[i][:], offset); err != nil || n < 20 { |
||||||
return nil |
return nil |
||||||
} |
} |
||||||
} |
} |
||||||
return hashes |
return hashes |
||||||
} |
} |
||||||
|
@ -1,72 +1,72 @@ |
|||||||
package commitgraph |
package commitgraph |
||||||
|
|
||||||
import ( |
import ( |
||||||
"github.com/go-git/go-git/v5/plumbing" |
"github.com/go-git/go-git/v5/plumbing" |
||||||
) |
) |
||||||
|
|
||||||
// MemoryIndex provides a way to build the commit-graph in memory
|
// MemoryIndex provides a way to build the commit-graph in memory
|
||||||
// for later encoding to file.
|
// for later encoding to file.
|
||||||
type MemoryIndex struct { |
type MemoryIndex struct { |
||||||
commitData []*CommitData |
commitData []*CommitData |
||||||
indexMap map[plumbing.Hash]int |
indexMap map[plumbing.Hash]int |
||||||
} |
} |
||||||
|
|
||||||
// NewMemoryIndex creates in-memory commit graph representation
|
// NewMemoryIndex creates in-memory commit graph representation
|
||||||
func NewMemoryIndex() *MemoryIndex { |
func NewMemoryIndex() *MemoryIndex { |
||||||
return &MemoryIndex{ |
return &MemoryIndex{ |
||||||
indexMap: make(map[plumbing.Hash]int), |
indexMap: make(map[plumbing.Hash]int), |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
// GetIndexByHash gets the index in the commit graph from commit hash, if available
|
// GetIndexByHash gets the index in the commit graph from commit hash, if available
|
||||||
func (mi *MemoryIndex) GetIndexByHash(h plumbing.Hash) (int, error) { |
func (mi *MemoryIndex) GetIndexByHash(h plumbing.Hash) (int, error) { |
||||||
i, ok := mi.indexMap[h] |
i, ok := mi.indexMap[h] |
||||||
if ok { |
if ok { |
||||||
return i, nil |
return i, nil |
||||||
} |
} |
||||||
|
|
||||||
return 0, plumbing.ErrObjectNotFound |
return 0, plumbing.ErrObjectNotFound |
||||||
} |
} |
||||||
|
|
||||||
// GetCommitDataByIndex gets the commit node from the commit graph using index
|
// GetCommitDataByIndex gets the commit node from the commit graph using index
|
||||||
// obtained from child node, if available
|
// obtained from child node, if available
|
||||||
func (mi *MemoryIndex) GetCommitDataByIndex(i int) (*CommitData, error) { |
func (mi *MemoryIndex) GetCommitDataByIndex(i int) (*CommitData, error) { |
||||||
if i >= len(mi.commitData) { |
if i >= len(mi.commitData) { |
||||||
return nil, plumbing.ErrObjectNotFound |
return nil, plumbing.ErrObjectNotFound |
||||||
} |
} |
||||||
|
|
||||||
commitData := mi.commitData[i] |
commitData := mi.commitData[i] |
||||||
|
|
||||||
// Map parent hashes to parent indexes
|
// Map parent hashes to parent indexes
|
||||||
if commitData.ParentIndexes == nil { |
if commitData.ParentIndexes == nil { |
||||||
parentIndexes := make([]int, len(commitData.ParentHashes)) |
parentIndexes := make([]int, len(commitData.ParentHashes)) |
||||||
for i, parentHash := range commitData.ParentHashes { |
for i, parentHash := range commitData.ParentHashes { |
||||||
var err error |
var err error |
||||||
if parentIndexes[i], err = mi.GetIndexByHash(parentHash); err != nil { |
if parentIndexes[i], err = mi.GetIndexByHash(parentHash); err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
} |
} |
||||||
commitData.ParentIndexes = parentIndexes |
commitData.ParentIndexes = parentIndexes |
||||||
} |
} |
||||||
|
|
||||||
return commitData, nil |
return commitData, nil |
||||||
} |
} |
||||||
|
|
||||||
// Hashes returns all the hashes that are available in the index
|
// Hashes returns all the hashes that are available in the index
|
||||||
func (mi *MemoryIndex) Hashes() []plumbing.Hash { |
func (mi *MemoryIndex) Hashes() []plumbing.Hash { |
||||||
hashes := make([]plumbing.Hash, 0, len(mi.indexMap)) |
hashes := make([]plumbing.Hash, 0, len(mi.indexMap)) |
||||||
for k := range mi.indexMap { |
for k := range mi.indexMap { |
||||||
hashes = append(hashes, k) |
hashes = append(hashes, k) |
||||||
} |
} |
||||||
return hashes |
return hashes |
||||||
} |
} |
||||||
|
|
||||||
// Add adds new node to the memory index
|
// Add adds new node to the memory index
|
||||||
func (mi *MemoryIndex) Add(hash plumbing.Hash, commitData *CommitData) { |
func (mi *MemoryIndex) Add(hash plumbing.Hash, commitData *CommitData) { |
||||||
// The parent indexes are calculated lazily in GetNodeByIndex
|
// The parent indexes are calculated lazily in GetNodeByIndex
|
||||||
// which allows adding nodes out of order as long as all parents
|
// which allows adding nodes out of order as long as all parents
|
||||||
// are eventually resolved
|
// are eventually resolved
|
||||||
commitData.ParentIndexes = nil |
commitData.ParentIndexes = nil |
||||||
mi.indexMap[hash] = len(mi.commitData) |
mi.indexMap[hash] = len(mi.commitData) |
||||||
mi.commitData = append(mi.commitData, commitData) |
mi.commitData = append(mi.commitData, commitData) |
||||||
} |
} |
||||||
|
@ -1,98 +1,98 @@ |
|||||||
package commitgraph |
package commitgraph |
||||||
|
|
||||||
import ( |
import ( |
||||||
"io" |
"io" |
||||||
"time" |
"time" |
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing" |
"github.com/go-git/go-git/v5/plumbing" |
||||||
"github.com/go-git/go-git/v5/plumbing/object" |
"github.com/go-git/go-git/v5/plumbing/object" |
||||||
"github.com/go-git/go-git/v5/plumbing/storer" |
"github.com/go-git/go-git/v5/plumbing/storer" |
||||||
) |
) |
||||||
|
|
||||||
// CommitNode is generic interface encapsulating a lightweight commit object retrieved
|
// CommitNode is generic interface encapsulating a lightweight commit object retrieved
|
||||||
// from CommitNodeIndex
|
// from CommitNodeIndex
|
||||||
type CommitNode interface { |
type CommitNode interface { |
||||||
// ID returns the Commit object id referenced by the commit graph node.
|
// ID returns the Commit object id referenced by the commit graph node.
|
||||||
ID() plumbing.Hash |
ID() plumbing.Hash |
||||||
// Tree returns the Tree referenced by the commit graph node.
|
// Tree returns the Tree referenced by the commit graph node.
|
||||||
Tree() (*object.Tree, error) |
Tree() (*object.Tree, error) |
||||||
// CommitTime returns the Commiter.When time of the Commit referenced by the commit graph node.
|
// CommitTime returns the Commiter.When time of the Commit referenced by the commit graph node.
|
||||||
CommitTime() time.Time |
CommitTime() time.Time |
||||||
// NumParents returns the number of parents in a commit.
|
// NumParents returns the number of parents in a commit.
|
||||||
NumParents() int |
NumParents() int |
||||||
// ParentNodes return a CommitNodeIter for parents of specified node.
|
// ParentNodes return a CommitNodeIter for parents of specified node.
|
||||||
ParentNodes() CommitNodeIter |
ParentNodes() CommitNodeIter |
||||||
// ParentNode returns the ith parent of a commit.
|
// ParentNode returns the ith parent of a commit.
|
||||||
ParentNode(i int) (CommitNode, error) |
ParentNode(i int) (CommitNode, error) |
||||||
// ParentHashes returns hashes of the parent commits for a specified node
|
// ParentHashes returns hashes of the parent commits for a specified node
|
||||||
ParentHashes() []plumbing.Hash |
ParentHashes() []plumbing.Hash |
||||||
// Generation returns the generation of the commit for reachability analysis.
|
// Generation returns the generation of the commit for reachability analysis.
|
||||||
// Objects with newer generation are not reachable from objects of older generation.
|
// Objects with newer generation are not reachable from objects of older generation.
|
||||||
Generation() uint64 |
Generation() uint64 |
||||||
// Commit returns the full commit object from the node
|
// Commit returns the full commit object from the node
|
||||||
Commit() (*object.Commit, error) |
Commit() (*object.Commit, error) |
||||||
} |
} |
||||||
|
|
||||||
// CommitNodeIndex is generic interface encapsulating an index of CommitNode objects
|
// CommitNodeIndex is generic interface encapsulating an index of CommitNode objects
|
||||||
type CommitNodeIndex interface { |
type CommitNodeIndex interface { |
||||||
// Get returns a commit node from a commit hash
|
// Get returns a commit node from a commit hash
|
||||||
Get(hash plumbing.Hash) (CommitNode, error) |
Get(hash plumbing.Hash) (CommitNode, error) |
||||||
} |
} |
||||||
|
|
||||||
// CommitNodeIter is a generic closable interface for iterating over commit nodes.
|
// CommitNodeIter is a generic closable interface for iterating over commit nodes.
|
||||||
type CommitNodeIter interface { |
type CommitNodeIter interface { |
||||||
Next() (CommitNode, error) |
Next() (CommitNode, error) |
||||||
ForEach(func(CommitNode) error) error |
ForEach(func(CommitNode) error) error |
||||||
Close() |
Close() |
||||||
} |
} |
||||||
|
|
||||||
// parentCommitNodeIter provides an iterator for parent commits from associated CommitNodeIndex.
|
// parentCommitNodeIter provides an iterator for parent commits from associated CommitNodeIndex.
|
||||||
type parentCommitNodeIter struct { |
type parentCommitNodeIter struct { |
||||||
node CommitNode |
node CommitNode |
||||||
i int |
i int |
||||||
} |
} |
||||||
|
|
||||||
func newParentgraphCommitNodeIter(node CommitNode) CommitNodeIter { |
func newParentgraphCommitNodeIter(node CommitNode) CommitNodeIter { |
||||||
return &parentCommitNodeIter{node, 0} |
return &parentCommitNodeIter{node, 0} |
||||||
} |
} |
||||||
|
|
||||||
// Next moves the iterator to the next commit and returns a pointer to it. If
|
// Next moves the iterator to the next commit and returns a pointer to it. If
|
||||||
// there are no more commits, it returns io.EOF.
|
// there are no more commits, it returns io.EOF.
|
||||||
func (iter *parentCommitNodeIter) Next() (CommitNode, error) { |
func (iter *parentCommitNodeIter) Next() (CommitNode, error) { |
||||||
obj, err := iter.node.ParentNode(iter.i) |
obj, err := iter.node.ParentNode(iter.i) |
||||||
if err == object.ErrParentNotFound { |
if err == object.ErrParentNotFound { |
||||||
return nil, io.EOF |
return nil, io.EOF |
||||||
} |
} |
||||||
if err == nil { |
if err == nil { |
||||||
iter.i++ |
iter.i++ |
||||||
} |
} |
||||||
|
|
||||||
return obj, err |
return obj, err |
||||||
} |
} |
||||||
|
|
||||||
// ForEach call the cb function for each commit contained on this iter until
|
// ForEach call the cb function for each commit contained on this iter until
|
||||||
// an error appends or the end of the iter is reached. If ErrStop is sent
|
// an error appends or the end of the iter is reached. If ErrStop is sent
|
||||||
// the iteration is stopped but no error is returned. The iterator is closed.
|
// the iteration is stopped but no error is returned. The iterator is closed.
|
||||||
func (iter *parentCommitNodeIter) ForEach(cb func(CommitNode) error) error { |
func (iter *parentCommitNodeIter) ForEach(cb func(CommitNode) error) error { |
||||||
for { |
for { |
||||||
obj, err := iter.Next() |
obj, err := iter.Next() |
||||||
if err != nil { |
if err != nil { |
||||||
if err == io.EOF { |
if err == io.EOF { |
||||||
return nil |
return nil |
||||||
} |
} |
||||||
|
|
||||||
return err |
return err |
||||||
} |
} |
||||||
|
|
||||||
if err := cb(obj); err != nil { |
if err := cb(obj); err != nil { |
||||||
if err == storer.ErrStop { |
if err == storer.ErrStop { |
||||||
return nil |
return nil |
||||||
} |
} |
||||||
|
|
||||||
return err |
return err |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
func (iter *parentCommitNodeIter) Close() { |
func (iter *parentCommitNodeIter) Close() { |
||||||
} |
} |
||||||
|
262
vendor/github.com/go-git/go-git/v5/plumbing/object/commitgraph/commitnode_graph.go
generated
vendored
262
vendor/github.com/go-git/go-git/v5/plumbing/object/commitgraph/commitnode_graph.go
generated
vendored
@ -1,131 +1,131 @@ |
|||||||
package commitgraph |
package commitgraph |
||||||
|
|
||||||
import ( |
import ( |
||||||
"fmt" |
"fmt" |
||||||
"time" |
"time" |
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing" |
"github.com/go-git/go-git/v5/plumbing" |
||||||
"github.com/go-git/go-git/v5/plumbing/format/commitgraph" |
"github.com/go-git/go-git/v5/plumbing/format/commitgraph" |
||||||
"github.com/go-git/go-git/v5/plumbing/object" |
"github.com/go-git/go-git/v5/plumbing/object" |
||||||
"github.com/go-git/go-git/v5/plumbing/storer" |
"github.com/go-git/go-git/v5/plumbing/storer" |
||||||
) |
) |
||||||
|
|
||||||
// graphCommitNode is a reduced representation of Commit as presented in the commit
|
// graphCommitNode is a reduced representation of Commit as presented in the commit
|
||||||
// graph file (commitgraph.Node). It is merely useful as an optimization for walking
|
// graph file (commitgraph.Node). It is merely useful as an optimization for walking
|
||||||
// the commit graphs.
|
// the commit graphs.
|
||||||
//
|
//
|
||||||
// graphCommitNode implements the CommitNode interface.
|
// graphCommitNode implements the CommitNode interface.
|
||||||
type graphCommitNode struct { |
type graphCommitNode struct { |
||||||
// Hash for the Commit object
|
// Hash for the Commit object
|
||||||
hash plumbing.Hash |
hash plumbing.Hash |
||||||
// Index of the node in the commit graph file
|
// Index of the node in the commit graph file
|
||||||
index int |
index int |
||||||
|
|
||||||
commitData *commitgraph.CommitData |
commitData *commitgraph.CommitData |
||||||
gci *graphCommitNodeIndex |
gci *graphCommitNodeIndex |
||||||
} |
} |
||||||
|
|
||||||
// graphCommitNodeIndex is an index that can load CommitNode objects from both the commit
|
// graphCommitNodeIndex is an index that can load CommitNode objects from both the commit
|
||||||
// graph files and the object store.
|
// graph files and the object store.
|
||||||
//
|
//
|
||||||
// graphCommitNodeIndex implements the CommitNodeIndex interface
|
// graphCommitNodeIndex implements the CommitNodeIndex interface
|
||||||
type graphCommitNodeIndex struct { |
type graphCommitNodeIndex struct { |
||||||
commitGraph commitgraph.Index |
commitGraph commitgraph.Index |
||||||
s storer.EncodedObjectStorer |
s storer.EncodedObjectStorer |
||||||
} |
} |
||||||
|
|
||||||
// NewGraphCommitNodeIndex returns CommitNodeIndex implementation that uses commit-graph
|
// NewGraphCommitNodeIndex returns CommitNodeIndex implementation that uses commit-graph
|
||||||
// files as backing storage and falls back to object storage when necessary
|
// files as backing storage and falls back to object storage when necessary
|
||||||
func NewGraphCommitNodeIndex(commitGraph commitgraph.Index, s storer.EncodedObjectStorer) CommitNodeIndex { |
func NewGraphCommitNodeIndex(commitGraph commitgraph.Index, s storer.EncodedObjectStorer) CommitNodeIndex { |
||||||
return &graphCommitNodeIndex{commitGraph, s} |
return &graphCommitNodeIndex{commitGraph, s} |
||||||
} |
} |
||||||
|
|
||||||
func (gci *graphCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) { |
func (gci *graphCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) { |
||||||
// Check the commit graph first
|
// Check the commit graph first
|
||||||
parentIndex, err := gci.commitGraph.GetIndexByHash(hash) |
parentIndex, err := gci.commitGraph.GetIndexByHash(hash) |
||||||
if err == nil { |
if err == nil { |
||||||
parent, err := gci.commitGraph.GetCommitDataByIndex(parentIndex) |
parent, err := gci.commitGraph.GetCommitDataByIndex(parentIndex) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
|
|
||||||
return &graphCommitNode{ |
return &graphCommitNode{ |
||||||
hash: hash, |
hash: hash, |
||||||
index: parentIndex, |
index: parentIndex, |
||||||
commitData: parent, |
commitData: parent, |
||||||
gci: gci, |
gci: gci, |
||||||
}, nil |
}, nil |
||||||
} |
} |
||||||
|
|
||||||
// Fallback to loading full commit object
|
// Fallback to loading full commit object
|
||||||
commit, err := object.GetCommit(gci.s, hash) |
commit, err := object.GetCommit(gci.s, hash) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
|
|
||||||
return &objectCommitNode{ |
return &objectCommitNode{ |
||||||
nodeIndex: gci, |
nodeIndex: gci, |
||||||
commit: commit, |
commit: commit, |
||||||
}, nil |
}, nil |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) ID() plumbing.Hash { |
func (c *graphCommitNode) ID() plumbing.Hash { |
||||||
return c.hash |
return c.hash |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) Tree() (*object.Tree, error) { |
func (c *graphCommitNode) Tree() (*object.Tree, error) { |
||||||
return object.GetTree(c.gci.s, c.commitData.TreeHash) |
return object.GetTree(c.gci.s, c.commitData.TreeHash) |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) CommitTime() time.Time { |
func (c *graphCommitNode) CommitTime() time.Time { |
||||||
return c.commitData.When |
return c.commitData.When |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) NumParents() int { |
func (c *graphCommitNode) NumParents() int { |
||||||
return len(c.commitData.ParentIndexes) |
return len(c.commitData.ParentIndexes) |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) ParentNodes() CommitNodeIter { |
func (c *graphCommitNode) ParentNodes() CommitNodeIter { |
||||||
return newParentgraphCommitNodeIter(c) |
return newParentgraphCommitNodeIter(c) |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) ParentNode(i int) (CommitNode, error) { |
func (c *graphCommitNode) ParentNode(i int) (CommitNode, error) { |
||||||
if i < 0 || i >= len(c.commitData.ParentIndexes) { |
if i < 0 || i >= len(c.commitData.ParentIndexes) { |
||||||
return nil, object.ErrParentNotFound |
return nil, object.ErrParentNotFound |
||||||
} |
} |
||||||
|
|
||||||
parent, err := c.gci.commitGraph.GetCommitDataByIndex(c.commitData.ParentIndexes[i]) |
parent, err := c.gci.commitGraph.GetCommitDataByIndex(c.commitData.ParentIndexes[i]) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
|
|
||||||
return &graphCommitNode{ |
return &graphCommitNode{ |
||||||
hash: c.commitData.ParentHashes[i], |
hash: c.commitData.ParentHashes[i], |
||||||
index: c.commitData.ParentIndexes[i], |
index: c.commitData.ParentIndexes[i], |
||||||
commitData: parent, |
commitData: parent, |
||||||
gci: c.gci, |
gci: c.gci, |
||||||
}, nil |
}, nil |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) ParentHashes() []plumbing.Hash { |
func (c *graphCommitNode) ParentHashes() []plumbing.Hash { |
||||||
return c.commitData.ParentHashes |
return c.commitData.ParentHashes |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) Generation() uint64 { |
func (c *graphCommitNode) Generation() uint64 { |
||||||
// If the commit-graph file was generated with older Git version that
|
// If the commit-graph file was generated with older Git version that
|
||||||
// set the generation to zero for every commit the generation assumption
|
// set the generation to zero for every commit the generation assumption
|
||||||
// is still valid. It is just less useful.
|
// is still valid. It is just less useful.
|
||||||
return uint64(c.commitData.Generation) |
return uint64(c.commitData.Generation) |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) Commit() (*object.Commit, error) { |
func (c *graphCommitNode) Commit() (*object.Commit, error) { |
||||||
return object.GetCommit(c.gci.s, c.hash) |
return object.GetCommit(c.gci.s, c.hash) |
||||||
} |
} |
||||||
|
|
||||||
func (c *graphCommitNode) String() string { |
func (c *graphCommitNode) String() string { |
||||||
return fmt.Sprintf( |
return fmt.Sprintf( |
||||||
"%s %s\nDate: %s", |
"%s %s\nDate: %s", |
||||||
plumbing.CommitObject, c.ID(), |
plumbing.CommitObject, c.ID(), |
||||||
c.CommitTime().Format(object.DateFormat), |
c.CommitTime().Format(object.DateFormat), |
||||||
) |
) |
||||||
} |
} |
||||||
|
180
vendor/github.com/go-git/go-git/v5/plumbing/object/commitgraph/commitnode_object.go
generated
vendored
180
vendor/github.com/go-git/go-git/v5/plumbing/object/commitgraph/commitnode_object.go
generated
vendored
@ -1,90 +1,90 @@ |
|||||||
package commitgraph |
package commitgraph |
||||||
|
|
||||||
import ( |
import ( |
||||||
"math" |
"math" |
||||||
"time" |
"time" |
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing" |
"github.com/go-git/go-git/v5/plumbing" |
||||||
"github.com/go-git/go-git/v5/plumbing/object" |
"github.com/go-git/go-git/v5/plumbing/object" |
||||||
"github.com/go-git/go-git/v5/plumbing/storer" |
"github.com/go-git/go-git/v5/plumbing/storer" |
||||||
) |
) |
||||||
|
|
||||||
// objectCommitNode is a representation of Commit as presented in the GIT object format.
|
// objectCommitNode is a representation of Commit as presented in the GIT object format.
|
||||||
//
|
//
|
||||||
// objectCommitNode implements the CommitNode interface.
|
// objectCommitNode implements the CommitNode interface.
|
||||||
type objectCommitNode struct { |
type objectCommitNode struct { |
||||||
nodeIndex CommitNodeIndex |
nodeIndex CommitNodeIndex |
||||||
commit *object.Commit |
commit *object.Commit |
||||||
} |
} |
||||||
|
|
||||||
// NewObjectCommitNodeIndex returns CommitNodeIndex implementation that uses
|
// NewObjectCommitNodeIndex returns CommitNodeIndex implementation that uses
|
||||||
// only object storage to load the nodes
|
// only object storage to load the nodes
|
||||||
func NewObjectCommitNodeIndex(s storer.EncodedObjectStorer) CommitNodeIndex { |
func NewObjectCommitNodeIndex(s storer.EncodedObjectStorer) CommitNodeIndex { |
||||||
return &objectCommitNodeIndex{s} |
return &objectCommitNodeIndex{s} |
||||||
} |
} |
||||||
|
|
||||||
func (oci *objectCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) { |
func (oci *objectCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) { |
||||||
commit, err := object.GetCommit(oci.s, hash) |
commit, err := object.GetCommit(oci.s, hash) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
|
|
||||||
return &objectCommitNode{ |
return &objectCommitNode{ |
||||||
nodeIndex: oci, |
nodeIndex: oci, |
||||||
commit: commit, |
commit: commit, |
||||||
}, nil |
}, nil |
||||||
} |
} |
||||||
|
|
||||||
// objectCommitNodeIndex is an index that can load CommitNode objects only from the
|
// objectCommitNodeIndex is an index that can load CommitNode objects only from the
|
||||||
// object store.
|
// object store.
|
||||||
//
|
//
|
||||||
// objectCommitNodeIndex implements the CommitNodeIndex interface
|
// objectCommitNodeIndex implements the CommitNodeIndex interface
|
||||||
type objectCommitNodeIndex struct { |
type objectCommitNodeIndex struct { |
||||||
s storer.EncodedObjectStorer |
s storer.EncodedObjectStorer |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) CommitTime() time.Time { |
func (c *objectCommitNode) CommitTime() time.Time { |
||||||
return c.commit.Committer.When |
return c.commit.Committer.When |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) ID() plumbing.Hash { |
func (c *objectCommitNode) ID() plumbing.Hash { |
||||||
return c.commit.ID() |
return c.commit.ID() |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) Tree() (*object.Tree, error) { |
func (c *objectCommitNode) Tree() (*object.Tree, error) { |
||||||
return c.commit.Tree() |
return c.commit.Tree() |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) NumParents() int { |
func (c *objectCommitNode) NumParents() int { |
||||||
return c.commit.NumParents() |
return c.commit.NumParents() |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) ParentNodes() CommitNodeIter { |
func (c *objectCommitNode) ParentNodes() CommitNodeIter { |
||||||
return newParentgraphCommitNodeIter(c) |
return newParentgraphCommitNodeIter(c) |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) ParentNode(i int) (CommitNode, error) { |
func (c *objectCommitNode) ParentNode(i int) (CommitNode, error) { |
||||||
if i < 0 || i >= len(c.commit.ParentHashes) { |
if i < 0 || i >= len(c.commit.ParentHashes) { |
||||||
return nil, object.ErrParentNotFound |
return nil, object.ErrParentNotFound |
||||||
} |
} |
||||||
|
|
||||||
// Note: It's necessary to go through CommitNodeIndex here to ensure
|
// Note: It's necessary to go through CommitNodeIndex here to ensure
|
||||||
// that if the commit-graph file covers only part of the history we
|
// that if the commit-graph file covers only part of the history we
|
||||||
// start using it when that part is reached.
|
// start using it when that part is reached.
|
||||||
return c.nodeIndex.Get(c.commit.ParentHashes[i]) |
return c.nodeIndex.Get(c.commit.ParentHashes[i]) |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) ParentHashes() []plumbing.Hash { |
func (c *objectCommitNode) ParentHashes() []plumbing.Hash { |
||||||
return c.commit.ParentHashes |
return c.commit.ParentHashes |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) Generation() uint64 { |
func (c *objectCommitNode) Generation() uint64 { |
||||||
// Commit nodes representing objects outside of the commit graph can never
|
// Commit nodes representing objects outside of the commit graph can never
|
||||||
// be reached by objects from the commit-graph thus we return the highest
|
// be reached by objects from the commit-graph thus we return the highest
|
||||||
// possible value.
|
// possible value.
|
||||||
return math.MaxUint64 |
return math.MaxUint64 |
||||||
} |
} |
||||||
|
|
||||||
func (c *objectCommitNode) Commit() (*object.Commit, error) { |
func (c *objectCommitNode) Commit() (*object.Commit, error) { |
||||||
return c.commit, nil |
return c.commit, nil |
||||||
} |
} |
||||||
|
210
vendor/github.com/go-git/go-git/v5/plumbing/object/commitgraph/commitnode_walker_ctime.go
generated
vendored
210
vendor/github.com/go-git/go-git/v5/plumbing/object/commitgraph/commitnode_walker_ctime.go
generated
vendored
@ -1,105 +1,105 @@ |
|||||||
package commitgraph |
package commitgraph |
||||||
|
|
||||||
import ( |
import ( |
||||||
"io" |
"io" |
||||||
|
|
||||||
"github.com/emirpasic/gods/trees/binaryheap" |
"github.com/emirpasic/gods/trees/binaryheap" |
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing" |
"github.com/go-git/go-git/v5/plumbing" |
||||||
"github.com/go-git/go-git/v5/plumbing/storer" |
"github.com/go-git/go-git/v5/plumbing/storer" |
||||||
) |
) |
||||||
|
|
||||||
type commitNodeIteratorByCTime struct { |
type commitNodeIteratorByCTime struct { |
||||||
heap *binaryheap.Heap |
heap *binaryheap.Heap |
||||||
seenExternal map[plumbing.Hash]bool |
seenExternal map[plumbing.Hash]bool |
||||||
seen map[plumbing.Hash]bool |
seen map[plumbing.Hash]bool |
||||||
} |
} |
||||||
|
|
||||||
// NewCommitNodeIterCTime returns a CommitNodeIter that walks the commit history,
|
// NewCommitNodeIterCTime returns a CommitNodeIter that walks the commit history,
|
||||||
// starting at the given commit and visiting its parents while preserving Committer Time order.
|
// starting at the given commit and visiting its parents while preserving Committer Time order.
|
||||||
// this appears to be the closest order to `git log`
|
// this appears to be the closest order to `git log`
|
||||||
// The given callback will be called for each visited commit. Each commit will
|
// The given callback will be called for each visited commit. Each commit will
|
||||||
// be visited only once. If the callback returns an error, walking will stop
|
// be visited only once. If the callback returns an error, walking will stop
|
||||||
// and will return the error. Other errors might be returned if the history
|
// and will return the error. Other errors might be returned if the history
|
||||||
// cannot be traversed (e.g. missing objects). Ignore allows to skip some
|
// cannot be traversed (e.g. missing objects). Ignore allows to skip some
|
||||||
// commits from being iterated.
|
// commits from being iterated.
|
||||||
func NewCommitNodeIterCTime( |
func NewCommitNodeIterCTime( |
||||||
c CommitNode, |
c CommitNode, |
||||||
seenExternal map[plumbing.Hash]bool, |
seenExternal map[plumbing.Hash]bool, |
||||||
ignore []plumbing.Hash, |
ignore []plumbing.Hash, |
||||||
) CommitNodeIter { |
) CommitNodeIter { |
||||||
seen := make(map[plumbing.Hash]bool) |
seen := make(map[plumbing.Hash]bool) |
||||||
for _, h := range ignore { |
for _, h := range ignore { |
||||||
seen[h] = true |
seen[h] = true |
||||||
} |
} |
||||||
|
|
||||||
heap := binaryheap.NewWith(func(a, b interface{}) int { |
heap := binaryheap.NewWith(func(a, b interface{}) int { |
||||||
if a.(CommitNode).CommitTime().Before(b.(CommitNode).CommitTime()) { |
if a.(CommitNode).CommitTime().Before(b.(CommitNode).CommitTime()) { |
||||||
return 1 |
return 1 |
||||||
} |
} |
||||||
return -1 |
return -1 |
||||||
}) |
}) |
||||||
|
|
||||||
heap.Push(c) |
heap.Push(c) |
||||||
|
|
||||||
return &commitNodeIteratorByCTime{ |
return &commitNodeIteratorByCTime{ |
||||||
heap: heap, |
heap: heap, |
||||||
seenExternal: seenExternal, |
seenExternal: seenExternal, |
||||||
seen: seen, |
seen: seen, |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
func (w *commitNodeIteratorByCTime) Next() (CommitNode, error) { |
func (w *commitNodeIteratorByCTime) Next() (CommitNode, error) { |
||||||
var c CommitNode |
var c CommitNode |
||||||
for { |
for { |
||||||
cIn, ok := w.heap.Pop() |
cIn, ok := w.heap.Pop() |
||||||
if !ok { |
if !ok { |
||||||
return nil, io.EOF |
return nil, io.EOF |
||||||
} |
} |
||||||
c = cIn.(CommitNode) |
c = cIn.(CommitNode) |
||||||
cID := c.ID() |
cID := c.ID() |
||||||
|
|
||||||
if w.seen[cID] || w.seenExternal[cID] { |
if w.seen[cID] || w.seenExternal[cID] { |
||||||
continue |
continue |
||||||
} |
} |
||||||
|
|
||||||
w.seen[cID] = true |
w.seen[cID] = true |
||||||
|
|
||||||
for i, h := range c.ParentHashes() { |
for i, h := range c.ParentHashes() { |
||||||
if w.seen[h] || w.seenExternal[h] { |
if w.seen[h] || w.seenExternal[h] { |
||||||
continue |
continue |
||||||
} |
} |
||||||
pc, err := c.ParentNode(i) |
pc, err := c.ParentNode(i) |
||||||
if err != nil { |
if err != nil { |
||||||
return nil, err |
return nil, err |
||||||
} |
} |
||||||
w.heap.Push(pc) |
w.heap.Push(pc) |
||||||
} |
} |
||||||
|
|
||||||
return c, nil |
return c, nil |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
func (w *commitNodeIteratorByCTime) ForEach(cb func(CommitNode) error) error { |
func (w *commitNodeIteratorByCTime) ForEach(cb func(CommitNode) error) error { |
||||||
for { |
for { |
||||||
c, err := w.Next() |
c, err := w.Next() |
||||||
if err == io.EOF { |
if err == io.EOF { |
||||||
break |
break |
||||||
} |
} |
||||||
if err != nil { |
if err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
|
|
||||||
err = cb(c) |
err = cb(c) |
||||||
if err == storer.ErrStop { |
if err == storer.ErrStop { |
||||||
break |
break |
||||||
} |
} |
||||||
if err != nil { |
if err != nil { |
||||||
return err |
return err |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return nil |
return nil |
||||||
} |
} |
||||||
|
|
||||||
func (w *commitNodeIteratorByCTime) Close() {} |
func (w *commitNodeIteratorByCTime) Close() {} |
||||||
|
@ -1,22 +1,22 @@ |
|||||||
Copyright (c) 2013 Caleb Spare |
Copyright (c) 2013 Caleb Spare |
||||||
|
|
||||||
MIT License |
MIT License |
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining |
Permission is hereby granted, free of charge, to any person obtaining |
||||||
a copy of this software and associated documentation files (the |
a copy of this software and associated documentation files (the |
||||||
"Software"), to deal in the Software without restriction, including |
"Software"), to deal in the Software without restriction, including |
||||||
without limitation the rights to use, copy, modify, merge, publish, |
without limitation the rights to use, copy, modify, merge, publish, |
||||||
distribute, sublicense, and/or sell copies of the Software, and to |
distribute, sublicense, and/or sell copies of the Software, and to |
||||||
permit persons to whom the Software is furnished to do so, subject to |
permit persons to whom the Software is furnished to do so, subject to |
||||||
the following conditions: |
the following conditions: |
||||||
|
|
||||||
The above copyright notice and this permission notice shall be |
The above copyright notice and this permission notice shall be |
||||||
included in all copies or substantial portions of the Software. |
included in all copies or substantial portions of the Software. |
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||||
|
Loading…
Reference in new issue