mirror of
https://github.com/cheat/cheat.git
synced 2026-04-17 00:13:32 +02:00
chore(deps): bump github.com/go-git/go-git/v5 from 5.16.5 to 5.18.0
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.16.5 to 5.18.0. - [Release notes](https://github.com/go-git/go-git/releases) - [Commits](https://github.com/go-git/go-git/compare/v5.16.5...v5.18.0) --- updated-dependencies: - dependency-name: github.com/go-git/go-git/v5 dependency-version: 5.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
4
go.mod
4
go.mod
@@ -5,7 +5,7 @@ go 1.26
|
|||||||
require (
|
require (
|
||||||
github.com/alecthomas/chroma/v2 v2.23.1
|
github.com/alecthomas/chroma/v2 v2.23.1
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/go-git/go-git/v5 v5.16.5
|
github.com/go-git/go-git/v5 v5.18.0
|
||||||
github.com/mattn/go-isatty v0.0.20
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
@@ -21,7 +21,7 @@ require (
|
|||||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.7.0 // indirect
|
github.com/go-git/go-billy/v5 v5.8.0 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -33,12 +33,12 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
|||||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
github.com/go-git/go-billy/v5 v5.7.0 h1:83lBUJhGWhYp0ngzCMSgllhUSuoHP1iEWYjsPl9nwqM=
|
github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0=
|
||||||
github.com/go-git/go-billy/v5 v5.7.0/go.mod h1:/1IUejTKH8xipsAcdfcSAlUlo2J7lkYV8GTKxAT/L3E=
|
github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.16.5 h1:mdkuqblwr57kVfXri5TTH+nMFLNUxIj9Z7F5ykFbw5s=
|
github.com/go-git/go-git/v5 v5.18.0 h1:O831KI+0PR51hM2kep6T8k+w0/LIAD490gvqMCvL5hM=
|
||||||
github.com/go-git/go-git/v5 v5.16.5/go.mod h1:QOMLpNf1qxuSY4StA/ArOdfFR2TrKEjJiye2kel2m+M=
|
github.com/go-git/go-git/v5 v5.18.0/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
|||||||
11
vendor/github.com/go-git/go-billy/v5/helper/polyfill/polyfill.go
generated
vendored
11
vendor/github.com/go-git/go-billy/v5/helper/polyfill/polyfill.go
generated
vendored
@@ -13,7 +13,7 @@ type Polyfill struct {
|
|||||||
c capabilities
|
c capabilities
|
||||||
}
|
}
|
||||||
|
|
||||||
type capabilities struct{ tempfile, dir, symlink, chroot bool }
|
type capabilities struct{ tempfile, dir, symlink, chroot, chmod bool }
|
||||||
|
|
||||||
// New creates a new filesystem wrapping up 'fs' the intercepts all the calls
|
// New creates a new filesystem wrapping up 'fs' the intercepts all the calls
|
||||||
// made and errors if fs doesn't implement any of the billy interfaces.
|
// made and errors if fs doesn't implement any of the billy interfaces.
|
||||||
@@ -28,6 +28,7 @@ func New(fs billy.Basic) billy.Filesystem {
|
|||||||
_, h.c.dir = h.Basic.(billy.Dir)
|
_, h.c.dir = h.Basic.(billy.Dir)
|
||||||
_, h.c.symlink = h.Basic.(billy.Symlink)
|
_, h.c.symlink = h.Basic.(billy.Symlink)
|
||||||
_, h.c.chroot = h.Basic.(billy.Chroot)
|
_, h.c.chroot = h.Basic.(billy.Chroot)
|
||||||
|
_, h.c.chmod = h.Basic.(billy.Chmod)
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +88,14 @@ func (h *Polyfill) Chroot(path string) (billy.Filesystem, error) {
|
|||||||
return h.Basic.(billy.Chroot).Chroot(path)
|
return h.Basic.(billy.Chroot).Chroot(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Polyfill) Chmod(path string, mode os.FileMode) error {
|
||||||
|
if !h.c.chmod {
|
||||||
|
return billy.ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.Basic.(billy.Chmod).Chmod(path, mode)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Polyfill) Root() string {
|
func (h *Polyfill) Root() string {
|
||||||
if !h.c.chroot {
|
if !h.c.chroot {
|
||||||
return string(filepath.Separator)
|
return string(filepath.Separator)
|
||||||
|
|||||||
8
vendor/github.com/go-git/go-billy/v5/osfs/os_bound.go
generated
vendored
8
vendor/github.com/go-git/go-billy/v5/osfs/os_bound.go
generated
vendored
@@ -126,6 +126,14 @@ func (fs *BoundOS) TempFile(dir, prefix string) (billy.File, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = os.Stat(dir)
|
||||||
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
err = os.MkdirAll(dir, defaultDirectoryMode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tempFile(dir, prefix)
|
return tempFile(dir, prefix)
|
||||||
|
|||||||
10
vendor/github.com/go-git/go-git/v5/plumbing/format/idxfile/decoder.go
generated
vendored
10
vendor/github.com/go-git/go-git/v5/plumbing/format/idxfile/decoder.go
generated
vendored
@@ -91,8 +91,8 @@ func readVersion(idx *MemoryIndex, r io.Reader) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if v > VersionSupported {
|
if v != VersionSupported {
|
||||||
return ErrUnsupportedVersion
|
return fmt.Errorf("%w: v%d", ErrUnsupportedVersion, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
idx.Version = v
|
idx.Version = v
|
||||||
@@ -106,6 +106,10 @@ func readFanout(idx *MemoryIndex, r io.Reader) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if k > 0 && n < idx.Fanout[k-1] {
|
||||||
|
return fmt.Errorf("%w: fanout table is not monotonically non-decreasing at entry %d", ErrMalformedIdxFile, k)
|
||||||
|
}
|
||||||
|
|
||||||
idx.Fanout[k] = n
|
idx.Fanout[k] = n
|
||||||
idx.FanoutMapping[k] = noMapping
|
idx.FanoutMapping[k] = noMapping
|
||||||
}
|
}
|
||||||
@@ -155,7 +159,7 @@ func readCRC32(idx *MemoryIndex, r io.Reader) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func readOffsets(idx *MemoryIndex, r io.Reader) error {
|
func readOffsets(idx *MemoryIndex, r io.Reader) error {
|
||||||
var o64cnt int
|
var o64cnt int64
|
||||||
for k := 0; k < fanout; k++ {
|
for k := 0; k < fanout; k++ {
|
||||||
if pos := idx.FanoutMapping[k]; pos != noMapping {
|
if pos := idx.FanoutMapping[k]; pos != noMapping {
|
||||||
if _, err := io.ReadFull(r, idx.Offset32[pos]); err != nil {
|
if _, err := io.ReadFull(r, idx.Offset32[pos]); err != nil {
|
||||||
|
|||||||
108
vendor/github.com/go-git/go-git/v5/plumbing/format/index/decoder.go
generated
vendored
108
vendor/github.com/go-git/go-git/v5/plumbing/format/index/decoder.go
generated
vendored
@@ -4,8 +4,8 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -26,12 +26,14 @@ var (
|
|||||||
ErrInvalidChecksum = errors.New("invalid checksum")
|
ErrInvalidChecksum = errors.New("invalid checksum")
|
||||||
// ErrUnknownExtension is returned when an index extension is encountered that is considered mandatory
|
// ErrUnknownExtension is returned when an index extension is encountered that is considered mandatory
|
||||||
ErrUnknownExtension = errors.New("unknown extension")
|
ErrUnknownExtension = errors.New("unknown extension")
|
||||||
|
// ErrMalformedIndexFile is returned when the index file contents are
|
||||||
|
// structurally invalid.
|
||||||
|
ErrMalformedIndexFile = errors.New("index decoder: malformed index file")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
entryHeaderLength = 62
|
entryHeaderLength = 62
|
||||||
entryExtended = 0x4000
|
entryExtended = 0x4000
|
||||||
entryValid = 0x8000
|
|
||||||
nameMask = 0xfff
|
nameMask = 0xfff
|
||||||
intentToAddMask = 1 << 13
|
intentToAddMask = 1 << 13
|
||||||
skipWorkTreeMask = 1 << 14
|
skipWorkTreeMask = 1 << 14
|
||||||
@@ -140,33 +142,55 @@ func (d *Decoder) readEntry(idx *Index) (*Entry, error) {
|
|||||||
e.SkipWorktree = extended&skipWorkTreeMask != 0
|
e.SkipWorktree = extended&skipWorkTreeMask != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.readEntryName(idx, e, flags); err != nil {
|
nameConsumed, err := d.readEntryName(idx, e, flags)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return e, d.padEntry(idx, e, read)
|
return e, d.padEntry(idx, e, read, nameConsumed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) readEntryName(idx *Index, e *Entry, flags uint16) error {
|
// readEntryName reads the entry path and sets e.Name. It returns the
|
||||||
var name string
|
// number of bytes consumed from the stream for the name portion.
|
||||||
var err error
|
func (d *Decoder) readEntryName(idx *Index, e *Entry, flags uint16) (int, error) {
|
||||||
|
|
||||||
switch idx.Version {
|
switch idx.Version {
|
||||||
case 2, 3:
|
case 2, 3:
|
||||||
len := flags & nameMask
|
nameLen := flags & nameMask
|
||||||
name, err = d.doReadEntryName(len)
|
name, consumed, err := d.doReadEntryName(nameLen)
|
||||||
case 4:
|
|
||||||
name, err = d.doReadEntryNameV4()
|
|
||||||
default:
|
|
||||||
return ErrUnsupportedVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
|
}
|
||||||
|
e.Name = name
|
||||||
|
return consumed, nil
|
||||||
|
case 4:
|
||||||
|
name, err := d.doReadEntryNameV4()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
e.Name = name
|
||||||
|
return 0, nil // V4 has no padding; consumed count unused
|
||||||
|
default:
|
||||||
|
return 0, ErrUnsupportedVersion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Name = name
|
// doReadEntryName reads the entry path for V2/V3 indexes. It returns the
|
||||||
return nil
|
// name, the number of bytes consumed from the stream, and any error.
|
||||||
|
// When nameLen equals nameMask (0xFFF), the name was too long to fit in
|
||||||
|
// the 12-bit field and the real length is found by scanning for the NUL
|
||||||
|
// terminator — matching C Git's strlen(name) fallback in create_from_disk.
|
||||||
|
func (d *Decoder) doReadEntryName(nameLen uint16) (string, int, error) {
|
||||||
|
if nameLen == nameMask {
|
||||||
|
name, err := binary.ReadUntil(d.r, '\x00')
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
return string(name), len(name) + 1, nil // +1 for the consumed NUL delimiter
|
||||||
|
}
|
||||||
|
|
||||||
|
name := make([]byte, nameLen)
|
||||||
|
_, err := io.ReadFull(d.r, name)
|
||||||
|
return string(name), int(nameLen), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) doReadEntryNameV4() (string, error) {
|
func (d *Decoder) doReadEntryNameV4() (string, error) {
|
||||||
@@ -177,7 +201,14 @@ func (d *Decoder) doReadEntryNameV4() (string, error) {
|
|||||||
|
|
||||||
var base string
|
var base string
|
||||||
if d.lastEntry != nil {
|
if d.lastEntry != nil {
|
||||||
|
if l < 0 || int(l) > len(d.lastEntry.Name) {
|
||||||
|
return "", fmt.Errorf("%w: invalid V4 entry name strip length %d (previous name length: %d)",
|
||||||
|
ErrMalformedIndexFile, l, len(d.lastEntry.Name))
|
||||||
|
}
|
||||||
base = d.lastEntry.Name[:len(d.lastEntry.Name)-int(l)]
|
base = d.lastEntry.Name[:len(d.lastEntry.Name)-int(l)]
|
||||||
|
} else if l > 0 {
|
||||||
|
return "", fmt.Errorf("%w: non-zero strip length %d on first V4 entry",
|
||||||
|
ErrMalformedIndexFile, l)
|
||||||
}
|
}
|
||||||
|
|
||||||
name, err := binary.ReadUntil(d.r, '\x00')
|
name, err := binary.ReadUntil(d.r, '\x00')
|
||||||
@@ -188,25 +219,24 @@ func (d *Decoder) doReadEntryNameV4() (string, error) {
|
|||||||
return base + string(name), nil
|
return base + string(name), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) doReadEntryName(len uint16) (string, error) {
|
// padEntry discards NUL padding bytes that follow each V2/V3 entry on
|
||||||
name := make([]byte, len)
|
// disk. nameConsumed is the number of stream bytes consumed while reading
|
||||||
_, err := io.ReadFull(d.r, name)
|
// the entry name (which may exceed len(e.Name) when a NUL terminator was
|
||||||
|
// consumed for long names where the 12-bit length field overflowed).
|
||||||
return string(name), err
|
func (d *Decoder) padEntry(idx *Index, e *Entry, read, nameConsumed int) error {
|
||||||
}
|
|
||||||
|
|
||||||
// Index entries are padded out to the next 8 byte alignment
|
|
||||||
// for historical reasons related to how C Git read the files.
|
|
||||||
func (d *Decoder) padEntry(idx *Index, e *Entry, read int) error {
|
|
||||||
if idx.Version == 4 {
|
if idx.Version == 4 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
entrySize := read + len(e.Name)
|
entrySize := read + len(e.Name)
|
||||||
padLen := 8 - entrySize%8
|
padLen := 8 - entrySize%8
|
||||||
|
padLen -= nameConsumed - len(e.Name)
|
||||||
|
if padLen > 0 {
|
||||||
_, err := io.CopyN(io.Discard, d.r, int64(padLen))
|
_, err := io.CopyN(io.Discard, d.r, int64(padLen))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Decoder) readExtensions(idx *Index) error {
|
func (d *Decoder) readExtensions(idx *Index) error {
|
||||||
// TODO: support 'Split index' and 'Untracked cache' extensions, take in
|
// TODO: support 'Split index' and 'Untracked cache' extensions, take in
|
||||||
@@ -312,7 +342,7 @@ func (d *Decoder) readChecksum(expected []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateHeader(r io.Reader) (version uint32, err error) {
|
func validateHeader(r io.Reader) (version uint32, err error) {
|
||||||
var s = make([]byte, 4)
|
s := make([]byte, 4)
|
||||||
if _, err := io.ReadFull(r, s); err != nil {
|
if _, err := io.ReadFull(r, s); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -376,24 +406,26 @@ func (d *treeExtensionDecoder) readEntry() (*TreeEntry, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// An entry can be in an invalidated state and is represented by having a
|
|
||||||
// negative number in the entry_count field.
|
|
||||||
if i == -1 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Entries = i
|
e.Entries = i
|
||||||
trees, err := binary.ReadUntil(d.r, '\n')
|
trees, err := binary.ReadUntil(d.r, '\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
i, err = strconv.Atoi(string(trees))
|
subtrees, err := strconv.Atoi(string(trees))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Trees = i
|
e.Trees = subtrees
|
||||||
|
|
||||||
|
// An entry can be in an invalidated state and is represented by having a
|
||||||
|
// negative number in the entry_count field. In this case, there is no
|
||||||
|
// object name and the next entry starts immediately after the newline.
|
||||||
|
if i < 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
_, err = io.ReadFull(d.r, e.Hash[:])
|
_, err = io.ReadFull(d.r, e.Hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
37
vendor/github.com/go-git/go-git/v5/plumbing/format/index/encoder.go
generated
vendored
37
vendor/github.com/go-git/go-git/v5/plumbing/format/index/encoder.go
generated
vendored
@@ -5,9 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"path"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing/hash"
|
"github.com/go-git/go-git/v5/plumbing/hash"
|
||||||
@@ -160,26 +158,39 @@ func (e *Encoder) encodeEntryName(entry *Entry) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) encodeEntryNameV4(entry *Entry) error {
|
func (e *Encoder) encodeEntryNameV4(entry *Entry) error {
|
||||||
name := entry.Name
|
// V4 prefix compression: find the longest common prefix between the
|
||||||
l := 0
|
// previous entry's name and the current one. The strip length tells
|
||||||
|
// the decoder how many bytes to remove from the end of the previous
|
||||||
|
// name, and the suffix is the remainder of the current name.
|
||||||
|
prefix := 0
|
||||||
if e.lastEntry != nil {
|
if e.lastEntry != nil {
|
||||||
dir := path.Dir(e.lastEntry.Name) + "/"
|
prefix = commonPrefixLen(e.lastEntry.Name, entry.Name)
|
||||||
if strings.HasPrefix(entry.Name, dir) {
|
|
||||||
l = len(e.lastEntry.Name) - len(dir)
|
|
||||||
name = strings.TrimPrefix(entry.Name, dir)
|
|
||||||
} else {
|
|
||||||
l = len(e.lastEntry.Name)
|
|
||||||
}
|
}
|
||||||
|
stripLen := 0
|
||||||
|
if e.lastEntry != nil {
|
||||||
|
stripLen = len(e.lastEntry.Name) - prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
e.lastEntry = entry
|
e.lastEntry = entry
|
||||||
|
|
||||||
err := binary.WriteVariableWidthInt(e.w, int64(l))
|
if err := binary.WriteVariableWidthInt(e.w, int64(stripLen)); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return binary.Write(e.w, []byte(name+string('\x00')))
|
suffix := entry.Name[prefix:]
|
||||||
|
return binary.Write(e.w, append([]byte(suffix), '\x00'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// commonPrefixLen returns the length of the longest common byte prefix
|
||||||
|
// between a and b.
|
||||||
|
func commonPrefixLen(a, b string) int {
|
||||||
|
n := min(len(b), len(a))
|
||||||
|
for i := range n {
|
||||||
|
if a[i] != b[i] {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) encodeRawExtension(signature string, data []byte) error {
|
func (e *Encoder) encodeRawExtension(signature string, data []byte) error {
|
||||||
|
|||||||
2
vendor/github.com/go-git/go-git/v5/plumbing/format/index/index.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/plumbing/format/index/index.go
generated
vendored
@@ -54,6 +54,8 @@ type Index struct {
|
|||||||
ResolveUndo *ResolveUndo
|
ResolveUndo *ResolveUndo
|
||||||
// EndOfIndexEntry represents the 'End of Index Entry' extension
|
// EndOfIndexEntry represents the 'End of Index Entry' extension
|
||||||
EndOfIndexEntry *EndOfIndexEntry
|
EndOfIndexEntry *EndOfIndexEntry
|
||||||
|
// ModTime is the modification time of the index file
|
||||||
|
ModTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add creates a new Entry and returns it. The caller should first check that
|
// Add creates a new Entry and returns it. The caller should first check that
|
||||||
|
|||||||
168
vendor/github.com/go-git/go-git/v5/plumbing/transport/http/common.go
generated
vendored
168
vendor/github.com/go-git/go-git/v5/plumbing/transport/http/common.go
generated
vendored
@@ -7,7 +7,6 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -24,6 +23,33 @@ import (
|
|||||||
"github.com/go-git/go-git/v5/utils/ioutil"
|
"github.com/go-git/go-git/v5/utils/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type contextKey int
|
||||||
|
|
||||||
|
const initialRequestKey contextKey = iota
|
||||||
|
|
||||||
|
// RedirectPolicy controls how the HTTP transport follows redirects.
|
||||||
|
//
|
||||||
|
// The values mirror Git's http.followRedirects config:
|
||||||
|
// "true" follows redirects for all requests, "false" treats redirects as
|
||||||
|
// errors, and "initial" follows redirects only for the initial
|
||||||
|
// /info/refs discovery request. The zero value defaults to "initial".
|
||||||
|
type RedirectPolicy string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FollowInitialRedirects RedirectPolicy = "initial"
|
||||||
|
FollowRedirects RedirectPolicy = "true"
|
||||||
|
NoFollowRedirects RedirectPolicy = "false"
|
||||||
|
)
|
||||||
|
|
||||||
|
func withInitialRequest(ctx context.Context) context.Context {
|
||||||
|
return context.WithValue(ctx, initialRequestKey, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isInitialRequest(req *http.Request) bool {
|
||||||
|
v, _ := req.Context().Value(initialRequestKey).(bool)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// it requires a bytes.Buffer, because we need to know the length
|
// it requires a bytes.Buffer, because we need to know the length
|
||||||
func applyHeadersToRequest(req *http.Request, content *bytes.Buffer, host string, requestType string) {
|
func applyHeadersToRequest(req *http.Request, content *bytes.Buffer, host string, requestType string) {
|
||||||
req.Header.Add("User-Agent", capability.DefaultAgent())
|
req.Header.Add("User-Agent", capability.DefaultAgent())
|
||||||
@@ -54,12 +80,15 @@ func advertisedReferences(ctx context.Context, s *session, serviceName string) (
|
|||||||
|
|
||||||
s.ApplyAuthToRequest(req)
|
s.ApplyAuthToRequest(req)
|
||||||
applyHeadersToRequest(req, nil, s.endpoint.Host, serviceName)
|
applyHeadersToRequest(req, nil, s.endpoint.Host, serviceName)
|
||||||
res, err := s.client.Do(req.WithContext(ctx))
|
res, err := s.client.Do(req.WithContext(withInitialRequest(ctx)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.ModifyEndpointIfRedirect(res)
|
if err := s.ModifyEndpointIfRedirect(res); err != nil {
|
||||||
|
_ = res.Body.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer ioutil.CheckClose(res.Body, &err)
|
defer ioutil.CheckClose(res.Body, &err)
|
||||||
|
|
||||||
if err = NewErr(res); err != nil {
|
if err = NewErr(res); err != nil {
|
||||||
@@ -96,6 +125,7 @@ type client struct {
|
|||||||
client *http.Client
|
client *http.Client
|
||||||
transports *lru.Cache
|
transports *lru.Cache
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
|
follow RedirectPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientOptions holds user configurable options for the client.
|
// ClientOptions holds user configurable options for the client.
|
||||||
@@ -106,6 +136,11 @@ type ClientOptions struct {
|
|||||||
// size, will result in the least recently used transport getting deleted
|
// size, will result in the least recently used transport getting deleted
|
||||||
// before the provided transport is added to the cache.
|
// before the provided transport is added to the cache.
|
||||||
CacheMaxEntries int
|
CacheMaxEntries int
|
||||||
|
|
||||||
|
// RedirectPolicy controls redirect handling. Supported values are
|
||||||
|
// "true", "false", and "initial". The zero value defaults to
|
||||||
|
// "initial", matching Git's http.followRedirects default.
|
||||||
|
RedirectPolicy RedirectPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -150,12 +185,16 @@ func NewClientWithOptions(c *http.Client, opts *ClientOptions) transport.Transpo
|
|||||||
}
|
}
|
||||||
cl := &client{
|
cl := &client{
|
||||||
client: c,
|
client: c,
|
||||||
|
follow: FollowInitialRedirects,
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts != nil {
|
if opts != nil {
|
||||||
if opts.CacheMaxEntries > 0 {
|
if opts.CacheMaxEntries > 0 {
|
||||||
cl.transports = lru.New(opts.CacheMaxEntries)
|
cl.transports = lru.New(opts.CacheMaxEntries)
|
||||||
}
|
}
|
||||||
|
if opts.RedirectPolicy != "" {
|
||||||
|
cl.follow = opts.RedirectPolicy
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return cl
|
return cl
|
||||||
}
|
}
|
||||||
@@ -289,14 +328,9 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
httpClient = &http.Client{
|
httpClient = c.cloneHTTPClient(transport)
|
||||||
Transport: transport,
|
|
||||||
CheckRedirect: c.client.CheckRedirect,
|
|
||||||
Jar: c.client.Jar,
|
|
||||||
Timeout: c.client.Timeout,
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
httpClient = c.client
|
httpClient = c.cloneHTTPClient(c.client.Transport)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &session{
|
s := &session{
|
||||||
@@ -324,30 +358,122 @@ func (s *session) ApplyAuthToRequest(req *http.Request) {
|
|||||||
s.auth.SetAuth(req)
|
s.auth.SetAuth(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *session) ModifyEndpointIfRedirect(res *http.Response) {
|
func (s *session) ModifyEndpointIfRedirect(res *http.Response) error {
|
||||||
if res.Request == nil {
|
if res.Request == nil {
|
||||||
return
|
return nil
|
||||||
|
}
|
||||||
|
if s.endpoint == nil {
|
||||||
|
return fmt.Errorf("http redirect: nil endpoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
r := res.Request
|
r := res.Request
|
||||||
if !strings.HasSuffix(r.URL.Path, infoRefsPath) {
|
if !strings.HasSuffix(r.URL.Path, infoRefsPath) {
|
||||||
return
|
return fmt.Errorf("http redirect: target %q does not end with %s", r.URL.Path, infoRefsPath)
|
||||||
|
}
|
||||||
|
if r.URL.Scheme != "http" && r.URL.Scheme != "https" {
|
||||||
|
return fmt.Errorf("http redirect: unsupported scheme %q", r.URL.Scheme)
|
||||||
|
}
|
||||||
|
if r.URL.Scheme != s.endpoint.Protocol &&
|
||||||
|
!(s.endpoint.Protocol == "http" && r.URL.Scheme == "https") {
|
||||||
|
return fmt.Errorf("http redirect: changes scheme from %q to %q", s.endpoint.Protocol, r.URL.Scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
h, p, err := net.SplitHostPort(r.URL.Host)
|
host := endpointHost(r.URL.Hostname())
|
||||||
|
port, err := endpointPort(r.URL.Port())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h = r.URL.Host
|
return err
|
||||||
}
|
}
|
||||||
if p != "" {
|
|
||||||
port, err := strconv.Atoi(p)
|
if host != s.endpoint.Host || effectivePort(r.URL.Scheme, port) != effectivePort(s.endpoint.Protocol, s.endpoint.Port) {
|
||||||
if err == nil {
|
s.endpoint.User = ""
|
||||||
|
s.endpoint.Password = ""
|
||||||
|
s.auth = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s.endpoint.Host = host
|
||||||
s.endpoint.Port = port
|
s.endpoint.Port = port
|
||||||
}
|
|
||||||
}
|
|
||||||
s.endpoint.Host = h
|
|
||||||
|
|
||||||
s.endpoint.Protocol = r.URL.Scheme
|
s.endpoint.Protocol = r.URL.Scheme
|
||||||
s.endpoint.Path = r.URL.Path[:len(r.URL.Path)-len(infoRefsPath)]
|
s.endpoint.Path = r.URL.Path[:len(r.URL.Path)-len(infoRefsPath)]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func endpointHost(host string) string {
|
||||||
|
if strings.Contains(host, ":") {
|
||||||
|
return "[" + host + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
return host
|
||||||
|
}
|
||||||
|
|
||||||
|
func endpointPort(port string) (int, error) {
|
||||||
|
if port == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := strconv.Atoi(port)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("http redirect: invalid port %q", port)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func effectivePort(scheme string, port int) int {
|
||||||
|
if port != 0 {
|
||||||
|
return port
|
||||||
|
}
|
||||||
|
|
||||||
|
switch strings.ToLower(scheme) {
|
||||||
|
case "http":
|
||||||
|
return 80
|
||||||
|
case "https":
|
||||||
|
return 443
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) cloneHTTPClient(transport http.RoundTripper) *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: transport,
|
||||||
|
CheckRedirect: wrapCheckRedirect(c.follow, c.client.CheckRedirect),
|
||||||
|
Jar: c.client.Jar,
|
||||||
|
Timeout: c.client.Timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapCheckRedirect(policy RedirectPolicy, next func(*http.Request, []*http.Request) error) func(*http.Request, []*http.Request) error {
|
||||||
|
return func(req *http.Request, via []*http.Request) error {
|
||||||
|
if err := checkRedirect(req, via, policy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if next != nil {
|
||||||
|
return next(req, via)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRedirect(req *http.Request, via []*http.Request, policy RedirectPolicy) error {
|
||||||
|
switch policy {
|
||||||
|
case FollowRedirects:
|
||||||
|
case NoFollowRedirects:
|
||||||
|
return fmt.Errorf("http redirect: redirects disabled to %s", req.URL)
|
||||||
|
case "", FollowInitialRedirects:
|
||||||
|
if !isInitialRequest(req) {
|
||||||
|
return fmt.Errorf("http redirect: redirect on non-initial request to %s", req.URL)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("http redirect: invalid redirect policy %q", policy)
|
||||||
|
}
|
||||||
|
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
|
||||||
|
return fmt.Errorf("http redirect: unsupported scheme %q", req.URL.Scheme)
|
||||||
|
}
|
||||||
|
if len(via) >= 10 {
|
||||||
|
return fmt.Errorf("http redirect: too many redirects")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*session) Close() error {
|
func (*session) Close() error {
|
||||||
|
|||||||
6
vendor/github.com/go-git/go-git/v5/repository.go
generated
vendored
6
vendor/github.com/go-git/go-git/v5/repository.go
generated
vendored
@@ -208,6 +208,12 @@ func Open(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
|
|||||||
return nil, ErrRepositoryNotExists
|
return nil, ErrRepositoryNotExists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg, err := s.Config()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = verifyExtensions(s, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
121
vendor/github.com/go-git/go-git/v5/repository_extensions.go
generated
vendored
Normal file
121
vendor/github.com/go-git/go-git/v5/repository_extensions.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-git/go-git/v5/config"
|
||||||
|
cfgformat "github.com/go-git/go-git/v5/plumbing/format/config"
|
||||||
|
"github.com/go-git/go-git/v5/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrUnsupportedExtensionRepositoryFormatVersion represents when an
|
||||||
|
// extension being used is not compatible with the repository's
|
||||||
|
// core.repositoryFormatVersion.
|
||||||
|
ErrUnsupportedExtensionRepositoryFormatVersion = errors.New("core.repositoryformatversion does not support extension")
|
||||||
|
|
||||||
|
// ErrUnsupportedRepositoryFormatVersion represents when an repository
|
||||||
|
// is using a format version that is not supported.
|
||||||
|
ErrUnsupportedRepositoryFormatVersion = errors.New("core.repositoryformatversion not supported")
|
||||||
|
|
||||||
|
// ErrUnknownExtension represents when a repository has an extension
|
||||||
|
// which is unknown or unsupported by go-git.
|
||||||
|
ErrUnknownExtension = errors.New("unknown extension")
|
||||||
|
|
||||||
|
// builtinExtensions defines the Git extensions that are supported by
|
||||||
|
// the core go-git implementation.
|
||||||
|
//
|
||||||
|
// Some extensions are storage-specific, those are defined by the Storers
|
||||||
|
// themselves by implementing the ExtensionChecker interface.
|
||||||
|
builtinExtensions = map[string]struct{}{
|
||||||
|
// noop does not change git’s behavior at all.
|
||||||
|
// It is useful only for testing format-1 compatibility.
|
||||||
|
//
|
||||||
|
// This extension is respected regardless of the
|
||||||
|
// core.repositoryFormatVersion setting.
|
||||||
|
"noop": {},
|
||||||
|
|
||||||
|
// noop-v1 does not change git’s behavior at all.
|
||||||
|
// It is useful only for testing format-1 compatibility.
|
||||||
|
"noop-v1": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some Git extensions were supported upstream before the introduction
|
||||||
|
// of repositoryformatversion. These are the only extensions that can be
|
||||||
|
// enabled while core.repositoryformatversion is unset or set to 0.
|
||||||
|
extensionsValidForV0 = map[string]struct{}{
|
||||||
|
"noop": {},
|
||||||
|
"partialClone": {},
|
||||||
|
"preciousObjects": {},
|
||||||
|
"worktreeConfig": {},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type extension struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func extensions(cfg *config.Config) []extension {
|
||||||
|
if cfg == nil || cfg.Raw == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cfg.Raw.HasSection("extensions") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
section := cfg.Raw.Section("extensions")
|
||||||
|
out := make([]extension, 0, len(section.Options))
|
||||||
|
for _, opt := range section.Options {
|
||||||
|
out = append(out, extension{name: strings.ToLower(opt.Key), value: strings.ToLower(opt.Value)})
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyExtensions(st storage.Storer, cfg *config.Config) error {
|
||||||
|
needed := extensions(cfg)
|
||||||
|
|
||||||
|
switch cfg.Core.RepositoryFormatVersion {
|
||||||
|
case "", cfgformat.Version_0, cfgformat.Version_1:
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%w: %q",
|
||||||
|
ErrUnsupportedRepositoryFormatVersion,
|
||||||
|
cfg.Core.RepositoryFormatVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(needed) > 0 {
|
||||||
|
if cfg.Core.RepositoryFormatVersion == cfgformat.Version_0 ||
|
||||||
|
cfg.Core.RepositoryFormatVersion == "" {
|
||||||
|
var unsupported []string
|
||||||
|
for _, ext := range needed {
|
||||||
|
if _, ok := extensionsValidForV0[ext.name]; !ok {
|
||||||
|
unsupported = append(unsupported, ext.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(unsupported) > 0 {
|
||||||
|
return fmt.Errorf("%w: %s",
|
||||||
|
ErrUnsupportedExtensionRepositoryFormatVersion,
|
||||||
|
strings.Join(unsupported, ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var missing []string
|
||||||
|
for _, ext := range needed {
|
||||||
|
if _, ok := builtinExtensions[ext.name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
missing = append(missing, ext.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missing) > 0 {
|
||||||
|
return fmt.Errorf("%w: %s", ErrUnknownExtension, strings.Join(missing, ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
62
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/writers.go
generated
vendored
62
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/writers.go
generated
vendored
@@ -3,6 +3,7 @@ package dotgit
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
@@ -131,20 +132,62 @@ func (w *PackWriter) clean() error {
|
|||||||
|
|
||||||
func (w *PackWriter) save() error {
|
func (w *PackWriter) save() error {
|
||||||
base := w.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s", w.checksum))
|
base := w.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s", w.checksum))
|
||||||
idx, err := w.fs.Create(fmt.Sprintf("%s.idx", base))
|
|
||||||
|
// Pack files are content addressable. Each file is checked
|
||||||
|
// individually — if it already exists on disk, skip creating it.
|
||||||
|
idxPath := fmt.Sprintf("%s.idx", base)
|
||||||
|
exists, err := fileExists(w.fs, idxPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
idx, err := w.fs.Create(idxPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := w.encodeIdx(idx); err != nil {
|
if err := w.encodeIdx(idx); err != nil {
|
||||||
|
_ = idx.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := idx.Close(); err != nil {
|
if err := idx.Close(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
fixPermissions(w.fs, idxPath)
|
||||||
|
}
|
||||||
|
|
||||||
return w.fs.Rename(w.fw.Name(), fmt.Sprintf("%s.pack", base))
|
packPath := fmt.Sprintf("%s.pack", base)
|
||||||
|
exists, err = fileExists(w.fs, packPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
if err := w.fs.Rename(w.fw.Name(), packPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fixPermissions(w.fs, packPath)
|
||||||
|
} else {
|
||||||
|
// Pack already exists, clean up the temp file.
|
||||||
|
return w.clean()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileExists checks whether path already exists as a regular file.
|
||||||
|
// It returns (true, nil) for an existing regular file, (false, nil) when the
|
||||||
|
// path does not exist, and (false, err) if the path exists but is not a
|
||||||
|
// regular file (e.g. a directory or symlink).
|
||||||
|
func fileExists(fs billy.Filesystem, path string) (bool, error) {
|
||||||
|
fi, err := fs.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if !fi.Mode().IsRegular() {
|
||||||
|
return false, fmt.Errorf("unexpected file type for %q: %s", path, fi.Mode().Type())
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *PackWriter) encodeIdx(writer io.Writer) error {
|
func (w *PackWriter) encodeIdx(writer io.Writer) error {
|
||||||
@@ -226,7 +269,6 @@ func (s *syncedReader) sleep() {
|
|||||||
atomic.StoreUint32(&s.blocked, 1)
|
atomic.StoreUint32(&s.blocked, 1)
|
||||||
<-s.news
|
<-s.news
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncedReader) Seek(offset int64, whence int) (int64, error) {
|
func (s *syncedReader) Seek(offset int64, whence int) (int64, error) {
|
||||||
@@ -281,5 +323,17 @@ func (w *ObjectWriter) save() error {
|
|||||||
hex := w.Hash().String()
|
hex := w.Hash().String()
|
||||||
file := w.fs.Join(objectsPath, hex[0:2], hex[2:hash.HexSize])
|
file := w.fs.Join(objectsPath, hex[0:2], hex[2:hash.HexSize])
|
||||||
|
|
||||||
return w.fs.Rename(w.f.Name(), file)
|
// Loose objects are content addressable, if they already exist
|
||||||
|
// we can safely delete the temporary file and short-circuit the
|
||||||
|
// operation.
|
||||||
|
if _, err := w.fs.Lstat(file); err == nil || os.IsExist(err) {
|
||||||
|
return w.fs.Remove(w.f.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.fs.Rename(w.f.Name(), file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fixPermissions(w.fs, file)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
29
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/writers_unix.go
generated
vendored
Normal file
29
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/writers_unix.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package dotgit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-git/go-billy/v5"
|
||||||
|
"github.com/go-git/go-git/v5/utils/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fixPermissions(fs billy.Filesystem, path string) {
|
||||||
|
if chmodFS, ok := fs.(billy.Chmod); ok {
|
||||||
|
if err := chmodFS.Chmod(path, 0o444); err != nil {
|
||||||
|
trace.General.Printf("failed to chmod %s: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isReadOnly(fs billy.Filesystem, path string) (bool, error) {
|
||||||
|
fi, err := fs.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode().Perm() == 0o444 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
58
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/writers_windows.go
generated
vendored
Normal file
58
vendor/github.com/go-git/go-git/v5/storage/filesystem/dotgit/writers_windows.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package dotgit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/go-git/go-billy/v5"
|
||||||
|
"github.com/go-git/go-git/v5/utils/trace"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fixPermissions(fs billy.Filesystem, path string) {
|
||||||
|
fullpath := filepath.Join(fs.Root(), path)
|
||||||
|
p, err := windows.UTF16PtrFromString(fullpath)
|
||||||
|
if err != nil {
|
||||||
|
trace.General.Printf("failed to chmod %s: %v", fullpath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs, err := windows.GetFileAttributes(p)
|
||||||
|
if err != nil {
|
||||||
|
trace.General.Printf("failed to chmod %s: %v", fullpath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if attrs&windows.FILE_ATTRIBUTE_READONLY != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = windows.SetFileAttributes(p,
|
||||||
|
attrs|windows.FILE_ATTRIBUTE_READONLY,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
trace.General.Printf("failed to chmod %s: %v", fullpath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isReadOnly(fs billy.Filesystem, path string) (bool, error) {
|
||||||
|
fullpath := filepath.Join(fs.Root(), path)
|
||||||
|
p, err := windows.UTF16PtrFromString(fullpath)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("%w: %q", err, fullpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs, err := windows.GetFileAttributes(p)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("%w: %q", err, fullpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if attrs&windows.FILE_ATTRIBUTE_READONLY != 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
5
vendor/github.com/go-git/go-git/v5/storage/filesystem/index.go
generated
vendored
5
vendor/github.com/go-git/go-git/v5/storage/filesystem/index.go
generated
vendored
@@ -48,6 +48,11 @@ func (s *IndexStorage) Index() (i *index.Index, err error) {
|
|||||||
|
|
||||||
defer ioutil.CheckClose(f, &err)
|
defer ioutil.CheckClose(f, &err)
|
||||||
|
|
||||||
|
fi, statErr := s.dir.Fs().Stat(f.Name())
|
||||||
|
if statErr == nil {
|
||||||
|
idx.ModTime = fi.ModTime()
|
||||||
|
}
|
||||||
|
|
||||||
d := index.NewDecoder(f)
|
d := index.NewDecoder(f)
|
||||||
err = d.Decode(idx)
|
err = d.Decode(idx)
|
||||||
return idx, err
|
return idx, err
|
||||||
|
|||||||
4
vendor/github.com/go-git/go-git/v5/storage/memory/storage.go
generated
vendored
4
vendor/github.com/go-git/go-git/v5/storage/memory/storage.go
generated
vendored
@@ -69,7 +69,11 @@ type IndexStorage struct {
|
|||||||
index *index.Index
|
index *index.Index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIndex stores the given index.
|
||||||
|
// Note: this method sets idx.ModTime to simulate filesystem storage behavior.
|
||||||
func (c *IndexStorage) SetIndex(idx *index.Index) error {
|
func (c *IndexStorage) SetIndex(idx *index.Index) error {
|
||||||
|
// Set ModTime to enable racy git detection in the metadata optimization.
|
||||||
|
idx.ModTime = time.Now()
|
||||||
c.index = idx
|
c.index = idx
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
100
vendor/github.com/go-git/go-git/v5/utils/merkletrie/filesystem/node.go
generated
vendored
100
vendor/github.com/go-git/go-git/v5/utils/merkletrie/filesystem/node.go
generated
vendored
@@ -4,9 +4,11 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"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/filemode"
|
"github.com/go-git/go-git/v5/plumbing/filemode"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/format/index"
|
||||||
"github.com/go-git/go-git/v5/utils/merkletrie/noder"
|
"github.com/go-git/go-git/v5/utils/merkletrie/noder"
|
||||||
|
|
||||||
"github.com/go-git/go-billy/v5"
|
"github.com/go-git/go-billy/v5"
|
||||||
@@ -16,6 +18,14 @@ var ignore = map[string]bool{
|
|||||||
".git": true,
|
".git": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Options contains configuration for the filesystem node.
|
||||||
|
type Options struct {
|
||||||
|
// Index is used to enable the metadata-first comparison optimization while
|
||||||
|
// correctly handling the "racy git" condition. If no index is provided,
|
||||||
|
// the function works without the optimization.
|
||||||
|
Index *index.Index
|
||||||
|
}
|
||||||
|
|
||||||
// The node represents a file or a directory in a billy.Filesystem. It
|
// The node represents a file or a directory in a billy.Filesystem. It
|
||||||
// implements the interface noder.Noder of merkletrie package.
|
// implements the interface noder.Noder of merkletrie package.
|
||||||
//
|
//
|
||||||
@@ -24,6 +34,8 @@ var ignore = map[string]bool{
|
|||||||
type node struct {
|
type node struct {
|
||||||
fs billy.Filesystem
|
fs billy.Filesystem
|
||||||
submodules map[string]plumbing.Hash
|
submodules map[string]plumbing.Hash
|
||||||
|
idx *index.Index
|
||||||
|
idxMap map[string]*index.Entry
|
||||||
|
|
||||||
path string
|
path string
|
||||||
hash []byte
|
hash []byte
|
||||||
@@ -31,6 +43,7 @@ type node struct {
|
|||||||
isDir bool
|
isDir bool
|
||||||
mode os.FileMode
|
mode os.FileMode
|
||||||
size int64
|
size int64
|
||||||
|
modTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRootNode returns the root node based on a given billy.Filesystem.
|
// NewRootNode returns the root node based on a given billy.Filesystem.
|
||||||
@@ -42,7 +55,41 @@ func NewRootNode(
|
|||||||
fs billy.Filesystem,
|
fs billy.Filesystem,
|
||||||
submodules map[string]plumbing.Hash,
|
submodules map[string]plumbing.Hash,
|
||||||
) noder.Noder {
|
) noder.Noder {
|
||||||
return &node{fs: fs, submodules: submodules, isDir: true}
|
return NewRootNodeWithOptions(fs, submodules, Options{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRootNodeWithOptions returns the root node based on a given billy.Filesystem
|
||||||
|
// with options to set an index. Providing an index enables the metadata-first
|
||||||
|
// comparison optimization while correctly handling the "racy git" condition. If
|
||||||
|
// no index is provided, the function works without the optimization.
|
||||||
|
//
|
||||||
|
// The index's ModTime field is used to detect the racy git condition. When a file's
|
||||||
|
// mtime equals or is newer than the index ModTime, we must hash the file content
|
||||||
|
// even if other metadata matches, because the file may have been modified in the
|
||||||
|
// same second that the index was written.
|
||||||
|
//
|
||||||
|
// Reference: https://git-scm.com/docs/racy-git
|
||||||
|
func NewRootNodeWithOptions(
|
||||||
|
fs billy.Filesystem,
|
||||||
|
submodules map[string]plumbing.Hash,
|
||||||
|
options Options,
|
||||||
|
) noder.Noder {
|
||||||
|
var idxMap map[string]*index.Entry
|
||||||
|
|
||||||
|
if options.Index != nil {
|
||||||
|
idxMap = make(map[string]*index.Entry, len(options.Index.Entries))
|
||||||
|
for _, entry := range options.Index.Entries {
|
||||||
|
idxMap[entry.Name] = entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &node{
|
||||||
|
fs: fs,
|
||||||
|
submodules: submodules,
|
||||||
|
idx: options.Index,
|
||||||
|
idxMap: idxMap,
|
||||||
|
isDir: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash the hash of a filesystem is the result of concatenating the computed
|
// Hash the hash of a filesystem is the result of concatenating the computed
|
||||||
@@ -133,11 +180,14 @@ func (n *node) newChildNode(file os.FileInfo) (*node, error) {
|
|||||||
node := &node{
|
node := &node{
|
||||||
fs: n.fs,
|
fs: n.fs,
|
||||||
submodules: n.submodules,
|
submodules: n.submodules,
|
||||||
|
idx: n.idx,
|
||||||
|
idxMap: n.idxMap,
|
||||||
|
|
||||||
path: path,
|
path: path,
|
||||||
isDir: file.IsDir(),
|
isDir: file.IsDir(),
|
||||||
size: file.Size(),
|
size: file.Size(),
|
||||||
mode: file.Mode(),
|
mode: file.Mode(),
|
||||||
|
modTime: file.ModTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, isSubmodule := n.submodules[path]; isSubmodule {
|
if _, isSubmodule := n.submodules[path]; isSubmodule {
|
||||||
@@ -161,6 +211,16 @@ func (n *node) calculateHash() {
|
|||||||
n.hash = append(submoduleHash[:], filemode.Submodule.Bytes()...)
|
n.hash = append(submoduleHash[:], filemode.Submodule.Bytes()...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.idxMap != nil {
|
||||||
|
if entry, ok := n.idxMap[n.path]; ok {
|
||||||
|
if n.metadataMatches(entry) {
|
||||||
|
n.hash = append(entry.Hash[:], mode.Bytes()...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var hash plumbing.Hash
|
var hash plumbing.Hash
|
||||||
if n.mode&os.ModeSymlink != 0 {
|
if n.mode&os.ModeSymlink != 0 {
|
||||||
hash = n.doCalculateHashForSymlink()
|
hash = n.doCalculateHashForSymlink()
|
||||||
@@ -170,6 +230,44 @@ func (n *node) calculateHash() {
|
|||||||
n.hash = append(hash[:], mode.Bytes()...)
|
n.hash = append(hash[:], mode.Bytes()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *node) metadataMatches(entry *index.Entry) bool {
|
||||||
|
if entry == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint32(n.size) != entry.Size {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !n.modTime.IsZero() && !n.modTime.Equal(entry.ModifiedAt) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
mode, err := filemode.NewFromOSFileMode(n.mode)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode != entry.Mode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.idx != nil && !n.idx.ModTime.IsZero() && !n.modTime.IsZero() {
|
||||||
|
if !n.modTime.Before(n.idx.ModTime) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we couldn't perform the racy git check (idx is nil or idx.ModTime is zero),
|
||||||
|
// we cannot safely rely on metadata alone — force content hashing.
|
||||||
|
// This can occur with in-memory storage where the index file timestamp is unavailable.
|
||||||
|
if n.idx == nil || n.idx.ModTime.IsZero() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (n *node) doCalculateHashForRegular() plumbing.Hash {
|
func (n *node) doCalculateHashForRegular() plumbing.Hash {
|
||||||
f, err := n.fs.Open(n.path)
|
f, err := n.fs.Open(n.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
33
vendor/github.com/go-git/go-git/v5/worktree.go
generated
vendored
33
vendor/github.com/go-git/go-git/v5/worktree.go
generated
vendored
@@ -385,7 +385,8 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) ([]
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var removedFiles []string
|
removedFiles := make([]string, 0, len(changes))
|
||||||
|
filesMap := buildFilePathMap(files)
|
||||||
for _, ch := range changes {
|
for _, ch := range changes {
|
||||||
a, err := ch.Action()
|
a, err := ch.Action()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -407,7 +408,7 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) ([]
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(files) > 0 {
|
if len(files) > 0 {
|
||||||
contains := inFiles(files, name)
|
contains := inFiles(filesMap, name)
|
||||||
if !contains {
|
if !contains {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -436,15 +437,11 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) ([]
|
|||||||
return removedFiles, w.r.Storer.SetIndex(idx)
|
return removedFiles, w.r.Storer.SetIndex(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func inFiles(files []string, v string) bool {
|
// inFiles checks if the given file is in the list of files. The incoming filepaths in files should be cleaned before calling this function.
|
||||||
|
func inFiles(files map[string]struct{}, v string) bool {
|
||||||
v = filepath.Clean(v)
|
v = filepath.Clean(v)
|
||||||
for _, s := range files {
|
_, exists := files[v]
|
||||||
if filepath.Clean(s) == v {
|
return exists
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worktree) resetWorktree(t *object.Tree, files []string) error {
|
func (w *Worktree) resetWorktree(t *object.Tree, files []string) error {
|
||||||
@@ -459,6 +456,7 @@ func (w *Worktree) resetWorktree(t *object.Tree, files []string) error {
|
|||||||
}
|
}
|
||||||
b := newIndexBuilder(idx)
|
b := newIndexBuilder(idx)
|
||||||
|
|
||||||
|
filesMap := buildFilePathMap(files)
|
||||||
for _, ch := range changes {
|
for _, ch := range changes {
|
||||||
if err := w.validChange(ch); err != nil {
|
if err := w.validChange(ch); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -476,7 +474,7 @@ func (w *Worktree) resetWorktree(t *object.Tree, files []string) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
contains := inFiles(files, file)
|
contains := inFiles(filesMap, file)
|
||||||
if !contains {
|
if !contains {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1206,3 +1204,16 @@ func (b *indexBuilder) Add(e *index.Entry) {
|
|||||||
func (b *indexBuilder) Remove(name string) {
|
func (b *indexBuilder) Remove(name string) {
|
||||||
delete(b.entries, filepath.ToSlash(name))
|
delete(b.entries, filepath.ToSlash(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buildFilePathMap creates a map of cleaned file paths for efficient lookup.
|
||||||
|
// Returns nil if the input slice is empty.
|
||||||
|
func buildFilePathMap(files []string) map[string]struct{} {
|
||||||
|
if len(files) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
filesMap := make(map[string]struct{}, len(files))
|
||||||
|
for _, f := range files {
|
||||||
|
filesMap[filepath.Clean(f)] = struct{}{}
|
||||||
|
}
|
||||||
|
return filesMap
|
||||||
|
}
|
||||||
|
|||||||
2
vendor/github.com/go-git/go-git/v5/worktree_status.go
generated
vendored
2
vendor/github.com/go-git/go-git/v5/worktree_status.go
generated
vendored
@@ -141,7 +141,7 @@ func (w *Worktree) diffStagingWithWorktree(reverse, excludeIgnoredChanges bool)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
to := filesystem.NewRootNode(w.Filesystem, submodules)
|
to := filesystem.NewRootNodeWithOptions(w.Filesystem, submodules, filesystem.Options{Index: idx})
|
||||||
|
|
||||||
var c merkletrie.Changes
|
var c merkletrie.Changes
|
||||||
if reverse {
|
if reverse {
|
||||||
|
|||||||
6
vendor/modules.txt
vendored
6
vendor/modules.txt
vendored
@@ -80,15 +80,15 @@ github.com/go-git/gcfg
|
|||||||
github.com/go-git/gcfg/scanner
|
github.com/go-git/gcfg/scanner
|
||||||
github.com/go-git/gcfg/token
|
github.com/go-git/gcfg/token
|
||||||
github.com/go-git/gcfg/types
|
github.com/go-git/gcfg/types
|
||||||
# github.com/go-git/go-billy/v5 v5.7.0
|
# github.com/go-git/go-billy/v5 v5.8.0
|
||||||
## explicit; go 1.23.0
|
## explicit; go 1.24.0
|
||||||
github.com/go-git/go-billy/v5
|
github.com/go-git/go-billy/v5
|
||||||
github.com/go-git/go-billy/v5/helper/chroot
|
github.com/go-git/go-billy/v5/helper/chroot
|
||||||
github.com/go-git/go-billy/v5/helper/polyfill
|
github.com/go-git/go-billy/v5/helper/polyfill
|
||||||
github.com/go-git/go-billy/v5/memfs
|
github.com/go-git/go-billy/v5/memfs
|
||||||
github.com/go-git/go-billy/v5/osfs
|
github.com/go-git/go-billy/v5/osfs
|
||||||
github.com/go-git/go-billy/v5/util
|
github.com/go-git/go-billy/v5/util
|
||||||
# github.com/go-git/go-git/v5 v5.16.5
|
# github.com/go-git/go-git/v5 v5.18.0
|
||||||
## explicit; go 1.24.0
|
## explicit; go 1.24.0
|
||||||
github.com/go-git/go-git/v5
|
github.com/go-git/go-git/v5
|
||||||
github.com/go-git/go-git/v5/config
|
github.com/go-git/go-git/v5/config
|
||||||
|
|||||||
Reference in New Issue
Block a user