mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-15 01:34:26 +02:00
Bump go-git
This commit is contained in:
70
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/common.go
generated
vendored
70
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/common.go
generated
vendored
@ -44,6 +44,46 @@ func (c *Config) Section(name string) *Section {
|
||||
return s
|
||||
}
|
||||
|
||||
// HasSection checks if the Config has a section with the specified name.
|
||||
func (c *Config) HasSection(name string) bool {
|
||||
for _, s := range c.Sections {
|
||||
if s.IsName(name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveSection removes a section from a config file.
|
||||
func (c *Config) RemoveSection(name string) *Config {
|
||||
result := Sections{}
|
||||
for _, s := range c.Sections {
|
||||
if !s.IsName(name) {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
c.Sections = result
|
||||
return c
|
||||
}
|
||||
|
||||
// RemoveSubsection remove a subsection from a config file.
|
||||
func (c *Config) RemoveSubsection(section string, subsection string) *Config {
|
||||
for _, s := range c.Sections {
|
||||
if s.IsName(section) {
|
||||
result := Subsections{}
|
||||
for _, ss := range s.Subsections {
|
||||
if !ss.IsName(subsection) {
|
||||
result = append(result, ss)
|
||||
}
|
||||
}
|
||||
s.Subsections = result
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// AddOption adds an option to a given section and subsection. Use the
|
||||
// NoSubsection constant for the subsection argument if no subsection is wanted.
|
||||
func (c *Config) AddOption(section string, subsection string, key string, value string) *Config {
|
||||
@ -67,33 +107,3 @@ func (c *Config) SetOption(section string, subsection string, key string, value
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// RemoveSection removes a section from a config file.
|
||||
func (c *Config) RemoveSection(name string) *Config {
|
||||
result := Sections{}
|
||||
for _, s := range c.Sections {
|
||||
if !s.IsName(name) {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
c.Sections = result
|
||||
return c
|
||||
}
|
||||
|
||||
// RemoveSubsection remove s a subsection from a config file.
|
||||
func (c *Config) RemoveSubsection(section string, subsection string) *Config {
|
||||
for _, s := range c.Sections {
|
||||
if s.IsName(section) {
|
||||
result := Subsections{}
|
||||
for _, ss := range s.Subsections {
|
||||
if !ss.IsName(subsection) {
|
||||
result = append(result, ss)
|
||||
}
|
||||
}
|
||||
s.Subsections = result
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
17
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/encoder.go
generated
vendored
17
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/encoder.go
generated
vendored
@ -11,6 +11,10 @@ type Encoder struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
var (
|
||||
subsectionReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`)
|
||||
valueReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`, "\n", `\n`, "\t", `\t`, "\b", `\b`)
|
||||
)
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{w}
|
||||
@ -48,8 +52,7 @@ func (e *Encoder) encodeSection(s *Section) error {
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeSubsection(sectionName string, s *Subsection) error {
|
||||
//TODO: escape
|
||||
if err := e.printf("[%s \"%s\"]\n", sectionName, s.Name); err != nil {
|
||||
if err := e.printf("[%s \"%s\"]\n", sectionName, subsectionReplacer.Replace(s.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -58,12 +61,14 @@ func (e *Encoder) encodeSubsection(sectionName string, s *Subsection) error {
|
||||
|
||||
func (e *Encoder) encodeOptions(opts Options) error {
|
||||
for _, o := range opts {
|
||||
pattern := "\t%s = %s\n"
|
||||
if strings.Contains(o.Value, "\\") {
|
||||
pattern = "\t%s = %q\n"
|
||||
var value string
|
||||
if strings.ContainsAny(o.Value, "#;\"\t\n\\") || strings.HasPrefix(o.Value, " ") || strings.HasSuffix(o.Value, " ") {
|
||||
value = `"`+valueReplacer.Replace(o.Value)+`"`
|
||||
} else {
|
||||
value = o.Value
|
||||
}
|
||||
|
||||
if err := e.printf(pattern, o.Key, o.Value); err != nil {
|
||||
if err := e.printf("\t%s = %s\n", o.Key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
53
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/format.go
generated
vendored
Normal file
53
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/format.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
package config
|
||||
|
||||
// RepositoryFormatVersion represents the repository format version,
|
||||
// as per defined at:
|
||||
//
|
||||
// https://git-scm.com/docs/repository-version
|
||||
type RepositoryFormatVersion string
|
||||
|
||||
const (
|
||||
// Version_0 is the format defined by the initial version of git,
|
||||
// including but not limited to the format of the repository
|
||||
// directory, the repository configuration file, and the object
|
||||
// and ref storage.
|
||||
//
|
||||
// Specifying the complete behavior of git is beyond the scope
|
||||
// of this document.
|
||||
Version_0 = "0"
|
||||
|
||||
// Version_1 is identical to version 0, with the following exceptions:
|
||||
//
|
||||
// 1. When reading the core.repositoryformatversion variable, a git
|
||||
// implementation which supports version 1 MUST also read any
|
||||
// configuration keys found in the extensions section of the
|
||||
// configuration file.
|
||||
//
|
||||
// 2. If a version-1 repository specifies any extensions.* keys that
|
||||
// the running git has not implemented, the operation MUST NOT proceed.
|
||||
// Similarly, if the value of any known key is not understood by the
|
||||
// implementation, the operation MUST NOT proceed.
|
||||
//
|
||||
// Note that if no extensions are specified in the config file, then
|
||||
// core.repositoryformatversion SHOULD be set to 0 (setting it to 1 provides
|
||||
// no benefit, and makes the repository incompatible with older
|
||||
// implementations of git).
|
||||
Version_1 = "1"
|
||||
|
||||
// DefaultRepositoryFormatVersion holds the default repository format version.
|
||||
DefaultRepositoryFormatVersion = Version_0
|
||||
)
|
||||
|
||||
// ObjectFormat defines the object format.
|
||||
type ObjectFormat string
|
||||
|
||||
const (
|
||||
// SHA1 represents the object format used for SHA1.
|
||||
SHA1 ObjectFormat = "sha1"
|
||||
|
||||
// SHA256 represents the object format used for SHA256.
|
||||
SHA256 ObjectFormat = "sha256"
|
||||
|
||||
// DefaultObjectFormat holds the default object format.
|
||||
DefaultObjectFormat = SHA1
|
||||
)
|
10
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/option.go
generated
vendored
10
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/option.go
generated
vendored
@ -54,6 +54,16 @@ func (opts Options) Get(key string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Has checks if an Option exist with the given key.
|
||||
func (opts Options) Has(key string) bool {
|
||||
for _, o := range opts {
|
||||
if o.IsKey(key) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetAll returns all possible values for the same key.
|
||||
func (opts Options) GetAll(key string) []string {
|
||||
result := []string{}
|
||||
|
85
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/section.go
generated
vendored
85
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/config/section.go
generated
vendored
@ -64,31 +64,6 @@ func (s *Section) IsName(name string) bool {
|
||||
return strings.EqualFold(s.Name, name)
|
||||
}
|
||||
|
||||
// Option return the value for the specified key. Empty string is returned if
|
||||
// key does not exists.
|
||||
func (s *Section) Option(key string) string {
|
||||
return s.Options.Get(key)
|
||||
}
|
||||
|
||||
// AddOption adds a new Option to the Section. The updated Section is returned.
|
||||
func (s *Section) AddOption(key string, value string) *Section {
|
||||
s.Options = s.Options.withAddedOption(key, value)
|
||||
return s
|
||||
}
|
||||
|
||||
// SetOption adds a new Option to the Section. If the option already exists, is replaced.
|
||||
// The updated Section is returned.
|
||||
func (s *Section) SetOption(key string, value string) *Section {
|
||||
s.Options = s.Options.withSettedOption(key, value)
|
||||
return s
|
||||
}
|
||||
|
||||
// Remove an option with the specified key. The updated Section is returned.
|
||||
func (s *Section) RemoveOption(key string) *Section {
|
||||
s.Options = s.Options.withoutOption(key)
|
||||
return s
|
||||
}
|
||||
|
||||
// Subsection returns a Subsection from the specified Section. If the
|
||||
// Subsection does not exists, new one is created and added to Section.
|
||||
func (s *Section) Subsection(name string) *Subsection {
|
||||
@ -115,6 +90,55 @@ func (s *Section) HasSubsection(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveSubsection removes a subsection from a Section.
|
||||
func (s *Section) RemoveSubsection(name string) *Section {
|
||||
result := Subsections{}
|
||||
for _, s := range s.Subsections {
|
||||
if !s.IsName(name) {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
s.Subsections = result
|
||||
return s
|
||||
}
|
||||
|
||||
// Option returns the value for the specified key. Empty string is returned if
|
||||
// key does not exists.
|
||||
func (s *Section) Option(key string) string {
|
||||
return s.Options.Get(key)
|
||||
}
|
||||
|
||||
// OptionAll returns all possible values for an option with the specified key.
|
||||
// If the option does not exists, an empty slice will be returned.
|
||||
func (s *Section) OptionAll(key string) []string {
|
||||
return s.Options.GetAll(key)
|
||||
}
|
||||
|
||||
// HasOption checks if the Section has an Option with the given key.
|
||||
func (s *Section) HasOption(key string) bool {
|
||||
return s.Options.Has(key)
|
||||
}
|
||||
|
||||
// AddOption adds a new Option to the Section. The updated Section is returned.
|
||||
func (s *Section) AddOption(key string, value string) *Section {
|
||||
s.Options = s.Options.withAddedOption(key, value)
|
||||
return s
|
||||
}
|
||||
|
||||
// SetOption adds a new Option to the Section. If the option already exists, is replaced.
|
||||
// The updated Section is returned.
|
||||
func (s *Section) SetOption(key string, value string) *Section {
|
||||
s.Options = s.Options.withSettedOption(key, value)
|
||||
return s
|
||||
}
|
||||
|
||||
// Remove an option with the specified key. The updated Section is returned.
|
||||
func (s *Section) RemoveOption(key string) *Section {
|
||||
s.Options = s.Options.withoutOption(key)
|
||||
return s
|
||||
}
|
||||
|
||||
// IsName checks if the name of the subsection is exactly the specified name.
|
||||
func (s *Subsection) IsName(name string) bool {
|
||||
return s.Name == name
|
||||
@ -126,6 +150,17 @@ func (s *Subsection) Option(key string) string {
|
||||
return s.Options.Get(key)
|
||||
}
|
||||
|
||||
// OptionAll returns all possible values for an option with the specified key.
|
||||
// If the option does not exists, an empty slice will be returned.
|
||||
func (s *Subsection) OptionAll(key string) []string {
|
||||
return s.Options.GetAll(key)
|
||||
}
|
||||
|
||||
// HasOption checks if the Subsection has an Option with the given key.
|
||||
func (s *Subsection) HasOption(key string) bool {
|
||||
return s.Options.Has(key)
|
||||
}
|
||||
|
||||
// AddOption adds a new Option to the Subsection. The updated Subsection is returned.
|
||||
func (s *Subsection) AddOption(key string, value string) *Subsection {
|
||||
s.Options = s.Options.withAddedOption(key, value)
|
||||
|
10
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/diff/patch.go
generated
vendored
10
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/diff/patch.go
generated
vendored
@ -9,7 +9,7 @@ import (
|
||||
type Operation int
|
||||
|
||||
const (
|
||||
// Equal item represents a equals diff.
|
||||
// Equal item represents an equals diff.
|
||||
Equal Operation = iota
|
||||
// Add item represents an insert diff.
|
||||
Add
|
||||
@ -26,15 +26,15 @@ type Patch interface {
|
||||
Message() string
|
||||
}
|
||||
|
||||
// FilePatch represents the necessary steps to transform one file to another.
|
||||
// FilePatch represents the necessary steps to transform one file into another.
|
||||
type FilePatch interface {
|
||||
// IsBinary returns true if this patch is representing a binary file.
|
||||
IsBinary() bool
|
||||
// Files returns the from and to Files, with all the necessary metadata to
|
||||
// Files returns the from and to Files, with all the necessary metadata
|
||||
// about them. If the patch creates a new file, "from" will be nil.
|
||||
// If the patch deletes a file, "to" will be nil.
|
||||
Files() (from, to File)
|
||||
// Chunks returns a slice of ordered changes to transform "from" File to
|
||||
// Chunks returns a slice of ordered changes to transform "from" File into
|
||||
// "to" File. If the file is a binary one, Chunks will be empty.
|
||||
Chunks() []Chunk
|
||||
}
|
||||
@ -49,7 +49,7 @@ type File interface {
|
||||
Path() string
|
||||
}
|
||||
|
||||
// Chunk represents a portion of a file transformation to another.
|
||||
// Chunk represents a portion of a file transformation into another.
|
||||
type Chunk interface {
|
||||
// Content contains the portion of the file.
|
||||
Content() string
|
||||
|
31
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/diff/unified_encoder.go
generated
vendored
31
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/diff/unified_encoder.go
generated
vendored
@ -38,6 +38,10 @@ type UnifiedEncoder struct {
|
||||
// a change.
|
||||
contextLines int
|
||||
|
||||
// srcPrefix and dstPrefix are prepended to file paths when encoding a diff.
|
||||
srcPrefix string
|
||||
dstPrefix string
|
||||
|
||||
// colorConfig is the color configuration. The default is no color.
|
||||
color ColorConfig
|
||||
}
|
||||
@ -46,6 +50,8 @@ type UnifiedEncoder struct {
|
||||
func NewUnifiedEncoder(w io.Writer, contextLines int) *UnifiedEncoder {
|
||||
return &UnifiedEncoder{
|
||||
Writer: w,
|
||||
srcPrefix: "a/",
|
||||
dstPrefix: "b/",
|
||||
contextLines: contextLines,
|
||||
}
|
||||
}
|
||||
@ -56,6 +62,18 @@ func (e *UnifiedEncoder) SetColor(colorConfig ColorConfig) *UnifiedEncoder {
|
||||
return e
|
||||
}
|
||||
|
||||
// SetSrcPrefix sets e's srcPrefix and returns e.
|
||||
func (e *UnifiedEncoder) SetSrcPrefix(prefix string) *UnifiedEncoder {
|
||||
e.srcPrefix = prefix
|
||||
return e
|
||||
}
|
||||
|
||||
// SetDstPrefix sets e's dstPrefix and returns e.
|
||||
func (e *UnifiedEncoder) SetDstPrefix(prefix string) *UnifiedEncoder {
|
||||
e.dstPrefix = prefix
|
||||
return e
|
||||
}
|
||||
|
||||
// Encode encodes patch.
|
||||
func (e *UnifiedEncoder) Encode(patch Patch) error {
|
||||
sb := &strings.Builder{}
|
||||
@ -91,7 +109,8 @@ func (e *UnifiedEncoder) writeFilePatchHeader(sb *strings.Builder, filePatch Fil
|
||||
case from != nil && to != nil:
|
||||
hashEquals := from.Hash() == to.Hash()
|
||||
lines = append(lines,
|
||||
fmt.Sprintf("diff --git a/%s b/%s", from.Path(), to.Path()),
|
||||
fmt.Sprintf("diff --git %s%s %s%s",
|
||||
e.srcPrefix, from.Path(), e.dstPrefix, to.Path()),
|
||||
)
|
||||
if from.Mode() != to.Mode() {
|
||||
lines = append(lines,
|
||||
@ -115,22 +134,22 @@ func (e *UnifiedEncoder) writeFilePatchHeader(sb *strings.Builder, filePatch Fil
|
||||
)
|
||||
}
|
||||
if !hashEquals {
|
||||
lines = e.appendPathLines(lines, "a/"+from.Path(), "b/"+to.Path(), isBinary)
|
||||
lines = e.appendPathLines(lines, e.srcPrefix+from.Path(), e.dstPrefix+to.Path(), isBinary)
|
||||
}
|
||||
case from == nil:
|
||||
lines = append(lines,
|
||||
fmt.Sprintf("diff --git a/%s b/%s", to.Path(), to.Path()),
|
||||
fmt.Sprintf("diff --git %s %s", e.srcPrefix+to.Path(), e.dstPrefix+to.Path()),
|
||||
fmt.Sprintf("new file mode %o", to.Mode()),
|
||||
fmt.Sprintf("index %s..%s", plumbing.ZeroHash, to.Hash()),
|
||||
)
|
||||
lines = e.appendPathLines(lines, "/dev/null", "b/"+to.Path(), isBinary)
|
||||
lines = e.appendPathLines(lines, "/dev/null", e.dstPrefix+to.Path(), isBinary)
|
||||
case to == nil:
|
||||
lines = append(lines,
|
||||
fmt.Sprintf("diff --git a/%s b/%s", from.Path(), from.Path()),
|
||||
fmt.Sprintf("diff --git %s %s", e.srcPrefix+from.Path(), e.dstPrefix+from.Path()),
|
||||
fmt.Sprintf("deleted file mode %o", from.Mode()),
|
||||
fmt.Sprintf("index %s..%s", from.Hash(), plumbing.ZeroHash),
|
||||
)
|
||||
lines = e.appendPathLines(lines, "a/"+from.Path(), "/dev/null", isBinary)
|
||||
lines = e.appendPathLines(lines, e.srcPrefix+from.Path(), "/dev/null", isBinary)
|
||||
}
|
||||
|
||||
sb.WriteString(e.color[Meta])
|
||||
|
48
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/gitignore/dir.go
generated
vendored
48
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/gitignore/dir.go
generated
vendored
@ -3,28 +3,32 @@ package gitignore
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"os/user"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
"github.com/jesseduffield/go-git/v5/internal/path_util"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/format/config"
|
||||
gioutil "github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
)
|
||||
|
||||
const (
|
||||
commentPrefix = "#"
|
||||
coreSection = "core"
|
||||
excludesfile = "excludesfile"
|
||||
gitDir = ".git"
|
||||
gitignoreFile = ".gitignore"
|
||||
gitconfigFile = ".gitconfig"
|
||||
systemFile = "/etc/gitconfig"
|
||||
commentPrefix = "#"
|
||||
coreSection = "core"
|
||||
excludesfile = "excludesfile"
|
||||
gitDir = ".git"
|
||||
gitignoreFile = ".gitignore"
|
||||
gitconfigFile = ".gitconfig"
|
||||
systemFile = "/etc/gitconfig"
|
||||
infoExcludeFile = gitDir + "/info/exclude"
|
||||
)
|
||||
|
||||
// readIgnoreFile reads a specific git ignore file.
|
||||
func readIgnoreFile(fs billy.Filesystem, path []string, ignoreFile string) (ps []Pattern, err error) {
|
||||
|
||||
ignoreFile, _ = path_util.ReplaceTildeWithHome(ignoreFile)
|
||||
|
||||
f, err := fs.Open(fs.Join(append(path, ignoreFile)...))
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
@ -43,10 +47,14 @@ func readIgnoreFile(fs billy.Filesystem, path []string, ignoreFile string) (ps [
|
||||
return
|
||||
}
|
||||
|
||||
// ReadPatterns reads gitignore patterns recursively traversing through the directory
|
||||
// structure. The result is in the ascending order of priority (last higher).
|
||||
// ReadPatterns reads the .git/info/exclude and then the gitignore patterns
|
||||
// recursively traversing through the directory structure. The result is in
|
||||
// the ascending order of priority (last higher).
|
||||
func ReadPatterns(fs billy.Filesystem, path []string) (ps []Pattern, err error) {
|
||||
ps, _ = readIgnoreFile(fs, path, gitignoreFile)
|
||||
ps, _ = readIgnoreFile(fs, path, infoExcludeFile)
|
||||
|
||||
subps, _ := readIgnoreFile(fs, path, gitignoreFile)
|
||||
ps = append(ps, subps...)
|
||||
|
||||
var fis []os.FileInfo
|
||||
fis, err = fs.ReadDir(fs.Join(path...))
|
||||
@ -56,6 +64,10 @@ func ReadPatterns(fs billy.Filesystem, path []string) (ps []Pattern, err error)
|
||||
|
||||
for _, fi := range fis {
|
||||
if fi.IsDir() && fi.Name() != gitDir {
|
||||
if NewMatcher(ps).Match(append(path, fi.Name()), true) {
|
||||
continue
|
||||
}
|
||||
|
||||
var subps []Pattern
|
||||
subps, err = ReadPatterns(fs, append(path, fi.Name()))
|
||||
if err != nil {
|
||||
@ -82,7 +94,7 @@ func loadPatterns(fs billy.Filesystem, path string) (ps []Pattern, err error) {
|
||||
|
||||
defer gioutil.CheckClose(f, &err)
|
||||
|
||||
b, err := ioutil.ReadAll(f)
|
||||
b, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -108,7 +120,7 @@ func loadPatterns(fs billy.Filesystem, path string) (ps []Pattern, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// LoadGlobalPatterns loads gitignore patterns from from the gitignore file
|
||||
// LoadGlobalPatterns loads gitignore patterns from the gitignore file
|
||||
// declared in a user's ~/.gitconfig file. If the ~/.gitconfig file does not
|
||||
// exist the function will return nil. If the core.excludesfile property
|
||||
// is not declared, the function will return nil. If the file pointed to by
|
||||
@ -116,16 +128,16 @@ func loadPatterns(fs billy.Filesystem, path string) (ps []Pattern, err error) {
|
||||
//
|
||||
// The function assumes fs is rooted at the root filesystem.
|
||||
func LoadGlobalPatterns(fs billy.Filesystem) (ps []Pattern, err error) {
|
||||
usr, err := user.Current()
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return loadPatterns(fs, fs.Join(usr.HomeDir, gitconfigFile))
|
||||
return loadPatterns(fs, fs.Join(home, gitconfigFile))
|
||||
}
|
||||
|
||||
// LoadSystemPatterns loads gitignore patterns from from the gitignore file
|
||||
// declared in a system's /etc/gitconfig file. If the ~/.gitconfig file does
|
||||
// LoadSystemPatterns loads gitignore patterns from the gitignore file
|
||||
// declared in a system's /etc/gitconfig file. If the /etc/gitconfig file does
|
||||
// not exist the function will return nil. If the core.excludesfile property
|
||||
// is not declared, the function will return nil. If the file pointed to by
|
||||
// the core.excludesfile property does not exist, the function will return nil.
|
||||
|
2
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/gitignore/pattern.go
generated
vendored
2
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/gitignore/pattern.go
generated
vendored
@ -39,6 +39,8 @@ type pattern struct {
|
||||
|
||||
// ParsePattern parses a gitignore pattern string into the Pattern structure.
|
||||
func ParsePattern(p string, domain []string) Pattern {
|
||||
// storing domain, copy it to ensure it isn't changed externally
|
||||
domain = append([]string(nil), domain...)
|
||||
res := pattern{domain: domain}
|
||||
|
||||
if strings.HasPrefix(p, inclusionPrefix) {
|
||||
|
7
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/idxfile/decoder.go
generated
vendored
7
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/idxfile/decoder.go
generated
vendored
@ -6,20 +6,21 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/hash"
|
||||
"github.com/jesseduffield/go-git/v5/utils/binary"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrUnsupportedVersion is returned by Decode when the idx file version
|
||||
// is not supported.
|
||||
ErrUnsupportedVersion = errors.New("Unsupported version")
|
||||
ErrUnsupportedVersion = errors.New("unsupported version")
|
||||
// ErrMalformedIdxFile is returned by Decode when the idx file is corrupted.
|
||||
ErrMalformedIdxFile = errors.New("Malformed IDX file")
|
||||
ErrMalformedIdxFile = errors.New("malformed IDX file")
|
||||
)
|
||||
|
||||
const (
|
||||
fanout = 256
|
||||
objectIDLength = 20
|
||||
objectIDLength = hash.Size
|
||||
)
|
||||
|
||||
// Decoder reads and decodes idx files from an input stream.
|
||||
|
9
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/idxfile/encoder.go
generated
vendored
9
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/idxfile/encoder.go
generated
vendored
@ -1,10 +1,9 @@
|
||||
package idxfile
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
"io"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/hash"
|
||||
"github.com/jesseduffield/go-git/v5/utils/binary"
|
||||
)
|
||||
|
||||
@ -16,7 +15,7 @@ type Encoder struct {
|
||||
|
||||
// NewEncoder returns a new stream encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
h := sha1.New()
|
||||
h := hash.New(hash.CryptoType)
|
||||
mw := io.MultiWriter(w, h)
|
||||
return &Encoder{mw, h}
|
||||
}
|
||||
@ -133,10 +132,10 @@ func (e *Encoder) encodeChecksums(idx *MemoryIndex) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
copy(idx.IdxChecksum[:], e.hash.Sum(nil)[:20])
|
||||
copy(idx.IdxChecksum[:], e.hash.Sum(nil)[:hash.Size])
|
||||
if _, err := e.Write(idx.IdxChecksum[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return 40, nil
|
||||
return hash.HexSize, nil
|
||||
}
|
||||
|
5
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/idxfile/idxfile.go
generated
vendored
5
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/idxfile/idxfile.go
generated
vendored
@ -8,6 +8,7 @@ import (
|
||||
encbin "encoding/binary"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/hash"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -53,8 +54,8 @@ type MemoryIndex struct {
|
||||
Offset32 [][]byte
|
||||
CRC32 [][]byte
|
||||
Offset64 []byte
|
||||
PackfileChecksum [20]byte
|
||||
IdxChecksum [20]byte
|
||||
PackfileChecksum [hash.Size]byte
|
||||
IdxChecksum [hash.Size]byte
|
||||
|
||||
offsetHash map[int64]plumbing.Hash
|
||||
offsetHashIsFull bool
|
||||
|
29
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/idxfile/writer.go
generated
vendored
29
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/idxfile/writer.go
generated
vendored
@ -84,11 +84,8 @@ func (w *Writer) OnFooter(h plumbing.Hash) error {
|
||||
w.checksum = h
|
||||
w.finished = true
|
||||
_, err := w.createIndex()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// creatIndex returns a filled MemoryIndex with the information filled by
|
||||
@ -139,15 +136,23 @@ func (w *Writer) createIndex() (*MemoryIndex, error) {
|
||||
|
||||
offset := o.Offset
|
||||
if offset > math.MaxInt32 {
|
||||
offset = w.addOffset64(offset)
|
||||
var err error
|
||||
offset, err = w.addOffset64(offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
buf.Truncate(0)
|
||||
binary.WriteUint32(buf, uint32(offset))
|
||||
if err := binary.WriteUint32(buf, uint32(offset)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idx.Offset32[bucket] = append(idx.Offset32[bucket], buf.Bytes()...)
|
||||
|
||||
buf.Truncate(0)
|
||||
binary.WriteUint32(buf, o.CRC32)
|
||||
if err := binary.WriteUint32(buf, o.CRC32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idx.CRC32[bucket] = append(idx.CRC32[bucket], buf.Bytes()...)
|
||||
}
|
||||
|
||||
@ -161,15 +166,17 @@ func (w *Writer) createIndex() (*MemoryIndex, error) {
|
||||
return idx, nil
|
||||
}
|
||||
|
||||
func (w *Writer) addOffset64(pos uint64) uint64 {
|
||||
func (w *Writer) addOffset64(pos uint64) (uint64, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
binary.WriteUint64(buf, pos)
|
||||
w.index.Offset64 = append(w.index.Offset64, buf.Bytes()...)
|
||||
if err := binary.WriteUint64(buf, pos); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
w.index.Offset64 = append(w.index.Offset64, buf.Bytes()...)
|
||||
index := uint64(w.offset64 | (1 << 31))
|
||||
w.offset64++
|
||||
|
||||
return index
|
||||
return index, nil
|
||||
}
|
||||
|
||||
func (o objects) Len() int {
|
||||
|
124
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/index/decoder.go
generated
vendored
124
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/index/decoder.go
generated
vendored
@ -3,15 +3,14 @@ package index
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/hash"
|
||||
"github.com/jesseduffield/go-git/v5/utils/binary"
|
||||
)
|
||||
|
||||
@ -25,8 +24,8 @@ var (
|
||||
// ErrInvalidChecksum is returned by Decode if the SHA1 hash mismatch with
|
||||
// the read content
|
||||
ErrInvalidChecksum = errors.New("invalid checksum")
|
||||
|
||||
errUnknownExtension = errors.New("unknown extension")
|
||||
// ErrUnknownExtension is returned when an index extension is encountered that is considered mandatory
|
||||
ErrUnknownExtension = errors.New("unknown extension")
|
||||
)
|
||||
|
||||
const (
|
||||
@ -40,6 +39,7 @@ const (
|
||||
|
||||
// A Decoder reads and decodes index files from an input stream.
|
||||
type Decoder struct {
|
||||
buf *bufio.Reader
|
||||
r io.Reader
|
||||
hash hash.Hash
|
||||
lastEntry *Entry
|
||||
@ -49,9 +49,11 @@ type Decoder struct {
|
||||
|
||||
// NewDecoder returns a new decoder that reads from r.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
h := sha1.New()
|
||||
h := hash.New(hash.CryptoType)
|
||||
buf := bufio.NewReader(r)
|
||||
return &Decoder{
|
||||
r: io.TeeReader(r, h),
|
||||
buf: buf,
|
||||
r: io.TeeReader(buf, h),
|
||||
hash: h,
|
||||
extReader: bufio.NewReader(nil),
|
||||
}
|
||||
@ -202,7 +204,7 @@ func (d *Decoder) padEntry(idx *Index, e *Entry, read int) error {
|
||||
|
||||
entrySize := read + len(e.Name)
|
||||
padLen := 8 - entrySize%8
|
||||
_, err := io.CopyN(ioutil.Discard, d.r, int64(padLen))
|
||||
_, err := io.CopyN(io.Discard, d.r, int64(padLen))
|
||||
return err
|
||||
}
|
||||
|
||||
@ -211,71 +213,75 @@ func (d *Decoder) readExtensions(idx *Index) error {
|
||||
// count that they are not supported by jgit or libgit
|
||||
|
||||
var expected []byte
|
||||
var peeked []byte
|
||||
var err error
|
||||
|
||||
var header [4]byte
|
||||
// we should always be able to peek for 4 bytes (header) + 4 bytes (extlen) + final hash
|
||||
// if this fails, we know that we're at the end of the index
|
||||
peekLen := 4 + 4 + d.hash.Size()
|
||||
|
||||
for {
|
||||
expected = d.hash.Sum(nil)
|
||||
|
||||
var n int
|
||||
if n, err = io.ReadFull(d.r, header[:]); err != nil {
|
||||
if n == 0 {
|
||||
err = io.EOF
|
||||
}
|
||||
|
||||
peeked, err = d.buf.Peek(peekLen)
|
||||
if len(peeked) < peekLen {
|
||||
// there can't be an extension at this point, so let's bail out
|
||||
break
|
||||
}
|
||||
|
||||
err = d.readExtension(idx, header[:])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != errUnknownExtension {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.readChecksum(expected, header)
|
||||
}
|
||||
|
||||
func (d *Decoder) readExtension(idx *Index, header []byte) error {
|
||||
switch {
|
||||
case bytes.Equal(header, treeExtSignature):
|
||||
r, err := d.getExtensionReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = d.readExtension(idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return d.readChecksum(expected)
|
||||
}
|
||||
|
||||
func (d *Decoder) readExtension(idx *Index) error {
|
||||
var header [4]byte
|
||||
|
||||
if _, err := io.ReadFull(d.r, header[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := d.getExtensionReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case bytes.Equal(header[:], treeExtSignature):
|
||||
idx.Cache = &Tree{}
|
||||
d := &treeExtensionDecoder{r}
|
||||
if err := d.Decode(idx.Cache); err != nil {
|
||||
return err
|
||||
}
|
||||
case bytes.Equal(header, resolveUndoExtSignature):
|
||||
r, err := d.getExtensionReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case bytes.Equal(header[:], resolveUndoExtSignature):
|
||||
idx.ResolveUndo = &ResolveUndo{}
|
||||
d := &resolveUndoDecoder{r}
|
||||
if err := d.Decode(idx.ResolveUndo); err != nil {
|
||||
return err
|
||||
}
|
||||
case bytes.Equal(header, endOfIndexEntryExtSignature):
|
||||
r, err := d.getExtensionReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case bytes.Equal(header[:], endOfIndexEntryExtSignature):
|
||||
idx.EndOfIndexEntry = &EndOfIndexEntry{}
|
||||
d := &endOfIndexEntryDecoder{r}
|
||||
if err := d.Decode(idx.EndOfIndexEntry); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errUnknownExtension
|
||||
// See https://git-scm.com/docs/index-format, which says:
|
||||
// If the first byte is 'A'..'Z' the extension is optional and can be ignored.
|
||||
if header[0] < 'A' || header[0] > 'Z' {
|
||||
return ErrUnknownExtension
|
||||
}
|
||||
|
||||
d := &unknownExtensionDecoder{r}
|
||||
if err := d.Decode(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -291,11 +297,10 @@ func (d *Decoder) getExtensionReader() (*bufio.Reader, error) {
|
||||
return d.extReader, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readChecksum(expected []byte, alreadyRead [4]byte) error {
|
||||
func (d *Decoder) readChecksum(expected []byte) error {
|
||||
var h plumbing.Hash
|
||||
copy(h[:4], alreadyRead[:])
|
||||
|
||||
if _, err := io.ReadFull(d.r, h[4:]); err != nil {
|
||||
if _, err := io.ReadFull(d.r, h[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -477,3 +482,22 @@ func (d *endOfIndexEntryDecoder) Decode(e *EndOfIndexEntry) error {
|
||||
_, err = io.ReadFull(d.r, e.Hash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
type unknownExtensionDecoder struct {
|
||||
r *bufio.Reader
|
||||
}
|
||||
|
||||
func (d *unknownExtensionDecoder) Decode() error {
|
||||
var buf [1024]byte
|
||||
|
||||
for {
|
||||
_, err := d.r.Read(buf[:])
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
129
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/index/encoder.go
generated
vendored
129
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/index/encoder.go
generated
vendored
@ -2,19 +2,21 @@ package index
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"hash"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/hash"
|
||||
"github.com/jesseduffield/go-git/v5/utils/binary"
|
||||
)
|
||||
|
||||
var (
|
||||
// EncodeVersionSupported is the range of supported index versions
|
||||
EncodeVersionSupported uint32 = 2
|
||||
EncodeVersionSupported uint32 = 4
|
||||
|
||||
// ErrInvalidTimestamp is returned by Encode if a Index with a Entry with
|
||||
// negative timestamp values
|
||||
@ -23,22 +25,27 @@ var (
|
||||
|
||||
// An Encoder writes an Index to an output stream.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
hash hash.Hash
|
||||
w io.Writer
|
||||
hash hash.Hash
|
||||
lastEntry *Entry
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
h := sha1.New()
|
||||
h := hash.New(hash.CryptoType)
|
||||
mw := io.MultiWriter(w, h)
|
||||
return &Encoder{mw, h}
|
||||
return &Encoder{mw, h, nil}
|
||||
}
|
||||
|
||||
// Encode writes the Index to the stream of the encoder.
|
||||
func (e *Encoder) Encode(idx *Index) error {
|
||||
// TODO: support versions v3 and v4
|
||||
return e.encode(idx, true)
|
||||
}
|
||||
|
||||
func (e *Encoder) encode(idx *Index, footer bool) error {
|
||||
|
||||
// TODO: support extensions
|
||||
if idx.Version != EncodeVersionSupported {
|
||||
if idx.Version > EncodeVersionSupported {
|
||||
return ErrUnsupportedVersion
|
||||
}
|
||||
|
||||
@ -50,7 +57,10 @@ func (e *Encoder) Encode(idx *Index) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.encodeFooter()
|
||||
if footer {
|
||||
return e.encodeFooter()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeHeader(idx *Index) error {
|
||||
@ -65,12 +75,16 @@ func (e *Encoder) encodeEntries(idx *Index) error {
|
||||
sort.Sort(byName(idx.Entries))
|
||||
|
||||
for _, entry := range idx.Entries {
|
||||
if err := e.encodeEntry(entry); err != nil {
|
||||
if err := e.encodeEntry(idx, entry); err != nil {
|
||||
return err
|
||||
}
|
||||
entryLength := entryHeaderLength
|
||||
if entry.IntentToAdd || entry.SkipWorktree {
|
||||
entryLength += 2
|
||||
}
|
||||
|
||||
wrote := entryHeaderLength + len(entry.Name)
|
||||
if err := e.padEntry(wrote); err != nil {
|
||||
wrote := entryLength + len(entry.Name)
|
||||
if err := e.padEntry(idx, wrote); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -78,11 +92,7 @@ func (e *Encoder) encodeEntries(idx *Index) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeEntry(entry *Entry) error {
|
||||
if entry.IntentToAdd || entry.SkipWorktree {
|
||||
return ErrUnsupportedVersion
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeEntry(idx *Index, entry *Entry) error {
|
||||
sec, nsec, err := e.timeToUint32(&entry.CreatedAt)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -110,16 +120,91 @@ func (e *Encoder) encodeEntry(entry *Entry) error {
|
||||
entry.GID,
|
||||
entry.Size,
|
||||
entry.Hash[:],
|
||||
flags,
|
||||
}
|
||||
|
||||
flagsFlow := []interface{}{flags}
|
||||
|
||||
if entry.IntentToAdd || entry.SkipWorktree {
|
||||
var extendedFlags uint16
|
||||
|
||||
if entry.IntentToAdd {
|
||||
extendedFlags |= intentToAddMask
|
||||
}
|
||||
if entry.SkipWorktree {
|
||||
extendedFlags |= skipWorkTreeMask
|
||||
}
|
||||
|
||||
flagsFlow = []interface{}{flags | entryExtended, extendedFlags}
|
||||
}
|
||||
|
||||
flow = append(flow, flagsFlow...)
|
||||
|
||||
if err := binary.Write(e.w, flow...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch idx.Version {
|
||||
case 2, 3:
|
||||
err = e.encodeEntryName(entry)
|
||||
case 4:
|
||||
err = e.encodeEntryNameV4(entry)
|
||||
default:
|
||||
err = ErrUnsupportedVersion
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeEntryName(entry *Entry) error {
|
||||
return binary.Write(e.w, []byte(entry.Name))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeEntryNameV4(entry *Entry) error {
|
||||
name := entry.Name
|
||||
l := 0
|
||||
if e.lastEntry != nil {
|
||||
dir := path.Dir(e.lastEntry.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)
|
||||
}
|
||||
}
|
||||
|
||||
e.lastEntry = entry
|
||||
|
||||
err := binary.WriteVariableWidthInt(e.w, int64(l))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return binary.Write(e.w, []byte(name+string('\x00')))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeRawExtension(signature string, data []byte) error {
|
||||
if len(signature) != 4 {
|
||||
return fmt.Errorf("invalid signature length")
|
||||
}
|
||||
|
||||
_, err := e.w.Write([]byte(signature))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = binary.WriteUint32(e.w, uint32(len(data)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = e.w.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) timeToUint32(t *time.Time) (uint32, uint32, error) {
|
||||
if t.IsZero() {
|
||||
return 0, 0, nil
|
||||
@ -132,7 +217,11 @@ func (e *Encoder) timeToUint32(t *time.Time) (uint32, uint32, error) {
|
||||
return uint32(t.Unix()), uint32(t.Nanosecond()), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) padEntry(wrote int) error {
|
||||
func (e *Encoder) padEntry(idx *Index, wrote int) error {
|
||||
if idx.Version == 4 {
|
||||
return nil
|
||||
}
|
||||
|
||||
padLen := 8 - wrote%8
|
||||
|
||||
_, err := e.w.Write(bytes.Repeat([]byte{'\x00'}, padLen))
|
||||
|
18
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/index/index.go
generated
vendored
18
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/index/index.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
@ -211,3 +212,20 @@ type EndOfIndexEntry struct {
|
||||
// their contents).
|
||||
Hash plumbing.Hash
|
||||
}
|
||||
|
||||
// SkipUnless applies patterns in the form of A, A/B, A/B/C
|
||||
// to the index to prevent the files from being checked out
|
||||
func (i *Index) SkipUnless(patterns []string) {
|
||||
for _, e := range i.Entries {
|
||||
var include bool
|
||||
for _, pattern := range patterns {
|
||||
if strings.HasPrefix(e.Name, pattern) {
|
||||
include = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !include {
|
||||
e.SkipWorktree = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/objfile/reader.go
generated
vendored
17
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/objfile/reader.go
generated
vendored
@ -1,13 +1,13 @@
|
||||
package objfile
|
||||
|
||||
import (
|
||||
"compress/zlib"
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/format/packfile"
|
||||
"github.com/jesseduffield/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -20,20 +20,22 @@ var (
|
||||
// Reader implements io.ReadCloser. Close should be called when finished with
|
||||
// the Reader. Close will not close the underlying io.Reader.
|
||||
type Reader struct {
|
||||
multi io.Reader
|
||||
zlib io.ReadCloser
|
||||
hasher plumbing.Hasher
|
||||
multi io.Reader
|
||||
zlib io.Reader
|
||||
zlibref sync.ZLibReader
|
||||
hasher plumbing.Hasher
|
||||
}
|
||||
|
||||
// NewReader returns a new Reader reading from r.
|
||||
func NewReader(r io.Reader) (*Reader, error) {
|
||||
zlib, err := zlib.NewReader(r)
|
||||
zlib, err := sync.GetZlibReader(r)
|
||||
if err != nil {
|
||||
return nil, packfile.ErrZLib.AddDetails(err.Error())
|
||||
}
|
||||
|
||||
return &Reader{
|
||||
zlib: zlib,
|
||||
zlib: zlib.Reader,
|
||||
zlibref: zlib,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -110,5 +112,6 @@ func (r *Reader) Hash() plumbing.Hash {
|
||||
// Close releases any resources consumed by the Reader. Calling Close does not
|
||||
// close the wrapped io.Reader originally passed to NewReader.
|
||||
func (r *Reader) Close() error {
|
||||
return r.zlib.Close()
|
||||
sync.PutZlibReader(r.zlibref)
|
||||
return nil
|
||||
}
|
||||
|
7
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/objfile/writer.go
generated
vendored
7
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/objfile/writer.go
generated
vendored
@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -18,9 +19,9 @@ var (
|
||||
// not close the underlying io.Writer.
|
||||
type Writer struct {
|
||||
raw io.Writer
|
||||
zlib io.WriteCloser
|
||||
hasher plumbing.Hasher
|
||||
multi io.Writer
|
||||
zlib *zlib.Writer
|
||||
|
||||
closed bool
|
||||
pending int64 // number of unwritten bytes
|
||||
@ -31,9 +32,10 @@ type Writer struct {
|
||||
// The returned Writer implements io.WriteCloser. Close should be called when
|
||||
// finished with the Writer. Close will not close the underlying io.Writer.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
zlib := sync.GetZlibWriter(w)
|
||||
return &Writer{
|
||||
raw: w,
|
||||
zlib: zlib.NewWriter(w),
|
||||
zlib: zlib,
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,6 +102,7 @@ func (w *Writer) Hash() plumbing.Hash {
|
||||
// Calling Close does not close the wrapped io.Writer originally passed to
|
||||
// NewWriter.
|
||||
func (w *Writer) Close() error {
|
||||
defer sync.PutZlibWriter(w.zlib)
|
||||
if err := w.zlib.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
18
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/common.go
generated
vendored
18
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/common.go
generated
vendored
@ -1,10 +1,7 @@
|
||||
package packfile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/storer"
|
||||
"github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
@ -61,18 +58,3 @@ func WritePackfileToObjectStorage(
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return bytes.NewBuffer(nil)
|
||||
},
|
||||
}
|
||||
|
||||
var zlibInitBytes = []byte{0x78, 0x9c, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01}
|
||||
|
||||
var zlibReaderPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
r, _ := zlib.NewReader(bytes.NewReader(zlibInitBytes))
|
||||
return r
|
||||
},
|
||||
}
|
||||
|
20
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/delta_index.go
generated
vendored
20
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/delta_index.go
generated
vendored
@ -32,19 +32,17 @@ func (idx *deltaIndex) findMatch(src, tgt []byte, tgtOffset int) (srcOffset, l i
|
||||
return 0, -1
|
||||
}
|
||||
|
||||
if len(tgt) >= tgtOffset+s && len(src) >= blksz {
|
||||
h := hashBlock(tgt, tgtOffset)
|
||||
tIdx := h & idx.mask
|
||||
eIdx := idx.table[tIdx]
|
||||
if eIdx != 0 {
|
||||
srcOffset = idx.entries[eIdx]
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
l = matchLength(src, tgt, tgtOffset, srcOffset)
|
||||
h := hashBlock(tgt, tgtOffset)
|
||||
tIdx := h & idx.mask
|
||||
eIdx := idx.table[tIdx]
|
||||
if eIdx == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
srcOffset = idx.entries[eIdx]
|
||||
|
||||
l = matchLength(src, tgt, tgtOffset, srcOffset)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
26
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/diff_delta.go
generated
vendored
26
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/diff_delta.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
"github.com/jesseduffield/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
// See https://github.com/jelmer/dulwich/blob/master/dulwich/pack.py and
|
||||
@ -16,8 +17,11 @@ const (
|
||||
s = 16
|
||||
|
||||
// https://github.com/git/git/blob/f7466e94375b3be27f229c78873f0acf8301c0a5/diff-delta.c#L428
|
||||
// Max size of a copy operation (64KB)
|
||||
// Max size of a copy operation (64KB).
|
||||
maxCopySize = 64 * 1024
|
||||
|
||||
// Min size of a copy operation.
|
||||
minCopySize = 4
|
||||
)
|
||||
|
||||
// GetDelta returns an EncodedObject of type OFSDeltaObject. Base and Target object,
|
||||
@ -43,18 +47,16 @@ func getDelta(index *deltaIndex, base, target plumbing.EncodedObject) (o plumbin
|
||||
|
||||
defer ioutil.CheckClose(tr, &err)
|
||||
|
||||
bb := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(bb)
|
||||
bb.Reset()
|
||||
bb := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(bb)
|
||||
|
||||
_, err = bb.ReadFrom(br)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tb := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(tb)
|
||||
tb.Reset()
|
||||
tb := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(tb)
|
||||
|
||||
_, err = tb.ReadFrom(tr)
|
||||
if err != nil {
|
||||
@ -80,9 +82,8 @@ func DiffDelta(src, tgt []byte) []byte {
|
||||
}
|
||||
|
||||
func diffDelta(index *deltaIndex, src []byte, tgt []byte) []byte {
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(buf)
|
||||
buf.Reset()
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
buf.Write(deltaEncodeSize(len(src)))
|
||||
buf.Write(deltaEncodeSize(len(tgt)))
|
||||
|
||||
@ -90,9 +91,8 @@ func diffDelta(index *deltaIndex, src []byte, tgt []byte) []byte {
|
||||
index.init(src)
|
||||
}
|
||||
|
||||
ibuf := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(ibuf)
|
||||
ibuf.Reset()
|
||||
ibuf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(ibuf)
|
||||
for i := 0; i < len(tgt); i++ {
|
||||
offset, l := index.findMatch(src, tgt, i)
|
||||
|
||||
|
10
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/encoder.go
generated
vendored
10
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/encoder.go
generated
vendored
@ -2,11 +2,11 @@ package packfile
|
||||
|
||||
import (
|
||||
"compress/zlib"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/hash"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/storer"
|
||||
"github.com/jesseduffield/go-git/v5/utils/binary"
|
||||
"github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
@ -28,7 +28,7 @@ type Encoder struct {
|
||||
// OFSDeltaObject. To use Reference deltas, set useRefDeltas to true.
|
||||
func NewEncoder(w io.Writer, s storer.EncodedObjectStorer, useRefDeltas bool) *Encoder {
|
||||
h := plumbing.Hasher{
|
||||
Hash: sha1.New(),
|
||||
Hash: hash.New(hash.CryptoType),
|
||||
}
|
||||
mw := io.MultiWriter(w, h)
|
||||
ow := newOffsetWriter(mw)
|
||||
@ -131,11 +131,7 @@ func (e *Encoder) entry(o *ObjectToPack) (err error) {
|
||||
defer ioutil.CheckClose(or, &err)
|
||||
|
||||
_, err = io.Copy(e.zw, or)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) writeBaseIfDelta(o *ObjectToPack) error {
|
||||
|
67
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/fsobject.go
generated
vendored
67
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/fsobject.go
generated
vendored
@ -7,19 +7,20 @@ import (
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/cache"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/format/idxfile"
|
||||
"github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
)
|
||||
|
||||
// FSObject is an object from the packfile on the filesystem.
|
||||
type FSObject struct {
|
||||
hash plumbing.Hash
|
||||
h *ObjectHeader
|
||||
offset int64
|
||||
size int64
|
||||
typ plumbing.ObjectType
|
||||
index idxfile.Index
|
||||
fs billy.Filesystem
|
||||
path string
|
||||
cache cache.Object
|
||||
hash plumbing.Hash
|
||||
offset int64
|
||||
size int64
|
||||
typ plumbing.ObjectType
|
||||
index idxfile.Index
|
||||
fs billy.Filesystem
|
||||
path string
|
||||
cache cache.Object
|
||||
largeObjectThreshold int64
|
||||
}
|
||||
|
||||
// NewFSObject creates a new filesystem object.
|
||||
@ -32,16 +33,18 @@ func NewFSObject(
|
||||
fs billy.Filesystem,
|
||||
path string,
|
||||
cache cache.Object,
|
||||
largeObjectThreshold int64,
|
||||
) *FSObject {
|
||||
return &FSObject{
|
||||
hash: hash,
|
||||
offset: offset,
|
||||
size: contentSize,
|
||||
typ: finalType,
|
||||
index: index,
|
||||
fs: fs,
|
||||
path: path,
|
||||
cache: cache,
|
||||
hash: hash,
|
||||
offset: offset,
|
||||
size: contentSize,
|
||||
typ: finalType,
|
||||
index: index,
|
||||
fs: fs,
|
||||
path: path,
|
||||
cache: cache,
|
||||
largeObjectThreshold: largeObjectThreshold,
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +65,21 @@ func (o *FSObject) Reader() (io.ReadCloser, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := NewPackfileWithCache(o.index, nil, f, o.cache)
|
||||
p := NewPackfileWithCache(o.index, nil, f, o.cache, o.largeObjectThreshold)
|
||||
if o.largeObjectThreshold > 0 && o.size > o.largeObjectThreshold {
|
||||
// We have a big object
|
||||
h, err := p.objectHeaderAtOffset(o.offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := p.getReaderDirect(h)
|
||||
if err != nil {
|
||||
_ = f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.NewReadCloserWithCloser(r, f.Close), nil
|
||||
}
|
||||
r, err := p.getObjectContent(o.offset)
|
||||
if err != nil {
|
||||
_ = f.Close()
|
||||
@ -100,17 +117,3 @@ func (o *FSObject) Type() plumbing.ObjectType {
|
||||
func (o *FSObject) Writer() (io.WriteCloser, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type objectReader struct {
|
||||
io.ReadCloser
|
||||
f billy.File
|
||||
}
|
||||
|
||||
func (r *objectReader) Close() error {
|
||||
if err := r.ReadCloser.Close(); err != nil {
|
||||
_ = r.f.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
return r.f.Close()
|
||||
}
|
||||
|
114
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/packfile.go
generated
vendored
114
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/packfile.go
generated
vendored
@ -2,6 +2,7 @@ package packfile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
@ -11,6 +12,7 @@ import (
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/format/idxfile"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/storer"
|
||||
"github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
"github.com/jesseduffield/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -35,11 +37,12 @@ const smallObjectThreshold = 16 * 1024
|
||||
// Packfile allows retrieving information from inside a packfile.
|
||||
type Packfile struct {
|
||||
idxfile.Index
|
||||
fs billy.Filesystem
|
||||
file billy.File
|
||||
s *Scanner
|
||||
deltaBaseCache cache.Object
|
||||
offsetToType map[int64]plumbing.ObjectType
|
||||
fs billy.Filesystem
|
||||
file billy.File
|
||||
s *Scanner
|
||||
deltaBaseCache cache.Object
|
||||
offsetToType map[int64]plumbing.ObjectType
|
||||
largeObjectThreshold int64
|
||||
}
|
||||
|
||||
// NewPackfileWithCache creates a new Packfile with the given object cache.
|
||||
@ -50,6 +53,7 @@ func NewPackfileWithCache(
|
||||
fs billy.Filesystem,
|
||||
file billy.File,
|
||||
cache cache.Object,
|
||||
largeObjectThreshold int64,
|
||||
) *Packfile {
|
||||
s := NewScanner(file)
|
||||
return &Packfile{
|
||||
@ -59,6 +63,7 @@ func NewPackfileWithCache(
|
||||
s,
|
||||
cache,
|
||||
make(map[int64]plumbing.ObjectType),
|
||||
largeObjectThreshold,
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,8 +71,8 @@ func NewPackfileWithCache(
|
||||
// and packfile idx.
|
||||
// If the filesystem is provided, the packfile will return FSObjects, otherwise
|
||||
// it will return MemoryObjects.
|
||||
func NewPackfile(index idxfile.Index, fs billy.Filesystem, file billy.File) *Packfile {
|
||||
return NewPackfileWithCache(index, fs, file, cache.NewObjectLRUDefault())
|
||||
func NewPackfile(index idxfile.Index, fs billy.Filesystem, file billy.File, largeObjectThreshold int64) *Packfile {
|
||||
return NewPackfileWithCache(index, fs, file, cache.NewObjectLRUDefault(), largeObjectThreshold)
|
||||
}
|
||||
|
||||
// Get retrieves the encoded object in the packfile with the given hash.
|
||||
@ -133,9 +138,8 @@ func (p *Packfile) getObjectSize(h *ObjectHeader) (int64, error) {
|
||||
case plumbing.CommitObject, plumbing.TreeObject, plumbing.BlobObject, plumbing.TagObject:
|
||||
return h.Length, nil
|
||||
case plumbing.REFDeltaObject, plumbing.OFSDeltaObject:
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(buf)
|
||||
buf.Reset()
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
|
||||
if _, _, err := p.s.NextObject(buf); err != nil {
|
||||
return 0, err
|
||||
@ -222,9 +226,9 @@ func (p *Packfile) getNextObject(h *ObjectHeader, hash plumbing.Hash) (plumbing.
|
||||
// For delta objects we read the delta data and apply the small object
|
||||
// optimization only if the expanded version of the object still meets
|
||||
// the small object threshold condition.
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(buf)
|
||||
buf.Reset()
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
|
||||
if _, _, err := p.s.NextObject(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -263,6 +267,7 @@ func (p *Packfile) getNextObject(h *ObjectHeader, hash plumbing.Hash) (plumbing.
|
||||
p.fs,
|
||||
p.file.Name(),
|
||||
p.deltaBaseCache,
|
||||
p.largeObjectThreshold,
|
||||
), nil
|
||||
}
|
||||
|
||||
@ -282,6 +287,49 @@ func (p *Packfile) getObjectContent(offset int64) (io.ReadCloser, error) {
|
||||
return obj.Reader()
|
||||
}
|
||||
|
||||
func asyncReader(p *Packfile) (io.ReadCloser, error) {
|
||||
reader := ioutil.NewReaderUsingReaderAt(p.file, p.s.r.offset)
|
||||
zr, err := sync.GetZlibReader(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("zlib reset error: %s", err)
|
||||
}
|
||||
|
||||
return ioutil.NewReadCloserWithCloser(zr.Reader, func() error {
|
||||
sync.PutZlibReader(zr)
|
||||
return nil
|
||||
}), nil
|
||||
|
||||
}
|
||||
|
||||
func (p *Packfile) getReaderDirect(h *ObjectHeader) (io.ReadCloser, error) {
|
||||
switch h.Type {
|
||||
case plumbing.CommitObject, plumbing.TreeObject, plumbing.BlobObject, plumbing.TagObject:
|
||||
return asyncReader(p)
|
||||
case plumbing.REFDeltaObject:
|
||||
deltaRc, err := asyncReader(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := p.readREFDeltaObjectContent(h, deltaRc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
case plumbing.OFSDeltaObject:
|
||||
deltaRc, err := asyncReader(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := p.readOFSDeltaObjectContent(h, deltaRc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
default:
|
||||
return nil, ErrInvalidObject.AddDetails("type %q", h.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Packfile) getNextMemoryObject(h *ObjectHeader) (plumbing.EncodedObject, error) {
|
||||
var obj = new(plumbing.MemoryObject)
|
||||
obj.SetSize(h.Length)
|
||||
@ -323,9 +371,9 @@ func (p *Packfile) fillRegularObjectContent(obj plumbing.EncodedObject) (err err
|
||||
}
|
||||
|
||||
func (p *Packfile) fillREFDeltaObjectContent(obj plumbing.EncodedObject, ref plumbing.Hash) error {
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(buf)
|
||||
buf.Reset()
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
|
||||
_, _, err := p.s.NextObject(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -334,6 +382,20 @@ func (p *Packfile) fillREFDeltaObjectContent(obj plumbing.EncodedObject, ref plu
|
||||
return p.fillREFDeltaObjectContentWithBuffer(obj, ref, buf)
|
||||
}
|
||||
|
||||
func (p *Packfile) readREFDeltaObjectContent(h *ObjectHeader, deltaRC io.Reader) (io.ReadCloser, error) {
|
||||
var err error
|
||||
|
||||
base, ok := p.cacheGet(h.Reference)
|
||||
if !ok {
|
||||
base, err = p.Get(h.Reference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return ReaderFromDelta(base, deltaRC)
|
||||
}
|
||||
|
||||
func (p *Packfile) fillREFDeltaObjectContentWithBuffer(obj plumbing.EncodedObject, ref plumbing.Hash, buf *bytes.Buffer) error {
|
||||
var err error
|
||||
|
||||
@ -353,9 +415,9 @@ func (p *Packfile) fillREFDeltaObjectContentWithBuffer(obj plumbing.EncodedObjec
|
||||
}
|
||||
|
||||
func (p *Packfile) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset int64) error {
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(buf)
|
||||
buf.Reset()
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
|
||||
_, _, err := p.s.NextObject(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -364,6 +426,20 @@ func (p *Packfile) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset
|
||||
return p.fillOFSDeltaObjectContentWithBuffer(obj, offset, buf)
|
||||
}
|
||||
|
||||
func (p *Packfile) readOFSDeltaObjectContent(h *ObjectHeader, deltaRC io.Reader) (io.ReadCloser, error) {
|
||||
hash, err := p.FindHash(h.OffsetReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base, err := p.objectAtOffset(h.OffsetReference, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ReaderFromDelta(base, deltaRC)
|
||||
}
|
||||
|
||||
func (p *Packfile) fillOFSDeltaObjectContentWithBuffer(obj plumbing.EncodedObject, offset int64, buf *bytes.Buffer) error {
|
||||
hash, err := p.FindHash(offset)
|
||||
if err != nil {
|
||||
|
232
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/parser.go
generated
vendored
232
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/parser.go
generated
vendored
@ -3,13 +3,14 @@ package packfile
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
stdioutil "io/ioutil"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/cache"
|
||||
"github.com/jesseduffield/go-git/v5/plumbing/storer"
|
||||
"github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
"github.com/jesseduffield/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -46,7 +47,6 @@ type Parser struct {
|
||||
oi []*objectInfo
|
||||
oiByHash map[plumbing.Hash]*objectInfo
|
||||
oiByOffset map[int64]*objectInfo
|
||||
hashOffset map[plumbing.Hash]int64
|
||||
checksum plumbing.Hash
|
||||
|
||||
cache *cache.BufferLRU
|
||||
@ -175,12 +175,25 @@ func (p *Parser) init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type objectHeaderWriter func(typ plumbing.ObjectType, sz int64) error
|
||||
|
||||
type lazyObjectWriter interface {
|
||||
// LazyWriter enables an object to be lazily written.
|
||||
// It returns:
|
||||
// - w: a writer to receive the object's content.
|
||||
// - lwh: a func to write the object header.
|
||||
// - err: any error from the initial writer creation process.
|
||||
//
|
||||
// Note that if the object header is not written BEFORE the writer
|
||||
// is used, this will result in an invalid object.
|
||||
LazyWriter() (w io.WriteCloser, lwh objectHeaderWriter, err error)
|
||||
}
|
||||
|
||||
func (p *Parser) indexObjects() error {
|
||||
buf := new(bytes.Buffer)
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
|
||||
for i := uint32(0); i < p.count; i++ {
|
||||
buf.Reset()
|
||||
|
||||
oh, err := p.scanner.NextObjectHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -220,39 +233,76 @@ func (p *Parser) indexObjects() error {
|
||||
ota = newBaseObject(oh.Offset, oh.Length, t)
|
||||
}
|
||||
|
||||
_, crc, err := p.scanner.NextObject(buf)
|
||||
hasher := plumbing.NewHasher(oh.Type, oh.Length)
|
||||
writers := []io.Writer{hasher}
|
||||
var obj *plumbing.MemoryObject
|
||||
|
||||
// Lazy writing is only available for non-delta objects.
|
||||
if p.storage != nil && !delta {
|
||||
// When a storage is set and supports lazy writing,
|
||||
// use that instead of creating a memory object.
|
||||
if low, ok := p.storage.(lazyObjectWriter); ok {
|
||||
ow, lwh, err := low.LazyWriter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = lwh(oh.Type, oh.Length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer ow.Close()
|
||||
writers = append(writers, ow)
|
||||
} else {
|
||||
obj = new(plumbing.MemoryObject)
|
||||
obj.SetSize(oh.Length)
|
||||
obj.SetType(oh.Type)
|
||||
|
||||
writers = append(writers, obj)
|
||||
}
|
||||
}
|
||||
if delta && !p.scanner.IsSeekable {
|
||||
buf.Reset()
|
||||
buf.Grow(int(oh.Length))
|
||||
writers = append(writers, buf)
|
||||
}
|
||||
|
||||
mw := io.MultiWriter(writers...)
|
||||
|
||||
_, crc, err := p.scanner.NextObject(mw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Non delta objects needs to be added into the storage. This
|
||||
// is only required when lazy writing is not supported.
|
||||
if obj != nil {
|
||||
if _, err := p.storage.SetEncodedObject(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ota.Crc32 = crc
|
||||
ota.Length = oh.Length
|
||||
|
||||
data := buf.Bytes()
|
||||
if !delta {
|
||||
sha1, err := getSHA1(ota.Type, data)
|
||||
if err != nil {
|
||||
return err
|
||||
sha1 := hasher.Sum()
|
||||
|
||||
// Move children of placeholder parent into actual parent, in case this
|
||||
// was a non-external delta reference.
|
||||
if placeholder, ok := p.oiByHash[sha1]; ok {
|
||||
ota.Children = placeholder.Children
|
||||
for _, c := range ota.Children {
|
||||
c.Parent = ota
|
||||
}
|
||||
}
|
||||
|
||||
ota.SHA1 = sha1
|
||||
p.oiByHash[ota.SHA1] = ota
|
||||
}
|
||||
|
||||
if p.storage != nil && !delta {
|
||||
obj := new(plumbing.MemoryObject)
|
||||
obj.SetSize(oh.Length)
|
||||
obj.SetType(oh.Type)
|
||||
if _, err := obj.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := p.storage.SetEncodedObject(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if delta && !p.scanner.IsSeekable {
|
||||
data := buf.Bytes()
|
||||
p.deltas[oh.Offset] = make([]byte, len(data))
|
||||
copy(p.deltas[oh.Offset], data)
|
||||
}
|
||||
@ -265,28 +315,37 @@ func (p *Parser) indexObjects() error {
|
||||
}
|
||||
|
||||
func (p *Parser) resolveDeltas() error {
|
||||
buf := &bytes.Buffer{}
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
|
||||
for _, obj := range p.oi {
|
||||
buf.Reset()
|
||||
buf.Grow(int(obj.Length))
|
||||
err := p.get(obj, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content := buf.Bytes()
|
||||
|
||||
if err := p.onInflatedObjectHeader(obj.Type, obj.Length, obj.Offset); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := p.onInflatedObjectContent(obj.SHA1, obj.Offset, obj.Crc32, content); err != nil {
|
||||
if err := p.onInflatedObjectContent(obj.SHA1, obj.Offset, obj.Crc32, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !obj.IsDelta() && len(obj.Children) > 0 {
|
||||
// Dealing with an io.ReaderAt object, means we can
|
||||
// create it once and reuse across all children.
|
||||
r := bytes.NewReader(buf.Bytes())
|
||||
for _, child := range obj.Children {
|
||||
if err := p.resolveObject(stdioutil.Discard, child, content); err != nil {
|
||||
// Even though we are discarding the output, we still need to read it to
|
||||
// so that the scanner can advance to the next object, and the SHA1 can be
|
||||
// calculated.
|
||||
if err := p.resolveObject(io.Discard, child, r); err != nil {
|
||||
return err
|
||||
}
|
||||
p.resolveExternalRef(child)
|
||||
}
|
||||
|
||||
// Remove the delta from the cache.
|
||||
@ -299,6 +358,16 @@ func (p *Parser) resolveDeltas() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) resolveExternalRef(o *objectInfo) {
|
||||
if ref, ok := p.oiByHash[o.SHA1]; ok && ref.ExternalRef {
|
||||
p.oiByHash[o.SHA1] = o
|
||||
o.Children = ref.Children
|
||||
for _, c := range o.Children {
|
||||
c.Parent = o
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) get(o *objectInfo, buf *bytes.Buffer) (err error) {
|
||||
if !o.ExternalRef { // skip cache check for placeholder parents
|
||||
b, ok := p.cache.Get(o.Offset)
|
||||
@ -336,16 +405,15 @@ func (p *Parser) get(o *objectInfo, buf *bytes.Buffer) (err error) {
|
||||
}
|
||||
|
||||
if o.DiskType.IsDelta() {
|
||||
b := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(b)
|
||||
b.Reset()
|
||||
b := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(b)
|
||||
buf.Grow(int(o.Length))
|
||||
err := p.get(o.Parent, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
base := b.Bytes()
|
||||
|
||||
err = p.resolveObject(buf, o, base)
|
||||
err = p.resolveObject(buf, o, bytes.NewReader(b.Bytes()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -356,6 +424,13 @@ func (p *Parser) get(o *objectInfo, buf *bytes.Buffer) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// If the scanner is seekable, caching this data into
|
||||
// memory by offset seems wasteful.
|
||||
// There is a trade-off to be considered here in terms
|
||||
// of execution time vs memory consumption.
|
||||
//
|
||||
// TODO: improve seekable execution time, so that we can
|
||||
// skip this cache.
|
||||
if len(o.Children) > 0 {
|
||||
data := make([]byte, buf.Len())
|
||||
copy(data, buf.Bytes())
|
||||
@ -364,41 +439,75 @@ func (p *Parser) get(o *objectInfo, buf *bytes.Buffer) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolveObject resolves an object from base, using information
|
||||
// provided by o.
|
||||
//
|
||||
// This call has the side-effect of changing field values
|
||||
// from the object info o:
|
||||
// - Type: OFSDeltaObject may become the target type (e.g. Blob).
|
||||
// - Size: The size may be update with the target size.
|
||||
// - Hash: Zero hashes will be calculated as part of the object
|
||||
// resolution. Hence why this process can't be avoided even when w
|
||||
// is an io.Discard.
|
||||
//
|
||||
// base must be an io.ReaderAt, which is a requirement from
|
||||
// patchDeltaStream. The main reason being that reversing an
|
||||
// delta object may lead to going backs and forths within base,
|
||||
// which is not supported by io.Reader.
|
||||
func (p *Parser) resolveObject(
|
||||
w io.Writer,
|
||||
o *objectInfo,
|
||||
base []byte,
|
||||
base io.ReaderAt,
|
||||
) error {
|
||||
if !o.DiskType.IsDelta() {
|
||||
return nil
|
||||
}
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(buf)
|
||||
buf.Reset()
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
err := p.readData(buf, o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := buf.Bytes()
|
||||
|
||||
data, err = applyPatchBase(o, data, base)
|
||||
writers := []io.Writer{w}
|
||||
var obj *plumbing.MemoryObject
|
||||
var lwh objectHeaderWriter
|
||||
|
||||
if p.storage != nil {
|
||||
if low, ok := p.storage.(lazyObjectWriter); ok {
|
||||
ow, wh, err := low.LazyWriter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lwh = wh
|
||||
|
||||
defer ow.Close()
|
||||
writers = append(writers, ow)
|
||||
} else {
|
||||
obj = new(plumbing.MemoryObject)
|
||||
ow, err := obj.Writer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
writers = append(writers, ow)
|
||||
}
|
||||
}
|
||||
|
||||
mw := io.MultiWriter(writers...)
|
||||
|
||||
err = applyPatchBase(o, base, buf, mw, lwh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.storage != nil {
|
||||
obj := new(plumbing.MemoryObject)
|
||||
obj.SetSize(o.Size())
|
||||
if obj != nil {
|
||||
obj.SetType(o.Type)
|
||||
if _, err := obj.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
obj.SetSize(o.Size()) // Size here is correct as it was populated by applyPatchBase.
|
||||
if _, err := p.storage.SetEncodedObject(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -422,24 +531,31 @@ func (p *Parser) readData(w io.Writer, o *objectInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyPatchBase(ota *objectInfo, data, base []byte) ([]byte, error) {
|
||||
patched, err := PatchDelta(base, data)
|
||||
// applyPatchBase applies the patch to target.
|
||||
//
|
||||
// Note that ota will be updated based on the description in resolveObject.
|
||||
func applyPatchBase(ota *objectInfo, base io.ReaderAt, delta io.Reader, target io.Writer, wh objectHeaderWriter) error {
|
||||
if target == nil {
|
||||
return fmt.Errorf("cannot apply patch against nil target")
|
||||
}
|
||||
|
||||
typ := ota.Type
|
||||
if ota.SHA1 == plumbing.ZeroHash {
|
||||
typ = ota.Parent.Type
|
||||
}
|
||||
|
||||
sz, h, err := patchDeltaWriter(target, base, delta, typ, wh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if ota.SHA1 == plumbing.ZeroHash {
|
||||
ota.Type = ota.Parent.Type
|
||||
sha1, err := getSHA1(ota.Type, patched)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ota.SHA1 = sha1
|
||||
ota.Length = int64(len(patched))
|
||||
ota.Type = typ
|
||||
ota.Length = int64(sz)
|
||||
ota.SHA1 = h
|
||||
}
|
||||
|
||||
return patched, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSHA1(t plumbing.ObjectType, data []byte) (plumbing.Hash, error) {
|
||||
|
437
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/patch_delta.go
generated
vendored
437
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/patch_delta.go
generated
vendored
@ -1,12 +1,16 @@
|
||||
package packfile
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
"github.com/jesseduffield/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
// See https://github.com/git/git/blob/49fa3dc76179e04b0833542fa52d0f287a4955ac/delta.h
|
||||
@ -14,7 +18,40 @@ import (
|
||||
// and https://github.com/tarruda/node-git-core/blob/master/src/js/delta.js
|
||||
// for details about the delta format.
|
||||
|
||||
const deltaSizeMin = 4
|
||||
var (
|
||||
ErrInvalidDelta = errors.New("invalid delta")
|
||||
ErrDeltaCmd = errors.New("wrong delta command")
|
||||
)
|
||||
|
||||
const (
|
||||
payload = 0x7f // 0111 1111
|
||||
continuation = 0x80 // 1000 0000
|
||||
|
||||
// maxPatchPreemptionSize defines what is the max size of bytes to be
|
||||
// premptively made available for a patch operation.
|
||||
maxPatchPreemptionSize uint = 65536
|
||||
|
||||
// minDeltaSize defines the smallest size for a delta.
|
||||
minDeltaSize = 4
|
||||
)
|
||||
|
||||
type offset struct {
|
||||
mask byte
|
||||
shift uint
|
||||
}
|
||||
|
||||
var offsets = []offset{
|
||||
{mask: 0x01, shift: 0},
|
||||
{mask: 0x02, shift: 8},
|
||||
{mask: 0x04, shift: 16},
|
||||
{mask: 0x08, shift: 24},
|
||||
}
|
||||
|
||||
var sizes = []offset{
|
||||
{mask: 0x10, shift: 0},
|
||||
{mask: 0x20, shift: 8},
|
||||
{mask: 0x40, shift: 16},
|
||||
}
|
||||
|
||||
// ApplyDelta writes to target the result of applying the modification deltas in delta to base.
|
||||
func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) (err error) {
|
||||
@ -32,18 +69,16 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) (err error) {
|
||||
|
||||
defer ioutil.CheckClose(w, &err)
|
||||
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(buf)
|
||||
buf.Reset()
|
||||
buf := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(buf)
|
||||
_, err = buf.ReadFrom(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src := buf.Bytes()
|
||||
|
||||
dst := bufPool.Get().(*bytes.Buffer)
|
||||
defer bufPool.Put(dst)
|
||||
dst.Reset()
|
||||
dst := sync.GetBytesBuffer()
|
||||
defer sync.PutBytesBuffer(dst)
|
||||
err = patchDelta(dst, src, delta)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -51,21 +86,20 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) (err error) {
|
||||
|
||||
target.SetSize(int64(dst.Len()))
|
||||
|
||||
b := byteSlicePool.Get().([]byte)
|
||||
_, err = io.CopyBuffer(w, dst, b)
|
||||
byteSlicePool.Put(b)
|
||||
b := sync.GetByteSlice()
|
||||
_, err = io.CopyBuffer(w, dst, *b)
|
||||
sync.PutByteSlice(b)
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidDelta = errors.New("invalid delta")
|
||||
ErrDeltaCmd = errors.New("wrong delta command")
|
||||
)
|
||||
|
||||
// PatchDelta returns the result of applying the modification deltas in delta to src.
|
||||
// An error will be returned if delta is corrupted (ErrDeltaLen) or an action command
|
||||
// An error will be returned if delta is corrupted (ErrInvalidDelta) or an action command
|
||||
// is not copy from source or copy from delta (ErrDeltaCmd).
|
||||
func PatchDelta(src, delta []byte) ([]byte, error) {
|
||||
if len(src) == 0 || len(delta) < minDeltaSize {
|
||||
return nil, ErrInvalidDelta
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
if err := patchDelta(b, src, delta); err != nil {
|
||||
return nil, err
|
||||
@ -73,8 +107,137 @@ func PatchDelta(src, delta []byte) ([]byte, error) {
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func ReaderFromDelta(base plumbing.EncodedObject, deltaRC io.Reader) (io.ReadCloser, error) {
|
||||
deltaBuf := bufio.NewReaderSize(deltaRC, 1024)
|
||||
srcSz, err := decodeLEB128ByteReader(deltaBuf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return nil, ErrInvalidDelta
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if srcSz != uint(base.Size()) {
|
||||
return nil, ErrInvalidDelta
|
||||
}
|
||||
|
||||
targetSz, err := decodeLEB128ByteReader(deltaBuf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return nil, ErrInvalidDelta
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
remainingTargetSz := targetSz
|
||||
|
||||
dstRd, dstWr := io.Pipe()
|
||||
|
||||
go func() {
|
||||
baseRd, err := base.Reader()
|
||||
if err != nil {
|
||||
_ = dstWr.CloseWithError(ErrInvalidDelta)
|
||||
return
|
||||
}
|
||||
defer baseRd.Close()
|
||||
|
||||
baseBuf := bufio.NewReader(baseRd)
|
||||
basePos := uint(0)
|
||||
|
||||
for {
|
||||
cmd, err := deltaBuf.ReadByte()
|
||||
if err == io.EOF {
|
||||
_ = dstWr.CloseWithError(ErrInvalidDelta)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
_ = dstWr.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
switch {
|
||||
case isCopyFromSrc(cmd):
|
||||
offset, err := decodeOffsetByteReader(cmd, deltaBuf)
|
||||
if err != nil {
|
||||
_ = dstWr.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
sz, err := decodeSizeByteReader(cmd, deltaBuf)
|
||||
if err != nil {
|
||||
_ = dstWr.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if invalidSize(sz, targetSz) ||
|
||||
invalidOffsetSize(offset, sz, srcSz) {
|
||||
_ = dstWr.Close()
|
||||
return
|
||||
}
|
||||
|
||||
discard := offset - basePos
|
||||
if basePos > offset {
|
||||
_ = baseRd.Close()
|
||||
baseRd, err = base.Reader()
|
||||
if err != nil {
|
||||
_ = dstWr.CloseWithError(ErrInvalidDelta)
|
||||
return
|
||||
}
|
||||
baseBuf.Reset(baseRd)
|
||||
discard = offset
|
||||
}
|
||||
for discard > math.MaxInt32 {
|
||||
n, err := baseBuf.Discard(math.MaxInt32)
|
||||
if err != nil {
|
||||
_ = dstWr.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
basePos += uint(n)
|
||||
discard -= uint(n)
|
||||
}
|
||||
for discard > 0 {
|
||||
n, err := baseBuf.Discard(int(discard))
|
||||
if err != nil {
|
||||
_ = dstWr.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
basePos += uint(n)
|
||||
discard -= uint(n)
|
||||
}
|
||||
if _, err := io.Copy(dstWr, io.LimitReader(baseBuf, int64(sz))); err != nil {
|
||||
_ = dstWr.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
remainingTargetSz -= sz
|
||||
basePos += sz
|
||||
|
||||
case isCopyFromDelta(cmd):
|
||||
sz := uint(cmd) // cmd is the size itself
|
||||
if invalidSize(sz, targetSz) {
|
||||
_ = dstWr.CloseWithError(ErrInvalidDelta)
|
||||
return
|
||||
}
|
||||
if _, err := io.Copy(dstWr, io.LimitReader(deltaBuf, int64(sz))); err != nil {
|
||||
_ = dstWr.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
remainingTargetSz -= sz
|
||||
|
||||
default:
|
||||
_ = dstWr.CloseWithError(ErrDeltaCmd)
|
||||
return
|
||||
}
|
||||
|
||||
if remainingTargetSz <= 0 {
|
||||
_ = dstWr.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return dstRd, nil
|
||||
}
|
||||
|
||||
func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
if len(delta) < deltaSizeMin {
|
||||
if len(delta) < minCopySize {
|
||||
return ErrInvalidDelta
|
||||
}
|
||||
|
||||
@ -87,7 +250,9 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
remainingTargetSz := targetSz
|
||||
|
||||
var cmd byte
|
||||
dst.Grow(int(targetSz))
|
||||
|
||||
growSz := min(targetSz, maxPatchPreemptionSize)
|
||||
dst.Grow(int(growSz))
|
||||
for {
|
||||
if len(delta) == 0 {
|
||||
return ErrInvalidDelta
|
||||
@ -95,7 +260,9 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
|
||||
cmd = delta[0]
|
||||
delta = delta[1:]
|
||||
if isCopyFromSrc(cmd) {
|
||||
|
||||
switch {
|
||||
case isCopyFromSrc(cmd):
|
||||
var offset, sz uint
|
||||
var err error
|
||||
offset, delta, err = decodeOffset(cmd, delta)
|
||||
@ -114,7 +281,8 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
}
|
||||
dst.Write(src[offset : offset+sz])
|
||||
remainingTargetSz -= sz
|
||||
} else if isCopyFromDelta(cmd) {
|
||||
|
||||
case isCopyFromDelta(cmd):
|
||||
sz := uint(cmd) // cmd is the size itself
|
||||
if invalidSize(sz, targetSz) {
|
||||
return ErrInvalidDelta
|
||||
@ -127,7 +295,8 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
dst.Write(delta[0:sz])
|
||||
remainingTargetSz -= sz
|
||||
delta = delta[sz:]
|
||||
} else {
|
||||
|
||||
default:
|
||||
return ErrDeltaCmd
|
||||
}
|
||||
|
||||
@ -139,6 +308,107 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func patchDeltaWriter(dst io.Writer, base io.ReaderAt, delta io.Reader,
|
||||
typ plumbing.ObjectType, writeHeader objectHeaderWriter) (uint, plumbing.Hash, error) {
|
||||
deltaBuf := bufio.NewReaderSize(delta, 1024)
|
||||
srcSz, err := decodeLEB128ByteReader(deltaBuf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return 0, plumbing.ZeroHash, ErrInvalidDelta
|
||||
}
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
if r, ok := base.(*bytes.Reader); ok && srcSz != uint(r.Size()) {
|
||||
return 0, plumbing.ZeroHash, ErrInvalidDelta
|
||||
}
|
||||
|
||||
targetSz, err := decodeLEB128ByteReader(deltaBuf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return 0, plumbing.ZeroHash, ErrInvalidDelta
|
||||
}
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
// If header still needs to be written, caller will provide
|
||||
// a LazyObjectWriterHeader. This seems to be the case when
|
||||
// dealing with thin-packs.
|
||||
if writeHeader != nil {
|
||||
err = writeHeader(typ, int64(targetSz))
|
||||
if err != nil {
|
||||
return 0, plumbing.ZeroHash, fmt.Errorf("could not lazy write header: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
remainingTargetSz := targetSz
|
||||
|
||||
hasher := plumbing.NewHasher(typ, int64(targetSz))
|
||||
mw := io.MultiWriter(dst, hasher)
|
||||
|
||||
bufp := sync.GetByteSlice()
|
||||
defer sync.PutByteSlice(bufp)
|
||||
|
||||
sr := io.NewSectionReader(base, int64(0), int64(srcSz))
|
||||
// Keep both the io.LimitedReader types, so we can reset N.
|
||||
baselr := io.LimitReader(sr, 0).(*io.LimitedReader)
|
||||
deltalr := io.LimitReader(deltaBuf, 0).(*io.LimitedReader)
|
||||
|
||||
for {
|
||||
buf := *bufp
|
||||
cmd, err := deltaBuf.ReadByte()
|
||||
if err == io.EOF {
|
||||
return 0, plumbing.ZeroHash, ErrInvalidDelta
|
||||
}
|
||||
if err != nil {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
if isCopyFromSrc(cmd) {
|
||||
offset, err := decodeOffsetByteReader(cmd, deltaBuf)
|
||||
if err != nil {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
sz, err := decodeSizeByteReader(cmd, deltaBuf)
|
||||
if err != nil {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
if invalidSize(sz, targetSz) ||
|
||||
invalidOffsetSize(offset, sz, srcSz) {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
if _, err := sr.Seek(int64(offset), io.SeekStart); err != nil {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
baselr.N = int64(sz)
|
||||
if _, err := io.CopyBuffer(mw, baselr, buf); err != nil {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
remainingTargetSz -= sz
|
||||
} else if isCopyFromDelta(cmd) {
|
||||
sz := uint(cmd) // cmd is the size itself
|
||||
if invalidSize(sz, targetSz) {
|
||||
return 0, plumbing.ZeroHash, ErrInvalidDelta
|
||||
}
|
||||
deltalr.N = int64(sz)
|
||||
if _, err := io.CopyBuffer(mw, deltalr, buf); err != nil {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
|
||||
remainingTargetSz -= sz
|
||||
} else {
|
||||
return 0, plumbing.ZeroHash, err
|
||||
}
|
||||
if remainingTargetSz <= 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return targetSz, hasher.Sum(), nil
|
||||
}
|
||||
|
||||
// Decodes a number encoded as an unsigned LEB128 at the start of some
|
||||
// binary data and returns the decoded number and the rest of the
|
||||
// stream.
|
||||
@ -146,6 +416,10 @@ func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
|
||||
// This must be called twice on the delta data buffer, first to get the
|
||||
// expected source buffer size, and again to get the target buffer size.
|
||||
func decodeLEB128(input []byte) (uint, []byte) {
|
||||
if len(input) == 0 {
|
||||
return 0, input
|
||||
}
|
||||
|
||||
var num, sz uint
|
||||
var b byte
|
||||
for {
|
||||
@ -161,78 +435,95 @@ func decodeLEB128(input []byte) (uint, []byte) {
|
||||
return num, input[sz:]
|
||||
}
|
||||
|
||||
const (
|
||||
payload = 0x7f // 0111 1111
|
||||
continuation = 0x80 // 1000 0000
|
||||
)
|
||||
func decodeLEB128ByteReader(input io.ByteReader) (uint, error) {
|
||||
var num, sz uint
|
||||
for {
|
||||
b, err := input.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
num |= (uint(b) & payload) << (sz * 7) // concats 7 bits chunks
|
||||
sz++
|
||||
|
||||
if uint(b)&continuation == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return num, nil
|
||||
}
|
||||
|
||||
func isCopyFromSrc(cmd byte) bool {
|
||||
return (cmd & 0x80) != 0
|
||||
return (cmd & continuation) != 0
|
||||
}
|
||||
|
||||
func isCopyFromDelta(cmd byte) bool {
|
||||
return (cmd&0x80) == 0 && cmd != 0
|
||||
return (cmd&continuation) == 0 && cmd != 0
|
||||
}
|
||||
|
||||
func decodeOffsetByteReader(cmd byte, delta io.ByteReader) (uint, error) {
|
||||
var offset uint
|
||||
for _, o := range offsets {
|
||||
if (cmd & o.mask) != 0 {
|
||||
next, err := delta.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset |= uint(next) << o.shift
|
||||
}
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func decodeOffset(cmd byte, delta []byte) (uint, []byte, error) {
|
||||
var offset uint
|
||||
if (cmd & 0x01) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
for _, o := range offsets {
|
||||
if (cmd & o.mask) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
}
|
||||
offset |= uint(delta[0]) << o.shift
|
||||
delta = delta[1:]
|
||||
}
|
||||
offset = uint(delta[0])
|
||||
delta = delta[1:]
|
||||
}
|
||||
if (cmd & 0x02) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
}
|
||||
offset |= uint(delta[0]) << 8
|
||||
delta = delta[1:]
|
||||
}
|
||||
if (cmd & 0x04) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
}
|
||||
offset |= uint(delta[0]) << 16
|
||||
delta = delta[1:]
|
||||
}
|
||||
if (cmd & 0x08) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
}
|
||||
offset |= uint(delta[0]) << 24
|
||||
delta = delta[1:]
|
||||
}
|
||||
|
||||
return offset, delta, nil
|
||||
}
|
||||
|
||||
func decodeSizeByteReader(cmd byte, delta io.ByteReader) (uint, error) {
|
||||
var sz uint
|
||||
for _, s := range sizes {
|
||||
if (cmd & s.mask) != 0 {
|
||||
next, err := delta.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
sz |= uint(next) << s.shift
|
||||
}
|
||||
}
|
||||
|
||||
if sz == 0 {
|
||||
sz = maxCopySize
|
||||
}
|
||||
|
||||
return sz, nil
|
||||
}
|
||||
|
||||
func decodeSize(cmd byte, delta []byte) (uint, []byte, error) {
|
||||
var sz uint
|
||||
if (cmd & 0x10) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
for _, s := range sizes {
|
||||
if (cmd & s.mask) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
}
|
||||
sz |= uint(delta[0]) << s.shift
|
||||
delta = delta[1:]
|
||||
}
|
||||
sz = uint(delta[0])
|
||||
delta = delta[1:]
|
||||
}
|
||||
if (cmd & 0x20) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
}
|
||||
sz |= uint(delta[0]) << 8
|
||||
delta = delta[1:]
|
||||
}
|
||||
if (cmd & 0x40) != 0 {
|
||||
if len(delta) == 0 {
|
||||
return 0, nil, ErrInvalidDelta
|
||||
}
|
||||
sz |= uint(delta[0]) << 16
|
||||
delta = delta[1:]
|
||||
}
|
||||
if sz == 0 {
|
||||
sz = 0x10000
|
||||
sz = maxCopySize
|
||||
}
|
||||
|
||||
return sz, delta, nil
|
||||
|
64
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/scanner.go
generated
vendored
64
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/packfile/scanner.go
generated
vendored
@ -3,17 +3,15 @@ package packfile
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"fmt"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
stdioutil "io/ioutil"
|
||||
"sync"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/plumbing"
|
||||
"github.com/jesseduffield/go-git/v5/utils/binary"
|
||||
"github.com/jesseduffield/go-git/v5/utils/ioutil"
|
||||
"github.com/jesseduffield/go-git/v5/utils/sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -114,7 +112,7 @@ func (s *Scanner) Header() (version, objects uint32, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// readSignature reads an returns the signature field in the packfile.
|
||||
// readSignature reads a returns the signature field in the packfile.
|
||||
func (s *Scanner) readSignature() ([]byte, error) {
|
||||
var sig = make([]byte, 4)
|
||||
if _, err := io.ReadFull(s.r, sig); err != nil {
|
||||
@ -243,7 +241,7 @@ func (s *Scanner) discardObjectIfNeeded() error {
|
||||
}
|
||||
|
||||
h := s.pendingObject
|
||||
n, _, err := s.NextObject(stdioutil.Discard)
|
||||
n, _, err := s.NextObject(io.Discard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -320,29 +318,38 @@ func (s *Scanner) NextObject(w io.Writer) (written int64, crc32 uint32, err erro
|
||||
return
|
||||
}
|
||||
|
||||
// ReadObject returns a reader for the object content and an error
|
||||
func (s *Scanner) ReadObject() (io.ReadCloser, error) {
|
||||
s.pendingObject = nil
|
||||
zr, err := sync.GetZlibReader(s.r)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("zlib reset error: %s", err)
|
||||
}
|
||||
|
||||
return ioutil.NewReadCloserWithCloser(zr.Reader, func() error {
|
||||
sync.PutZlibReader(zr)
|
||||
return nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
// ReadRegularObject reads and write a non-deltified object
|
||||
// from it zlib stream in an object entry in the packfile.
|
||||
func (s *Scanner) copyObject(w io.Writer) (n int64, err error) {
|
||||
zr := zlibReaderPool.Get().(io.ReadCloser)
|
||||
defer zlibReaderPool.Put(zr)
|
||||
zr, err := sync.GetZlibReader(s.r)
|
||||
defer sync.PutZlibReader(zr)
|
||||
|
||||
if err = zr.(zlib.Resetter).Reset(s.r, nil); err != nil {
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("zlib reset error: %s", err)
|
||||
}
|
||||
|
||||
defer ioutil.CheckClose(zr, &err)
|
||||
buf := byteSlicePool.Get().([]byte)
|
||||
n, err = io.CopyBuffer(w, zr, buf)
|
||||
byteSlicePool.Put(buf)
|
||||
defer ioutil.CheckClose(zr.Reader, &err)
|
||||
buf := sync.GetByteSlice()
|
||||
n, err = io.CopyBuffer(w, zr.Reader, *buf)
|
||||
sync.PutByteSlice(buf)
|
||||
return
|
||||
}
|
||||
|
||||
var byteSlicePool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, 32*1024)
|
||||
},
|
||||
}
|
||||
|
||||
// SeekFromStart sets a new offset from start, returns the old position before
|
||||
// the change.
|
||||
func (s *Scanner) SeekFromStart(offset int64) (previous int64, err error) {
|
||||
@ -372,9 +379,10 @@ func (s *Scanner) Checksum() (plumbing.Hash, error) {
|
||||
|
||||
// Close reads the reader until io.EOF
|
||||
func (s *Scanner) Close() error {
|
||||
buf := byteSlicePool.Get().([]byte)
|
||||
_, err := io.CopyBuffer(stdioutil.Discard, s.r, buf)
|
||||
byteSlicePool.Put(buf)
|
||||
buf := sync.GetByteSlice()
|
||||
_, err := io.CopyBuffer(io.Discard, s.r, *buf)
|
||||
sync.PutByteSlice(buf)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@ -384,13 +392,13 @@ func (s *Scanner) Flush() error {
|
||||
}
|
||||
|
||||
// scannerReader has the following characteristics:
|
||||
// - Provides an io.SeekReader impl for bufio.Reader, when the underlying
|
||||
// reader supports it.
|
||||
// - Keeps track of the current read position, for when the underlying reader
|
||||
// isn't an io.SeekReader, but we still want to know the current offset.
|
||||
// - Writes to the hash writer what it reads, with the aid of a smaller buffer.
|
||||
// The buffer helps avoid a performance penality for performing small writes
|
||||
// to the crc32 hash writer.
|
||||
// - Provides an io.SeekReader impl for bufio.Reader, when the underlying
|
||||
// reader supports it.
|
||||
// - Keeps track of the current read position, for when the underlying reader
|
||||
// isn't an io.SeekReader, but we still want to know the current offset.
|
||||
// - Writes to the hash writer what it reads, with the aid of a smaller buffer.
|
||||
// The buffer helps avoid a performance penalty for performing small writes
|
||||
// to the crc32 hash writer.
|
||||
type scannerReader struct {
|
||||
reader io.Reader
|
||||
crc io.Writer
|
||||
|
4
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/pktline/encoder.go
generated
vendored
4
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/pktline/encoder.go
generated
vendored
@ -7,6 +7,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/utils/trace"
|
||||
)
|
||||
|
||||
// An Encoder writes pkt-lines to an output stream.
|
||||
@ -43,6 +45,7 @@ func NewEncoder(w io.Writer) *Encoder {
|
||||
|
||||
// Flush encodes a flush-pkt to the output stream.
|
||||
func (e *Encoder) Flush() error {
|
||||
defer trace.Packet.Print("packet: > 0000")
|
||||
_, err := e.w.Write(FlushPkt)
|
||||
return err
|
||||
}
|
||||
@ -70,6 +73,7 @@ func (e *Encoder) encodeLine(p []byte) error {
|
||||
}
|
||||
|
||||
n := len(p) + 4
|
||||
defer trace.Packet.Printf("packet: > %04x %s", n, p)
|
||||
if _, err := e.w.Write(asciiHex16(n)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
51
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/pktline/error.go
generated
vendored
Normal file
51
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/pktline/error.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
package pktline
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidErrorLine is returned by Decode when the packet line is not an
|
||||
// error line.
|
||||
ErrInvalidErrorLine = errors.New("expected an error-line")
|
||||
|
||||
errPrefix = []byte("ERR ")
|
||||
)
|
||||
|
||||
// ErrorLine is a packet line that contains an error message.
|
||||
// Once this packet is sent by client or server, the data transfer process is
|
||||
// terminated.
|
||||
// See https://git-scm.com/docs/pack-protocol#_pkt_line_format
|
||||
type ErrorLine struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e *ErrorLine) Error() string {
|
||||
return e.Text
|
||||
}
|
||||
|
||||
// Encode encodes the ErrorLine into a packet line.
|
||||
func (e *ErrorLine) Encode(w io.Writer) error {
|
||||
p := NewEncoder(w)
|
||||
return p.Encodef("%s%s\n", string(errPrefix), e.Text)
|
||||
}
|
||||
|
||||
// Decode decodes a packet line into an ErrorLine.
|
||||
func (e *ErrorLine) Decode(r io.Reader) error {
|
||||
s := NewScanner(r)
|
||||
if !s.Scan() {
|
||||
return s.Err()
|
||||
}
|
||||
|
||||
line := s.Bytes()
|
||||
if !bytes.HasPrefix(line, errPrefix) {
|
||||
return ErrInvalidErrorLine
|
||||
}
|
||||
|
||||
e.Text = strings.TrimSpace(string(line[4:]))
|
||||
return nil
|
||||
}
|
14
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/pktline/scanner.go
generated
vendored
14
vendor/github.com/jesseduffield/go-git/v5/plumbing/format/pktline/scanner.go
generated
vendored
@ -1,8 +1,12 @@
|
||||
package pktline
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/go-git/v5/utils/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -65,6 +69,14 @@ func (s *Scanner) Scan() bool {
|
||||
return false
|
||||
}
|
||||
s.payload = s.payload[:l]
|
||||
trace.Packet.Printf("packet: < %04x %s", l, s.payload)
|
||||
|
||||
if bytes.HasPrefix(s.payload, errPrefix) {
|
||||
s.err = &ErrorLine{
|
||||
Text: strings.TrimSpace(string(s.payload[4:])),
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@ -128,6 +140,8 @@ func asciiHexToByte(b byte) (byte, error) {
|
||||
return b - '0', nil
|
||||
case b >= 'a' && b <= 'f':
|
||||
return b - 'a' + 10, nil
|
||||
case b >= 'A' && b <= 'F':
|
||||
return b - 'A' + 10, nil
|
||||
default:
|
||||
return 0, ErrInvalidPktLen
|
||||
}
|
||||
|
Reference in New Issue
Block a user