aboutsummaryrefslogtreecommitdiffstats
path: root/formats/packp/advrefs/encoder.go
diff options
context:
space:
mode:
authorAlberto Cortés <alcortesm@gmail.com>2016-10-26 17:56:26 +0200
committerMáximo Cuadros <mcuadros@gmail.com>2016-10-26 15:56:26 +0000
commit73fa9ef25a8af9c8337a4cf34a67cfe208f1a7c5 (patch)
tree66886d9b47e373b748c1bceafe1885e6f47868dd /formats/packp/advrefs/encoder.go
parentf3ab3a6c73015b5ae9b2a4756dc646e1211cedb9 (diff)
downloadgo-git-73fa9ef25a8af9c8337a4cf34a67cfe208f1a7c5.tar.gz
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
Diffstat (limited to 'formats/packp/advrefs/encoder.go')
-rw-r--r--formats/packp/advrefs/encoder.go155
1 files changed, 155 insertions, 0 deletions
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
+}