From 73fa9ef25a8af9c8337a4cf34a67cfe208f1a7c5 Mon Sep 17 00:00:00 2001 From: Alberto Cortés Date: Wed, 26 Oct 2016 17:56:26 +0200 Subject: Use advrefs in gituploadpackinfo (#92) * add advrefs encoder and parser * modify advrefs encoder to resemble json encoder * turn advrefs parser into a decoder * clean code * improve documentation * improve documentation * clean code * upgrade to new pktline.Add and add Flush const to easy integration * gometalinter * Use packp/advrefs for GitUploadPackInfo parsing - GitUploadPackInfo now uses packp/advrefs instead of parsing the message by itself. - Capabilities has been moved from clients/common to packp to avoid a circular import. - Cleaning of advrefs_test code. - Add support for prefix encoding and decoding in advrefs. * clean advrefs test code * clean advrefs test code * clean advrefs test code * gometalinter * add pktline encoder * change pktline.EncodeFlush to pktline.Flush * make scanner tests use the encoder instead of Pktlines * check errors on flush and clean constants * ubstitute the PktLines type with a pktline.Encoder * use pktline.Encoder in all go-git * add example of pktline.Encodef() * add package overview * documentation * support symbolic links other than HEAD * simplify decoding of shallows * packp: fix mcuadros comments - all abbreviates removed (by visual inspection, some may remain) - all empty maps are initialized using make - simplify readRef with a switch - make decodeShallow malformed error more verbose - add pktline.Encoder.encodeLine - remove infamous panic in checkPayloadLength by refactoring out the whole function --- formats/packp/advrefs/encoder.go | 155 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 formats/packp/advrefs/encoder.go (limited to 'formats/packp/advrefs/encoder.go') diff --git a/formats/packp/advrefs/encoder.go b/formats/packp/advrefs/encoder.go new file mode 100644 index 0000000..9874884 --- /dev/null +++ b/formats/packp/advrefs/encoder.go @@ -0,0 +1,155 @@ +package advrefs + +import ( + "bytes" + "io" + "sort" + + "gopkg.in/src-d/go-git.v4/core" + "gopkg.in/src-d/go-git.v4/formats/packp" + "gopkg.in/src-d/go-git.v4/formats/packp/pktline" +) + +// An Encoder writes AdvRefs values to an output stream. +type Encoder struct { + data *AdvRefs // data to encode + pe *pktline.Encoder // where to write the encoded data + err error // sticky error +} + +// NewEncoder returns a new encoder that writes to w. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{ + pe: pktline.NewEncoder(w), + } +} + +// Encode writes the AdvRefs encoding of v to the stream. +// +// All the payloads will end with a newline character. Capabilities, +// references and shallows are writen in alphabetical order, except for +// peeled references that always follow their corresponding references. +func (e *Encoder) Encode(v *AdvRefs) error { + e.data = v + + for state := encodePrefix; state != nil; { + state = state(e) + } + + return e.err +} + +type encoderStateFn func(*Encoder) encoderStateFn + +func encodePrefix(e *Encoder) encoderStateFn { + for _, p := range e.data.Prefix { + if bytes.Equal(p, pktline.Flush) { + if e.err = e.pe.Flush(); e.err != nil { + return nil + } + continue + } + if e.err = e.pe.Encodef("%s\n", string(p)); e.err != nil { + return nil + } + } + + return encodeFirstLine +} + +// Adds the first pkt-line payload: head hash, head ref and capabilities. +// Also handle the special case when no HEAD ref is found. +func encodeFirstLine(e *Encoder) encoderStateFn { + head := formatHead(e.data.Head) + separator := formatSeparator(e.data.Head) + capabilities := formatCaps(e.data.Capabilities) + + if e.err = e.pe.Encodef("%s %s\x00%s\n", head, separator, capabilities); e.err != nil { + return nil + } + + return encodeRefs +} + +func formatHead(h *core.Hash) string { + if h == nil { + return core.ZeroHash.String() + } + + return h.String() +} + +func formatSeparator(h *core.Hash) string { + if h == nil { + return noHead + } + + return head +} + +func formatCaps(c *packp.Capabilities) string { + if c == nil { + return "" + } + + c.Sort() + + return c.String() +} + +// Adds the (sorted) refs: hash SP refname EOL +// and their peeled refs if any. +func encodeRefs(e *Encoder) encoderStateFn { + refs := sortRefs(e.data.References) + for _, r := range refs { + hash, _ := e.data.References[r] + if e.err = e.pe.Encodef("%s %s\n", hash.String(), r); e.err != nil { + return nil + } + + if hash, ok := e.data.Peeled[r]; ok { + if e.err = e.pe.Encodef("%s %s^{}\n", hash.String(), r); e.err != nil { + return nil + } + } + } + + return encodeShallow +} + +func sortRefs(m map[string]core.Hash) []string { + ret := make([]string, 0, len(m)) + for k := range m { + ret = append(ret, k) + } + sort.Strings(ret) + + return ret +} + +// Adds the (sorted) shallows: "shallow" SP hash EOL +func encodeShallow(e *Encoder) encoderStateFn { + sorted := sortShallows(e.data.Shallows) + for _, hash := range sorted { + if e.err = e.pe.Encodef("shallow %s\n", hash); e.err != nil { + return nil + } + } + + return encodeFlush +} + +func sortShallows(c []core.Hash) []string { + ret := []string{} + for _, h := range c { + ret = append(ret, h.String()) + } + sort.Strings(ret) + + return ret +} + +func encodeFlush(e *Encoder) encoderStateFn { + e.err = e.pe.Flush() + return nil +} -- cgit