aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/format/packp/ulreq/encoder.go
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2016-11-08 23:46:38 +0100
committerGitHub <noreply@github.com>2016-11-08 23:46:38 +0100
commitac095bb12c4d29722b60ba9f20590fa7cfa6bc7d (patch)
tree223f36f336ba3414b1e45cac8af6c4744a5d7ef6 /plumbing/format/packp/ulreq/encoder.go
parente523701393598f4fa241dd407af9ff8925507a1a (diff)
downloadgo-git-ac095bb12c4d29722b60ba9f20590fa7cfa6bc7d.tar.gz
new plumbing package (#118)
* plumbing: now core was renamed to core, and formats and clients moved inside
Diffstat (limited to 'plumbing/format/packp/ulreq/encoder.go')
-rw-r--r--plumbing/format/packp/ulreq/encoder.go140
1 files changed, 140 insertions, 0 deletions
diff --git a/plumbing/format/packp/ulreq/encoder.go b/plumbing/format/packp/ulreq/encoder.go
new file mode 100644
index 0000000..1264e0e
--- /dev/null
+++ b/plumbing/format/packp/ulreq/encoder.go
@@ -0,0 +1,140 @@
+package ulreq
+
+import (
+ "fmt"
+ "io"
+ "sort"
+ "time"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/format/packp/pktline"
+)
+
+// An Encoder writes UlReq values to an output stream.
+type Encoder struct {
+ pe *pktline.Encoder // where to write the encoded data
+ data *UlReq // the data to encode
+ sortedWants []string
+ 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 UlReq encoding of v to the stream.
+//
+// All the payloads will end with a newline character. Wants and
+// shallows are sorted alphabetically. A depth of 0 means no depth
+// request is sent.
+func (e *Encoder) Encode(v *UlReq) error {
+ if len(v.Wants) == 0 {
+ return fmt.Errorf("empty wants provided")
+ }
+
+ e.data = v
+ e.sortedWants = sortHashes(v.Wants)
+
+ for state := encodeFirstWant; state != nil; {
+ state = state(e)
+ }
+
+ return e.err
+}
+
+type encoderStateFn func(*Encoder) encoderStateFn
+
+func sortHashes(list []plumbing.Hash) []string {
+ sorted := make([]string, len(list))
+ for i, hash := range list {
+ sorted[i] = hash.String()
+ }
+ sort.Strings(sorted)
+
+ return sorted
+}
+
+func encodeFirstWant(e *Encoder) encoderStateFn {
+ var err error
+ if e.data.Capabilities.IsEmpty() {
+ err = e.pe.Encodef("want %s\n", e.sortedWants[0])
+ } else {
+ e.data.Capabilities.Sort()
+ err = e.pe.Encodef(
+ "want %s %s\n",
+ e.sortedWants[0],
+ e.data.Capabilities.String(),
+ )
+ }
+ if err != nil {
+ e.err = fmt.Errorf("encoding first want line: %s", err)
+ return nil
+ }
+
+ return encodeAditionalWants
+}
+
+func encodeAditionalWants(e *Encoder) encoderStateFn {
+ for _, w := range e.sortedWants[1:] {
+ if err := e.pe.Encodef("want %s\n", w); err != nil {
+ e.err = fmt.Errorf("encoding want %q: %s", w, err)
+ return nil
+ }
+ }
+
+ return encodeShallows
+}
+
+func encodeShallows(e *Encoder) encoderStateFn {
+ sorted := sortHashes(e.data.Shallows)
+ for _, s := range sorted {
+ if err := e.pe.Encodef("shallow %s\n", s); err != nil {
+ e.err = fmt.Errorf("encoding shallow %q: %s", s, err)
+ return nil
+ }
+ }
+
+ return encodeDepth
+}
+
+func encodeDepth(e *Encoder) encoderStateFn {
+ switch depth := e.data.Depth.(type) {
+ case DepthCommits:
+ if depth != 0 {
+ commits := int(depth)
+ if err := e.pe.Encodef("deepen %d\n", commits); err != nil {
+ e.err = fmt.Errorf("encoding depth %d: %s", depth, err)
+ return nil
+ }
+ }
+ case DepthSince:
+ when := time.Time(depth).UTC()
+ if err := e.pe.Encodef("deepen-since %d\n", when.Unix()); err != nil {
+ e.err = fmt.Errorf("encoding depth %s: %s", when, err)
+ return nil
+ }
+ case DepthReference:
+ reference := string(depth)
+ if err := e.pe.Encodef("deepen-not %s\n", reference); err != nil {
+ e.err = fmt.Errorf("encoding depth %s: %s", reference, err)
+ return nil
+ }
+ default:
+ e.err = fmt.Errorf("unsupported depth type")
+ return nil
+ }
+
+ return encodeFlush
+}
+
+func encodeFlush(e *Encoder) encoderStateFn {
+ if err := e.pe.Flush(); err != nil {
+ e.err = fmt.Errorf("encoding flush-pkt: %s", err)
+ return nil
+ }
+
+ return nil
+}