Skip to content

Commit 5b35c41

Browse files
authored
Merge pull request #9 from weafscast/cherrypicks
2 parents 75279d8 + 830e987 commit 5b35c41

File tree

17 files changed

+174
-33
lines changed

17 files changed

+174
-33
lines changed

_examples/azure_devops/main.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
git "github.com/go-git/go-git/v5"
8+
. "github.com/go-git/go-git/v5/_examples"
9+
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
10+
"github.com/go-git/go-git/v5/plumbing/transport"
11+
"github.com/go-git/go-git/v5/plumbing/transport/http"
12+
)
13+
14+
func main() {
15+
CheckArgs("<url>", "<directory>", "<azuredevops_username>", "<azuredevops_password>")
16+
url, directory, username, password := os.Args[1], os.Args[2], os.Args[3], os.Args[4]
17+
18+
// Clone the given repository to the given directory
19+
Info("git clone %s %s", url, directory)
20+
21+
// Azure DevOps requires capabilities multi_ack / multi_ack_detailed,
22+
// which are not fully implemented and by default are included in
23+
// transport.UnsupportedCapabilities.
24+
//
25+
// The initial clone operations require a full download of the repository,
26+
// and therefore those unsupported capabilities are not as crucial, so
27+
// by removing them from that list allows for the first clone to work
28+
// successfully.
29+
//
30+
// Additional fetches will yield issues, therefore work always from a clean
31+
// clone until those capabilities are fully supported.
32+
//
33+
// New commits and pushes against a remote worked without any issues.
34+
transport.UnsupportedCapabilities = []capability.Capability{
35+
capability.ThinPack,
36+
}
37+
38+
r, err := git.PlainClone(directory, false, &git.CloneOptions{
39+
Auth: &http.BasicAuth{
40+
Username: username,
41+
Password: password,
42+
},
43+
URL: url,
44+
Progress: os.Stdout,
45+
})
46+
CheckIfError(err)
47+
48+
// ... retrieving the branch being pointed by HEAD
49+
ref, err := r.Head()
50+
CheckIfError(err)
51+
// ... retrieving the commit object
52+
commit, err := r.CommitObject(ref.Hash())
53+
CheckIfError(err)
54+
55+
fmt.Println(commit)
56+
}

config/config.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"github.com/go-git/go-billy/v5/osfs"
1616
"github.com/go-git/go-git/v5/internal/url"
1717
format "github.com/go-git/go-git/v5/plumbing/format/config"
18-
"github.com/mitchellh/go-homedir"
1918
)
2019

2120
const (
@@ -185,7 +184,7 @@ func Paths(scope Scope) ([]string, error) {
185184
files = append(files, filepath.Join(xdg, "git/config"))
186185
}
187186

188-
home, err := homedir.Dir()
187+
home, err := os.UserHomeDir()
189188
if err != nil {
190189
return nil, err
191190
}

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ require (
1616
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
1717
github.com/jessevdk/go-flags v1.5.0
1818
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351
19-
github.com/mitchellh/go-homedir v1.1.0
2019
github.com/sergi/go-diff v1.1.0
2120
github.com/whilp/git-urls v1.0.0
2221
github.com/xanzy/ssh-agent v0.3.1

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
4343
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
4444
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
4545
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
46-
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
47-
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
4846
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
4947
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
5048
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

plumbing/format/config/encoder.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ type Encoder struct {
1111
w io.Writer
1212
}
1313

14+
var (
15+
subsectionReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`)
16+
valueReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`, "\n", `\n`, "\t", `\t`, "\b", `\b`)
17+
)
1418
// NewEncoder returns a new encoder that writes to w.
1519
func NewEncoder(w io.Writer) *Encoder {
1620
return &Encoder{w}
@@ -48,8 +52,7 @@ func (e *Encoder) encodeSection(s *Section) error {
4852
}
4953

5054
func (e *Encoder) encodeSubsection(sectionName string, s *Subsection) error {
51-
//TODO: escape
52-
if err := e.printf("[%s \"%s\"]\n", sectionName, s.Name); err != nil {
55+
if err := e.printf("[%s \"%s\"]\n", sectionName, subsectionReplacer.Replace(s.Name)); err != nil {
5356
return err
5457
}
5558

@@ -58,12 +61,14 @@ func (e *Encoder) encodeSubsection(sectionName string, s *Subsection) error {
5861

5962
func (e *Encoder) encodeOptions(opts Options) error {
6063
for _, o := range opts {
61-
pattern := "\t%s = %s\n"
62-
if strings.Contains(o.Value, "\\") {
63-
pattern = "\t%s = %q\n"
64+
var value string
65+
if strings.ContainsAny(o.Value, "#;\"\t\n\\") || strings.HasPrefix(o.Value, " ") || strings.HasSuffix(o.Value, " ") {
66+
value = `"`+valueReplacer.Replace(o.Value)+`"`
67+
} else {
68+
value = o.Value
6469
}
6570

66-
if err := e.printf(pattern, o.Key, o.Value); err != nil {
71+
if err := e.printf("\t%s = %s\n", o.Key, value); err != nil {
6772
return err
6873
}
6974
}

plumbing/format/config/fixtures_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,41 @@ var fixtures = []*Fixture{
4242
Text: "[core]\n\trepositoryformatversion = 0\n",
4343
Config: New().AddOption("core", "", "repositoryformatversion", "0"),
4444
},
45+
{
46+
Raw: `[section]
47+
option1 = "has # hash"
48+
option2 = "has \" quote"
49+
option3 = "has \\ backslash"
50+
option4 = "has ; semicolon"
51+
option5 = "has \n line-feed"
52+
option6 = "has \t tab"
53+
option7 = " has leading spaces"
54+
option8 = "has trailing spaces "
55+
option9 = has no special characters
56+
option10 = has unusual ` + "\x01\x7f\xc8\x80 characters\n",
57+
Text: `[section]
58+
option1 = "has # hash"
59+
option2 = "has \" quote"
60+
option3 = "has \\ backslash"
61+
option4 = "has ; semicolon"
62+
option5 = "has \n line-feed"
63+
option6 = "has \t tab"
64+
option7 = " has leading spaces"
65+
option8 = "has trailing spaces "
66+
option9 = has no special characters
67+
option10 = has unusual ` + "\x01\x7f\xc8\x80 characters\n",
68+
Config: New().
69+
AddOption("section", "", "option1", `has # hash`).
70+
AddOption("section", "", "option2", `has " quote`).
71+
AddOption("section", "", "option3", `has \ backslash`).
72+
AddOption("section", "", "option4", `has ; semicolon`).
73+
AddOption("section", "", "option5", "has \n line-feed").
74+
AddOption("section", "", "option6", "has \t tab").
75+
AddOption("section", "", "option7", ` has leading spaces`).
76+
AddOption("section", "", "option8", `has trailing spaces `).
77+
AddOption("section", "", "option9", `has no special characters`).
78+
AddOption("section", "", "option10", "has unusual \x01\x7f\u0200 characters"),
79+
},
4580
{
4681
Raw: `
4782
[sect1]

plumbing/object/rename.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,16 @@ func min(a, b int) int {
403403
return b
404404
}
405405

406+
const maxMatrixSize = 10000
407+
406408
func buildSimilarityMatrix(srcs, dsts []*Change, renameScore int) (similarityMatrix, error) {
407409
// Allocate for the worst-case scenario where every pair has a score
408410
// that we need to consider. We might not need that many.
409-
matrix := make(similarityMatrix, 0, len(srcs)*len(dsts))
411+
matrixSize := len(srcs) * len(dsts)
412+
if matrixSize > maxMatrixSize {
413+
matrixSize = maxMatrixSize
414+
}
415+
matrix := make(similarityMatrix, 0, matrixSize)
410416
srcSizes := make([]int64, len(srcs))
411417
dstSizes := make([]int64, len(dsts))
412418
dstTooLarge := make(map[int]bool)

plumbing/protocol/packp/capability/list.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ func (l *List) Get(capability Capability) []string {
8686

8787
// Set sets a capability removing the previous values
8888
func (l *List) Set(capability Capability, values ...string) error {
89-
delete(l.m, capability)
89+
if _, ok := l.m[capability]; ok {
90+
l.m[capability].Values = l.m[capability].Values[:0]
91+
}
9092
return l.Add(capability, values...)
9193
}
9294

plumbing/protocol/packp/capability/list_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@ func (s *SuiteCapabilities) TestSetEmpty(c *check.C) {
122122
c.Assert(cap.Get(Agent), check.HasLen, 1)
123123
}
124124

125+
func (s *SuiteCapabilities) TestSetDuplicate(c *check.C) {
126+
cap := NewList()
127+
err := cap.Set(Agent, "baz")
128+
c.Assert(err, check.IsNil)
129+
130+
err = cap.Set(Agent, "bar")
131+
c.Assert(err, check.IsNil)
132+
133+
c.Assert(cap.String(), check.Equals, "agent=bar")
134+
}
135+
125136
func (s *SuiteCapabilities) TestGetEmpty(c *check.C) {
126137
cap := NewList()
127138
c.Assert(cap.Get(Agent), check.HasLen, 0)

plumbing/protocol/packp/srvresp.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ type ServerResponse struct {
2121
// Decode decodes the response into the struct, isMultiACK should be true, if
2222
// the request was done with multi_ack or multi_ack_detailed capabilities.
2323
func (r *ServerResponse) Decode(reader *bufio.Reader, isMultiACK bool) error {
24-
// TODO: implement support for multi_ack or multi_ack_detailed responses
25-
if isMultiACK {
26-
return errors.New("multi_ack and multi_ack_detailed are not supported")
27-
}
28-
2924
s := pktline.NewScanner(reader)
3025

3126
for s.Scan() {
@@ -48,7 +43,23 @@ func (r *ServerResponse) Decode(reader *bufio.Reader, isMultiACK bool) error {
4843
}
4944
}
5045

51-
return s.Err()
46+
// isMultiACK is true when the remote server advertises the related
47+
// capabilities when they are not in transport.UnsupportedCapabilities.
48+
//
49+
// Users may decide to remove multi_ack and multi_ack_detailed from the
50+
// unsupported capabilities list, which allows them to do initial clones
51+
// from Azure DevOps.
52+
//
53+
// Follow-up fetches may error, therefore errors are wrapped with additional
54+
// information highlighting that this capabilities are not supported by go-git.
55+
//
56+
// TODO: Implement support for multi_ack or multi_ack_detailed responses.
57+
err := s.Err()
58+
if err != nil && isMultiACK {
59+
return fmt.Errorf("multi_ack and multi_ack_detailed are not supported: %w", err)
60+
}
61+
62+
return err
5263
}
5364

5465
// stopReading detects when a valid command such as ACK or NAK is found to be
@@ -113,8 +124,9 @@ func (r *ServerResponse) decodeACKLine(line []byte) error {
113124
}
114125

115126
// Encode encodes the ServerResponse into a writer.
116-
func (r *ServerResponse) Encode(w io.Writer) error {
117-
if len(r.ACKs) > 1 {
127+
func (r *ServerResponse) Encode(w io.Writer, isMultiACK bool) error {
128+
if len(r.ACKs) > 1 && !isMultiACK {
129+
// For further information, refer to comments in the Decode func above.
118130
return errors.New("multi_ack and multi_ack_detailed are not supported")
119131
}
120132

0 commit comments

Comments
 (0)