diff --git a/deps.bzl b/deps.bzl index c238c37c..97c17c61 100644 --- a/deps.bzl +++ b/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", diff --git a/go.mod b/go.mod index 8eb0a89f..e6aee046 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 32db6934..b66488fd 100644 --- a/go.sum +++ b/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= diff --git a/vendor/github.com/bluekeyes/go-gitdiff/LICENSE b/vendor/github.com/bluekeyes/go-gitdiff/LICENSE new file mode 100644 index 00000000..d041cc12 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/LICENSE @@ -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. diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/BUILD b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/BUILD new file mode 100644 index 00000000..65d4f631 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/BUILD @@ -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"], +) diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/apply.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/apply.go new file mode 100644 index 00000000..4397d995 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/apply.go @@ -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 +} diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/base85.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/base85.go new file mode 100644 index 00000000..385aa644 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/base85.go @@ -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 +} diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/binary.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/binary.go new file mode 100644 index 00000000..c65a9a64 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/binary.go @@ -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 +} diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/file_header.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/file_header.go new file mode 100644 index 00000000..fadfc4ee --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/file_header.go @@ -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 +} diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/gitdiff.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/gitdiff.go new file mode 100644 index 00000000..18645bd0 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/gitdiff.go @@ -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 + ) + + // count the types of lines in the fragment content + for i, line := range f.Lines { + switch line.Op { + case OpContext: + oldLines++ + newLines++ + contextLines++ + if addedLines == 0 && deletedLines == 0 { + leadingContext++ + } else { + trailingContext++ + } + case OpAdd: + newLines++ + addedLines++ + trailingContext = 0 + case OpDelete: + oldLines++ + deletedLines++ + trailingContext = 0 + default: + return fmt.Errorf("unknown operator %q on line %d", line.Op, i+1) + } + } + + // check the actual counts against the reported counts + if oldLines != f.OldLines { + return lineCountErr("old", oldLines, f.OldLines) + } + if newLines != f.NewLines { + return lineCountErr("new", newLines, f.NewLines) + } + if leadingContext != f.LeadingContext { + return lineCountErr("leading context", leadingContext, f.LeadingContext) + } + if trailingContext != f.TrailingContext { + return lineCountErr("trailing context", trailingContext, f.TrailingContext) + } + if addedLines != f.LinesAdded { + return lineCountErr("added", addedLines, f.LinesAdded) + } + if deletedLines != f.LinesDeleted { + return lineCountErr("deleted", deletedLines, f.LinesDeleted) + } + + // if a file is being created, it can only contain additions + if f.OldPosition == 0 && f.OldLines != 0 { + return errors.New("file creation fragment contains context or deletion lines") + } + + return nil +} + +func lineCountErr(kind string, actual, reported int64) error { + return fmt.Errorf("fragment contains %d %s lines but reports %d", actual, kind, reported) +} + +// Line is a line in a text fragment. +type Line struct { + Op LineOp + Line string +} + +func (fl Line) String() string { + return fl.Op.String() + fl.Line +} + +// Old returns true if the line appears in the old content of the fragment. +func (fl Line) Old() bool { + return fl.Op == OpContext || fl.Op == OpDelete +} + +// New returns true if the line appears in the new content of the fragment. +func (fl Line) New() bool { + return fl.Op == OpContext || fl.Op == OpAdd +} + +// NoEOL returns true if the line is missing a trailing newline character. +func (fl Line) NoEOL() bool { + return len(fl.Line) == 0 || fl.Line[len(fl.Line)-1] != '\n' +} + +// LineOp describes the type of a text fragment line: context, added, or removed. +type LineOp int + +const ( + // OpContext indicates a context line + OpContext LineOp = iota + // OpDelete indicates a deleted line + OpDelete + // OpAdd indicates an added line + OpAdd +) + +func (op LineOp) String() string { + switch op { + case OpContext: + return " " + case OpDelete: + return "-" + case OpAdd: + return "+" + } + return "?" +} + +// BinaryFragment describes changes to a binary file. +type BinaryFragment struct { + Method BinaryPatchMethod + Size int64 + Data []byte +} + +// BinaryPatchMethod is the method used to create and apply the binary patch. +type BinaryPatchMethod int + +const ( + // BinaryPatchDelta indicates the data uses Git's packfile encoding + BinaryPatchDelta BinaryPatchMethod = iota + // BinaryPatchLiteral indicates the data is the exact file content + BinaryPatchLiteral +) diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/io.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/io.go new file mode 100644 index 00000000..af5c8473 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/io.go @@ -0,0 +1,220 @@ +package gitdiff + +import ( + "errors" + "io" +) + +// LineReaderAt is the interface that wraps the ReadLinesAt method. +// +// ReadLinesAt reads len(lines) into lines starting at line offset in the +// input source. It returns number of full lines read (0 <= n <= len(lines)) +// and any error encountered. Line numbers are zero-indexed. +// +// If n < len(lines), ReadLinesAt returns a non-nil error explaining why more +// lines were not returned. +// +// Each full line includes the line ending character(s). If the last line of +// the input does not have a line ending character, ReadLinesAt returns the +// content of the line and io.EOF. +// +// If the content of the input source changes after the first call to +// ReadLinesAt, the behavior of future calls is undefined. +type LineReaderAt interface { + ReadLinesAt(lines [][]byte, offset int64) (n int, err error) +} + +type lineReaderAt struct { + r io.ReaderAt + index []int64 + eof bool +} + +func (r *lineReaderAt) ReadLinesAt(lines [][]byte, offset int64) (n int, err error) { + if offset < 0 { + return 0, errors.New("ReadLinesAt: negative offset") + } + if len(lines) == 0 { + return 0, nil + } + + count := len(lines) + startLine := offset + endLine := startLine + int64(count) + + if endLine > int64(len(r.index)) && !r.eof { + if err := r.indexTo(endLine); err != nil { + return 0, err + } + } + if startLine >= int64(len(r.index)) { + return 0, io.EOF + } + + buf, byteOffset, err := r.readBytes(startLine, int64(count)) + if err != nil { + return 0, err + } + + for n = 0; n < count && startLine+int64(n) < int64(len(r.index)); n++ { + lineno := startLine + int64(n) + start, end := int64(0), r.index[lineno]-byteOffset + if lineno > 0 { + start = r.index[lineno-1] - byteOffset + } + lines[n] = buf[start:end] + } + + if n < count || buf[len(buf)-1] != '\n' { + return n, io.EOF + } + return n, nil +} + +// indexTo reads data and computes the line index until there is information +// for line or a read returns io.EOF. It returns an error if and only if there +// is an error reading data. +func (r *lineReaderAt) indexTo(line int64) error { + var buf [1024]byte + + var offset int64 + if len(r.index) > 0 { + offset = r.index[len(r.index)-1] + } + + for int64(len(r.index)) < line { + n, err := r.r.ReadAt(buf[:], offset) + if err != nil && err != io.EOF { + return err + } + for _, b := range buf[:n] { + offset++ + if b == '\n' { + r.index = append(r.index, offset) + } + } + if err == io.EOF { + if n > 0 && buf[n-1] != '\n' { + r.index = append(r.index, offset) + } + r.eof = true + break + } + } + return nil +} + +// readBytes reads the bytes of the n lines starting at line and returns the +// bytes and the offset of the first byte in the underlying source. +func (r *lineReaderAt) readBytes(line, n int64) (b []byte, offset int64, err error) { + indexLen := int64(len(r.index)) + + var size int64 + if line > indexLen { + offset = r.index[indexLen-1] + } else if line > 0 { + offset = r.index[line-1] + } + if n > 0 { + if line+n > indexLen { + size = r.index[indexLen-1] - offset + } else { + size = r.index[line+n-1] - offset + } + } + + b = make([]byte, size) + if _, err := r.r.ReadAt(b, offset); err != nil { + if err == io.EOF { + err = errors.New("ReadLinesAt: corrupt line index or changed source data") + } + return nil, 0, err + } + return b, offset, nil +} + +func isLen(r io.ReaderAt, n int64) (bool, error) { + off := n - 1 + if off < 0 { + off = 0 + } + + var b [2]byte + nr, err := r.ReadAt(b[:], off) + if err == io.EOF { + return (n == 0 && nr == 0) || (n > 0 && nr == 1), nil + } + return false, err +} + +const ( + byteBufferSize = 32 * 1024 // from io.Copy + lineBufferSize = 32 +) + +// copyFrom writes bytes starting from offset off in src to dst stopping at the +// end of src or at the first error. copyFrom returns the number of bytes +// written and any error. +func copyFrom(dst io.Writer, src io.ReaderAt, off int64) (written int64, err error) { + buf := make([]byte, byteBufferSize) + for { + nr, rerr := src.ReadAt(buf, off) + if nr > 0 { + nw, werr := dst.Write(buf[0:nr]) + if nw > 0 { + written += int64(nw) + } + if werr != nil { + err = werr + break + } + if nr != nw { + err = io.ErrShortWrite + break + } + off += int64(nr) + } + if rerr != nil { + if rerr != io.EOF { + err = rerr + } + break + } + } + return written, err +} + +// copyLinesFrom writes lines starting from line off in src to dst stopping at +// the end of src or at the first error. copyLinesFrom returns the number of +// lines written and any error. +func copyLinesFrom(dst io.Writer, src LineReaderAt, off int64) (written int64, err error) { + buf := make([][]byte, lineBufferSize) +ReadLoop: + for { + nr, rerr := src.ReadLinesAt(buf, off) + if nr > 0 { + for _, line := range buf[0:nr] { + nw, werr := dst.Write(line) + if nw > 0 { + written++ + } + if werr != nil { + err = werr + break ReadLoop + } + if len(line) != nw { + err = io.ErrShortWrite + break ReadLoop + } + } + off += int64(nr) + } + if rerr != nil { + if rerr != io.EOF { + err = rerr + } + break + } + } + return written, err +} diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/parser.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/parser.go new file mode 100644 index 00000000..d44465a9 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/parser.go @@ -0,0 +1,138 @@ +// Package gitdiff parses and applies patches generated by Git. It supports +// line-oriented text patches, binary patches, and can also parse standard +// unified diffs generated by other tools. +package gitdiff + +import ( + "bufio" + "fmt" + "io" +) + +// Parse parses a patch with changes to one or more files. Any content before +// the first file is returned as the second value. If an error occurs while +// parsing, it returns all files parsed before the error. +func Parse(r io.Reader) ([]*File, string, error) { + p := newParser(r) + + if err := p.Next(); err != nil { + if err == io.EOF { + return nil, "", nil + } + return nil, "", err + } + + var preamble string + var files []*File + for { + file, pre, err := p.ParseNextFileHeader() + if err != nil { + return files, preamble, err + } + if file == nil { + break + } + + for _, fn := range []func(*File) (int, error){ + p.ParseTextFragments, + p.ParseBinaryFragments, + } { + n, err := fn(file) + if err != nil { + return files, preamble, err + } + if n > 0 { + break + } + } + + if len(files) == 0 { + preamble = pre + } + files = append(files, file) + } + + return files, preamble, nil +} + +// TODO(bkeyes): consider exporting the parser type with configuration +// this would enable OID validation, p-value guessing, and prefix stripping +// by allowing users to set or override defaults + +// parser invariants: +// - methods that parse objects: +// - start with the parser on the first line of the first object +// - if returning nil, do not advance +// - if returning an error, do not advance past the object +// - if returning an object, advance to the first line after the object +// - any exported parsing methods must initialize the parser by calling Next() + +type stringReader interface { + ReadString(delim byte) (string, error) +} + +type parser struct { + r stringReader + + eof bool + lineno int64 + lines [3]string +} + +func newParser(r io.Reader) *parser { + if r, ok := r.(stringReader); ok { + return &parser{r: r} + } + return &parser{r: bufio.NewReader(r)} +} + +// Next advances the parser by one line. It returns any error encountered while +// reading the line, including io.EOF when the end of stream is reached. +func (p *parser) Next() error { + if p.eof { + return io.EOF + } + + if p.lineno == 0 { + // on first call to next, need to shift in all lines + for i := 0; i < len(p.lines)-1; i++ { + if err := p.shiftLines(); err != nil && err != io.EOF { + return err + } + } + } + + err := p.shiftLines() + if err != nil && err != io.EOF { + return err + } + + p.lineno++ + if p.lines[0] == "" { + p.eof = true + return io.EOF + } + return nil +} + +func (p *parser) shiftLines() (err error) { + for i := 0; i < len(p.lines)-1; i++ { + p.lines[i] = p.lines[i+1] + } + p.lines[len(p.lines)-1], err = p.r.ReadString('\n') + return +} + +// Line returns a line from the parser without advancing it. A delta of 0 +// returns the current line, while higher deltas return read-ahead lines. It +// returns an empty string if the delta is higher than the available lines, +// either because of the buffer size or because the parser reached the end of +// the input. Valid lines always contain at least a newline character. +func (p *parser) Line(delta uint) string { + return p.lines[delta] +} + +// Errorf generates an error and appends the current line information. +func (p *parser) Errorf(delta int64, msg string, args ...interface{}) error { + return fmt.Errorf("gitdiff: line %d: %s", p.lineno+delta, fmt.Sprintf(msg, args...)) +} diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/patch_header.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/patch_header.go new file mode 100644 index 00000000..ae508701 --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/patch_header.go @@ -0,0 +1,455 @@ +package gitdiff + +import ( + "bufio" + "errors" + "fmt" + "io" + "net/mail" + "strconv" + "strings" + "time" + "unicode" +) + +const ( + mailHeaderPrefix = "From " + prettyHeaderPrefix = "commit " +) + +// PatchHeader is a parsed version of the preamble content that appears before +// the first diff in a patch. It includes metadata about the patch, such as the +// author and a subject. +type PatchHeader struct { + // The SHA of the commit the patch was generated from. Empty if the SHA is + // not included in the header. + SHA string + + // The author details of the patch. If these details are not included in + // the header, Author is nil and AuthorDate is the zero time. + Author *PatchIdentity + AuthorDate time.Time + + // The committer details of the patch. If these details are not included in + // the header, Committer is nil and CommitterDate is the zero time. + Committer *PatchIdentity + CommitterDate time.Time + + // The title and body of the commit message describing the changes in the + // patch. Empty if no message is included in the header. + Title string + Body string + + // If the preamble looks like an email, ParsePatchHeader will + // remove prefixes such as `Re: ` and `[PATCH v3 5/17]` from the + // Title and place them here. + SubjectPrefix string + + // If the preamble looks like an email, and it contains a `---` + // line, that line will be removed and everything after it will be + // placed in BodyAppendix. + BodyAppendix string +} + +// Message returns the commit message for the header. The message consists of +// the title and the body separated by an empty line. +func (h *PatchHeader) Message() string { + var msg strings.Builder + if h != nil { + msg.WriteString(h.Title) + if h.Body != "" { + msg.WriteString("\n\n") + msg.WriteString(h.Body) + } + } + return msg.String() +} + +// PatchIdentity identifies a person who authored or committed a patch. +type PatchIdentity struct { + Name string + Email string +} + +func (i PatchIdentity) String() string { + name := i.Name + if name == "" { + name = `""` + } + return fmt.Sprintf("%s <%s>", name, i.Email) +} + +// ParsePatchIdentity parses a patch identity string. A valid string contains a +// non-empty name followed by an email address in angle brackets. Like Git, +// ParsePatchIdentity does not require that the email address is valid or +// properly formatted, only that it is non-empty. The name must not contain a +// left angle bracket, '<', and the email address must not contain a right +// angle bracket, '>'. +func ParsePatchIdentity(s string) (PatchIdentity, error) { + var emailStart, emailEnd int + for i, c := range s { + if c == '<' && emailStart == 0 { + emailStart = i + 1 + } + if c == '>' && emailStart > 0 { + emailEnd = i + break + } + } + if emailStart > 0 && emailEnd == 0 { + return PatchIdentity{}, fmt.Errorf("invalid identity string: unclosed email section: %s", s) + } + + var name, email string + if emailStart > 0 { + name = strings.TrimSpace(s[:emailStart-1]) + } + if emailStart > 0 && emailEnd > 0 { + email = strings.TrimSpace(s[emailStart:emailEnd]) + } + if name == "" || email == "" { + return PatchIdentity{}, fmt.Errorf("invalid identity string: %s", s) + } + + return PatchIdentity{Name: name, Email: email}, nil +} + +// ParsePatchDate parses a patch date string. It returns the parsed time or an +// error if s has an unknown format. ParsePatchDate supports the iso, rfc, +// short, raw, unix, and default formats (with local variants) used by the +// --date flag in Git. +func ParsePatchDate(s string) (time.Time, error) { + const ( + isoFormat = "2006-01-02 15:04:05 -0700" + isoStrictFormat = "2006-01-02T15:04:05-07:00" + rfc2822Format = "Mon, 2 Jan 2006 15:04:05 -0700" + shortFormat = "2006-01-02" + defaultFormat = "Mon Jan 2 15:04:05 2006 -0700" + defaultLocalFormat = "Mon Jan 2 15:04:05 2006" + ) + + if s == "" { + return time.Time{}, nil + } + + for _, fmt := range []string{ + isoFormat, + isoStrictFormat, + rfc2822Format, + shortFormat, + defaultFormat, + defaultLocalFormat, + } { + if t, err := time.ParseInLocation(fmt, s, time.Local); err == nil { + return t, nil + } + } + + // unix format + if unix, err := strconv.ParseInt(s, 10, 64); err == nil { + return time.Unix(unix, 0), nil + } + + // raw format + if space := strings.IndexByte(s, ' '); space > 0 { + unix, uerr := strconv.ParseInt(s[:space], 10, 64) + zone, zerr := time.Parse("-0700", s[space+1:]) + if uerr == nil && zerr == nil { + return time.Unix(unix, 0).In(zone.Location()), nil + } + } + + return time.Time{}, fmt.Errorf("unknown date format: %s", s) +} + +// ParsePatchHeader parses a preamble string as returned by Parse into a +// PatchHeader. Due to the variety of header formats, some fields of the parsed +// PatchHeader may be unset after parsing. +// +// Supported formats are the short, medium, full, fuller, and email pretty +// formats used by git diff, git log, and git show and the UNIX mailbox format +// used by git format-patch. +// +// If ParsePatchHeader detects that it is handling an email, it will +// remove extra content at the beginning of the title line, such as +// `[PATCH]` or `Re:` in the same way that `git mailinfo` does. +// SubjectPrefix will be set to the value of this removed string. +// (`git mailinfo` is the core part of `git am` that pulls information +// out of an individual mail.) +// +// Additionally, if ParsePatchHeader detects that it's handling an +// email, it will remove a `---` line and put anything after it into +// BodyAppendix. +// +// Those wishing the effect of a plain `git am` should use +// `PatchHeader.Title + "\n" + PatchHeader.Body` (or +// `PatchHeader.Message()`). Those wishing to retain the subject +// prefix and appendix material should use `PatchHeader.SubjectPrefix +// + PatchHeader.Title + "\n" + PatchHeader.Body + "\n" + +// PatchHeader.BodyAppendix`. +func ParsePatchHeader(s string) (*PatchHeader, error) { + r := bufio.NewReader(strings.NewReader(s)) + + var line string + for { + var err error + line, err = r.ReadString('\n') + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + + line = strings.TrimSpace(line) + if len(line) > 0 { + break + } + } + + switch { + case strings.HasPrefix(line, mailHeaderPrefix): + return parseHeaderMail(line, r) + case strings.HasPrefix(line, prettyHeaderPrefix): + return parseHeaderPretty(line, r) + } + return nil, errors.New("unrecognized patch header format") +} + +func parseHeaderPretty(prettyLine string, r io.Reader) (*PatchHeader, error) { + const ( + authorPrefix = "Author:" + commitPrefix = "Commit:" + datePrefix = "Date:" + authorDatePrefix = "AuthorDate:" + commitDatePrefix = "CommitDate:" + ) + + h := &PatchHeader{} + + prettyLine = prettyLine[len(prettyHeaderPrefix):] + if i := strings.IndexByte(prettyLine, ' '); i > 0 { + h.SHA = prettyLine[:i] + } else { + h.SHA = prettyLine + } + + s := bufio.NewScanner(r) + for s.Scan() { + line := s.Text() + + // empty line marks end of fields, remaining lines are title/message + if strings.TrimSpace(line) == "" { + break + } + + switch { + case strings.HasPrefix(line, authorPrefix): + u, err := ParsePatchIdentity(line[len(authorPrefix):]) + if err != nil { + return nil, err + } + h.Author = &u + + case strings.HasPrefix(line, commitPrefix): + u, err := ParsePatchIdentity(line[len(commitPrefix):]) + if err != nil { + return nil, err + } + h.Committer = &u + + case strings.HasPrefix(line, datePrefix): + d, err := ParsePatchDate(strings.TrimSpace(line[len(datePrefix):])) + if err != nil { + return nil, err + } + h.AuthorDate = d + + case strings.HasPrefix(line, authorDatePrefix): + d, err := ParsePatchDate(strings.TrimSpace(line[len(authorDatePrefix):])) + if err != nil { + return nil, err + } + h.AuthorDate = d + + case strings.HasPrefix(line, commitDatePrefix): + d, err := ParsePatchDate(strings.TrimSpace(line[len(commitDatePrefix):])) + if err != nil { + return nil, err + } + h.CommitterDate = d + } + } + if s.Err() != nil { + return nil, s.Err() + } + + title, indent := scanMessageTitle(s) + if s.Err() != nil { + return nil, s.Err() + } + h.Title = title + + if title != "" { + // Don't check for an appendix + body, _ := scanMessageBody(s, indent, false) + if s.Err() != nil { + return nil, s.Err() + } + h.Body = body + } + + return h, nil +} + +func scanMessageTitle(s *bufio.Scanner) (title string, indent string) { + var b strings.Builder + for i := 0; s.Scan(); i++ { + line := s.Text() + trimLine := strings.TrimSpace(line) + if trimLine == "" { + break + } + + if i == 0 { + if start := strings.IndexFunc(line, func(c rune) bool { return !unicode.IsSpace(c) }); start > 0 { + indent = line[:start] + } + } + if b.Len() > 0 { + b.WriteByte(' ') + } + b.WriteString(trimLine) + } + return b.String(), indent +} + +func scanMessageBody(s *bufio.Scanner, indent string, separateAppendix bool) (string, string) { + // Body and appendix + var body, appendix strings.Builder + c := &body + var empty int + for i := 0; s.Scan(); i++ { + line := s.Text() + + line = strings.TrimRightFunc(line, unicode.IsSpace) + line = strings.TrimPrefix(line, indent) + + if line == "" { + empty++ + continue + } + + // If requested, parse out "appendix" information (often added + // by `git format-patch` and removed by `git am`). + if separateAppendix && c == &body && line == "---" { + c = &appendix + continue + } + + if c.Len() > 0 { + c.WriteByte('\n') + if empty > 0 { + c.WriteByte('\n') + } + } + empty = 0 + + c.WriteString(line) + } + return body.String(), appendix.String() +} + +func parseHeaderMail(mailLine string, r io.Reader) (*PatchHeader, error) { + msg, err := mail.ReadMessage(r) + if err != nil { + return nil, err + } + + h := &PatchHeader{} + + mailLine = mailLine[len(mailHeaderPrefix):] + if i := strings.IndexByte(mailLine, ' '); i > 0 { + h.SHA = mailLine[:i] + } + + addrs, err := msg.Header.AddressList("From") + if err != nil && !errors.Is(err, mail.ErrHeaderNotPresent) { + return nil, err + } + if len(addrs) > 0 { + addr := addrs[0] + if addr.Name == "" { + return nil, fmt.Errorf("invalid user string: %s", addr) + } + h.Author = &PatchIdentity{Name: addr.Name, Email: addr.Address} + } + + date := msg.Header.Get("Date") + if date != "" { + d, err := ParsePatchDate(date) + if err != nil { + return nil, err + } + h.AuthorDate = d + } + + subject := msg.Header.Get("Subject") + h.SubjectPrefix, h.Title = parseSubject(subject) + + s := bufio.NewScanner(msg.Body) + h.Body, h.BodyAppendix = scanMessageBody(s, "", true) + if s.Err() != nil { + return nil, s.Err() + } + + return h, nil +} + +// Takes an email subject and returns the patch prefix and commit +// title. i.e., `[PATCH v3 3/5] Implement foo` would return `[PATCH +// v3 3/5] ` and `Implement foo` +func parseSubject(s string) (string, string) { + // This is meant to be compatible with + // https://github.com/git/git/blob/master/mailinfo.c:cleanup_subject(). + // If compatibility with `git am` drifts, go there to see if there + // are any updates. + + at := 0 + for at < len(s) { + switch s[at] { + case 'r', 'R': + // Detect re:, Re:, rE: and RE: + if at+2 < len(s) && + (s[at+1] == 'e' || s[at+1] == 'E') && + s[at+2] == ':' { + at += 3 + continue + } + + case ' ', '\t', ':': + // Delete whitespace and duplicate ':' characters + at++ + continue + + case '[': + // Look for closing parenthesis + j := at + 1 + for ; j < len(s); j++ { + if s[j] == ']' { + break + } + } + + if j < len(s) { + at = j + 1 + continue + } + } + + // Only loop if we actually removed something + break + } + + return s[:at], s[at:] +} diff --git a/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/text.go b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/text.go new file mode 100644 index 00000000..04de8f4c --- /dev/null +++ b/vendor/github.com/bluekeyes/go-gitdiff/gitdiff/text.go @@ -0,0 +1,180 @@ +package gitdiff + +import ( + "fmt" + "io" + "strconv" + "strings" +) + +// ParseTextFragments parses text fragments until the next file header or the +// end of the stream and attaches them to the given file. It returns the number +// of fragments that were added. +func (p *parser) ParseTextFragments(f *File) (n int, err error) { + for { + frag, err := p.ParseTextFragmentHeader() + if err != nil { + return n, err + } + if frag == nil { + return n, nil + } + + if f.IsNew && frag.OldLines > 0 { + return n, p.Errorf(-1, "new file depends on old contents") + } + if f.IsDelete && frag.NewLines > 0 { + return n, p.Errorf(-1, "deleted file still has contents") + } + + if err := p.ParseTextChunk(frag); err != nil { + return n, err + } + + f.TextFragments = append(f.TextFragments, frag) + n++ + } +} + +func (p *parser) ParseTextFragmentHeader() (*TextFragment, error) { + const ( + startMark = "@@ -" + endMark = " @@" + ) + + if !strings.HasPrefix(p.Line(0), startMark) { + return nil, nil + } + + parts := strings.SplitAfterN(p.Line(0), endMark, 2) + if len(parts) < 2 { + return nil, p.Errorf(0, "invalid fragment header") + } + + f := &TextFragment{} + f.Comment = strings.TrimSpace(parts[1]) + + header := parts[0][len(startMark) : len(parts[0])-len(endMark)] + ranges := strings.Split(header, " +") + if len(ranges) != 2 { + return nil, p.Errorf(0, "invalid fragment header") + } + + var err error + if f.OldPosition, f.OldLines, err = parseRange(ranges[0]); err != nil { + return nil, p.Errorf(0, "invalid fragment header: %v", err) + } + if f.NewPosition, f.NewLines, err = parseRange(ranges[1]); err != nil { + return nil, p.Errorf(0, "invalid fragment header: %v", err) + } + + if err := p.Next(); err != nil && err != io.EOF { + return nil, err + } + return f, nil +} + +func (p *parser) ParseTextChunk(frag *TextFragment) error { + if p.Line(0) == "" { + return p.Errorf(0, "no content following fragment header") + } + + isNoNewlineLine := func(s string) bool { + // test for "\ No newline at end of file" by prefix because the text + // changes by locale (git claims all versions are at least 12 chars) + return len(s) >= 12 && s[:2] == "\\ " + } + + oldLines, newLines := frag.OldLines, frag.NewLines + for { + line := p.Line(0) + op, data := line[0], line[1:] + + switch op { + case '\n': + data = "\n" + fallthrough // newer GNU diff versions create empty context lines + case ' ': + oldLines-- + newLines-- + if frag.LinesAdded == 0 && frag.LinesDeleted == 0 { + frag.LeadingContext++ + } else { + frag.TrailingContext++ + } + frag.Lines = append(frag.Lines, Line{OpContext, data}) + case '-': + oldLines-- + frag.LinesDeleted++ + frag.TrailingContext = 0 + frag.Lines = append(frag.Lines, Line{OpDelete, data}) + case '+': + newLines-- + frag.LinesAdded++ + frag.TrailingContext = 0 + frag.Lines = append(frag.Lines, Line{OpAdd, data}) + default: + // this may appear in middle of fragment if it's for a deleted line + if isNoNewlineLine(line) { + last := &frag.Lines[len(frag.Lines)-1] + last.Line = strings.TrimSuffix(last.Line, "\n") + break + } + // TODO(bkeyes): if this is because we hit the next header, it + // would be helpful to return the miscounts line error. We could + // either test for the common headers ("@@ -", "diff --git") or + // assume any invalid op ends the fragment; git returns the same + // generic error in all cases so either is compatible + return p.Errorf(0, "invalid line operation: %q", op) + } + + next := p.Line(1) + if oldLines <= 0 && newLines <= 0 && !isNoNewlineLine(next) { + break + } + + if err := p.Next(); err != nil { + if err == io.EOF { + break + } + return err + } + } + + if oldLines != 0 || newLines != 0 { + hdr := max(frag.OldLines-oldLines, frag.NewLines-newLines) + 1 + return p.Errorf(-hdr, "fragment header miscounts lines: %+d old, %+d new", -oldLines, -newLines) + } + + if err := p.Next(); err != nil && err != io.EOF { + return err + } + return nil +} + +func parseRange(s string) (start int64, end int64, err error) { + parts := strings.SplitN(s, ",", 2) + + if start, err = strconv.ParseInt(parts[0], 10, 64); err != nil { + nerr := err.(*strconv.NumError) + return 0, 0, fmt.Errorf("bad start of range: %s: %v", parts[0], nerr.Err) + } + + if len(parts) > 1 { + if end, err = strconv.ParseInt(parts[1], 10, 64); err != nil { + nerr := err.(*strconv.NumError) + return 0, 0, fmt.Errorf("bad end of range: %s: %v", parts[1], nerr.Err) + } + } else { + end = 1 + } + + return +} + +func max(a, b int64) int64 { + if a > b { + return a + } + return b +} diff --git a/vendor/github.com/rocky-linux/srpmproc/AUTHORS b/vendor/github.com/rocky-linux/srpmproc/AUTHORS new file mode 100644 index 00000000..74b6c2d9 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/AUTHORS @@ -0,0 +1 @@ +Mustafa Gezen diff --git a/vendor/github.com/rocky-linux/srpmproc/CONTRIBUTORS b/vendor/github.com/rocky-linux/srpmproc/CONTRIBUTORS new file mode 100644 index 00000000..74b6c2d9 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/CONTRIBUTORS @@ -0,0 +1 @@ +Mustafa Gezen diff --git a/vendor/github.com/rocky-linux/srpmproc/LICENSE b/vendor/github.com/rocky-linux/srpmproc/LICENSE new file mode 100644 index 00000000..fd7021bc --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2021 The Srpmproc Authors + +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. diff --git a/vendor/github.com/rocky-linux/srpmproc/pb/BUILD b/vendor/github.com/rocky-linux/srpmproc/pb/BUILD new file mode 100644 index 00000000..cea07d2f --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pb/BUILD @@ -0,0 +1,16 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "pb", + srcs = [ + "cfg.pb.go", + "response.pb.go", + ], + importmap = "go.resf.org/peridot/vendor/github.com/rocky-linux/srpmproc/pb", + importpath = "github.com/rocky-linux/srpmproc/pb", + visibility = ["//visibility:public"], + deps = [ + "@org_golang_google_protobuf//reflect/protoreflect", + "@org_golang_google_protobuf//runtime/protoimpl", + ], +) diff --git a/vendor/github.com/rocky-linux/srpmproc/pb/cfg.pb.go b/vendor/github.com/rocky-linux/srpmproc/pb/cfg.pb.go new file mode 100644 index 00000000..431d7949 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pb/cfg.pb.go @@ -0,0 +1,1446 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.3 +// source: cfg.proto + +package srpmprocpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SpecChange_FileOperation_Type int32 + +const ( + SpecChange_FileOperation_Unknown SpecChange_FileOperation_Type = 0 + SpecChange_FileOperation_Source SpecChange_FileOperation_Type = 1 + SpecChange_FileOperation_Patch SpecChange_FileOperation_Type = 2 +) + +// Enum value maps for SpecChange_FileOperation_Type. +var ( + SpecChange_FileOperation_Type_name = map[int32]string{ + 0: "Unknown", + 1: "Source", + 2: "Patch", + } + SpecChange_FileOperation_Type_value = map[string]int32{ + "Unknown": 0, + "Source": 1, + "Patch": 2, + } +) + +func (x SpecChange_FileOperation_Type) Enum() *SpecChange_FileOperation_Type { + p := new(SpecChange_FileOperation_Type) + *p = x + return p +} + +func (x SpecChange_FileOperation_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SpecChange_FileOperation_Type) Descriptor() protoreflect.EnumDescriptor { + return file_cfg_proto_enumTypes[0].Descriptor() +} + +func (SpecChange_FileOperation_Type) Type() protoreflect.EnumType { + return &file_cfg_proto_enumTypes[0] +} + +func (x SpecChange_FileOperation_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SpecChange_FileOperation_Type.Descriptor instead. +func (SpecChange_FileOperation_Type) EnumDescriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{4, 0, 0} +} + +// Replace directive replaces a file from the rpm repository +// with a file from the patch repository. +// Replacing content can either be inline or in the same patch-tree. +type Replace struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required - Replaced file + File string `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` + // Types that are assignable to Replacing: + // *Replace_WithFile + // *Replace_WithInline + // *Replace_WithLookaside + Replacing isReplace_Replacing `protobuf_oneof:"replacing"` +} + +func (x *Replace) Reset() { + *x = Replace{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Replace) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Replace) ProtoMessage() {} + +func (x *Replace) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Replace.ProtoReflect.Descriptor instead. +func (*Replace) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{0} +} + +func (x *Replace) GetFile() string { + if x != nil { + return x.File + } + return "" +} + +func (m *Replace) GetReplacing() isReplace_Replacing { + if m != nil { + return m.Replacing + } + return nil +} + +func (x *Replace) GetWithFile() string { + if x, ok := x.GetReplacing().(*Replace_WithFile); ok { + return x.WithFile + } + return "" +} + +func (x *Replace) GetWithInline() string { + if x, ok := x.GetReplacing().(*Replace_WithInline); ok { + return x.WithInline + } + return "" +} + +func (x *Replace) GetWithLookaside() string { + if x, ok := x.GetReplacing().(*Replace_WithLookaside); ok { + return x.WithLookaside + } + return "" +} + +type isReplace_Replacing interface { + isReplace_Replacing() +} + +type Replace_WithFile struct { + // Replace with in-tree file + WithFile string `protobuf:"bytes,2,opt,name=with_file,json=withFile,proto3,oneof"` +} + +type Replace_WithInline struct { + // Replace with inline content + WithInline string `protobuf:"bytes,3,opt,name=with_inline,json=withInline,proto3,oneof"` +} + +type Replace_WithLookaside struct { + // Replace with lookaside cache object + WithLookaside string `protobuf:"bytes,4,opt,name=with_lookaside,json=withLookaside,proto3,oneof"` +} + +func (*Replace_WithFile) isReplace_Replacing() {} + +func (*Replace_WithInline) isReplace_Replacing() {} + +func (*Replace_WithLookaside) isReplace_Replacing() {} + +// Delete directive deletes literal files from the rpm repository. +// Won't delete from spec automatically. +// Use the `SpecChange` directive for that +type Delete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required + File string `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` +} + +func (x *Delete) Reset() { + *x = Delete{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Delete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Delete) ProtoMessage() {} + +func (x *Delete) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Delete.ProtoReflect.Descriptor instead. +func (*Delete) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{1} +} + +func (x *Delete) GetFile() string { + if x != nil { + return x.File + } + return "" +} + +// Add directive adds a file from the patch repository to the rpm repository. +// The file is added in the `SOURCES` directory +// Won't add to spec automatically. +// Use the `SpecChange` directive for that +type Add struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required - file to add + // + // Types that are assignable to Source: + // *Add_File + // *Add_Lookaside + Source isAdd_Source `protobuf_oneof:"source"` + // Overrides file name if specified + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *Add) Reset() { + *x = Add{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Add) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Add) ProtoMessage() {} + +func (x *Add) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Add.ProtoReflect.Descriptor instead. +func (*Add) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{2} +} + +func (m *Add) GetSource() isAdd_Source { + if m != nil { + return m.Source + } + return nil +} + +func (x *Add) GetFile() string { + if x, ok := x.GetSource().(*Add_File); ok { + return x.File + } + return "" +} + +func (x *Add) GetLookaside() string { + if x, ok := x.GetSource().(*Add_Lookaside); ok { + return x.Lookaside + } + return "" +} + +func (x *Add) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type isAdd_Source interface { + isAdd_Source() +} + +type Add_File struct { + File string `protobuf:"bytes,1,opt,name=file,proto3,oneof"` +} + +type Add_Lookaside struct { + Lookaside string `protobuf:"bytes,2,opt,name=lookaside,proto3,oneof"` +} + +func (*Add_File) isAdd_Source() {} + +func (*Add_Lookaside) isAdd_Source() {} + +// Lookaside directive puts patched files in blob storage. +// If tar is true, the files will be put into a tarball and gzipped +type Lookaside struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required - List of files that should be stored in blob storage + File []string `protobuf:"bytes,1,rep,name=file,proto3" json:"file,omitempty"` + // Whether files should be put into a tarball and gzipped + Tar bool `protobuf:"varint,2,opt,name=tar,proto3" json:"tar,omitempty"` + // Name of tar file, only used and required if tar is true + ArchiveName string `protobuf:"bytes,3,opt,name=archive_name,json=archiveName,proto3" json:"archive_name,omitempty"` + // Whether if files should be retrieved from patch tree + FromPatchTree bool `protobuf:"varint,4,opt,name=from_patch_tree,json=fromPatchTree,proto3" json:"from_patch_tree,omitempty"` +} + +func (x *Lookaside) Reset() { + *x = Lookaside{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Lookaside) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Lookaside) ProtoMessage() {} + +func (x *Lookaside) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Lookaside.ProtoReflect.Descriptor instead. +func (*Lookaside) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{3} +} + +func (x *Lookaside) GetFile() []string { + if x != nil { + return x.File + } + return nil +} + +func (x *Lookaside) GetTar() bool { + if x != nil { + return x.Tar + } + return false +} + +func (x *Lookaside) GetArchiveName() string { + if x != nil { + return x.ArchiveName + } + return "" +} + +func (x *Lookaside) GetFromPatchTree() bool { + if x != nil { + return x.FromPatchTree + } + return false +} + +// SpecChange directive makes it possible to execute certain +// plans against the package spec +type SpecChange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + File []*SpecChange_FileOperation `protobuf:"bytes,1,rep,name=file,proto3" json:"file,omitempty"` + Changelog []*SpecChange_ChangelogOperation `protobuf:"bytes,2,rep,name=changelog,proto3" json:"changelog,omitempty"` + SearchAndReplace []*SpecChange_SearchAndReplaceOperation `protobuf:"bytes,3,rep,name=search_and_replace,json=searchAndReplace,proto3" json:"search_and_replace,omitempty"` + Append []*SpecChange_AppendOperation `protobuf:"bytes,4,rep,name=append,proto3" json:"append,omitempty"` + NewField []*SpecChange_NewFieldOperation `protobuf:"bytes,5,rep,name=new_field,json=newField,proto3" json:"new_field,omitempty"` + DisableAutoAlign bool `protobuf:"varint,6,opt,name=disable_auto_align,json=disableAutoAlign,proto3" json:"disable_auto_align,omitempty"` +} + +func (x *SpecChange) Reset() { + *x = SpecChange{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SpecChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SpecChange) ProtoMessage() {} + +func (x *SpecChange) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SpecChange.ProtoReflect.Descriptor instead. +func (*SpecChange) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{4} +} + +func (x *SpecChange) GetFile() []*SpecChange_FileOperation { + if x != nil { + return x.File + } + return nil +} + +func (x *SpecChange) GetChangelog() []*SpecChange_ChangelogOperation { + if x != nil { + return x.Changelog + } + return nil +} + +func (x *SpecChange) GetSearchAndReplace() []*SpecChange_SearchAndReplaceOperation { + if x != nil { + return x.SearchAndReplace + } + return nil +} + +func (x *SpecChange) GetAppend() []*SpecChange_AppendOperation { + if x != nil { + return x.Append + } + return nil +} + +func (x *SpecChange) GetNewField() []*SpecChange_NewFieldOperation { + if x != nil { + return x.NewField + } + return nil +} + +func (x *SpecChange) GetDisableAutoAlign() bool { + if x != nil { + return x.DisableAutoAlign + } + return false +} + +type Patch struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Path to patch file from repo root + File string `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` + // Srpmproc adds `SOURCES/` to files in a diff + // without a prefix if strict is false. + // If strict is true, then that is disabled. + Strict bool `protobuf:"varint,2,opt,name=strict,proto3" json:"strict,omitempty"` +} + +func (x *Patch) Reset() { + *x = Patch{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Patch) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Patch) ProtoMessage() {} + +func (x *Patch) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Patch.ProtoReflect.Descriptor instead. +func (*Patch) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{5} +} + +func (x *Patch) GetFile() string { + if x != nil { + return x.File + } + return "" +} + +func (x *Patch) GetStrict() bool { + if x != nil { + return x.Strict + } + return false +} + +type Cfg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Replace []*Replace `protobuf:"bytes,1,rep,name=replace,proto3" json:"replace,omitempty"` + Delete []*Delete `protobuf:"bytes,2,rep,name=delete,proto3" json:"delete,omitempty"` + Add []*Add `protobuf:"bytes,3,rep,name=add,proto3" json:"add,omitempty"` + Lookaside []*Lookaside `protobuf:"bytes,4,rep,name=lookaside,proto3" json:"lookaside,omitempty"` + SpecChange *SpecChange `protobuf:"bytes,5,opt,name=spec_change,json=specChange,proto3" json:"spec_change,omitempty"` + Patch []*Patch `protobuf:"bytes,6,rep,name=patch,proto3" json:"patch,omitempty"` +} + +func (x *Cfg) Reset() { + *x = Cfg{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Cfg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Cfg) ProtoMessage() {} + +func (x *Cfg) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Cfg.ProtoReflect.Descriptor instead. +func (*Cfg) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{6} +} + +func (x *Cfg) GetReplace() []*Replace { + if x != nil { + return x.Replace + } + return nil +} + +func (x *Cfg) GetDelete() []*Delete { + if x != nil { + return x.Delete + } + return nil +} + +func (x *Cfg) GetAdd() []*Add { + if x != nil { + return x.Add + } + return nil +} + +func (x *Cfg) GetLookaside() []*Lookaside { + if x != nil { + return x.Lookaside + } + return nil +} + +func (x *Cfg) GetSpecChange() *SpecChange { + if x != nil { + return x.SpecChange + } + return nil +} + +func (x *Cfg) GetPatch() []*Patch { + if x != nil { + return x.Patch + } + return nil +} + +// The FileOperation plan allows patchers to add or delete +// a file from the spec. +type SpecChange_FileOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // File name + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // File type + Type SpecChange_FileOperation_Type `protobuf:"varint,2,opt,name=type,proto3,enum=srpmproc.SpecChange_FileOperation_Type" json:"type,omitempty"` + // Types that are assignable to Mode: + // *SpecChange_FileOperation_Add + // *SpecChange_FileOperation_Delete + Mode isSpecChange_FileOperation_Mode `protobuf_oneof:"mode"` + // Only works for patch type + AddToPrep bool `protobuf:"varint,5,opt,name=add_to_prep,json=addToPrep,proto3" json:"add_to_prep,omitempty"` + NPath int32 `protobuf:"varint,6,opt,name=n_path,json=nPath,proto3" json:"n_path,omitempty"` +} + +func (x *SpecChange_FileOperation) Reset() { + *x = SpecChange_FileOperation{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SpecChange_FileOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SpecChange_FileOperation) ProtoMessage() {} + +func (x *SpecChange_FileOperation) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SpecChange_FileOperation.ProtoReflect.Descriptor instead. +func (*SpecChange_FileOperation) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{4, 0} +} + +func (x *SpecChange_FileOperation) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SpecChange_FileOperation) GetType() SpecChange_FileOperation_Type { + if x != nil { + return x.Type + } + return SpecChange_FileOperation_Unknown +} + +func (m *SpecChange_FileOperation) GetMode() isSpecChange_FileOperation_Mode { + if m != nil { + return m.Mode + } + return nil +} + +func (x *SpecChange_FileOperation) GetAdd() bool { + if x, ok := x.GetMode().(*SpecChange_FileOperation_Add); ok { + return x.Add + } + return false +} + +func (x *SpecChange_FileOperation) GetDelete() bool { + if x, ok := x.GetMode().(*SpecChange_FileOperation_Delete); ok { + return x.Delete + } + return false +} + +func (x *SpecChange_FileOperation) GetAddToPrep() bool { + if x != nil { + return x.AddToPrep + } + return false +} + +func (x *SpecChange_FileOperation) GetNPath() int32 { + if x != nil { + return x.NPath + } + return 0 +} + +type isSpecChange_FileOperation_Mode interface { + isSpecChange_FileOperation_Mode() +} + +type SpecChange_FileOperation_Add struct { + // Add won't add the file to the tree. + // Use the `Add` directive for that + Add bool `protobuf:"varint,3,opt,name=add,proto3,oneof"` +} + +type SpecChange_FileOperation_Delete struct { + // Delete won't delete the file from the tree. + // Use the `Delete` directive for that + Delete bool `protobuf:"varint,4,opt,name=delete,proto3,oneof"` +} + +func (*SpecChange_FileOperation_Add) isSpecChange_FileOperation_Mode() {} + +func (*SpecChange_FileOperation_Delete) isSpecChange_FileOperation_Mode() {} + +// ChangelogOperation adds a new changelog entry +type SpecChange_ChangelogOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AuthorName string `protobuf:"bytes,1,opt,name=author_name,json=authorName,proto3" json:"author_name,omitempty"` + AuthorEmail string `protobuf:"bytes,2,opt,name=author_email,json=authorEmail,proto3" json:"author_email,omitempty"` + Message []string `protobuf:"bytes,3,rep,name=message,proto3" json:"message,omitempty"` +} + +func (x *SpecChange_ChangelogOperation) Reset() { + *x = SpecChange_ChangelogOperation{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SpecChange_ChangelogOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SpecChange_ChangelogOperation) ProtoMessage() {} + +func (x *SpecChange_ChangelogOperation) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SpecChange_ChangelogOperation.ProtoReflect.Descriptor instead. +func (*SpecChange_ChangelogOperation) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{4, 1} +} + +func (x *SpecChange_ChangelogOperation) GetAuthorName() string { + if x != nil { + return x.AuthorName + } + return "" +} + +func (x *SpecChange_ChangelogOperation) GetAuthorEmail() string { + if x != nil { + return x.AuthorEmail + } + return "" +} + +func (x *SpecChange_ChangelogOperation) GetMessage() []string { + if x != nil { + return x.Message + } + return nil +} + +// SearchAndReplaceOperation replaces substring with value +// in a specified field +type SpecChange_SearchAndReplaceOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Identifier: + // *SpecChange_SearchAndReplaceOperation_Field + // *SpecChange_SearchAndReplaceOperation_Any + // *SpecChange_SearchAndReplaceOperation_StartsWith + // *SpecChange_SearchAndReplaceOperation_EndsWith + Identifier isSpecChange_SearchAndReplaceOperation_Identifier `protobuf_oneof:"identifier"` + Find string `protobuf:"bytes,5,opt,name=find,proto3" json:"find,omitempty"` + Replace string `protobuf:"bytes,6,opt,name=replace,proto3" json:"replace,omitempty"` + // How many occurences to replace. + // Set to -1 for all + N int32 `protobuf:"zigzag32,7,opt,name=n,proto3" json:"n,omitempty"` +} + +func (x *SpecChange_SearchAndReplaceOperation) Reset() { + *x = SpecChange_SearchAndReplaceOperation{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SpecChange_SearchAndReplaceOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SpecChange_SearchAndReplaceOperation) ProtoMessage() {} + +func (x *SpecChange_SearchAndReplaceOperation) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SpecChange_SearchAndReplaceOperation.ProtoReflect.Descriptor instead. +func (*SpecChange_SearchAndReplaceOperation) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{4, 2} +} + +func (m *SpecChange_SearchAndReplaceOperation) GetIdentifier() isSpecChange_SearchAndReplaceOperation_Identifier { + if m != nil { + return m.Identifier + } + return nil +} + +func (x *SpecChange_SearchAndReplaceOperation) GetField() string { + if x, ok := x.GetIdentifier().(*SpecChange_SearchAndReplaceOperation_Field); ok { + return x.Field + } + return "" +} + +func (x *SpecChange_SearchAndReplaceOperation) GetAny() bool { + if x, ok := x.GetIdentifier().(*SpecChange_SearchAndReplaceOperation_Any); ok { + return x.Any + } + return false +} + +func (x *SpecChange_SearchAndReplaceOperation) GetStartsWith() bool { + if x, ok := x.GetIdentifier().(*SpecChange_SearchAndReplaceOperation_StartsWith); ok { + return x.StartsWith + } + return false +} + +func (x *SpecChange_SearchAndReplaceOperation) GetEndsWith() bool { + if x, ok := x.GetIdentifier().(*SpecChange_SearchAndReplaceOperation_EndsWith); ok { + return x.EndsWith + } + return false +} + +func (x *SpecChange_SearchAndReplaceOperation) GetFind() string { + if x != nil { + return x.Find + } + return "" +} + +func (x *SpecChange_SearchAndReplaceOperation) GetReplace() string { + if x != nil { + return x.Replace + } + return "" +} + +func (x *SpecChange_SearchAndReplaceOperation) GetN() int32 { + if x != nil { + return x.N + } + return 0 +} + +type isSpecChange_SearchAndReplaceOperation_Identifier interface { + isSpecChange_SearchAndReplaceOperation_Identifier() +} + +type SpecChange_SearchAndReplaceOperation_Field struct { + // replace occurrences in field value + Field string `protobuf:"bytes,1,opt,name=field,proto3,oneof"` +} + +type SpecChange_SearchAndReplaceOperation_Any struct { + // replace occurrences in any line + Any bool `protobuf:"varint,2,opt,name=any,proto3,oneof"` +} + +type SpecChange_SearchAndReplaceOperation_StartsWith struct { + // replace occurrences that starts with find + StartsWith bool `protobuf:"varint,3,opt,name=starts_with,json=startsWith,proto3,oneof"` +} + +type SpecChange_SearchAndReplaceOperation_EndsWith struct { + // replace occurrences that ends with find + EndsWith bool `protobuf:"varint,4,opt,name=ends_with,json=endsWith,proto3,oneof"` +} + +func (*SpecChange_SearchAndReplaceOperation_Field) isSpecChange_SearchAndReplaceOperation_Identifier() { +} + +func (*SpecChange_SearchAndReplaceOperation_Any) isSpecChange_SearchAndReplaceOperation_Identifier() { +} + +func (*SpecChange_SearchAndReplaceOperation_StartsWith) isSpecChange_SearchAndReplaceOperation_Identifier() { +} + +func (*SpecChange_SearchAndReplaceOperation_EndsWith) isSpecChange_SearchAndReplaceOperation_Identifier() { +} + +// AppendOperation appends a value to specified field or section +type SpecChange_AppendOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *SpecChange_AppendOperation) Reset() { + *x = SpecChange_AppendOperation{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SpecChange_AppendOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SpecChange_AppendOperation) ProtoMessage() {} + +func (x *SpecChange_AppendOperation) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SpecChange_AppendOperation.ProtoReflect.Descriptor instead. +func (*SpecChange_AppendOperation) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{4, 3} +} + +func (x *SpecChange_AppendOperation) GetField() string { + if x != nil { + return x.Field + } + return "" +} + +func (x *SpecChange_AppendOperation) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +// NewFieldOperation adds a new kv to the spec +// The field will be grouped if other fields of same name exists +type SpecChange_NewFieldOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Key cannot be Source or Patch + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *SpecChange_NewFieldOperation) Reset() { + *x = SpecChange_NewFieldOperation{} + if protoimpl.UnsafeEnabled { + mi := &file_cfg_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SpecChange_NewFieldOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SpecChange_NewFieldOperation) ProtoMessage() {} + +func (x *SpecChange_NewFieldOperation) ProtoReflect() protoreflect.Message { + mi := &file_cfg_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SpecChange_NewFieldOperation.ProtoReflect.Descriptor instead. +func (*SpecChange_NewFieldOperation) Descriptor() ([]byte, []int) { + return file_cfg_proto_rawDescGZIP(), []int{4, 4} +} + +func (x *SpecChange_NewFieldOperation) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *SpecChange_NewFieldOperation) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +var File_cfg_proto protoreflect.FileDescriptor + +var file_cfg_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x63, 0x66, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x73, 0x72, 0x70, + 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x22, 0x95, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x66, 0x69, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x77, 0x69, 0x74, 0x68, + 0x46, 0x69, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x6c, + 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x77, 0x69, 0x74, + 0x68, 0x49, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x27, 0x0a, 0x0e, 0x77, 0x69, 0x74, 0x68, 0x5f, + 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x73, 0x69, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x0d, 0x77, 0x69, 0x74, 0x68, 0x4c, 0x6f, 0x6f, 0x6b, 0x61, 0x73, 0x69, 0x64, 0x65, + 0x42, 0x0b, 0x0a, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x22, 0x1c, 0x0a, + 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x59, 0x0a, 0x03, 0x41, + 0x64, 0x64, 0x12, 0x14, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1e, 0x0a, 0x09, 0x6c, 0x6f, 0x6f, 0x6b, + 0x61, 0x73, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x6c, + 0x6f, 0x6f, 0x6b, 0x61, 0x73, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x08, 0x0a, 0x06, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x7c, 0x0a, 0x09, 0x4c, 0x6f, 0x6f, 0x6b, 0x61, 0x73, + 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x61, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0f, + 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63, 0x68, + 0x54, 0x72, 0x65, 0x65, 0x22, 0xdc, 0x08, 0x0a, 0x0a, 0x53, 0x70, 0x65, 0x63, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x53, 0x70, 0x65, + 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x09, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x53, 0x70, 0x65, 0x63, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, + 0x6f, 0x67, 0x12, 0x5c, 0x0a, 0x12, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x61, 0x6e, 0x64, + 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, + 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x53, 0x70, 0x65, 0x63, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x6e, 0x64, 0x52, 0x65, + 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, + 0x12, 0x3c, 0x0a, 0x06, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x53, 0x70, 0x65, 0x63, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x43, + 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x53, 0x70, 0x65, + 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x4e, 0x65, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, + 0x75, 0x74, 0x6f, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x10, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x41, 0x6c, 0x69, 0x67, + 0x6e, 0x1a, 0xf9, 0x01, 0x0a, 0x0d, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, + 0x2e, 0x53, 0x70, 0x65, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6c, 0x65, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x48, 0x00, 0x52, 0x03, 0x61, 0x64, 0x64, 0x12, 0x18, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x70, 0x72, 0x65, + 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x64, 0x64, 0x54, 0x6f, 0x50, 0x72, + 0x65, 0x70, 0x12, 0x15, 0x0a, 0x06, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2a, 0x0a, 0x04, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0a, + 0x0a, 0x06, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x61, + 0x74, 0x63, 0x68, 0x10, 0x02, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x1a, 0x72, 0x0a, + 0x12, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x5f, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0xd3, 0x01, 0x0a, 0x19, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x6e, 0x64, 0x52, + 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x16, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x6e, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6e, 0x79, 0x12, 0x21, 0x0a, 0x0b, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x73, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x48, 0x00, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x57, 0x69, 0x74, 0x68, 0x12, 0x1d, + 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x73, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x48, 0x00, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x73, 0x57, 0x69, 0x74, 0x68, 0x12, 0x12, 0x0a, + 0x04, 0x66, 0x69, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6e, + 0x64, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x6e, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x11, 0x52, 0x01, 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x65, 0x6e, + 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x3b, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x22, 0x33, 0x0a, 0x05, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, 0x12, 0x0a, 0x04, + 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x06, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x22, 0x8e, 0x02, 0x0a, 0x03, 0x43, 0x66, 0x67, + 0x12, 0x2b, 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x52, 0x65, 0x70, + 0x6c, 0x61, 0x63, 0x65, 0x52, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x28, 0x0a, + 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, + 0x41, 0x64, 0x64, 0x52, 0x03, 0x61, 0x64, 0x64, 0x12, 0x31, 0x0a, 0x09, 0x6c, 0x6f, 0x6f, 0x6b, + 0x61, 0x73, 0x69, 0x64, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x72, + 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x61, 0x73, 0x69, 0x64, 0x65, + 0x52, 0x09, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x73, 0x69, 0x64, 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x73, + 0x70, 0x65, 0x63, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x53, 0x70, 0x65, 0x63, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x73, 0x70, 0x65, 0x63, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x63, 0x68, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x50, 0x61, 0x74, + 0x63, 0x68, 0x52, 0x05, 0x70, 0x61, 0x74, 0x63, 0x68, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x6f, 0x63, 0x6b, 0x79, 0x2d, 0x6c, 0x69, + 0x6e, 0x75, 0x78, 0x2f, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2f, 0x70, 0x62, 0x3b, + 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_cfg_proto_rawDescOnce sync.Once + file_cfg_proto_rawDescData = file_cfg_proto_rawDesc +) + +func file_cfg_proto_rawDescGZIP() []byte { + file_cfg_proto_rawDescOnce.Do(func() { + file_cfg_proto_rawDescData = protoimpl.X.CompressGZIP(file_cfg_proto_rawDescData) + }) + return file_cfg_proto_rawDescData +} + +var file_cfg_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_cfg_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_cfg_proto_goTypes = []interface{}{ + (SpecChange_FileOperation_Type)(0), // 0: srpmproc.SpecChange.FileOperation.Type + (*Replace)(nil), // 1: srpmproc.Replace + (*Delete)(nil), // 2: srpmproc.Delete + (*Add)(nil), // 3: srpmproc.Add + (*Lookaside)(nil), // 4: srpmproc.Lookaside + (*SpecChange)(nil), // 5: srpmproc.SpecChange + (*Patch)(nil), // 6: srpmproc.Patch + (*Cfg)(nil), // 7: srpmproc.Cfg + (*SpecChange_FileOperation)(nil), // 8: srpmproc.SpecChange.FileOperation + (*SpecChange_ChangelogOperation)(nil), // 9: srpmproc.SpecChange.ChangelogOperation + (*SpecChange_SearchAndReplaceOperation)(nil), // 10: srpmproc.SpecChange.SearchAndReplaceOperation + (*SpecChange_AppendOperation)(nil), // 11: srpmproc.SpecChange.AppendOperation + (*SpecChange_NewFieldOperation)(nil), // 12: srpmproc.SpecChange.NewFieldOperation +} +var file_cfg_proto_depIdxs = []int32{ + 8, // 0: srpmproc.SpecChange.file:type_name -> srpmproc.SpecChange.FileOperation + 9, // 1: srpmproc.SpecChange.changelog:type_name -> srpmproc.SpecChange.ChangelogOperation + 10, // 2: srpmproc.SpecChange.search_and_replace:type_name -> srpmproc.SpecChange.SearchAndReplaceOperation + 11, // 3: srpmproc.SpecChange.append:type_name -> srpmproc.SpecChange.AppendOperation + 12, // 4: srpmproc.SpecChange.new_field:type_name -> srpmproc.SpecChange.NewFieldOperation + 1, // 5: srpmproc.Cfg.replace:type_name -> srpmproc.Replace + 2, // 6: srpmproc.Cfg.delete:type_name -> srpmproc.Delete + 3, // 7: srpmproc.Cfg.add:type_name -> srpmproc.Add + 4, // 8: srpmproc.Cfg.lookaside:type_name -> srpmproc.Lookaside + 5, // 9: srpmproc.Cfg.spec_change:type_name -> srpmproc.SpecChange + 6, // 10: srpmproc.Cfg.patch:type_name -> srpmproc.Patch + 0, // 11: srpmproc.SpecChange.FileOperation.type:type_name -> srpmproc.SpecChange.FileOperation.Type + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_cfg_proto_init() } +func file_cfg_proto_init() { + if File_cfg_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_cfg_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Replace); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Delete); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Add); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Lookaside); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SpecChange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Patch); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Cfg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SpecChange_FileOperation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SpecChange_ChangelogOperation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SpecChange_SearchAndReplaceOperation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SpecChange_AppendOperation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cfg_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SpecChange_NewFieldOperation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_cfg_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Replace_WithFile)(nil), + (*Replace_WithInline)(nil), + (*Replace_WithLookaside)(nil), + } + file_cfg_proto_msgTypes[2].OneofWrappers = []interface{}{ + (*Add_File)(nil), + (*Add_Lookaside)(nil), + } + file_cfg_proto_msgTypes[7].OneofWrappers = []interface{}{ + (*SpecChange_FileOperation_Add)(nil), + (*SpecChange_FileOperation_Delete)(nil), + } + file_cfg_proto_msgTypes[9].OneofWrappers = []interface{}{ + (*SpecChange_SearchAndReplaceOperation_Field)(nil), + (*SpecChange_SearchAndReplaceOperation_Any)(nil), + (*SpecChange_SearchAndReplaceOperation_StartsWith)(nil), + (*SpecChange_SearchAndReplaceOperation_EndsWith)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_cfg_proto_rawDesc, + NumEnums: 1, + NumMessages: 12, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_cfg_proto_goTypes, + DependencyIndexes: file_cfg_proto_depIdxs, + EnumInfos: file_cfg_proto_enumTypes, + MessageInfos: file_cfg_proto_msgTypes, + }.Build() + File_cfg_proto = out.File + file_cfg_proto_rawDesc = nil + file_cfg_proto_goTypes = nil + file_cfg_proto_depIdxs = nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pb/response.pb.go b/vendor/github.com/rocky-linux/srpmproc/pb/response.pb.go new file mode 100644 index 00000000..4ada5dfa --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pb/response.pb.go @@ -0,0 +1,249 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.3 +// source: response.proto + +package srpmprocpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type VersionRelease struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + Release string `protobuf:"bytes,2,opt,name=release,proto3" json:"release,omitempty"` +} + +func (x *VersionRelease) Reset() { + *x = VersionRelease{} + if protoimpl.UnsafeEnabled { + mi := &file_response_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VersionRelease) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VersionRelease) ProtoMessage() {} + +func (x *VersionRelease) ProtoReflect() protoreflect.Message { + mi := &file_response_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VersionRelease.ProtoReflect.Descriptor instead. +func (*VersionRelease) Descriptor() ([]byte, []int) { + return file_response_proto_rawDescGZIP(), []int{0} +} + +func (x *VersionRelease) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *VersionRelease) GetRelease() string { + if x != nil { + return x.Release + } + return "" +} + +type ProcessResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BranchCommits map[string]string `protobuf:"bytes,1,rep,name=branch_commits,json=branchCommits,proto3" json:"branch_commits,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + BranchVersions map[string]*VersionRelease `protobuf:"bytes,2,rep,name=branch_versions,json=branchVersions,proto3" json:"branch_versions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *ProcessResponse) Reset() { + *x = ProcessResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_response_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProcessResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProcessResponse) ProtoMessage() {} + +func (x *ProcessResponse) ProtoReflect() protoreflect.Message { + mi := &file_response_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProcessResponse.ProtoReflect.Descriptor instead. +func (*ProcessResponse) Descriptor() ([]byte, []int) { + return file_response_proto_rawDescGZIP(), []int{1} +} + +func (x *ProcessResponse) GetBranchCommits() map[string]string { + if x != nil { + return x.BranchCommits + } + return nil +} + +func (x *ProcessResponse) GetBranchVersions() map[string]*VersionRelease { + if x != nil { + return x.BranchVersions + } + return nil +} + +var File_response_proto protoreflect.FileDescriptor + +var file_response_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x08, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x22, 0x44, 0x0a, 0x0e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x22, 0xdd, 0x02, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x0e, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x73, + 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x62, 0x72, 0x61, 0x6e, + 0x63, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x56, 0x0a, 0x0f, 0x62, 0x72, 0x61, + 0x6e, 0x63, 0x68, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x50, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x72, + 0x61, 0x6e, 0x63, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0e, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x5b, 0x0a, 0x13, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x72, + 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, + 0x6f, 0x63, 0x6b, 0x79, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2f, 0x73, 0x72, 0x70, 0x6d, 0x70, + 0x72, 0x6f, 0x63, 0x2f, 0x70, 0x62, 0x3b, 0x73, 0x72, 0x70, 0x6d, 0x70, 0x72, 0x6f, 0x63, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_response_proto_rawDescOnce sync.Once + file_response_proto_rawDescData = file_response_proto_rawDesc +) + +func file_response_proto_rawDescGZIP() []byte { + file_response_proto_rawDescOnce.Do(func() { + file_response_proto_rawDescData = protoimpl.X.CompressGZIP(file_response_proto_rawDescData) + }) + return file_response_proto_rawDescData +} + +var file_response_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_response_proto_goTypes = []interface{}{ + (*VersionRelease)(nil), // 0: srpmproc.VersionRelease + (*ProcessResponse)(nil), // 1: srpmproc.ProcessResponse + nil, // 2: srpmproc.ProcessResponse.BranchCommitsEntry + nil, // 3: srpmproc.ProcessResponse.BranchVersionsEntry +} +var file_response_proto_depIdxs = []int32{ + 2, // 0: srpmproc.ProcessResponse.branch_commits:type_name -> srpmproc.ProcessResponse.BranchCommitsEntry + 3, // 1: srpmproc.ProcessResponse.branch_versions:type_name -> srpmproc.ProcessResponse.BranchVersionsEntry + 0, // 2: srpmproc.ProcessResponse.BranchVersionsEntry.value:type_name -> srpmproc.VersionRelease + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_response_proto_init() } +func file_response_proto_init() { + if File_response_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_response_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VersionRelease); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_response_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProcessResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_response_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_response_proto_goTypes, + DependencyIndexes: file_response_proto_depIdxs, + MessageInfos: file_response_proto_msgTypes, + }.Build() + File_response_proto = out.File + file_response_proto_rawDesc = nil + file_response_proto_goTypes = nil + file_response_proto_depIdxs = nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/blob/BUILD b/vendor/github.com/rocky-linux/srpmproc/pkg/blob/BUILD new file mode 100644 index 00000000..1febf3d6 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/blob/BUILD @@ -0,0 +1,9 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "blob", + srcs = ["blob.go"], + importmap = "go.resf.org/peridot/vendor/github.com/rocky-linux/srpmproc/pkg/blob", + importpath = "github.com/rocky-linux/srpmproc/pkg/blob", + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/blob/blob.go b/vendor/github.com/rocky-linux/srpmproc/pkg/blob/blob.go new file mode 100644 index 00000000..b6d7bb25 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/blob/blob.go @@ -0,0 +1,27 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package blob + +type Storage interface { + Write(path string, content []byte) error + Read(path string) ([]byte, error) + Exists(path string) (bool, error) +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/data/BUILD b/vendor/github.com/rocky-linux/srpmproc/pkg/data/BUILD new file mode 100644 index 00000000..cf00a89e --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/data/BUILD @@ -0,0 +1,19 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "data", + srcs = [ + "import.go", + "process.go", + "utils.go", + ], + importmap = "go.resf.org/peridot/vendor/github.com/rocky-linux/srpmproc/pkg/data", + importpath = "github.com/rocky-linux/srpmproc/pkg/data", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/go-git/go-billy/v5:go-billy", + "//vendor/github.com/go-git/go-git/v5:go-git", + "//vendor/github.com/go-git/go-git/v5/plumbing/transport", + "//vendor/github.com/rocky-linux/srpmproc/pkg/blob", + ], +) diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/data/import.go b/vendor/github.com/rocky-linux/srpmproc/pkg/data/import.go new file mode 100644 index 00000000..da9694a2 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/data/import.go @@ -0,0 +1,52 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package data + +import ( + "hash" + + "github.com/go-git/go-git/v5" +) + +type ImportMode interface { + RetrieveSource(pd *ProcessData) (*ModeData, error) + WriteSource(pd *ProcessData, md *ModeData) error + PostProcess(md *ModeData) error + ImportName(pd *ProcessData, md *ModeData) string +} + +type ModeData struct { + Name string + Repo *git.Repository + Worktree *git.Worktree + FileWrites map[string][]byte + TagBranch string + PushBranch string + Branches []string + SourcesToIgnore []*IgnoredSource + BlobCache map[string][]byte +} + +type IgnoredSource struct { + Name string + HashFunction hash.Hash + Expired bool +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/data/process.go b/vendor/github.com/rocky-linux/srpmproc/pkg/data/process.go new file mode 100644 index 00000000..bdd01b99 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/data/process.go @@ -0,0 +1,63 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package data + +import ( + "log" + + "github.com/go-git/go-billy/v5" + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/rocky-linux/srpmproc/pkg/blob" +) + +type FsCreatorFunc func(branch string) (billy.Filesystem, error) + +type ProcessData struct { + RpmLocation string + UpstreamPrefix string + Version int + GitCommitterName string + GitCommitterEmail string + Mode int + ModulePrefix string + ImportBranchPrefix string + BranchPrefix string + SingleTag string + Authenticator transport.AuthMethod + Importer ImportMode + BlobStorage blob.Storage + NoDupMode bool + ModuleMode bool + TmpFsMode string + NoStorageDownload bool + NoStorageUpload bool + ManualCommits []string + ModuleFallbackStream string + BranchSuffix string + StrictBranchMode bool + FsCreator FsCreatorFunc + CdnUrl string + Log *log.Logger + PackageVersion string + PackageRelease string + TaglessMode bool + Cdn string +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/data/utils.go b/vendor/github.com/rocky-linux/srpmproc/pkg/data/utils.go new file mode 100644 index 00000000..ffdd6474 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/data/utils.go @@ -0,0 +1,131 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package data + +import ( + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/hex" + "fmt" + "hash" + "io" + "os" + "path/filepath" + + "github.com/go-git/go-billy/v5" +) + +func CopyFromFs(from billy.Filesystem, to billy.Filesystem, path string) error { + read, err := from.ReadDir(path) + if err != nil { + return fmt.Errorf("could not read dir: %v", err) + } + + for _, fi := range read { + fullPath := filepath.Join(path, fi.Name()) + + if fi.IsDir() { + _ = to.MkdirAll(fullPath, 0o755) + err := CopyFromFs(from, to, fullPath) + if err != nil { + return err + } + } else { + _ = to.Remove(fullPath) + + f, err := to.OpenFile(fullPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fi.Mode()) + if err != nil { + return fmt.Errorf("could not open file: %v", err) + } + + oldFile, err := from.Open(fullPath) + if err != nil { + return fmt.Errorf("could not open from file: %v", err) + } + + _, err = io.Copy(f, oldFile) + if err != nil { + return fmt.Errorf("could not copy from oldFile to new: %v", err) + } + } + } + + return nil +} + +func IgnoredContains(a []*IgnoredSource, b string) bool { + for _, val := range a { + if val.Name == b { + return true + } + } + + return false +} + +func StrContains(a []string, b string) bool { + for _, val := range a { + if val == b { + return true + } + } + + return false +} + +// CompareHash checks if content and checksum matches +// returns the hash type if success else nil +func (pd *ProcessData) CompareHash(content []byte, checksum string) hash.Hash { + var hashType hash.Hash + + switch len(checksum) { + case 128: + hashType = sha512.New() + break + case 64: + hashType = sha256.New() + break + case 40: + hashType = sha1.New() + break + case 32: + hashType = md5.New() + break + default: + return nil + } + + hashType.Reset() + _, err := hashType.Write(content) + if err != nil { + return nil + } + + calculated := hex.EncodeToString(hashType.Sum(nil)) + if calculated != checksum { + pd.Log.Printf("wanted checksum %s, but got %s", checksum, calculated) + return nil + } + + return hashType +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/directives/BUILD b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/BUILD new file mode 100644 index 00000000..867fae16 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/BUILD @@ -0,0 +1,23 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "directives", + srcs = [ + "add.go", + "delete.go", + "directives.go", + "lookaside.go", + "patch.go", + "replace.go", + "spec_change.go", + ], + importmap = "go.resf.org/peridot/vendor/github.com/rocky-linux/srpmproc/pkg/directives", + importpath = "github.com/rocky-linux/srpmproc/pkg/directives", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/bluekeyes/go-gitdiff/gitdiff", + "//vendor/github.com/go-git/go-git/v5:go-git", + "//vendor/github.com/rocky-linux/srpmproc/pb", + "//vendor/github.com/rocky-linux/srpmproc/pkg/data", + ], +) diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/directives/add.go b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/add.go new file mode 100644 index 00000000..079bb85a --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/add.go @@ -0,0 +1,95 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package directives + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/go-git/go-git/v5" + srpmprocpb "github.com/rocky-linux/srpmproc/pb" + "github.com/rocky-linux/srpmproc/pkg/data" +) + +// returns right if not empty, else left +func eitherString(left string, right string) string { + if right != "" { + return right + } + + return left +} + +func add(cfg *srpmprocpb.Cfg, pd *data.ProcessData, md *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) error { + for _, add := range cfg.Add { + var replacingBytes []byte + var filePath string + + switch addType := add.Source.(type) { + case *srpmprocpb.Add_File: + filePath = checkAddPrefix(eitherString(filepath.Base(addType.File), add.Name)) + + fPatch, err := patchTree.Filesystem.OpenFile(addType.File, os.O_RDONLY, 0o644) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_OPEN_FROM:%s", addType.File)) + } + + replacingBytes, err = ioutil.ReadAll(fPatch) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_READ_FROM:%s", addType.File)) + } + break + case *srpmprocpb.Add_Lookaside: + filePath = checkAddPrefix(eitherString(filepath.Base(addType.Lookaside), add.Name)) + var err error + replacingBytes, err = pd.BlobStorage.Read(addType.Lookaside) + if err != nil { + return err + } + + hashFunction := pd.CompareHash(replacingBytes, addType.Lookaside) + if hashFunction == nil { + return errors.New(fmt.Sprintf("LOOKASIDE_HASH_DOES_NOT_MATCH:%s", addType.Lookaside)) + } + + md.SourcesToIgnore = append(md.SourcesToIgnore, &data.IgnoredSource{ + Name: filePath, + HashFunction: hashFunction, + }) + break + } + + f, err := pushTree.Filesystem.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_OPEN_DESTINATION:%s", filePath)) + } + + _, err = f.Write(replacingBytes) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_DESTIONATION:%s", filePath)) + } + } + + return nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/directives/delete.go b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/delete.go new file mode 100644 index 00000000..daed71a8 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/delete.go @@ -0,0 +1,47 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package directives + +import ( + "errors" + "fmt" + + "github.com/go-git/go-git/v5" + srpmprocpb "github.com/rocky-linux/srpmproc/pb" + "github.com/rocky-linux/srpmproc/pkg/data" +) + +func del(cfg *srpmprocpb.Cfg, _ *data.ProcessData, _ *data.ModeData, _ *git.Worktree, pushTree *git.Worktree) error { + for _, del := range cfg.Delete { + filePath := del.File + _, err := pushTree.Filesystem.Stat(filePath) + if err != nil { + return errors.New(fmt.Sprintf("FILE_DOES_NOT_EXIST:%s", filePath)) + } + + err = pushTree.Filesystem.Remove(filePath) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_DELETE_FILE:%s", filePath)) + } + } + + return nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/directives/directives.go b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/directives.go new file mode 100644 index 00000000..f8d21ca3 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/directives.go @@ -0,0 +1,65 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package directives + +import ( + "path/filepath" + "strings" + + "github.com/go-git/go-git/v5" + srpmprocpb "github.com/rocky-linux/srpmproc/pb" + "github.com/rocky-linux/srpmproc/pkg/data" +) + +func checkAddPrefix(file string) string { + if strings.HasPrefix(file, "SOURCES/") || + strings.HasPrefix(file, "SPECS/") { + return file + } + + return filepath.Join("SOURCES", file) +} + +func Apply(cfg *srpmprocpb.Cfg, pd *data.ProcessData, md *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) []error { + var errs []error + + directives := []func(*srpmprocpb.Cfg, *data.ProcessData, *data.ModeData, *git.Worktree, *git.Worktree) error{ + replace, + del, + add, + patch, + lookaside, + specChange, + } + + for _, directive := range directives { + err := directive(cfg, pd, md, patchTree, pushTree) + if err != nil { + errs = append(errs, err) + } + } + + if len(errs) > 0 { + return errs + } + + return nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/directives/lookaside.go b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/lookaside.go new file mode 100644 index 00000000..d8d4f590 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/lookaside.go @@ -0,0 +1,148 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package directives + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "crypto/sha256" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "time" + + "github.com/go-git/go-git/v5" + srpmprocpb "github.com/rocky-linux/srpmproc/pb" + "github.com/rocky-linux/srpmproc/pkg/data" +) + +func lookaside(cfg *srpmprocpb.Cfg, _ *data.ProcessData, md *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) error { + for _, directive := range cfg.Lookaside { + var buf bytes.Buffer + writer := tar.NewWriter(&buf) + w := pushTree + if directive.FromPatchTree { + w = patchTree + } + + for _, file := range directive.File { + if directive.Tar && directive.ArchiveName == "" { + return errors.New("TAR_NO_ARCHIVE_NAME") + } + + path := filepath.Join("SOURCES", file) + if directive.FromPatchTree { + path = file + } + + stat, err := w.Filesystem.Stat(path) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_STAT_FILE:%s", path)) + } + + f, err := w.Filesystem.Open(path) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_OPEN_FILE:%s", path)) + } + + bts, err := ioutil.ReadAll(f) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_READ_FILE:%s", path)) + } + + if directive.Tar { + hdr := &tar.Header{ + Name: file, + Mode: int64(stat.Mode()), + Size: stat.Size(), + } + + err = writer.WriteHeader(hdr) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_TAR_HEADER:%s", file)) + } + + _, err = writer.Write(bts) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_TAR_FILE:%s", file)) + } + } else { + if directive.FromPatchTree { + pushF, err := pushTree.Filesystem.OpenFile(filepath.Join("SOURCES", filepath.Base(file)), os.O_CREATE|os.O_TRUNC|os.O_RDWR, stat.Mode()) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_CREATE_FILE_IN_PUSH_TREE:%s", file)) + } + + _, err = pushF.Write(bts) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_FILE_IN_PUSH_TREE:%s", file)) + } + } + + md.SourcesToIgnore = append(md.SourcesToIgnore, &data.IgnoredSource{ + Name: filepath.Join("SOURCES", file), + HashFunction: sha256.New(), + }) + } + } + + if directive.Tar { + err := writer.Close() + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_CLOSE_TAR:%s", directive.ArchiveName)) + } + + var gbuf bytes.Buffer + gw := gzip.NewWriter(&gbuf) + gw.Name = fmt.Sprintf("%s.tar.gz", directive.ArchiveName) + gw.ModTime = time.Now() + + _, err = gw.Write(buf.Bytes()) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_GZIP:%s", directive.ArchiveName)) + } + err = gw.Close() + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_CLOSE_GZIP:%s", directive.ArchiveName)) + } + + path := filepath.Join("SOURCES", fmt.Sprintf("%s.tar.gz", directive.ArchiveName)) + pushF, err := pushTree.Filesystem.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o644) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_CREATE_TAR_FILE:%s", path)) + } + + _, err = pushF.Write(gbuf.Bytes()) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_TAR_FILE:%s", path)) + } + + md.SourcesToIgnore = append(md.SourcesToIgnore, &data.IgnoredSource{ + Name: path, + HashFunction: sha256.New(), + }) + } + } + return nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/directives/patch.go b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/patch.go new file mode 100644 index 00000000..a2b562dd --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/patch.go @@ -0,0 +1,112 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package directives + +import ( + "bytes" + "errors" + "fmt" + + "github.com/bluekeyes/go-gitdiff/gitdiff" + "github.com/go-git/go-git/v5" + srpmprocpb "github.com/rocky-linux/srpmproc/pb" + "github.com/rocky-linux/srpmproc/pkg/data" +) + +func patch(cfg *srpmprocpb.Cfg, pd *data.ProcessData, _ *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) error { + for _, patch := range cfg.Patch { + patchFile, err := patchTree.Filesystem.Open(patch.File) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_OPEN_PATCH_FILE:%s", patch.File)) + } + files, _, err := gitdiff.Parse(patchFile) + if err != nil { + pd.Log.Printf("could not parse patch file: %v", err) + return errors.New(fmt.Sprintf("COULD_NOT_PARSE_PATCH_FILE:%s", patch.File)) + } + + for _, patchedFile := range files { + srcPath := patchedFile.NewName + if !patch.Strict { + srcPath = checkAddPrefix(patchedFile.NewName) + } + var output bytes.Buffer + if !patchedFile.IsDelete && !patchedFile.IsNew { + patchSubjectFile, err := pushTree.Filesystem.Open(srcPath) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_OPEN_PATCH_SUBJECT:%s", srcPath)) + } + + err = gitdiff.NewApplier(patchSubjectFile).ApplyFile(&output, patchedFile) + if err != nil { + pd.Log.Printf("could not apply patch: %v", err) + return errors.New(fmt.Sprintf("COULD_NOT_APPLY_PATCH_WITH_SUBJECT:%s", srcPath)) + } + } + + oldName := patchedFile.OldName + if !patch.Strict { + oldName = checkAddPrefix(patchedFile.OldName) + } + _ = pushTree.Filesystem.Remove(oldName) + _ = pushTree.Filesystem.Remove(srcPath) + + if patchedFile.IsNew { + newFile, err := pushTree.Filesystem.Create(srcPath) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_CREATE_NEW_FILE:%s", srcPath)) + } + err = gitdiff.NewApplier(newFile).ApplyFile(&output, patchedFile) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_APPLY_PATCH_TO_NEW_FILE:%s", srcPath)) + } + _, err = newFile.Write(output.Bytes()) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_TO_NEW_FILE:%s", srcPath)) + } + _, err = pushTree.Add(srcPath) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_ADD_NEW_FILE_TO_GIT:%s", srcPath)) + } + } else if !patchedFile.IsDelete { + newFile, err := pushTree.Filesystem.Create(srcPath) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_CREATE_POST_PATCH_FILE:%s", srcPath)) + } + _, err = newFile.Write(output.Bytes()) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_POST_PATCH_FILE:%s", srcPath)) + } + _, err = pushTree.Add(srcPath) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_ADD_POST_PATCH_FILE_TO_GIT:%s", srcPath)) + } + } else { + _, err = pushTree.Remove(oldName) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_REMOVE_FILE_FROM_GIT:%s", oldName)) + } + } + } + } + + return nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/directives/replace.go b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/replace.go new file mode 100644 index 00000000..41d31d0a --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/replace.go @@ -0,0 +1,94 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package directives + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + + "github.com/go-git/go-git/v5" + srpmprocpb "github.com/rocky-linux/srpmproc/pb" + "github.com/rocky-linux/srpmproc/pkg/data" +) + +func replace(cfg *srpmprocpb.Cfg, pd *data.ProcessData, _ *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) error { + for _, replace := range cfg.Replace { + filePath := checkAddPrefix(replace.File) + stat, err := pushTree.Filesystem.Stat(filePath) + if replace.File == "" || err != nil { + return errors.New(fmt.Sprintf("INVALID_FILE:%s", filePath)) + } + + err = pushTree.Filesystem.Remove(filePath) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_REMOVE_OLD_FILE:%s", filePath)) + } + + f, err := pushTree.Filesystem.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, stat.Mode()) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_OPEN_REPLACEMENT:%s", filePath)) + } + + switch replacing := replace.Replacing.(type) { + case *srpmprocpb.Replace_WithFile: + fPatch, err := patchTree.Filesystem.OpenFile(replacing.WithFile, os.O_RDONLY, 0o644) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_OPEN_REPLACING:%s", replacing.WithFile)) + } + + replacingBytes, err := ioutil.ReadAll(fPatch) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_READ_REPLACING:%s", replacing.WithFile)) + } + + _, err = f.Write(replacingBytes) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_REPLACING:%s", replacing.WithFile)) + } + break + case *srpmprocpb.Replace_WithInline: + _, err := f.Write([]byte(replacing.WithInline)) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_INLINE:%s", filePath)) + } + break + case *srpmprocpb.Replace_WithLookaside: + bts, err := pd.BlobStorage.Read(replacing.WithLookaside) + if err != nil { + return err + } + hasher := pd.CompareHash(bts, replacing.WithLookaside) + if hasher == nil { + return errors.New("LOOKASIDE_FILE_AND_HASH_NOT_MATCHING") + } + + _, err = f.Write(bts) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_WRITE_LOOKASIDE:%s", filePath)) + } + break + } + } + + return nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/directives/spec_change.go b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/spec_change.go new file mode 100644 index 00000000..ea1152b2 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/directives/spec_change.go @@ -0,0 +1,496 @@ +// Copyright (c) 2021 The Srpmproc Authors +// +// 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. + +package directives + +import ( + "errors" + "fmt" + "io/ioutil" + "math" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "time" + + "github.com/go-git/go-git/v5" + srpmprocpb "github.com/rocky-linux/srpmproc/pb" + "github.com/rocky-linux/srpmproc/pkg/data" +) + +const ( + sectionChangelog = "%changelog" +) + +var sections = []string{"%description", "%prep", "%build", "%install", "%files", "%changelog"} + +type sourcePatchOperationInLoopRequest struct { + cfg *srpmprocpb.Cfg + field string + value *string + longestField int + lastNum *int + in *string + expectedField string + operation srpmprocpb.SpecChange_FileOperation_Type +} + +type sourcePatchOperationAfterLoopRequest struct { + cfg *srpmprocpb.Cfg + inLoopNum int + lastNum *int + longestField int + newLines *[]string + in *string + expectedField string + operation srpmprocpb.SpecChange_FileOperation_Type +} + +func sourcePatchOperationInLoop(req *sourcePatchOperationInLoopRequest) error { + if strings.HasPrefix(req.field, req.expectedField) { + for _, file := range req.cfg.SpecChange.File { + if file.Type != req.operation { + continue + } + + switch file.Mode.(type) { + case *srpmprocpb.SpecChange_FileOperation_Delete: + if file.Name == *req.value { + *req.value = "" + } + break + } + } + if req.field != req.expectedField { + sourceNum, err := strconv.Atoi(strings.Split(req.field, req.expectedField)[1]) + if err != nil { + return errors.New(fmt.Sprintf("INVALID_%s_NUM:%s", strings.ToUpper(req.expectedField), req.field)) + } + *req.lastNum = sourceNum + } + } + + return nil +} + +func sourcePatchOperationAfterLoop(req *sourcePatchOperationAfterLoopRequest) (bool, error) { + if req.inLoopNum == *req.lastNum && *req.in == req.expectedField { + for _, file := range req.cfg.SpecChange.File { + if file.Type != req.operation { + continue + } + + switch file.Mode.(type) { + case *srpmprocpb.SpecChange_FileOperation_Add: + fieldNum := *req.lastNum + 1 + field := fmt.Sprintf("%s%d", req.expectedField, fieldNum) + spaces := calculateSpaces(req.longestField, len(field), req.cfg.SpecChange.DisableAutoAlign) + *req.newLines = append(*req.newLines, fmt.Sprintf("%s:%s%s", field, spaces, file.Name)) + + if req.expectedField == "Patch" && file.AddToPrep { + val := fmt.Sprintf("%%patch%d", fieldNum) + if file.NPath > 0 { + val = fmt.Sprintf("%s -p%d", val, file.NPath) + } + + req.cfg.SpecChange.Append = append(req.cfg.SpecChange.Append, &srpmprocpb.SpecChange_AppendOperation{ + Field: "%prep", + Value: val, + }) + } + + *req.lastNum++ + break + } + } + *req.in = "" + + return true, nil + } + + return false, nil +} + +func calculateSpaces(longestField int, fieldLength int, disableAutoAlign bool) string { + if disableAutoAlign { + return " " + } + return strings.Repeat(" ", longestField+8-fieldLength) +} + +func searchAndReplaceLine(line string, sar []*srpmprocpb.SpecChange_SearchAndReplaceOperation) string { + for _, searchAndReplace := range sar { + switch searchAndReplace.Identifier.(type) { + case *srpmprocpb.SpecChange_SearchAndReplaceOperation_Any: + line = strings.Replace(line, searchAndReplace.Find, searchAndReplace.Replace, int(searchAndReplace.N)) + break + case *srpmprocpb.SpecChange_SearchAndReplaceOperation_StartsWith: + if strings.HasPrefix(strings.TrimSpace(line), searchAndReplace.Find) { + line = strings.Replace(line, searchAndReplace.Find, searchAndReplace.Replace, int(searchAndReplace.N)) + } + break + case *srpmprocpb.SpecChange_SearchAndReplaceOperation_EndsWith: + if strings.HasSuffix(strings.TrimSpace(line), searchAndReplace.Find) { + line = strings.Replace(line, searchAndReplace.Find, searchAndReplace.Replace, int(searchAndReplace.N)) + } + break + } + } + + return line +} + +func isNextLineSection(lineNum int, lines []string) bool { + if len(lines)-1 > lineNum { + if strings.HasPrefix(strings.TrimSpace(lines[lineNum+1]), "%") { + return true + } + + return false + } + + return true +} + +func setFASlice(futureAdditions map[int][]string, key int, addition string) { + if futureAdditions[key] == nil { + futureAdditions[key] = []string{} + } + futureAdditions[key] = append(futureAdditions[key], addition) +} + +func strSliceContains(slice []string, str string) bool { + for _, x := range slice { + if str == x { + return true + } + } + + return false +} + +func specChange(cfg *srpmprocpb.Cfg, pd *data.ProcessData, md *data.ModeData, _ *git.Worktree, pushTree *git.Worktree) error { + // no spec change operations present + // skip parsing spec + if cfg.SpecChange == nil { + return nil + } + + specFiles, err := pushTree.Filesystem.ReadDir("SPECS") + if err != nil { + return errors.New("COULD_NOT_READ_SPECS_DIR") + } + + if len(specFiles) != 1 { + return errors.New("ONLY_ONE_SPEC_FILE_IS_SUPPORTED") + } + + filePath := filepath.Join("SPECS", specFiles[0].Name()) + stat, err := pushTree.Filesystem.Stat(filePath) + if err != nil { + return errors.New("COULD_NOT_STAT_SPEC_FILE") + } + + specFile, err := pushTree.Filesystem.OpenFile(filePath, os.O_RDONLY, 0o644) + if err != nil { + return errors.New("COULD_NOT_READ_SPEC_FILE") + } + + specBts, err := ioutil.ReadAll(specFile) + if err != nil { + return errors.New("COULD_NOT_READ_ALL_BYTES") + } + + specStr := string(specBts) + lines := strings.Split(specStr, "\n") + + var newLines []string + futureAdditions := map[int][]string{} + newFieldMemory := map[string]map[string]int{} + lastSourceNum := 0 + lastPatchNum := 0 + inSection := "" + inField := "" + lastSource := "" + lastPatch := "" + hasPatch := false + + version := "" + importName := strings.Replace(pd.Importer.ImportName(pd, md), md.Name, "1", 1) + importNameSplit := strings.SplitN(importName, "-", 2) + if len(importNameSplit) == 2 { + versionSplit := strings.SplitN(importNameSplit[1], ".el", 2) + if len(versionSplit) == 2 { + version = versionSplit[0] + } else { + versionSplit := strings.SplitN(importNameSplit[1], ".module", 2) + if len(versionSplit) == 2 { + version = versionSplit[0] + } + } + } + + fieldValueRegex := regexp.MustCompile("^[a-zA-Z0-9]+:") + + longestField := 0 + for lineNum, line := range lines { + if fieldValueRegex.MatchString(line) { + fieldValue := strings.SplitN(line, ":", 2) + field := strings.TrimSpace(fieldValue[0]) + longestField = int(math.Max(float64(len(field)), float64(longestField))) + + if strings.HasPrefix(field, "Source") { + lastSource = field + } else if strings.HasPrefix(field, "Patch") { + lastPatch = field + hasPatch = true + } else { + for _, nf := range cfg.SpecChange.NewField { + if field == nf.Key { + if newFieldMemory[field] == nil { + newFieldMemory[field] = map[string]int{} + } + newFieldMemory[field][nf.Value] = lineNum + } + } + } + } + } + for _, nf := range cfg.SpecChange.NewField { + if newFieldMemory[nf.Key] == nil { + newFieldMemory[nf.Key] = map[string]int{} + newFieldMemory[nf.Key][nf.Value] = 0 + } + } + + for field, nfm := range newFieldMemory { + for value, lineNum := range nfm { + if lineNum != 0 { + newLine := fmt.Sprintf("%s:%s%s", field, calculateSpaces(longestField, len(field), cfg.SpecChange.DisableAutoAlign), value) + setFASlice(futureAdditions, lineNum+1, newLine) + } + } + } + + for lineNum, line := range lines { + inLoopSourceNum := lastSourceNum + inLoopPatchNum := lastPatchNum + prefixLine := strings.TrimSpace(line) + + for i, additions := range futureAdditions { + if lineNum == i { + for _, addition := range additions { + newLines = append(newLines, addition) + } + } + } + + if fieldValueRegex.MatchString(line) { + line = searchAndReplaceLine(line, cfg.SpecChange.SearchAndReplace) + fieldValue := strings.SplitN(line, ":", 2) + field := strings.TrimSpace(fieldValue[0]) + value := strings.TrimSpace(fieldValue[1]) + + if field == lastSource { + inField = "Source" + } else if field == lastPatch { + inField = "Patch" + } + + if field == "Version" && version == "" { + version = value + } + + for _, searchAndReplace := range cfg.SpecChange.SearchAndReplace { + switch identifier := searchAndReplace.Identifier.(type) { + case *srpmprocpb.SpecChange_SearchAndReplaceOperation_Field: + if field == identifier.Field { + value = strings.Replace(value, searchAndReplace.Find, searchAndReplace.Replace, int(searchAndReplace.N)) + } + break + } + } + + for _, appendOp := range cfg.SpecChange.Append { + if field == appendOp.Field { + value = value + appendOp.Value + + if field == "Release" { + version = version + appendOp.Value + } + } + } + + spaces := calculateSpaces(longestField, len(field), cfg.SpecChange.DisableAutoAlign) + + err := sourcePatchOperationInLoop(&sourcePatchOperationInLoopRequest{ + cfg: cfg, + field: field, + value: &value, + lastNum: &lastSourceNum, + longestField: longestField, + in: &inField, + expectedField: "Source", + operation: srpmprocpb.SpecChange_FileOperation_Source, + }) + if err != nil { + return err + } + + err = sourcePatchOperationInLoop(&sourcePatchOperationInLoopRequest{ + cfg: cfg, + field: field, + value: &value, + longestField: longestField, + lastNum: &lastPatchNum, + in: &inField, + expectedField: "Patch", + operation: srpmprocpb.SpecChange_FileOperation_Patch, + }) + if err != nil { + return err + } + + if value != "" { + newLines = append(newLines, fmt.Sprintf("%s:%s%s", field, spaces, value)) + } + } else { + executed, err := sourcePatchOperationAfterLoop(&sourcePatchOperationAfterLoopRequest{ + cfg: cfg, + inLoopNum: inLoopSourceNum, + lastNum: &lastSourceNum, + longestField: longestField, + newLines: &newLines, + expectedField: "Source", + in: &inField, + operation: srpmprocpb.SpecChange_FileOperation_Source, + }) + if err != nil { + return err + } + + if executed && !hasPatch { + newLines = append(newLines, "") + inField = "Patch" + } + + executed, err = sourcePatchOperationAfterLoop(&sourcePatchOperationAfterLoopRequest{ + cfg: cfg, + inLoopNum: inLoopPatchNum, + lastNum: &lastPatchNum, + longestField: longestField, + newLines: &newLines, + expectedField: "Patch", + in: &inField, + operation: srpmprocpb.SpecChange_FileOperation_Patch, + }) + if err != nil { + return err + } + + if executed { + var innerNewLines []string + for field, nfm := range newFieldMemory { + for value, ln := range nfm { + newLine := fmt.Sprintf("%s:%s%s", field, calculateSpaces(longestField, len(field), cfg.SpecChange.DisableAutoAlign), value) + if ln == 0 { + if isNextLineSection(lineNum, lines) { + innerNewLines = append(innerNewLines, newLine) + } + } + } + } + if len(innerNewLines) > 0 { + newLines = append(newLines, "") + for _, il := range innerNewLines { + newLines = append(newLines, il) + } + } + } + + if executed && !strings.Contains(specStr, "%changelog") { + newLines = append(newLines, "") + newLines = append(newLines, "%changelog") + inSection = sectionChangelog + } + + if inSection == sectionChangelog { + now := time.Now().Format("Mon Jan 02 2006") + for _, changelog := range cfg.SpecChange.Changelog { + newLines = append(newLines, fmt.Sprintf("* %s %s <%s> - %s", now, changelog.AuthorName, changelog.AuthorEmail, version)) + for _, msg := range changelog.Message { + newLines = append(newLines, fmt.Sprintf("- %s", msg)) + } + newLines = append(newLines, "") + } + inSection = "" + } else { + line = searchAndReplaceLine(line, cfg.SpecChange.SearchAndReplace) + } + + if strings.HasPrefix(prefixLine, "%") { + inSection = prefixLine + + for _, appendOp := range cfg.SpecChange.Append { + if inSection == appendOp.Field { + insertedLine := 0 + for i, x := range lines[lineNum+1:] { + if strSliceContains(sections, strings.TrimSpace(x)) { + insertedLine = lineNum + i + setFASlice(futureAdditions, insertedLine, appendOp.Value) + break + } + } + if insertedLine == 0 { + for i, x := range lines[lineNum+1:] { + if strings.TrimSpace(x) == "" { + insertedLine = lineNum + i + 2 + setFASlice(futureAdditions, insertedLine, appendOp.Value) + break + } + } + } + } + } + } + + newLines = append(newLines, line) + } + } + + err = pushTree.Filesystem.Remove(filePath) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_REMOVE_OLD_SPEC_FILE:%s", filePath)) + } + + f, err := pushTree.Filesystem.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, stat.Mode()) + if err != nil { + return errors.New(fmt.Sprintf("COULD_NOT_OPEN_REPLACEMENT_SPEC_FILE:%s", filePath)) + } + + _, err = f.Write([]byte(strings.Join(newLines, "\n"))) + if err != nil { + return errors.New("COULD_NOT_WRITE_NEW_SPEC_FILE") + } + + return nil +} diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/misc/BUILD b/vendor/github.com/rocky-linux/srpmproc/pkg/misc/BUILD new file mode 100644 index 00000000..896cd669 --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/misc/BUILD @@ -0,0 +1,10 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "misc", + srcs = ["regex.go"], + importmap = "go.resf.org/peridot/vendor/github.com/rocky-linux/srpmproc/pkg/misc", + importpath = "github.com/rocky-linux/srpmproc/pkg/misc", + visibility = ["//visibility:public"], + deps = ["//vendor/github.com/rocky-linux/srpmproc/pkg/data"], +) diff --git a/vendor/github.com/rocky-linux/srpmproc/pkg/misc/regex.go b/vendor/github.com/rocky-linux/srpmproc/pkg/misc/regex.go new file mode 100644 index 00000000..6782919f --- /dev/null +++ b/vendor/github.com/rocky-linux/srpmproc/pkg/misc/regex.go @@ -0,0 +1,53 @@ +package misc + +import ( + "fmt" + "path/filepath" + "regexp" + "strings" + + "github.com/rocky-linux/srpmproc/pkg/data" +) + +func GetTagImportRegex(pd *data.ProcessData) *regexp.Regexp { + branchRegex := regexp.QuoteMeta(fmt.Sprintf("%s%d%s", pd.ImportBranchPrefix, pd.Version, pd.BranchSuffix)) + if !pd.StrictBranchMode { + branchRegex += "(?:.+|)" + } else { + branchRegex += "(?:-stream-.+|)" + } + + initialVerRegex := regexp.QuoteMeta(filepath.Base(pd.RpmLocation)) + "-" + if pd.PackageVersion != "" { + initialVerRegex += regexp.QuoteMeta(pd.PackageVersion) + "-" + } else { + initialVerRegex += ".+-" + } + if pd.PackageRelease != "" { + initialVerRegex += regexp.QuoteMeta(pd.PackageRelease) + } else { + initialVerRegex += ".+" + } + + regex := fmt.Sprintf("(?i)refs/tags/(imports/(%s)/(%s))", branchRegex, initialVerRegex) + + return regexp.MustCompile(regex) +} + +// Given a git reference in tagless mode (like "refs/heads/c9s", or "refs/heads/stream-httpd-2.4-rhel-9.1.0"), determine +// if we are ok with importing that reference. We are looking for the traditional pattern, like "c9s", and also the +// modular "stream---rhel- branch pattern as well +func TaglessRefOk(tag string, pd *data.ProcessData) bool { + // First case is very easy: if we are exactly "refs/heads/" , then this is def. a branch we should import + if tag == fmt.Sprintf("refs/heads/%s%d%s", pd.ImportBranchPrefix, pd.Version, pd.BranchSuffix) { + return true + } + + // Less easy: if a modular branch is present (starts w/ "stream-"), we need to check if it's part of our major version, and return true if it is + // (major version means we look for the text "rhel-X." in the branch name, like "rhel-9.1.0") + if strings.HasPrefix(tag, "refs/heads/stream-") && strings.Contains(tag, fmt.Sprintf("rhel-%d.", pd.Version)) { + return true + } + + return false +} diff --git a/vendor/go.temporal.io/sdk/interceptor/BUILD b/vendor/go.temporal.io/sdk/interceptor/BUILD new file mode 100644 index 00000000..e951d613 --- /dev/null +++ b/vendor/go.temporal.io/sdk/interceptor/BUILD @@ -0,0 +1,21 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "interceptor", + srcs = [ + "interceptor.go", + "tracing_interceptor.go", + ], + importmap = "go.resf.org/peridot/vendor/go.temporal.io/sdk/interceptor", + importpath = "go.temporal.io/sdk/interceptor", + visibility = ["//visibility:public"], + deps = [ + "//vendor/go.temporal.io/api/common/v1:common", + "//vendor/go.temporal.io/sdk/activity", + "//vendor/go.temporal.io/sdk/client", + "//vendor/go.temporal.io/sdk/converter", + "//vendor/go.temporal.io/sdk/internal", + "//vendor/go.temporal.io/sdk/log", + "//vendor/go.temporal.io/sdk/workflow", + ], +) diff --git a/vendor/go.temporal.io/sdk/interceptor/interceptor.go b/vendor/go.temporal.io/sdk/interceptor/interceptor.go new file mode 100644 index 00000000..008ba922 --- /dev/null +++ b/vendor/go.temporal.io/sdk/interceptor/interceptor.go @@ -0,0 +1,225 @@ +// The MIT License +// +// Copyright (c) 2021 Temporal Technologies Inc. All rights reserved. +// +// 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. + +// Package interceptor contains interceptors for client and worker calls. +package interceptor + +import ( + "context" + + commonpb "go.temporal.io/api/common/v1" + "go.temporal.io/sdk/internal" + "go.temporal.io/sdk/workflow" +) + +// Interceptor is a common interface for all interceptors. It combines +// ClientInterceptor and WorkerInterceptor. If an implementation of this +// interceptor is provided via client options, some client calls and all worker +// calls will be intercepted by it. If an implementation of this interceptor is +// provided via worker options, all worker calls will be intercepted by it. +// +// All implementations of this should embed InterceptorBase but are not required +// to. +type Interceptor = internal.Interceptor + +// InterceptorBase is a default implementation of Interceptor meant for +// embedding. It simply embeds ClientInterceptorBase and WorkerInterceptorBase. +type InterceptorBase = internal.InterceptorBase + +// WorkerInterceptor is an interface for all calls that can be intercepted +// during worker operation. This includes inbound (from server) and outbound +// (from SDK) workflow and activity calls. If an implementation of this is +// provided via client or worker options, all worker calls will be intercepted +// by it. +// +// All implementations must embed WorkerInterceptorBase to safely handle future +// changes. +type WorkerInterceptor = internal.WorkerInterceptor + +// WorkerInterceptorBase is a default implementation of WorkerInterceptor that +// simply instantiates ActivityInboundInterceptorBase or +// WorkflowInboundInterceptorBase when called to intercept activities or +// workflows respectively. +// +// This must be embedded into all WorkerInterceptor implementations to safely +// handle future changes. +type WorkerInterceptorBase = internal.WorkerInterceptorBase + +// ActivityInboundInterceptor is an interface for all activity calls originating +// from the server. Implementers wanting to intercept outbound (i.e. from SDK) +// activity calls, can change the outbound interceptor in Init before the next +// call in the chain. +// +// All implementations must embed ActivityInboundInterceptorBase to safely +// handle future changes. +type ActivityInboundInterceptor = internal.ActivityInboundInterceptor + +// ActivityInboundInterceptorBase is a default implementation of +// ActivityInboundInterceptor that forwards calls to the next inbound +// interceptor and uses an ActivityOutboundInterceptorBase on Init. +// +// This must be embedded into all ActivityInboundInterceptor implementations to +// safely handle future changes. +type ActivityInboundInterceptorBase = internal.ActivityInboundInterceptorBase + +// ExecuteActivityInput is input for ActivityInboundInterceptor.ExecuteActivity. +type ExecuteActivityInput = internal.ExecuteActivityInput + +// ActivityOutboundInterceptor is an interface for all activity calls +// originating from the SDK. +// +// All implementations must embed ActivityOutboundInterceptorBase to safely +// handle future changes. +type ActivityOutboundInterceptor = internal.ActivityOutboundInterceptor + +// ActivityOutboundInterceptorBase is a default implementation of +// ActivityOutboundInterceptor that forwards calls to the next outbound +// interceptor. +// +// This must be embedded into all ActivityOutboundInterceptor implementations to +// safely handle future changes. +type ActivityOutboundInterceptorBase = internal.ActivityOutboundInterceptorBase + +// WorkflowInboundInterceptor is an interface for all workflow calls originating +// from the server. Implementers wanting to intercept outbound (i.e. from SDK) +// workflow calls, can change the outbound interceptor in Init before the next +// call in the chain. +// +// All implementations must embed WorkflowInboundInterceptorBase to safely +// handle future changes. +type WorkflowInboundInterceptor = internal.WorkflowInboundInterceptor + +// WorkflowInboundInterceptorBase is a default implementation of +// WorkflowInboundInterceptor that forwards calls to the next inbound +// interceptor and uses an WorkflowOutboundInterceptorBase on Init. +// +// This must be embedded into all WorkflowInboundInterceptor implementations to +// safely handle future changes. +type WorkflowInboundInterceptorBase = internal.WorkflowInboundInterceptorBase + +// ExecuteWorkflowInput is input for WorkflowInboundInterceptor.ExecuteWorkflow. +type ExecuteWorkflowInput = internal.ExecuteWorkflowInput + +// HandleSignalInput is input for WorkflowInboundInterceptor.HandleSignal. +type HandleSignalInput = internal.HandleSignalInput + +// HandleQueryInput is input for WorkflowInboundInterceptor.HandleQuery. +type HandleQueryInput = internal.HandleQueryInput + +// WorkflowOutboundInterceptor is an interface for all workflow calls +// originating from the SDK. +// +// All implementations must embed WorkflowOutboundInterceptorBase to safely +// handle future changes. +type WorkflowOutboundInterceptor = internal.WorkflowOutboundInterceptor + +// WorkflowOutboundInterceptorBase is a default implementation of +// WorkflowOutboundInterceptor that forwards calls to the next outbound +// interceptor. +// +// This must be embedded into all WorkflowOutboundInterceptor implementations to +// safely handle future changes. +type WorkflowOutboundInterceptorBase = internal.WorkflowOutboundInterceptorBase + +// ClientInterceptor for providing a ClientOutboundInterceptor to intercept +// certain workflow-specific client calls from the SDK. If an implementation of +// this is provided via client or worker options, certain client calls will be +// intercepted by it. +// +// All implementations must embed ClientInterceptorBase to safely handle future +// changes. +type ClientInterceptor = internal.ClientInterceptor + +// ClientInterceptorBase is a default implementation of ClientInterceptor that +// simply instantiates ClientOutboundInterceptorBase when called to intercept +// the client. +// +// This must be embedded into all ClientInterceptor implementations to safely +// handle future changes. +type ClientInterceptorBase = internal.ClientInterceptorBase + +// ClientOutboundInterceptor is an interface for certain workflow-specific calls +// originating from the SDK. +// +// All implementations must embed ClientOutboundInterceptorBase to safely handle +// future changes. +type ClientOutboundInterceptor = internal.ClientOutboundInterceptor + +// ClientOutboundInterceptorBase is a default implementation of +// ClientOutboundInterceptor that forwards calls to the next outbound +// interceptor. +// +// This must be embedded into all ActivityInboundInterceptor implementations to +// safely handle future changes. +type ClientOutboundInterceptorBase = internal.ClientOutboundInterceptorBase + +// ClientExecuteWorkflowInput is input for +// ClientOutboundInterceptor.ExecuteWorkflow. +type ClientExecuteWorkflowInput = internal.ClientExecuteWorkflowInput + +// ClientSignalWorkflowInput is input for +// ClientOutboundInterceptor.SignalWorkflow. +type ClientSignalWorkflowInput = internal.ClientSignalWorkflowInput + +// ClientSignalWithStartWorkflowInput is input for +// ClientOutboundInterceptor.SignalWithStartWorkflow. +type ClientSignalWithStartWorkflowInput = internal.ClientSignalWithStartWorkflowInput + +// ClientCancelWorkflowInput is input for +// ClientOutboundInterceptor.CancelWorkflow. +type ClientCancelWorkflowInput = internal.ClientCancelWorkflowInput + +// ClientTerminateWorkflowInput is input for +// ClientOutboundInterceptor.TerminateWorkflow. +type ClientTerminateWorkflowInput = internal.ClientTerminateWorkflowInput + +// ClientQueryWorkflowInput is input for +// ClientOutboundInterceptor.QueryWorkflow. +type ClientQueryWorkflowInput = internal.ClientQueryWorkflowInput + +// ScheduleClientCreateInput is input for +// ScheduleClientInterceptor.CreateSchedule. +type ScheduleClientCreateInput = internal.ScheduleClientCreateInput + +// Header provides Temporal header information from the context for reading or +// writing during specific interceptor calls. +// +// This returns a non-nil map only for contexts inside +// ActivityInboundInterceptor.ExecuteActivity, +// ClientOutboundInterceptor.ExecuteWorkflow, and +// ClientOutboundInterceptor.SignalWithStartWorkflow. +func Header(ctx context.Context) map[string]*commonpb.Payload { + return internal.Header(ctx) +} + +// WorkflowHeader provides Temporal header information from the workflow context +// for reading or writing during specific interceptor calls. +// +// This returns a non-nil map only for contexts inside +// WorkflowInboundInterceptor.ExecuteWorkflow, +// WorkflowOutboundInterceptor.ExecuteActivity, +// WorkflowOutboundInterceptor.ExecuteLocalActivity, +// WorkflowOutboundInterceptor.ExecuteChildWorkflow, and +// WorkflowOutboundInterceptor.NewContinueAsNewError. +func WorkflowHeader(ctx workflow.Context) map[string]*commonpb.Payload { + return internal.WorkflowHeader(ctx) +} diff --git a/vendor/go.temporal.io/sdk/interceptor/tracing_interceptor.go b/vendor/go.temporal.io/sdk/interceptor/tracing_interceptor.go new file mode 100644 index 00000000..5eff9a5c --- /dev/null +++ b/vendor/go.temporal.io/sdk/interceptor/tracing_interceptor.go @@ -0,0 +1,759 @@ +// The MIT License +// +// Copyright (c) 2021 Temporal Technologies Inc. All rights reserved. +// +// 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. + +package interceptor + +import ( + "context" + "fmt" + "time" + + commonpb "go.temporal.io/api/common/v1" + + "go.temporal.io/sdk/activity" + "go.temporal.io/sdk/client" + "go.temporal.io/sdk/converter" + "go.temporal.io/sdk/log" + "go.temporal.io/sdk/workflow" +) + +const ( + workflowIDTagKey = "temporalWorkflowID" + runIDTagKey = "temporalRunID" + activityIDTagKey = "temporalActivityID" +) + +// Tracer is an interface for tracing implementations as used by +// NewTracingInterceptor. Most callers do not use this directly, but rather use +// the opentracing or opentelemetry packages. +// +// All implementations must embed BaseTracer to safely +// handle future changes. +type Tracer interface { + // Options returns the options for the tracer. This is only called once on + // initialization. + Options() TracerOptions + + // UnmarshalSpan unmarshals the given map into a span reference. + UnmarshalSpan(map[string]string) (TracerSpanRef, error) + + // MarshalSpan marshals the given span into a map. If the map is empty with no + // error, the span is simply not set. + MarshalSpan(TracerSpan) (map[string]string, error) + + // SpanFromContext returns the span from the general Go context or nil if not + // present. + SpanFromContext(context.Context) TracerSpan + + // ContextWithSpan creates a general Go context with the given span set. + ContextWithSpan(context.Context, TracerSpan) context.Context + + // StartSpan starts and returns a span with the given options. + StartSpan(*TracerStartSpanOptions) (TracerSpan, error) + + // GetLogger returns a log.Logger which may include additional fields in its + // output in order to support correlation of tracing and log data. + GetLogger(log.Logger, TracerSpanRef) log.Logger + + mustEmbedBaseTracer() +} + +// BaseTracer is a default implementation of Tracer meant for embedding. +type BaseTracer struct{} + +func (BaseTracer) GetLogger(logger log.Logger, ref TracerSpanRef) log.Logger { + return logger +} + +//lint:ignore U1000 Ignore unused method; it is only required to implement the Tracer interface but will never be called. +func (BaseTracer) mustEmbedBaseTracer() {} + +// TracerOptions are options returned from Tracer.Options. +type TracerOptions struct { + // SpanContextKey provides a key to put a span on a context unrelated to how a + // span might otherwise be put on a context by ContextWithSpan. This should + // never be nil. + // + // This is used internally to set the span on contexts not natively supported + // by tracing systems such as workflow.Context. + SpanContextKey interface{} + + // HeaderKey is the key name on the Temporal header to serialize the span to. + // This should never be empty. + HeaderKey string + + // DisableSignalTracing can be set to disable signal tracing. + DisableSignalTracing bool + + // DisableQueryTracing can be set to disable query tracing. + DisableQueryTracing bool +} + +// TracerStartSpanOptions are options for Tracer.StartSpan. +type TracerStartSpanOptions struct { + // Parent is the optional parent reference of the span. + Parent TracerSpanRef + // Operation is the general operation name without the specific name. + Operation string + + // Name is the specific activity, workflow, etc for the operation. + Name string + + // Time indicates the start time of the span. + // + // For RunWorkflow and RunActivity operation types, this will match workflow.Info.WorkflowStartTime and + // activity.Info.StartedTime respectively. All other operations use time.Now(). + Time time.Time + + // DependedOn is true if the parent depends on this span or false if it just + // is related to the parent. In OpenTracing terms, this is true for "ChildOf" + // reference types and false for "FollowsFrom" reference types. + DependedOn bool + + // Tags are a set of span tags. + Tags map[string]string + + // FromHeader is used internally, not by tracer implementations, to determine + // whether the parent span can be retrieved from the Temporal header. + FromHeader bool + + // ToHeader is used internally, not by tracer implementations, to determine + // whether the span should be placed on the Temporal header. + ToHeader bool + + // IdempotencyKey may optionally be used by tracing implementations to generate + // deterministic span IDs. + // + // This is useful in workflow contexts where spans may need to be "resumed" before + // ultimately being reported. Generating a deterministic span ID ensures that any + // child spans created before the parent span is resumed do not become orphaned. + // + // IdempotencyKey is not guaranteed to be set for all operations; Tracer + // implementations MUST therefore ignore zero values for this field. + // + // IdempotencyKey should be treated as opaque data by Tracer implementations. + // Do not attempt to parse it, as the format is subject to change. + IdempotencyKey string +} + +// TracerSpanRef represents a span reference such as a parent. +type TracerSpanRef interface{} + +// TracerSpan represents a span. +type TracerSpan interface { + TracerSpanRef + + // Finish is called when the span is complete. + Finish(*TracerFinishSpanOptions) +} + +// TracerFinishSpanOptions are options for TracerSpan.Finish. +type TracerFinishSpanOptions struct { + // Error is present if there was an error in the code traced by this specific + // span. + Error error +} + +type tracingInterceptor struct { + InterceptorBase + tracer Tracer + options TracerOptions +} + +// NewTracingInterceptor creates a new interceptor using the given tracer. Most +// callers do not use this directly, but rather use the opentracing or +// opentelemetry packages. This panics if options are not set as expected. +func NewTracingInterceptor(tracer Tracer) Interceptor { + options := tracer.Options() + if options.SpanContextKey == nil { + panic("missing span context key") + } else if options.HeaderKey == "" { + panic("missing header key") + } + return &tracingInterceptor{tracer: tracer, options: options} +} + +func (t *tracingInterceptor) InterceptClient(next ClientOutboundInterceptor) ClientOutboundInterceptor { + i := &tracingClientOutboundInterceptor{root: t} + i.Next = next + return i +} + +func (t *tracingInterceptor) InterceptActivity( + ctx context.Context, + next ActivityInboundInterceptor, +) ActivityInboundInterceptor { + i := &tracingActivityInboundInterceptor{root: t} + i.Next = next + return i +} + +func (t *tracingInterceptor) InterceptWorkflow( + ctx workflow.Context, + next WorkflowInboundInterceptor, +) WorkflowInboundInterceptor { + i := &tracingWorkflowInboundInterceptor{root: t, info: workflow.GetInfo(ctx)} + i.Next = next + return i +} + +type tracingClientOutboundInterceptor struct { + ClientOutboundInterceptorBase + root *tracingInterceptor +} + +func (t *tracingClientOutboundInterceptor) CreateSchedule(ctx context.Context, in *ScheduleClientCreateInput) (client.ScheduleHandle, error) { + // Start span and write to header + span, ctx, err := t.root.startSpanFromContext(ctx, &TracerStartSpanOptions{ + Operation: "CreateSchedule", + Name: in.Options.ID, + ToHeader: true, + Time: time.Now(), + }) + if err != nil { + return nil, err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + run, err := t.Next.CreateSchedule(ctx, in) + finishOpts.Error = err + return run, err +} + +func (t *tracingClientOutboundInterceptor) ExecuteWorkflow( + ctx context.Context, + in *ClientExecuteWorkflowInput, +) (client.WorkflowRun, error) { + // Start span and write to header + span, ctx, err := t.root.startSpanFromContext(ctx, &TracerStartSpanOptions{ + Operation: "StartWorkflow", + Name: in.WorkflowType, + Tags: map[string]string{workflowIDTagKey: in.Options.ID}, + ToHeader: true, + Time: time.Now(), + }) + if err != nil { + return nil, err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + run, err := t.Next.ExecuteWorkflow(ctx, in) + finishOpts.Error = err + return run, err +} + +func (t *tracingClientOutboundInterceptor) SignalWorkflow(ctx context.Context, in *ClientSignalWorkflowInput) error { + // Only add tracing if enabled + if t.root.options.DisableSignalTracing { + return t.Next.SignalWorkflow(ctx, in) + } + // Start span and write to header + span, ctx, err := t.root.startSpanFromContext(ctx, &TracerStartSpanOptions{ + Operation: "SignalWorkflow", + Name: in.SignalName, + Tags: map[string]string{workflowIDTagKey: in.WorkflowID}, + ToHeader: true, + Time: time.Now(), + }) + if err != nil { + return err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + err = t.Next.SignalWorkflow(ctx, in) + finishOpts.Error = err + return err +} + +func (t *tracingClientOutboundInterceptor) SignalWithStartWorkflow( + ctx context.Context, + in *ClientSignalWithStartWorkflowInput, +) (client.WorkflowRun, error) { + // Start span and write to header + span, ctx, err := t.root.startSpanFromContext(ctx, &TracerStartSpanOptions{ + Operation: "SignalWithStartWorkflow", + Name: in.WorkflowType, + Tags: map[string]string{workflowIDTagKey: in.Options.ID}, + ToHeader: true, + }) + if err != nil { + return nil, err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + run, err := t.Next.SignalWithStartWorkflow(ctx, in) + finishOpts.Error = err + return run, err +} + +func (t *tracingClientOutboundInterceptor) QueryWorkflow( + ctx context.Context, + in *ClientQueryWorkflowInput, +) (converter.EncodedValue, error) { + // Only add tracing if enabled + if t.root.options.DisableQueryTracing { + return t.Next.QueryWorkflow(ctx, in) + } + // Start span and write to header + span, ctx, err := t.root.startSpanFromContext(ctx, &TracerStartSpanOptions{ + Operation: "QueryWorkflow", + Name: in.QueryType, + Tags: map[string]string{workflowIDTagKey: in.WorkflowID}, + ToHeader: true, + Time: time.Now(), + }) + if err != nil { + return nil, err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + val, err := t.Next.QueryWorkflow(ctx, in) + finishOpts.Error = err + return val, err +} + +type tracingActivityOutboundInterceptor struct { + ActivityOutboundInterceptorBase + root *tracingInterceptor +} + +func (t *tracingActivityOutboundInterceptor) GetLogger(ctx context.Context) log.Logger { + if span := t.root.tracer.SpanFromContext(ctx); span != nil { + return t.root.tracer.GetLogger(t.Next.GetLogger(ctx), span) + } + return t.Next.GetLogger(ctx) +} + +type tracingActivityInboundInterceptor struct { + ActivityInboundInterceptorBase + root *tracingInterceptor +} + +func (t *tracingActivityInboundInterceptor) Init(outbound ActivityOutboundInterceptor) error { + i := &tracingActivityOutboundInterceptor{root: t.root} + i.Next = outbound + return t.Next.Init(i) +} + +func (t *tracingActivityInboundInterceptor) ExecuteActivity( + ctx context.Context, + in *ExecuteActivityInput, +) (interface{}, error) { + // Start span reading from header + info := activity.GetInfo(ctx) + span, ctx, err := t.root.startSpanFromContext(ctx, &TracerStartSpanOptions{ + Operation: "RunActivity", + Name: info.ActivityType.Name, + DependedOn: true, + Tags: map[string]string{ + workflowIDTagKey: info.WorkflowExecution.ID, + runIDTagKey: info.WorkflowExecution.RunID, + activityIDTagKey: info.ActivityID, + }, + FromHeader: true, + Time: info.StartedTime, + }) + if err != nil { + return nil, err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + ret, err := t.Next.ExecuteActivity(ctx, in) + finishOpts.Error = err + return ret, err +} + +type tracingWorkflowInboundInterceptor struct { + WorkflowInboundInterceptorBase + root *tracingInterceptor + spanCounter uint16 + info *workflow.Info +} + +// newIdempotencyKey returns a new idempotency key by incrementing the span counter and interpolating +// this new value into a string that includes the workflow namespace/id/run id and the interceptor type. +func (t *tracingWorkflowInboundInterceptor) newIdempotencyKey() string { + t.spanCounter++ + return fmt.Sprintf("WorkflowInboundInterceptor:%s:%s:%s:%d", + t.info.Namespace, + t.info.WorkflowExecution.ID, + t.info.WorkflowExecution.RunID, + t.spanCounter) +} + +func (t *tracingWorkflowInboundInterceptor) Init(outbound WorkflowOutboundInterceptor) error { + i := &tracingWorkflowOutboundInterceptor{root: t.root} + i.Next = outbound + return t.Next.Init(i) +} + +func (t *tracingWorkflowInboundInterceptor) ExecuteWorkflow( + ctx workflow.Context, + in *ExecuteWorkflowInput, +) (interface{}, error) { + // Start span reading from header + span, ctx, err := t.root.startSpanFromWorkflowContext(ctx, &TracerStartSpanOptions{ + Operation: "RunWorkflow", + Name: t.info.WorkflowType.Name, + Tags: map[string]string{ + workflowIDTagKey: t.info.WorkflowExecution.ID, + runIDTagKey: t.info.WorkflowExecution.RunID, + }, + FromHeader: true, + Time: t.info.WorkflowStartTime, + IdempotencyKey: t.newIdempotencyKey(), + }) + if err != nil { + return nil, err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + ret, err := t.Next.ExecuteWorkflow(ctx, in) + finishOpts.Error = err + return ret, err +} + +func (t *tracingWorkflowInboundInterceptor) HandleSignal(ctx workflow.Context, in *HandleSignalInput) error { + // Only add tracing if enabled and not replaying + if t.root.options.DisableSignalTracing || workflow.IsReplaying(ctx) { + return t.Next.HandleSignal(ctx, in) + } + // Start span reading from header + info := workflow.GetInfo(ctx) + span, ctx, err := t.root.startSpanFromWorkflowContext(ctx, &TracerStartSpanOptions{ + Operation: "HandleSignal", + Name: in.SignalName, + Tags: map[string]string{ + workflowIDTagKey: info.WorkflowExecution.ID, + runIDTagKey: info.WorkflowExecution.RunID, + }, + FromHeader: true, + Time: time.Now(), + IdempotencyKey: t.newIdempotencyKey(), + }) + if err != nil { + return err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + err = t.Next.HandleSignal(ctx, in) + finishOpts.Error = err + return err +} + +func (t *tracingWorkflowInboundInterceptor) HandleQuery( + ctx workflow.Context, + in *HandleQueryInput, +) (interface{}, error) { + // Only add tracing if enabled and not replaying + if t.root.options.DisableQueryTracing || workflow.IsReplaying(ctx) { + return t.Next.HandleQuery(ctx, in) + } + // Start span reading from header + info := workflow.GetInfo(ctx) + span, ctx, err := t.root.startSpanFromWorkflowContext(ctx, &TracerStartSpanOptions{ + Operation: "HandleQuery", + Name: in.QueryType, + Tags: map[string]string{ + workflowIDTagKey: info.WorkflowExecution.ID, + runIDTagKey: info.WorkflowExecution.RunID, + }, + FromHeader: true, + Time: time.Now(), + // We intentionally do not set IdempotencyKey here because queries are not recorded in + // workflow history. When the tracing interceptor's span counter is reset between workflow + // replays, old queries will not be processed which could result in idempotency key + // collisions with other queries or signals. + }) + if err != nil { + return nil, err + } + var finishOpts TracerFinishSpanOptions + defer span.Finish(&finishOpts) + + val, err := t.Next.HandleQuery(ctx, in) + finishOpts.Error = err + return val, err +} + +type tracingWorkflowOutboundInterceptor struct { + WorkflowOutboundInterceptorBase + root *tracingInterceptor +} + +func (t *tracingWorkflowOutboundInterceptor) ExecuteActivity( + ctx workflow.Context, + activityType string, + args ...interface{}, +) workflow.Future { + // Start span writing to header + span, ctx, err := t.startNonReplaySpan(ctx, "StartActivity", activityType, true) + if err != nil { + return err + } + defer span.Finish(&TracerFinishSpanOptions{}) + + return t.Next.ExecuteActivity(ctx, activityType, args...) +} + +func (t *tracingWorkflowOutboundInterceptor) ExecuteLocalActivity( + ctx workflow.Context, + activityType string, + args ...interface{}, +) workflow.Future { + // Start span writing to header + span, ctx, err := t.startNonReplaySpan(ctx, "StartActivity", activityType, true) + if err != nil { + return err + } + defer span.Finish(&TracerFinishSpanOptions{}) + + return t.Next.ExecuteLocalActivity(ctx, activityType, args...) +} + +func (t *tracingWorkflowOutboundInterceptor) GetLogger(ctx workflow.Context) log.Logger { + if span, _ := ctx.Value(t.root.options.SpanContextKey).(TracerSpan); span != nil { + return t.root.tracer.GetLogger(t.Next.GetLogger(ctx), span) + } + return t.Next.GetLogger(ctx) +} + +func (t *tracingWorkflowOutboundInterceptor) ExecuteChildWorkflow( + ctx workflow.Context, + childWorkflowType string, + args ...interface{}, +) workflow.ChildWorkflowFuture { + // Start span writing to header + span, ctx, err := t.startNonReplaySpan(ctx, "StartChildWorkflow", childWorkflowType, false) + if err != nil { + return err + } + defer span.Finish(&TracerFinishSpanOptions{}) + + return t.Next.ExecuteChildWorkflow(ctx, childWorkflowType, args...) +} + +func (t *tracingWorkflowOutboundInterceptor) SignalExternalWorkflow( + ctx workflow.Context, + workflowID string, + runID string, + signalName string, + arg interface{}, +) workflow.Future { + // Start span writing to header if enabled + if !t.root.options.DisableSignalTracing { + var span TracerSpan + var futErr workflow.ChildWorkflowFuture + span, ctx, futErr = t.startNonReplaySpan(ctx, "SignalExternalWorkflow", signalName, false) + if futErr != nil { + return futErr + } + defer span.Finish(&TracerFinishSpanOptions{}) + } + + return t.Next.SignalExternalWorkflow(ctx, workflowID, runID, signalName, arg) +} + +func (t *tracingWorkflowOutboundInterceptor) SignalChildWorkflow( + ctx workflow.Context, + workflowID string, + signalName string, + arg interface{}, +) workflow.Future { + // Start span writing to header if enabled + if !t.root.options.DisableSignalTracing { + var span TracerSpan + var futErr workflow.ChildWorkflowFuture + span, ctx, futErr = t.startNonReplaySpan(ctx, "SignalChildWorkflow", signalName, false) + if futErr != nil { + return futErr + } + defer span.Finish(&TracerFinishSpanOptions{}) + } + + return t.Next.SignalChildWorkflow(ctx, workflowID, signalName, arg) +} + +func (t *tracingWorkflowOutboundInterceptor) NewContinueAsNewError( + ctx workflow.Context, + wfn interface{}, + args ...interface{}, +) error { + err := t.Next.NewContinueAsNewError(ctx, wfn, args...) + if !workflow.IsReplaying(ctx) { + if contErr, _ := err.(*workflow.ContinueAsNewError); contErr != nil { + // Get the current span and write header + if span, _ := ctx.Value(t.root.options.SpanContextKey).(TracerSpan); span != nil { + if writeErr := t.root.writeSpanToHeader(span, WorkflowHeader(ctx)); writeErr != nil { + return fmt.Errorf("failed writing span when creating continue as new error: %w", writeErr) + } + } + } + } + return err +} + +type nopSpan struct{} + +func (nopSpan) Finish(*TracerFinishSpanOptions) {} + +// Span always returned, even in replay. futErr is non-nil on error. +func (t *tracingWorkflowOutboundInterceptor) startNonReplaySpan( + ctx workflow.Context, + operation string, + name string, + dependedOn bool, +) (span TracerSpan, newCtx workflow.Context, futErr workflow.ChildWorkflowFuture) { + // Noop span if replaying + if workflow.IsReplaying(ctx) { + return nopSpan{}, ctx, nil + } + info := workflow.GetInfo(ctx) + span, newCtx, err := t.root.startSpanFromWorkflowContext(ctx, &TracerStartSpanOptions{ + Operation: operation, + Name: name, + DependedOn: dependedOn, + Tags: map[string]string{ + workflowIDTagKey: info.WorkflowExecution.ID, + runIDTagKey: info.WorkflowExecution.RunID, + }, + ToHeader: true, + Time: time.Now(), + }) + if err != nil { + return nopSpan{}, ctx, newErrFut(ctx, err) + } + return span, newCtx, nil +} + +func (t *tracingInterceptor) startSpanFromContext( + ctx context.Context, + options *TracerStartSpanOptions, +) (TracerSpan, context.Context, error) { + // Try to get parent from context + options.Parent = t.tracer.SpanFromContext(ctx) + span, err := t.startSpan(ctx, Header(ctx), options) + if err != nil { + return nil, nil, err + } + return span, t.tracer.ContextWithSpan(context.WithValue(ctx, t.options.SpanContextKey, span), span), nil +} + +func (t *tracingInterceptor) startSpanFromWorkflowContext( + ctx workflow.Context, + options *TracerStartSpanOptions, +) (TracerSpan, workflow.Context, error) { + span, err := t.startSpan(ctx, WorkflowHeader(ctx), options) + if err != nil { + return nil, nil, err + } + return span, workflow.WithValue(ctx, t.options.SpanContextKey, span), nil +} + +// Note, this does not put the span on the context +func (t *tracingInterceptor) startSpan( + ctx interface{ Value(interface{}) interface{} }, + header map[string]*commonpb.Payload, + options *TracerStartSpanOptions, +) (TracerSpan, error) { + + // Get parent span from header if not already present and allowed + if options.Parent == nil && options.FromHeader { + if span, err := t.readSpanFromHeader(header); err != nil { + return nil, err + } else if span != nil { + options.Parent = span + } + } + + // If no parent span, try to get from context + if options.Parent == nil { + options.Parent, _ = ctx.Value(t.options.SpanContextKey).(TracerSpan) + } + + // Start the span + span, err := t.tracer.StartSpan(options) + if err != nil { + return nil, err + } + + // Put span in header if wanted + if options.ToHeader && header != nil { + if err := t.writeSpanToHeader(span, header); err != nil { + return nil, err + } + } + return span, nil +} + +func (t *tracingInterceptor) readSpanFromHeader(header map[string]*commonpb.Payload) (TracerSpanRef, error) { + // Get from map + payload := header[t.options.HeaderKey] + if payload == nil { + return nil, nil + } + // Convert from the payload + var data map[string]string + if err := converter.GetDefaultDataConverter().FromPayload(payload, &data); err != nil { + return nil, err + } + // Unmarshal + return t.tracer.UnmarshalSpan(data) +} + +func (t *tracingInterceptor) writeSpanToHeader(span TracerSpan, header map[string]*commonpb.Payload) error { + // Serialize span to map + data, err := t.tracer.MarshalSpan(span) + if err != nil || len(data) == 0 { + return err + } + // Convert to payload + payload, err := converter.GetDefaultDataConverter().ToPayload(data) + if err != nil { + return err + } + // Put on header + header[t.options.HeaderKey] = payload + return nil +} + +func newErrFut(ctx workflow.Context, err error) workflow.ChildWorkflowFuture { + fut, set := workflow.NewFuture(ctx) + set.SetError(err) + return errFut{fut} +} + +type errFut struct{ workflow.Future } + +func (e errFut) GetChildWorkflowExecution() workflow.Future { return e } + +func (e errFut) SignalChildWorkflow(ctx workflow.Context, signalName string, data interface{}) workflow.Future { + return e +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e9a630ee..c808b719 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -216,6 +216,9 @@ github.com/beorn7/perks/quantile # github.com/blang/semver/v4 v4.0.0 ## explicit; go 1.14 github.com/blang/semver/v4 +# github.com/bluekeyes/go-gitdiff v0.5.0 +## explicit; go 1.13 +github.com/bluekeyes/go-gitdiff/gitdiff # github.com/bmatcuk/doublestar/v4 v4.6.0 ## explicit; go 1.16 github.com/bmatcuk/doublestar/v4 @@ -932,6 +935,13 @@ github.com/robfig/cron # github.com/robfig/cron/v3 v3.0.1 ## explicit; go 1.12 github.com/robfig/cron/v3 +# github.com/rocky-linux/srpmproc v0.5.0 +## explicit; go 1.18 +github.com/rocky-linux/srpmproc/pb +github.com/rocky-linux/srpmproc/pkg/blob +github.com/rocky-linux/srpmproc/pkg/data +github.com/rocky-linux/srpmproc/pkg/directives +github.com/rocky-linux/srpmproc/pkg/misc # github.com/russellhaering/goxmldsig v1.4.0 ## explicit; go 1.15 github.com/russellhaering/goxmldsig @@ -1270,6 +1280,7 @@ go.temporal.io/api/workflowservicemock/v1 go.temporal.io/sdk/activity go.temporal.io/sdk/client go.temporal.io/sdk/converter +go.temporal.io/sdk/interceptor go.temporal.io/sdk/internal go.temporal.io/sdk/internal/common go.temporal.io/sdk/internal/common/backoff @@ -1918,3 +1929,4 @@ sigs.k8s.io/yaml # go.resf.org/peridot/tools/mothership/pb => ./bazel-bin/tools/mothership/proto/v1/mothershippb_go_proto_/go.resf.org/peridot/tools/mothership/pb # 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 # 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 +# google.golang.org/genproto/googleapis/longrunning => ./bazel-bin/third_party/googleapis/google/longrunning/longrunning_go_proto_/google.golang.org/genproto/googleapis/longrunning