This enables clients to move back and forth between parsed objects and
text patches. The generated patches are semantically equal to the parsed
object and should re-parse to the same object, but may not be
byte-for-byte identical to the original input.
In my testing, formatted text patches are usually identical to the
input, but there may be cases where this is not true. Binary patches
always differ. This is because Go's 'compress/flate' package ends
streams with an empty block instead of adding the end-of-stream flag to
the last non-empty block, like Git's C implementation. Since the streams
will always be different for this reason, I chose to also enable default
compression (the test patches I generated with Git used no compression.)
The main tests for this feature involve parsing, formatting, and then
re-parsing a patch to make sure we get equal objects.
Formatting is handled by a new internal formatter type, which allows
writing all data to the same stream. This isn't exposed publicly right
now, but will be useful if there's a need for more flexible formatting
functions in the future, like formatting to a user-provided io.Writer.
This removes the distinction between "strict" and "fuzzy" application
by allowing future methods on Applier that control settings. It also
avoids state tracking in the text fragment apply signature by moving it
into the Applier type.
While in practice, an Applier will be used once and discarded, the
capability is provided to reset it for multiple uses.
This is functionally equivalent to the previous version (except for one
error case), but uses the new interface. I think the code is simpler
overall because it removes the line tracking.
Applying a fragment requires the content to match the stored counts, so
there must be a way to check this. Parsed fragments should always be
valid, but manually created or modified fragments may be invalid.
The binary marker is the text that appears where a text fragment
normally would and indicates that the file is binary. It's not quite a
header, because content is optional in a binary patch. If the patch does
include binary fragments, they have their own format, with a header.
Fragment is now TextFragment to distinguish from a future
BinaryFragment. Also rename FragmentLine to Line, since the
text-orientation is implied by the name.
To make output better, also add some (temporary?) String() functions and
fix an assumption about the smallest fragment header I discovered was
wrong while looking at sample patches.
Track leading and trailing context lines because it's easy and Git
includes this information in the fragment type. Add validation for when
the fragment does not agree with the header or with the new/deleted
state of the file.
After considering fragment parsing, it made sense to change the
invariant estabilished in the previous commit. Specifically, parser
functions now assume they are call on the first line of their object and
return with the parser on the first line after their object. This means
code can call parse function immediately after each other without
advancing the parser in between.
It's possible this will change back later on... there seem to be
annoying edge cases with either choice, but I think making the functions
consistent is important.
The parsed OIDs are usually prefixes, not full hashes, so rename the
fields appropriately. Also note that values that are too long to be
valid OIDs are still accepted by the library.
I believe the structure is correct, but there are a lot of details to
fill in - translating the C string parsing logic into Go is not always
straightforward.