44 "errors"
55 "fmt"
66 "io"
7+ "sort"
78)
89
910// Conflict indicates an apply failed due to a conflict between the patch and
@@ -68,7 +69,10 @@ func applyError(err error, args ...interface{}) error {
6869
6970 e , ok := err .(* ApplyError )
7071 if ! ok {
71- e = & ApplyError {err : wrapEOF (err )}
72+ if err == io .EOF {
73+ err = io .ErrUnexpectedEOF
74+ }
75+ e = & ApplyError {err : err }
7276 }
7377 for _ , arg := range args {
7478 switch v := arg .(type ) {
@@ -91,6 +95,7 @@ const (
9195 applyInitial = iota
9296 applyText
9397 applyBinary
98+ applyFile
9499)
95100
96101// Applier applies changes described in fragments to source data. If changes
@@ -145,17 +150,35 @@ func (a *Applier) ApplyFile(dst io.Writer, f *File) error {
145150 if a .applyType != applyInitial {
146151 return applyError (errApplyInProgress )
147152 }
153+ defer func () { a .applyType = applyFile }()
148154
149- if f .IsBinary && f . BinaryFragment != nil {
150- return a . ApplyBinaryFragment ( dst , f . BinaryFragment )
155+ if f .IsBinary && len ( f . TextFragments ) > 0 {
156+ return applyError ( errors . New ( "binary file contains text fragments" ) )
151157 }
158+ if ! f .IsBinary && f .BinaryFragment != nil {
159+ return applyError (errors .New ("text file contains binary fragment" ))
160+ }
161+
162+ switch {
163+ case f .BinaryFragment != nil :
164+ return a .ApplyBinaryFragment (dst , f .BinaryFragment )
165+
166+ case len (f .TextFragments ) > 0 :
167+ frags := make ([]* TextFragment , len (f .TextFragments ))
168+ copy (frags , f .TextFragments )
169+
170+ sort .Slice (frags , func (i , j int ) bool {
171+ return frags [i ].OldPosition < frags [j ].OldPosition
172+ })
152173
153- // TODO(bkeyes): sort fragments by start position
154- // TODO(bkeyes): merge overlapping fragments
174+ // TODO(bkeyes): consider merging overlapping fragments
175+ // right now, the application fails if fragments overlap, but it should be
176+ // possible to precompute the result of applying them in order
155177
156- for i , frag := range f .TextFragments {
157- if err := a .ApplyTextFragment (dst , frag ); err != nil {
158- return applyError (err , fragNum (i ))
178+ for i , frag := range frags {
179+ if err := a .ApplyTextFragment (dst , frag ); err != nil {
180+ return applyError (err , fragNum (i ))
181+ }
159182 }
160183 }
161184
@@ -168,12 +191,10 @@ func (a *Applier) ApplyFile(dst io.Writer, f *File) error {
168191// order of increasing start position. As a result, each fragment can be
169192// applied at most once before a call to Reset.
170193func (a * Applier ) ApplyTextFragment (dst io.Writer , f * TextFragment ) error {
171- switch a .applyType {
172- case applyInitial , applyText :
173- default :
194+ if a .applyType != applyInitial && a .applyType != applyText {
174195 return applyError (errApplyInProgress )
175196 }
176- a .applyType = applyText
197+ defer func () { a .applyType = applyText }()
177198
178199 // application code assumes fragment fields are consistent
179200 if err := f .Validate (); err != nil {
@@ -265,7 +286,7 @@ func (a *Applier) ApplyBinaryFragment(dst io.Writer, f *BinaryFragment) error {
265286 if a .applyType != applyInitial {
266287 return applyError (errApplyInProgress )
267288 }
268- a .applyType = applyText
289+ defer func () { a .applyType = applyBinary }()
269290
270291 if f == nil {
271292 return applyError (errors .New ("nil fragment" ))
@@ -395,7 +416,7 @@ func applyBinaryDeltaCopy(w io.Writer, op byte, delta []byte, src io.ReaderAt) (
395416 // TODO(bkeyes): consider pooling these buffers
396417 b := make ([]byte , size )
397418 if _ , err := src .ReadAt (b , offset ); err != nil {
398- return 0 , delta , wrapEOF ( err )
419+ return 0 , delta , err
399420 }
400421
401422 _ , err = w .Write (b )
@@ -412,10 +433,3 @@ func checkBinarySrcSize(r io.ReaderAt, size int64) error {
412433 }
413434 return nil
414435}
415-
416- func wrapEOF (err error ) error {
417- if err == io .EOF {
418- err = io .ErrUnexpectedEOF
419- }
420- return err
421- }
0 commit comments