mirror of
https://github.com/peridotbuild/peridot.git
synced 2024-09-19 16:52:36 +00:00
govendor
This commit is contained in:
parent
6d46a34c82
commit
96cca525d1
58
deps.bzl
58
deps.bzl
@ -220,6 +220,12 @@ def go_dependencies():
|
||||
sum = "h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=",
|
||||
version = "v4.0.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_bluekeyes_go_gitdiff",
|
||||
importpath = "github.com/bluekeyes/go-gitdiff",
|
||||
sum = "h1:AXrIoy/VEA9Baz2lhwMlpdzDJ/sKof6C9yTt1oqw4hQ=",
|
||||
version = "v0.5.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_bmatcuk_doublestar_v4",
|
||||
@ -1214,6 +1220,13 @@ def go_dependencies():
|
||||
sum = "h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=",
|
||||
version = "v0.5.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_hashicorp_hcl",
|
||||
importpath = "github.com/hashicorp/hcl",
|
||||
sum = "h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=",
|
||||
version = "v1.0.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_hashicorp_hcl_v2",
|
||||
importpath = "github.com/hashicorp/hcl/v2",
|
||||
@ -1621,6 +1634,13 @@ def go_dependencies():
|
||||
sum = "h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=",
|
||||
version = "v1.2.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_mitchellh_go_homedir",
|
||||
importpath = "github.com/mitchellh/go-homedir",
|
||||
sum = "h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=",
|
||||
version = "v1.1.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_mitchellh_go_wordwrap",
|
||||
importpath = "github.com/mitchellh/go-wordwrap",
|
||||
@ -1962,6 +1982,12 @@ def go_dependencies():
|
||||
sum = "h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=",
|
||||
version = "v3.0.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_rocky_linux_srpmproc",
|
||||
importpath = "github.com/rocky-linux/srpmproc",
|
||||
sum = "h1:rVCtpFyrYI7kAj5XOCZEB4ZcBMfh/E2Vt01AxwJsfpE=",
|
||||
version = "v0.5.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_rogpeppe_fastuuid",
|
||||
@ -2099,6 +2125,12 @@ def go_dependencies():
|
||||
sum = "h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=",
|
||||
version = "v0.0.0-20180118202830-f09979ecbc72",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_spf13_afero",
|
||||
importpath = "github.com/spf13/afero",
|
||||
sum = "h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=",
|
||||
version = "v1.1.2",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_spf13_cast",
|
||||
@ -2113,6 +2145,12 @@ def go_dependencies():
|
||||
sum = "h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=",
|
||||
version = "v1.7.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_spf13_jwalterweatherman",
|
||||
importpath = "github.com/spf13/jwalterweatherman",
|
||||
sum = "h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=",
|
||||
version = "v1.0.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_spf13_pflag",
|
||||
@ -2120,6 +2158,13 @@ def go_dependencies():
|
||||
sum = "h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=",
|
||||
version = "v1.0.5",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_spf13_viper",
|
||||
importpath = "github.com/spf13/viper",
|
||||
sum = "h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=",
|
||||
version = "v1.7.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_stefanberger_go_pkcs11uri",
|
||||
importpath = "github.com/stefanberger/go-pkcs11uri",
|
||||
@ -2146,6 +2191,13 @@ def go_dependencies():
|
||||
sum = "h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=",
|
||||
version = "v1.8.4",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_subosito_gotenv",
|
||||
importpath = "github.com/subosito/gotenv",
|
||||
sum = "h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=",
|
||||
version = "v1.2.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_syndtr_gocapability",
|
||||
importpath = "github.com/syndtr/gocapability",
|
||||
@ -3197,6 +3249,12 @@ def go_dependencies():
|
||||
sum = "h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=",
|
||||
version = "v0.9.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "in_gopkg_ini_v1",
|
||||
importpath = "gopkg.in/ini.v1",
|
||||
sum = "h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=",
|
||||
version = "v1.51.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "in_gopkg_square_go_jose_v2",
|
||||
|
6
go.mod
6
go.mod
@ -26,6 +26,7 @@ require (
|
||||
github.com/jarcoal/httpmock v1.3.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/rocky-linux/srpmproc v0.5.0
|
||||
github.com/sassoftware/go-rpmutils v0.2.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/temporalio/temporalite v0.3.1-0.20230117200252-2df426ad3426
|
||||
@ -43,6 +44,7 @@ require (
|
||||
golang.org/x/crypto v0.12.0
|
||||
golang.org/x/mod v0.12.0
|
||||
golang.org/x/oauth2 v0.11.0
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d
|
||||
google.golang.org/grpc v1.57.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
@ -82,6 +84,7 @@ require (
|
||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/bluekeyes/go-gitdiff v0.5.0 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.0 // indirect
|
||||
github.com/bufbuild/protocompile v0.6.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
@ -258,7 +261,6 @@ require (
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.138.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
@ -289,3 +291,5 @@ replace go.resf.org/peridot/tools/mothership/pb => ./bazel-bin/tools/mothership/
|
||||
replace go.resf.org/peridot/third_party/bazel/src/main/protobuf => ./bazel-bin/third_party/bazel/src/main/protobuf/blaze_query_go_proto_/go.resf.org/peridot/third_party/bazel/src/main/protobuf
|
||||
|
||||
replace go.resf.org/peridot/tools/mothership/admin/pb => ./bazel-bin/tools/mothership/proto/admin/v1/mshipadminpb_go_proto_/go.resf.org/peridot/tools/mothership/admin/pb
|
||||
|
||||
replace google.golang.org/genproto/googleapis/longrunning => ./bazel-bin/third_party/googleapis/google/longrunning/longrunning_go_proto_/google.golang.org/genproto/googleapis/longrunning
|
||||
|
4
go.sum
4
go.sum
@ -452,6 +452,8 @@ github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCS
|
||||
github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bluekeyes/go-gitdiff v0.5.0 h1:AXrIoy/VEA9Baz2lhwMlpdzDJ/sKof6C9yTt1oqw4hQ=
|
||||
github.com/bluekeyes/go-gitdiff v0.5.0/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM=
|
||||
github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
@ -964,6 +966,8 @@ github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rocky-linux/srpmproc v0.5.0 h1:rVCtpFyrYI7kAj5XOCZEB4ZcBMfh/E2Vt01AxwJsfpE=
|
||||
github.com/rocky-linux/srpmproc v0.5.0/go.mod h1:x8Z2wqhV2JqRnYMhYz3thOQkfsSWjJkyX8DVGDPOb48=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
|
21
vendor/github.com/bluekeyes/go-gitdiff/LICENSE
generated
vendored
Normal file
21
vendor/github.com/bluekeyes/go-gitdiff/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Billy Keyes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
19
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/BUILD
generated
vendored
Normal file
19
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/BUILD
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "gitdiff",
|
||||
srcs = [
|
||||
"apply.go",
|
||||
"base85.go",
|
||||
"binary.go",
|
||||
"file_header.go",
|
||||
"gitdiff.go",
|
||||
"io.go",
|
||||
"parser.go",
|
||||
"patch_header.go",
|
||||
"text.go",
|
||||
],
|
||||
importmap = "go.resf.org/peridot/vendor/github.com/bluekeyes/go-gitdiff/gitdiff",
|
||||
importpath = "github.com/bluekeyes/go-gitdiff/gitdiff",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
454
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/apply.go
generated
vendored
Normal file
454
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/apply.go
generated
vendored
Normal file
@ -0,0 +1,454 @@
|
||||
package gitdiff
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Conflict indicates an apply failed due to a conflict between the patch and
|
||||
// the source content.
|
||||
//
|
||||
// Users can test if an error was caused by a conflict by using errors.Is with
|
||||
// an empty Conflict:
|
||||
//
|
||||
// if errors.Is(err, &Conflict{}) {
|
||||
// // handle conflict
|
||||
// }
|
||||
//
|
||||
type Conflict struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (c *Conflict) Error() string {
|
||||
return "conflict: " + c.msg
|
||||
}
|
||||
|
||||
// Is implements error matching for Conflict. Passing an empty instance of
|
||||
// Conflict always returns true.
|
||||
func (c *Conflict) Is(other error) bool {
|
||||
if other, ok := other.(*Conflict); ok {
|
||||
return other.msg == "" || other.msg == c.msg
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ApplyError wraps an error that occurs during patch application with
|
||||
// additional location information, if it is available.
|
||||
type ApplyError struct {
|
||||
// Line is the one-indexed line number in the source data
|
||||
Line int64
|
||||
// Fragment is the one-indexed fragment number in the file
|
||||
Fragment int
|
||||
// FragmentLine is the one-indexed line number in the fragment
|
||||
FragmentLine int
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
// Unwrap returns the wrapped error.
|
||||
func (e *ApplyError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func (e *ApplyError) Error() string {
|
||||
return fmt.Sprintf("%v", e.err)
|
||||
}
|
||||
|
||||
type lineNum int
|
||||
type fragNum int
|
||||
type fragLineNum int
|
||||
|
||||
// applyError creates a new *ApplyError wrapping err or augments the information
|
||||
// in err with args if it is already an *ApplyError. Returns nil if err is nil.
|
||||
func applyError(err error, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
e, ok := err.(*ApplyError)
|
||||
if !ok {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
e = &ApplyError{err: err}
|
||||
}
|
||||
for _, arg := range args {
|
||||
switch v := arg.(type) {
|
||||
case lineNum:
|
||||
e.Line = int64(v) + 1
|
||||
case fragNum:
|
||||
e.Fragment = int(v) + 1
|
||||
case fragLineNum:
|
||||
e.FragmentLine = int(v) + 1
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
errApplyInProgress = errors.New("gitdiff: incompatible apply in progress")
|
||||
)
|
||||
|
||||
const (
|
||||
applyInitial = iota
|
||||
applyText
|
||||
applyBinary
|
||||
applyFile
|
||||
)
|
||||
|
||||
// Apply is a convenience function that creates an Applier for src with default
|
||||
// settings and applies the changes in f, writing the result to dst.
|
||||
func Apply(dst io.Writer, src io.ReaderAt, f *File) error {
|
||||
return NewApplier(src).ApplyFile(dst, f)
|
||||
}
|
||||
|
||||
// Applier applies changes described in fragments to source data. If changes
|
||||
// are described in multiple fragments, those fragments must be applied in
|
||||
// order, usually by calling ApplyFile.
|
||||
//
|
||||
// By default, Applier operates in "strict" mode, where fragment content and
|
||||
// positions must exactly match those of the source.
|
||||
//
|
||||
// If an error occurs while applying, methods on Applier return instances of
|
||||
// *ApplyError that annotate the wrapped error with additional information
|
||||
// when available. If the error is because of a conflict between a fragment and
|
||||
// the source, the wrapped error will be a *Conflict.
|
||||
//
|
||||
// While an Applier can apply both text and binary fragments, only one fragment
|
||||
// type can be used without resetting the Applier. The first fragment applied
|
||||
// sets the type for the Applier. Mixing fragment types or mixing
|
||||
// fragment-level and file-level applies results in an error.
|
||||
type Applier struct {
|
||||
src io.ReaderAt
|
||||
lineSrc LineReaderAt
|
||||
nextLine int64
|
||||
applyType int
|
||||
}
|
||||
|
||||
// NewApplier creates an Applier that reads data from src. If src is a
|
||||
// LineReaderAt, it is used directly to apply text fragments.
|
||||
func NewApplier(src io.ReaderAt) *Applier {
|
||||
a := new(Applier)
|
||||
a.Reset(src)
|
||||
return a
|
||||
}
|
||||
|
||||
// Reset resets the input and internal state of the Applier. If src is nil, the
|
||||
// existing source is reused.
|
||||
func (a *Applier) Reset(src io.ReaderAt) {
|
||||
if src != nil {
|
||||
a.src = src
|
||||
if lineSrc, ok := src.(LineReaderAt); ok {
|
||||
a.lineSrc = lineSrc
|
||||
} else {
|
||||
a.lineSrc = &lineReaderAt{r: src}
|
||||
}
|
||||
}
|
||||
a.nextLine = 0
|
||||
a.applyType = applyInitial
|
||||
}
|
||||
|
||||
// ApplyFile applies the changes in all of the fragments of f and writes the
|
||||
// result to dst.
|
||||
func (a *Applier) ApplyFile(dst io.Writer, f *File) error {
|
||||
if a.applyType != applyInitial {
|
||||
return applyError(errApplyInProgress)
|
||||
}
|
||||
defer func() { a.applyType = applyFile }()
|
||||
|
||||
if f.IsBinary && len(f.TextFragments) > 0 {
|
||||
return applyError(errors.New("binary file contains text fragments"))
|
||||
}
|
||||
if !f.IsBinary && f.BinaryFragment != nil {
|
||||
return applyError(errors.New("text file contains binary fragment"))
|
||||
}
|
||||
|
||||
switch {
|
||||
case f.BinaryFragment != nil:
|
||||
return a.ApplyBinaryFragment(dst, f.BinaryFragment)
|
||||
|
||||
case len(f.TextFragments) > 0:
|
||||
frags := make([]*TextFragment, len(f.TextFragments))
|
||||
copy(frags, f.TextFragments)
|
||||
|
||||
sort.Slice(frags, func(i, j int) bool {
|
||||
return frags[i].OldPosition < frags[j].OldPosition
|
||||
})
|
||||
|
||||
// TODO(bkeyes): consider merging overlapping fragments
|
||||
// right now, the application fails if fragments overlap, but it should be
|
||||
// possible to precompute the result of applying them in order
|
||||
|
||||
for i, frag := range frags {
|
||||
if err := a.ApplyTextFragment(dst, frag); err != nil {
|
||||
return applyError(err, fragNum(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return applyError(a.Flush(dst))
|
||||
}
|
||||
|
||||
// ApplyTextFragment applies the changes in the fragment f and writes unwritten
|
||||
// data before the start of the fragment and the result to dst. If multiple
|
||||
// text fragments apply to the same source, ApplyTextFragment must be called in
|
||||
// order of increasing start position. As a result, each fragment can be
|
||||
// applied at most once before a call to Reset.
|
||||
func (a *Applier) ApplyTextFragment(dst io.Writer, f *TextFragment) error {
|
||||
if a.applyType != applyInitial && a.applyType != applyText {
|
||||
return applyError(errApplyInProgress)
|
||||
}
|
||||
defer func() { a.applyType = applyText }()
|
||||
|
||||
// application code assumes fragment fields are consistent
|
||||
if err := f.Validate(); err != nil {
|
||||
return applyError(err)
|
||||
}
|
||||
|
||||
// lines are 0-indexed, positions are 1-indexed (but new files have position = 0)
|
||||
fragStart := f.OldPosition - 1
|
||||
if fragStart < 0 {
|
||||
fragStart = 0
|
||||
}
|
||||
fragEnd := fragStart + f.OldLines
|
||||
|
||||
start := a.nextLine
|
||||
if fragStart < start {
|
||||
return applyError(&Conflict{"fragment overlaps with an applied fragment"})
|
||||
}
|
||||
|
||||
if f.OldPosition == 0 {
|
||||
ok, err := isLen(a.src, 0)
|
||||
if err != nil {
|
||||
return applyError(err)
|
||||
}
|
||||
if !ok {
|
||||
return applyError(&Conflict{"cannot create new file from non-empty src"})
|
||||
}
|
||||
}
|
||||
|
||||
preimage := make([][]byte, fragEnd-start)
|
||||
n, err := a.lineSrc.ReadLinesAt(preimage, start)
|
||||
switch {
|
||||
case err == nil:
|
||||
case err == io.EOF && n == len(preimage): // last line of frag has no newline character
|
||||
default:
|
||||
return applyError(err, lineNum(start+int64(n)))
|
||||
}
|
||||
|
||||
// copy leading data before the fragment starts
|
||||
for i, line := range preimage[:fragStart-start] {
|
||||
if _, err := dst.Write(line); err != nil {
|
||||
a.nextLine = start + int64(i)
|
||||
return applyError(err, lineNum(a.nextLine))
|
||||
}
|
||||
}
|
||||
preimage = preimage[fragStart-start:]
|
||||
|
||||
// apply the changes in the fragment
|
||||
used := int64(0)
|
||||
for i, line := range f.Lines {
|
||||
if err := applyTextLine(dst, line, preimage, used); err != nil {
|
||||
a.nextLine = fragStart + used
|
||||
return applyError(err, lineNum(a.nextLine), fragLineNum(i))
|
||||
}
|
||||
if line.Old() {
|
||||
used++
|
||||
}
|
||||
}
|
||||
a.nextLine = fragStart + used
|
||||
|
||||
// new position of +0,0 mean a full delete, so check for leftovers
|
||||
if f.NewPosition == 0 && f.NewLines == 0 {
|
||||
var b [1][]byte
|
||||
n, err := a.lineSrc.ReadLinesAt(b[:], a.nextLine)
|
||||
if err != nil && err != io.EOF {
|
||||
return applyError(err, lineNum(a.nextLine))
|
||||
}
|
||||
if n > 0 {
|
||||
return applyError(&Conflict{"src still has content after full delete"}, lineNum(a.nextLine))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyTextLine(dst io.Writer, line Line, preimage [][]byte, i int64) (err error) {
|
||||
if line.Old() && string(preimage[i]) != line.Line {
|
||||
return &Conflict{"fragment line does not match src line"}
|
||||
}
|
||||
if line.New() {
|
||||
_, err = io.WriteString(dst, line.Line)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Flush writes any data following the last applied fragment to dst.
|
||||
func (a *Applier) Flush(dst io.Writer) (err error) {
|
||||
switch a.applyType {
|
||||
case applyInitial:
|
||||
_, err = copyFrom(dst, a.src, 0)
|
||||
case applyText:
|
||||
_, err = copyLinesFrom(dst, a.lineSrc, a.nextLine)
|
||||
case applyBinary:
|
||||
// nothing to flush, binary apply "consumes" full source
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ApplyBinaryFragment applies the changes in the fragment f and writes the
|
||||
// result to dst. At most one binary fragment can be applied before a call to
|
||||
// Reset.
|
||||
func (a *Applier) ApplyBinaryFragment(dst io.Writer, f *BinaryFragment) error {
|
||||
if a.applyType != applyInitial {
|
||||
return applyError(errApplyInProgress)
|
||||
}
|
||||
defer func() { a.applyType = applyBinary }()
|
||||
|
||||
if f == nil {
|
||||
return applyError(errors.New("nil fragment"))
|
||||
}
|
||||
|
||||
switch f.Method {
|
||||
case BinaryPatchLiteral:
|
||||
if _, err := dst.Write(f.Data); err != nil {
|
||||
return applyError(err)
|
||||
}
|
||||
case BinaryPatchDelta:
|
||||
if err := applyBinaryDeltaFragment(dst, a.src, f.Data); err != nil {
|
||||
return applyError(err)
|
||||
}
|
||||
default:
|
||||
return applyError(fmt.Errorf("unsupported binary patch method: %v", f.Method))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyBinaryDeltaFragment(dst io.Writer, src io.ReaderAt, frag []byte) error {
|
||||
srcSize, delta := readBinaryDeltaSize(frag)
|
||||
if err := checkBinarySrcSize(src, srcSize); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dstSize, delta := readBinaryDeltaSize(delta)
|
||||
|
||||
for len(delta) > 0 {
|
||||
op := delta[0]
|
||||
if op == 0 {
|
||||
return errors.New("invalid delta opcode 0")
|
||||
}
|
||||
|
||||
var n int64
|
||||
var err error
|
||||
switch op & 0x80 {
|
||||
case 0x80:
|
||||
n, delta, err = applyBinaryDeltaCopy(dst, op, delta[1:], src)
|
||||
case 0x00:
|
||||
n, delta, err = applyBinaryDeltaAdd(dst, op, delta[1:])
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dstSize -= n
|
||||
}
|
||||
|
||||
if dstSize != 0 {
|
||||
return errors.New("corrupt binary delta: insufficient or extra data")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readBinaryDeltaSize reads a variable length size from a delta-encoded binary
|
||||
// fragment, returing the size and the unused data. Data is encoded as:
|
||||
//
|
||||
// [[1xxxxxxx]...] [0xxxxxxx]
|
||||
//
|
||||
// in little-endian order, with 7 bits of the value per byte.
|
||||
func readBinaryDeltaSize(d []byte) (size int64, rest []byte) {
|
||||
shift := uint(0)
|
||||
for i, b := range d {
|
||||
size |= int64(b&0x7F) << shift
|
||||
shift += 7
|
||||
if b <= 0x7F {
|
||||
return size, d[i+1:]
|
||||
}
|
||||
}
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// applyBinaryDeltaAdd applies an add opcode in a delta-encoded binary
|
||||
// fragment, returning the amount of data written and the usused part of the
|
||||
// fragment. An add operation takes the form:
|
||||
//
|
||||
// [0xxxxxx][[data1]...]
|
||||
//
|
||||
// where the lower seven bits of the opcode is the number of data bytes
|
||||
// following the opcode. See also pack-format.txt in the Git source.
|
||||
func applyBinaryDeltaAdd(w io.Writer, op byte, delta []byte) (n int64, rest []byte, err error) {
|
||||
size := int(op)
|
||||
if len(delta) < size {
|
||||
return 0, delta, errors.New("corrupt binary delta: incomplete add")
|
||||
}
|
||||
_, err = w.Write(delta[:size])
|
||||
return int64(size), delta[size:], err
|
||||
}
|
||||
|
||||
// applyBinaryDeltaCopy applies a copy opcode in a delta-encoded binary
|
||||
// fragment, returing the amount of data written and the unused part of the
|
||||
// fragment. A copy operation takes the form:
|
||||
//
|
||||
// [1xxxxxxx][offset1][offset2][offset3][offset4][size1][size2][size3]
|
||||
//
|
||||
// where the lower seven bits of the opcode determine which non-zero offset and
|
||||
// size bytes are present in little-endian order: if bit 0 is set, offset1 is
|
||||
// present, etc. If no offset or size bytes are present, offset is 0 and size
|
||||
// is 0x10000. See also pack-format.txt in the Git source.
|
||||
func applyBinaryDeltaCopy(w io.Writer, op byte, delta []byte, src io.ReaderAt) (n int64, rest []byte, err error) {
|
||||
const defaultSize = 0x10000
|
||||
|
||||
unpack := func(start, bits uint) (v int64) {
|
||||
for i := uint(0); i < bits; i++ {
|
||||
mask := byte(1 << (i + start))
|
||||
if op&mask > 0 {
|
||||
if len(delta) == 0 {
|
||||
err = errors.New("corrupt binary delta: incomplete copy")
|
||||
return
|
||||
}
|
||||
v |= int64(delta[0]) << (8 * i)
|
||||
delta = delta[1:]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
offset := unpack(0, 4)
|
||||
size := unpack(4, 3)
|
||||
if err != nil {
|
||||
return 0, delta, err
|
||||
}
|
||||
if size == 0 {
|
||||
size = defaultSize
|
||||
}
|
||||
|
||||
// TODO(bkeyes): consider pooling these buffers
|
||||
b := make([]byte, size)
|
||||
if _, err := src.ReadAt(b, offset); err != nil {
|
||||
return 0, delta, err
|
||||
}
|
||||
|
||||
_, err = w.Write(b)
|
||||
return size, delta, err
|
||||
}
|
||||
|
||||
func checkBinarySrcSize(r io.ReaderAt, size int64) error {
|
||||
ok, err := isLen(r, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return &Conflict{"fragment src size does not match actual src size"}
|
||||
}
|
||||
return nil
|
||||
}
|
52
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/base85.go
generated
vendored
Normal file
52
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/base85.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
package gitdiff
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
b85Table map[byte]byte
|
||||
b85Alpha = []byte(
|
||||
"0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "!#$%&()*+-;<=>?@^_`{|}~",
|
||||
)
|
||||
)
|
||||
|
||||
func init() {
|
||||
b85Table = make(map[byte]byte)
|
||||
for i, c := range b85Alpha {
|
||||
b85Table[c] = byte(i)
|
||||
}
|
||||
}
|
||||
|
||||
// base85Decode decodes Base85-encoded data from src into dst. It uses the
|
||||
// alphabet defined by base85.c in the Git source tree, which appears to be
|
||||
// unique. src must contain at least len(dst) bytes of encoded data.
|
||||
func base85Decode(dst, src []byte) error {
|
||||
var v uint32
|
||||
var n, ndst int
|
||||
for i, b := range src {
|
||||
if b, ok := b85Table[b]; ok {
|
||||
v = 85*v + uint32(b)
|
||||
n++
|
||||
} else {
|
||||
return fmt.Errorf("invalid base85 byte at index %d: 0x%X", i, src[i])
|
||||
}
|
||||
if n == 5 {
|
||||
rem := len(dst) - ndst
|
||||
for j := 0; j < 4 && j < rem; j++ {
|
||||
dst[ndst] = byte(v >> 24)
|
||||
ndst++
|
||||
v <<= 8
|
||||
}
|
||||
v = 0
|
||||
n = 0
|
||||
}
|
||||
}
|
||||
if n > 0 {
|
||||
return fmt.Errorf("base85 data terminated by underpadded sequence")
|
||||
}
|
||||
if ndst < len(dst) {
|
||||
return fmt.Errorf("base85 data underrun: %d < %d", ndst, len(dst))
|
||||
}
|
||||
return nil
|
||||
}
|
179
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/binary.go
generated
vendored
Normal file
179
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/binary.go
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
package gitdiff
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (p *parser) ParseBinaryFragments(f *File) (n int, err error) {
|
||||
isBinary, hasData, err := p.ParseBinaryMarker()
|
||||
if err != nil || !isBinary {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
f.IsBinary = true
|
||||
if !hasData {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
forward, err := p.ParseBinaryFragmentHeader()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if forward == nil {
|
||||
return 0, p.Errorf(0, "missing data for binary patch")
|
||||
}
|
||||
if err := p.ParseBinaryChunk(forward); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
f.BinaryFragment = forward
|
||||
|
||||
// valid for reverse to not exist, but it must be valid if present
|
||||
reverse, err := p.ParseBinaryFragmentHeader()
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
if reverse == nil {
|
||||
return 1, nil
|
||||
}
|
||||
if err := p.ParseBinaryChunk(reverse); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
f.ReverseBinaryFragment = reverse
|
||||
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func (p *parser) ParseBinaryMarker() (isBinary bool, hasData bool, err error) {
|
||||
switch p.Line(0) {
|
||||
case "GIT binary patch\n":
|
||||
hasData = true
|
||||
case "Binary files differ\n":
|
||||
case "Files differ\n":
|
||||
default:
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
if err = p.Next(); err != nil && err != io.EOF {
|
||||
return false, false, err
|
||||
}
|
||||
return true, hasData, nil
|
||||
}
|
||||
|
||||
func (p *parser) ParseBinaryFragmentHeader() (*BinaryFragment, error) {
|
||||
parts := strings.SplitN(strings.TrimSuffix(p.Line(0), "\n"), " ", 2)
|
||||
if len(parts) < 2 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
frag := &BinaryFragment{}
|
||||
switch parts[0] {
|
||||
case "delta":
|
||||
frag.Method = BinaryPatchDelta
|
||||
case "literal":
|
||||
frag.Method = BinaryPatchLiteral
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
if frag.Size, err = strconv.ParseInt(parts[1], 10, 64); err != nil {
|
||||
nerr := err.(*strconv.NumError)
|
||||
return nil, p.Errorf(0, "binary patch: invalid size: %v", nerr.Err)
|
||||
}
|
||||
|
||||
if err := p.Next(); err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
return frag, nil
|
||||
}
|
||||
|
||||
func (p *parser) ParseBinaryChunk(frag *BinaryFragment) error {
|
||||
// Binary fragments are encoded as a series of base85 encoded lines. Each
|
||||
// line starts with a character in [A-Za-z] giving the number of bytes on
|
||||
// the line, where A = 1 and z = 52, and ends with a newline character.
|
||||
//
|
||||
// The base85 encoding means each line is a multiple of 5 characters + 2
|
||||
// additional characters for the length byte and the newline. The fragment
|
||||
// ends with a blank line.
|
||||
const (
|
||||
shortestValidLine = "A00000\n"
|
||||
maxBytesPerLine = 52
|
||||
)
|
||||
|
||||
var data bytes.Buffer
|
||||
buf := make([]byte, maxBytesPerLine)
|
||||
for {
|
||||
line := p.Line(0)
|
||||
if line == "\n" {
|
||||
break
|
||||
}
|
||||
if len(line) < len(shortestValidLine) || (len(line)-2)%5 != 0 {
|
||||
return p.Errorf(0, "binary patch: corrupt data line")
|
||||
}
|
||||
|
||||
byteCount, seq := int(line[0]), line[1:len(line)-1]
|
||||
switch {
|
||||
case 'A' <= byteCount && byteCount <= 'Z':
|
||||
byteCount = byteCount - 'A' + 1
|
||||
case 'a' <= byteCount && byteCount <= 'z':
|
||||
byteCount = byteCount - 'a' + 27
|
||||
default:
|
||||
return p.Errorf(0, "binary patch: invalid length byte")
|
||||
}
|
||||
|
||||
// base85 encodes every 4 bytes into 5 characters, with up to 3 bytes of end padding
|
||||
maxByteCount := len(seq) / 5 * 4
|
||||
if byteCount > maxByteCount || byteCount < maxByteCount-3 {
|
||||
return p.Errorf(0, "binary patch: incorrect byte count")
|
||||
}
|
||||
|
||||
if err := base85Decode(buf[:byteCount], []byte(seq)); err != nil {
|
||||
return p.Errorf(0, "binary patch: %v", err)
|
||||
}
|
||||
data.Write(buf[:byteCount])
|
||||
|
||||
if err := p.Next(); err != nil {
|
||||
if err == io.EOF {
|
||||
return p.Errorf(0, "binary patch: unexpected EOF")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := inflateBinaryChunk(frag, &data); err != nil {
|
||||
return p.Errorf(0, "binary patch: %v", err)
|
||||
}
|
||||
|
||||
// consume the empty line that ended the fragment
|
||||
if err := p.Next(); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func inflateBinaryChunk(frag *BinaryFragment, r io.Reader) error {
|
||||
zr, err := zlib.NewReader(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(zr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := zr.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if int64(len(data)) != frag.Size {
|
||||
return fmt.Errorf("%d byte fragment inflated to %d", frag.Size, len(data))
|
||||
}
|
||||
frag.Data = data
|
||||
return nil
|
||||
}
|
470
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/file_header.go
generated
vendored
Normal file
470
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/file_header.go
generated
vendored
Normal file
@ -0,0 +1,470 @@
|
||||
package gitdiff
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
devNull = "/dev/null"
|
||||
)
|
||||
|
||||
// ParseNextFileHeader finds and parses the next file header in the stream. If
|
||||
// a header is found, it returns a file and all input before the header. It
|
||||
// returns nil if no headers are found before the end of the input.
|
||||
func (p *parser) ParseNextFileHeader() (*File, string, error) {
|
||||
var preamble strings.Builder
|
||||
var file *File
|
||||
for {
|
||||
// check for disconnected fragment headers (corrupt patch)
|
||||
frag, err := p.ParseTextFragmentHeader()
|
||||
if err != nil {
|
||||
// not a valid header, nothing to worry about
|
||||
goto NextLine
|
||||
}
|
||||
if frag != nil {
|
||||
return nil, "", p.Errorf(-1, "patch fragment without file header: %s", frag.Header())
|
||||
}
|
||||
|
||||
// check for a git-generated patch
|
||||
file, err = p.ParseGitFileHeader()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if file != nil {
|
||||
return file, preamble.String(), nil
|
||||
}
|
||||
|
||||
// check for a "traditional" patch
|
||||
file, err = p.ParseTraditionalFileHeader()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if file != nil {
|
||||
return file, preamble.String(), nil
|
||||
}
|
||||
|
||||
NextLine:
|
||||
preamble.WriteString(p.Line(0))
|
||||
if err := p.Next(); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
func (p *parser) ParseGitFileHeader() (*File, error) {
|
||||
const prefix = "diff --git "
|
||||
|
||||
if !strings.HasPrefix(p.Line(0), prefix) {
|
||||
return nil, nil
|
||||
}
|
||||
header := p.Line(0)[len(prefix):]
|
||||
|
||||
defaultName, err := parseGitHeaderName(header)
|
||||
if err != nil {
|
||||
return nil, p.Errorf(0, "git file header: %v", err)
|
||||
}
|
||||
|
||||
f := &File{}
|
||||
for {
|
||||
end, err := parseGitHeaderData(f, p.Line(1), defaultName)
|
||||
if err != nil {
|
||||
return nil, p.Errorf(1, "git file header: %v", err)
|
||||
}
|
||||
|
||||
if err := p.Next(); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if end {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if f.OldName == "" && f.NewName == "" {
|
||||
if defaultName == "" {
|
||||
return nil, p.Errorf(0, "git file header: missing filename information")
|
||||
}
|
||||
f.OldName = defaultName
|
||||
f.NewName = defaultName
|
||||
}
|
||||
|
||||
if (f.NewName == "" && !f.IsDelete) || (f.OldName == "" && !f.IsNew) {
|
||||
return nil, p.Errorf(0, "git file header: missing filename information")
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (p *parser) ParseTraditionalFileHeader() (*File, error) {
|
||||
const shortestValidFragHeader = "@@ -1 +1 @@\n"
|
||||
const (
|
||||
oldPrefix = "--- "
|
||||
newPrefix = "+++ "
|
||||
)
|
||||
|
||||
oldLine, newLine := p.Line(0), p.Line(1)
|
||||
|
||||
if !strings.HasPrefix(oldLine, oldPrefix) || !strings.HasPrefix(newLine, newPrefix) {
|
||||
return nil, nil
|
||||
}
|
||||
// heuristic: only a file header if followed by a (probable) fragment header
|
||||
if len(p.Line(2)) < len(shortestValidFragHeader) || !strings.HasPrefix(p.Line(2), "@@ -") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// advance past the first two lines so parser is after the header
|
||||
// no EOF check needed because we know there are >=3 valid lines
|
||||
if err := p.Next(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p.Next(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldName, _, err := parseName(oldLine[len(oldPrefix):], '\t', 0)
|
||||
if err != nil {
|
||||
return nil, p.Errorf(0, "file header: %v", err)
|
||||
}
|
||||
|
||||
newName, _, err := parseName(newLine[len(newPrefix):], '\t', 0)
|
||||
if err != nil {
|
||||
return nil, p.Errorf(1, "file header: %v", err)
|
||||
}
|
||||
|
||||
f := &File{}
|
||||
switch {
|
||||
case oldName == devNull || hasEpochTimestamp(oldLine):
|
||||
f.IsNew = true
|
||||
f.NewName = newName
|
||||
case newName == devNull || hasEpochTimestamp(newLine):
|
||||
f.IsDelete = true
|
||||
f.OldName = oldName
|
||||
default:
|
||||
// if old name is a prefix of new name, use that instead
|
||||
// this avoids picking variants like "file.bak" or "file~"
|
||||
if strings.HasPrefix(newName, oldName) {
|
||||
f.OldName = oldName
|
||||
f.NewName = oldName
|
||||
} else {
|
||||
f.OldName = newName
|
||||
f.NewName = newName
|
||||
}
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// parseGitHeaderName extracts a default file name from the Git file header
|
||||
// line. This is required for mode-only changes and creation/deletion of empty
|
||||
// files. Other types of patch include the file name(s) in the header data.
|
||||
// If the names in the header do not match because the patch is a rename,
|
||||
// return an empty default name.
|
||||
func parseGitHeaderName(header string) (string, error) {
|
||||
firstName, n, err := parseName(header, -1, 1)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if n < len(header) && (header[n] == ' ' || header[n] == '\t') {
|
||||
n++
|
||||
}
|
||||
|
||||
secondName, _, err := parseName(header[n:], -1, 1)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if firstName != secondName {
|
||||
return "", nil
|
||||
}
|
||||
return firstName, nil
|
||||
}
|
||||
|
||||
// parseGitHeaderData parses a single line of metadata from a Git file header.
|
||||
// It returns true when header parsing is complete; in that case, line was the
|
||||
// first line of non-header content.
|
||||
func parseGitHeaderData(f *File, line, defaultName string) (end bool, err error) {
|
||||
if len(line) > 0 && line[len(line)-1] == '\n' {
|
||||
line = line[:len(line)-1]
|
||||
}
|
||||
|
||||
for _, hdr := range []struct {
|
||||
prefix string
|
||||
end bool
|
||||
parse func(*File, string, string) error
|
||||
}{
|
||||
{"@@ -", true, nil},
|
||||
{"--- ", false, parseGitHeaderOldName},
|
||||
{"+++ ", false, parseGitHeaderNewName},
|
||||
{"old mode ", false, parseGitHeaderOldMode},
|
||||
{"new mode ", false, parseGitHeaderNewMode},
|
||||
{"deleted file mode ", false, parseGitHeaderDeletedMode},
|
||||
{"new file mode ", false, parseGitHeaderCreatedMode},
|
||||
{"copy from ", false, parseGitHeaderCopyFrom},
|
||||
{"copy to ", false, parseGitHeaderCopyTo},
|
||||
{"rename old ", false, parseGitHeaderRenameFrom},
|
||||
{"rename new ", false, parseGitHeaderRenameTo},
|
||||
{"rename from ", false, parseGitHeaderRenameFrom},
|
||||
{"rename to ", false, parseGitHeaderRenameTo},
|
||||
{"similarity index ", false, parseGitHeaderScore},
|
||||
{"dissimilarity index ", false, parseGitHeaderScore},
|
||||
{"index ", false, parseGitHeaderIndex},
|
||||
} {
|
||||
if strings.HasPrefix(line, hdr.prefix) {
|
||||
if hdr.parse != nil {
|
||||
err = hdr.parse(f, line[len(hdr.prefix):], defaultName)
|
||||
}
|
||||
return hdr.end, err
|
||||
}
|
||||
}
|
||||
|
||||
// unknown line indicates the end of the header
|
||||
// this usually happens if the diff is empty
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func parseGitHeaderOldName(f *File, line, defaultName string) error {
|
||||
name, _, err := parseName(line, '\t', 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.OldName == "" && !f.IsNew {
|
||||
f.OldName = name
|
||||
return nil
|
||||
}
|
||||
return verifyGitHeaderName(name, f.OldName, f.IsNew, "old")
|
||||
}
|
||||
|
||||
func parseGitHeaderNewName(f *File, line, defaultName string) error {
|
||||
name, _, err := parseName(line, '\t', 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.NewName == "" && !f.IsDelete {
|
||||
f.NewName = name
|
||||
return nil
|
||||
}
|
||||
return verifyGitHeaderName(name, f.NewName, f.IsDelete, "new")
|
||||
}
|
||||
|
||||
func parseGitHeaderOldMode(f *File, line, defaultName string) (err error) {
|
||||
f.OldMode, err = parseMode(line)
|
||||
return
|
||||
}
|
||||
|
||||
func parseGitHeaderNewMode(f *File, line, defaultName string) (err error) {
|
||||
f.NewMode, err = parseMode(line)
|
||||
return
|
||||
}
|
||||
|
||||
func parseGitHeaderDeletedMode(f *File, line, defaultName string) error {
|
||||
f.IsDelete = true
|
||||
f.OldName = defaultName
|
||||
return parseGitHeaderOldMode(f, line, defaultName)
|
||||
}
|
||||
|
||||
func parseGitHeaderCreatedMode(f *File, line, defaultName string) error {
|
||||
f.IsNew = true
|
||||
f.NewName = defaultName
|
||||
return parseGitHeaderNewMode(f, line, defaultName)
|
||||
}
|
||||
|
||||
func parseGitHeaderCopyFrom(f *File, line, defaultName string) (err error) {
|
||||
f.IsCopy = true
|
||||
f.OldName, _, err = parseName(line, -1, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func parseGitHeaderCopyTo(f *File, line, defaultName string) (err error) {
|
||||
f.IsCopy = true
|
||||
f.NewName, _, err = parseName(line, -1, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func parseGitHeaderRenameFrom(f *File, line, defaultName string) (err error) {
|
||||
f.IsRename = true
|
||||
f.OldName, _, err = parseName(line, -1, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func parseGitHeaderRenameTo(f *File, line, defaultName string) (err error) {
|
||||
f.IsRename = true
|
||||
f.NewName, _, err = parseName(line, -1, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func parseGitHeaderScore(f *File, line, defaultName string) error {
|
||||
score, err := strconv.ParseInt(strings.TrimSuffix(line, "%"), 10, 32)
|
||||
if err != nil {
|
||||
nerr := err.(*strconv.NumError)
|
||||
return fmt.Errorf("invalid score line: %v", nerr.Err)
|
||||
}
|
||||
if score <= 100 {
|
||||
f.Score = int(score)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseGitHeaderIndex(f *File, line, defaultName string) error {
|
||||
const sep = ".."
|
||||
|
||||
// note that git stops parsing if the OIDs are too long to be valid
|
||||
// checking this requires knowing if the repository uses SHA1 or SHA256
|
||||
// hashes, which we don't know, so we just skip that check
|
||||
|
||||
parts := strings.SplitN(line, " ", 2)
|
||||
oids := strings.SplitN(parts[0], sep, 2)
|
||||
|
||||
if len(oids) < 2 {
|
||||
return fmt.Errorf("invalid index line: missing %q", sep)
|
||||
}
|
||||
f.OldOIDPrefix, f.NewOIDPrefix = oids[0], oids[1]
|
||||
|
||||
if len(parts) > 1 {
|
||||
return parseGitHeaderOldMode(f, parts[1], defaultName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseMode(s string) (os.FileMode, error) {
|
||||
mode, err := strconv.ParseInt(s, 8, 32)
|
||||
if err != nil {
|
||||
nerr := err.(*strconv.NumError)
|
||||
return os.FileMode(0), fmt.Errorf("invalid mode line: %v", nerr.Err)
|
||||
}
|
||||
return os.FileMode(mode), nil
|
||||
}
|
||||
|
||||
// parseName extracts a file name from the start of a string and returns the
|
||||
// name and the index of the first character after the name. If the name is
|
||||
// unquoted and term is non-negative, parsing stops at the first occurrence of
|
||||
// term. Otherwise parsing of unquoted names stops at the first space or tab.
|
||||
//
|
||||
// If the name is exactly "/dev/null", no further processing occurs. Otherwise,
|
||||
// if dropPrefix is greater than zero, that number of prefix components
|
||||
// separated by forward slashes are dropped from the name and any duplicate
|
||||
// slashes are collapsed.
|
||||
func parseName(s string, term rune, dropPrefix int) (name string, n int, err error) {
|
||||
if len(s) > 0 && s[0] == '"' {
|
||||
name, n, err = parseQuotedName(s)
|
||||
} else {
|
||||
name, n, err = parseUnquotedName(s, term)
|
||||
}
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
if name == devNull {
|
||||
return name, n, nil
|
||||
}
|
||||
return cleanName(name, dropPrefix), n, nil
|
||||
}
|
||||
|
||||
func parseQuotedName(s string) (name string, n int, err error) {
|
||||
for n = 1; n < len(s); n++ {
|
||||
if s[n] == '"' && s[n-1] != '\\' {
|
||||
n++
|
||||
break
|
||||
}
|
||||
}
|
||||
if n == 2 {
|
||||
return "", 0, fmt.Errorf("missing name")
|
||||
}
|
||||
if name, err = strconv.Unquote(s[:n]); err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
return name, n, err
|
||||
}
|
||||
|
||||
func parseUnquotedName(s string, term rune) (name string, n int, err error) {
|
||||
for n = 0; n < len(s); n++ {
|
||||
if s[n] == '\n' {
|
||||
break
|
||||
}
|
||||
if term >= 0 && rune(s[n]) == term {
|
||||
break
|
||||
}
|
||||
if term < 0 && (s[n] == ' ' || s[n] == '\t') {
|
||||
break
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
return "", 0, fmt.Errorf("missing name")
|
||||
}
|
||||
return s[:n], n, nil
|
||||
}
|
||||
|
||||
// verifyGitHeaderName checks a parsed name against state set by previous lines
|
||||
func verifyGitHeaderName(parsed, existing string, isNull bool, side string) error {
|
||||
if existing != "" {
|
||||
if isNull {
|
||||
return fmt.Errorf("expected %s, but filename is set to %s", devNull, existing)
|
||||
}
|
||||
if existing != parsed {
|
||||
return fmt.Errorf("inconsistent %s filename", side)
|
||||
}
|
||||
}
|
||||
if isNull && parsed != devNull {
|
||||
return fmt.Errorf("expected %s", devNull)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// cleanName removes double slashes and drops prefix segments.
|
||||
func cleanName(name string, drop int) string {
|
||||
var b strings.Builder
|
||||
for i := 0; i < len(name); i++ {
|
||||
if name[i] == '/' {
|
||||
if i < len(name)-1 && name[i+1] == '/' {
|
||||
continue
|
||||
}
|
||||
if drop > 0 {
|
||||
drop--
|
||||
b.Reset()
|
||||
continue
|
||||
}
|
||||
}
|
||||
b.WriteByte(name[i])
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// hasEpochTimestamp returns true if the string ends with a POSIX-formatted
|
||||
// timestamp for the UNIX epoch after a tab character. According to git, this
|
||||
// is used by GNU diff to mark creations and deletions.
|
||||
func hasEpochTimestamp(s string) bool {
|
||||
const posixTimeLayout = "2006-01-02 15:04:05.9 -0700"
|
||||
|
||||
start := strings.IndexRune(s, '\t')
|
||||
if start < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
ts := strings.TrimSuffix(s[start+1:], "\n")
|
||||
|
||||
// a valid timestamp can have optional ':' in zone specifier
|
||||
// remove that if it exists so we have a single format
|
||||
if ts[len(ts)-3] == ':' {
|
||||
ts = ts[:len(ts)-3] + ts[len(ts)-2:]
|
||||
}
|
||||
|
||||
t, err := time.Parse(posixTimeLayout, ts)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if !t.Equal(time.Unix(0, 0)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
199
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/gitdiff.go
generated
vendored
Normal file
199
vendor/github.com/bluekeyes/go-gitdiff/gitdiff/gitdiff.go
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
package gitdiff
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// File describes changes to a single file. It can be either a text file or a
|
||||
// binary file.
|
||||
type File struct {
|
||||
OldName string
|
||||
NewName string
|
||||
|
||||
IsNew bool
|
||||
IsDelete bool
|
||||
IsCopy bool
|
||||
IsRename bool
|
||||
|
||||
OldMode os.FileMode
|
||||
NewMode os.FileMode
|
||||
|
||||
OldOIDPrefix string
|
||||
NewOIDPrefix string
|
||||
Score int
|
||||
|
||||
// TextFragments contains the fragments describing changes to a text file. It
|
||||
// may be empty if the file is empty or if only the mode changes.
|
||||
TextFragments []*TextFragment
|
||||
|
||||
// IsBinary is true if the file is a binary file. If the patch includes
|
||||
// binary data, BinaryFragment will be non-nil and describe the changes to
|
||||
// the data. If the patch is reversible, ReverseBinaryFragment will also be
|
||||
// non-nil and describe the changes needed to restore the original file
|
||||
// after applying the changes in BinaryFragment.
|
||||
IsBinary bool
|
||||
BinaryFragment *BinaryFragment
|
||||
ReverseBinaryFragment *BinaryFragment
|
||||
}
|
||||
|
||||
// TextFragment describes changed lines starting at a specific line in a text file.
|
||||
type TextFragment struct {
|
||||
Comment string
|
||||
|
||||
OldPosition int64
|
||||
OldLines int64
|
||||
|
||||
NewPosition int64
|
||||
NewLines int64
|
||||
|
||||
LinesAdded int64
|
||||
LinesDeleted int64
|
||||
|
||||
LeadingContext int64
|
||||
TrailingContext int64
|
||||
|
||||
Lines []Line
|
||||
}
|
||||
|
||||
// Header returns the canonical header of this fragment.
|
||||
func (f *TextFragment) Header() string {
|
||||
return fmt.Sprintf("@@ -%d,%d +%d,%d @@ %s", f.OldPosition, f.OldLines, f.NewPosition, f.NewLines, f.Comment)
|
||||
}
|
||||
|
||||
// Validate checks that the fragment is self-consistent and appliable. Validate
|
||||
// returns an error if and only if the fragment is invalid.
|
||||
func (f *TextFragment) Validate() error {
|
||||
if f == nil {
|
||||
return errors.New("nil fragment")
|
||||
}
|
||||
|
||||
var (
|
||||
oldLines, newLines int64
|
||||
leadingContext, trailingContext int64
|
||||
contextLines, addedLines, deletedLines int64
|
||||
)
|
||||
|