github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/gitconn.go (about) 1 package git 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 ) 8 9 // gitConn represents a remote which uses the git protocol 10 // for transport (ie. a remote that starts with git://) 11 type gitConn struct { 12 *sharedRemoteConn 13 conn io.ReadWriteCloser 14 } 15 16 var _ RemoteConn = &gitConn{} 17 18 func (g *gitConn) OpenConn(srv GitService) error { 19 host := g.uri.Hostname() 20 port := g.uri.Port() 21 if port == "" { 22 port = "9418" 23 } 24 25 conn, err := net.Dial("tcp", host+":"+port) 26 if err != nil { 27 return err 28 } 29 g.conn = conn 30 g.packProtocolReader = &packProtocolReader{g.conn, PktLineMode, nil, nil} 31 32 // Advertise the connection and try to negotiate protocol version 2 33 fmt.Fprintf( 34 g, 35 g.service+" %s\x00host=%s\x00\x00version=2\x00", 36 g.uri.Path, 37 host, 38 ) 39 40 v, cap, refs, err := parseRemoteInitialConnection(conn, false) 41 if err != nil { 42 conn.Close() 43 return err 44 } 45 g.protocolversion = v 46 g.capabilities = cap 47 g.refs = refs 48 return nil 49 } 50 51 func (g *gitConn) Close() error { 52 g.Flush() 53 return g.conn.Close() 54 } 55 56 func (g *gitConn) GetRefs(opts LsRemoteOptions, patterns []string) ([]Ref, error) { 57 switch g.protocolversion { 58 case 1: 59 return getRefsV1(g.refs, opts, patterns) 60 case 2: 61 g.SetWriteMode(PktLineMode) 62 cmd, err := buildLsRefsCmdV2(opts, patterns) 63 if err != nil { 64 return nil, err 65 } 66 fmt.Fprintf(g.conn, cmd) 67 line := make([]byte, 65536) 68 var vals []Ref 69 for { 70 n, err := g.Read(line) 71 switch err { 72 case flushPkt: 73 return vals, nil 74 case nil: // Nothing 75 default: 76 return nil, err 77 } 78 refstr := string(line[0:n]) 79 ref, err := parseLsRef(refstr) 80 if err != nil { 81 return nil, err 82 } 83 vals = append(vals, ref) 84 } 85 default: 86 return nil, fmt.Errorf("Protocol version not supported") 87 } 88 } 89 90 func (g *gitConn) Write(data []byte) (int, error) { 91 switch g.writemode { 92 case PktLineMode: 93 l, err := PktLineEncodeNoNl(data) 94 if err != nil { 95 return 0, err 96 } 97 fmt.Fprintf(g.conn, "%s", l) 98 // We lie about how much data was written since 99 // we wrote more than asked. 100 return len(data), nil 101 case DirectMode: 102 return g.conn.Write(data) 103 default: 104 return 0, fmt.Errorf("Invalid write mode") 105 } 106 } 107 108 func (g *gitConn) Flush() error { 109 fmt.Fprintf(g.conn, "0000") 110 return nil 111 } 112 113 func (g *gitConn) Delim() error { 114 fmt.Fprintf(g.conn, "0001") 115 return nil 116 }