Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 867b106

Browse files
authored
Merge pull request #270 from mcuadros/submodules-init
Submodules init and update
2 parents 0b8b8da + 790fbda commit 867b106

30 files changed

+1092
-131
lines changed

_examples/clone/main.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ func main() {
1414
directory := os.Args[2]
1515

1616
// Clone the given repository to the given directory
17-
Info("git clone %s %s", url, directory)
17+
Info("git clone %s %s --recursive", url, directory)
1818

1919
r, err := git.PlainClone(directory, false, &git.CloneOptions{
20-
URL: url,
21-
Depth: 1,
20+
URL: url,
21+
RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
2222
})
2323

2424
CheckIfError(err)

common.go

+2-17
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,8 @@
11
package git
22

3-
import (
4-
"strings"
3+
import "strings"
54

6-
"srcd.works/go-git.v4/config"
7-
"srcd.works/go-git.v4/plumbing/storer"
8-
)
9-
10-
// Storer is a generic storage of objects, references and any information
11-
// related to a particular repository. The package srcd.works/go-git.v4/storage
12-
// contains two implementation a filesystem base implementation (such as `.git`)
13-
// and a memory implementations being ephemeral
14-
type Storer interface {
15-
storer.EncodedObjectStorer
16-
storer.ReferenceStorer
17-
storer.ShallowStorer
18-
storer.IndexStorer
19-
config.ConfigStorer
20-
}
5+
const defaultDotGitPath = ".git"
216

227
// countLines returns the number of lines in a string à la git, this is
238
// The newline character is assumed to be '\n'. The empty string

config/config.go

+57-16
Original file line numberDiff line numberDiff line change
@@ -32,30 +32,36 @@ var (
3232
// Config contains the repository configuration
3333
// ftp://www.kernel.org/pub/software/scm/git/docs/git-config.html#FILES
3434
type Config struct {
35-
// Core variables
3635
Core struct {
3736
// IsBare if true this repository is assumed to be bare and has no
38-
// working directory associated with it
37+
// working directory associated with it.
3938
IsBare bool
39+
// Worktree is the path to the root of the working tree.
40+
Worktree string
4041
}
41-
// Remote list of repository remotes
42+
// Remotes list of repository remotes, the key of the map is the name
43+
// of the remote, should equal to RemoteConfig.Name.
4244
Remotes map[string]*RemoteConfig
45+
// Submodules list of repository submodules, the key of the map is the name
46+
// of the submodule, should equal to Submodule.Name.
47+
Submodules map[string]*Submodule
4348

4449
// contains the raw information of a config file, the main goal is preserve
4550
// the parsed information from the original format, to avoid missing
4651
// unsupported features.
4752
raw *format.Config
4853
}
4954

50-
// NewConfig returns a new empty Config
55+
// NewConfig returns a new empty Config.
5156
func NewConfig() *Config {
5257
return &Config{
53-
Remotes: make(map[string]*RemoteConfig, 0),
54-
raw: format.New(),
58+
Remotes: make(map[string]*RemoteConfig, 0),
59+
Submodules: make(map[string]*Submodule, 0),
60+
raw: format.New(),
5561
}
5662
}
5763

58-
// Validate validates the fields and sets the default values
64+
// Validate validates the fields and sets the default values.
5965
func (c *Config) Validate() error {
6066
for name, r := range c.Remotes {
6167
if r.Name != name {
@@ -71,14 +77,16 @@ func (c *Config) Validate() error {
7177
}
7278

7379
const (
74-
remoteSection = "remote"
75-
coreSection = "core"
76-
fetchKey = "fetch"
77-
urlKey = "url"
78-
bareKey = "bare"
80+
remoteSection = "remote"
81+
submoduleSection = "submodule"
82+
coreSection = "core"
83+
fetchKey = "fetch"
84+
urlKey = "url"
85+
bareKey = "bare"
86+
worktreeKey = "worktree"
7987
)
8088

81-
// Unmarshal parses a git-config file and stores it
89+
// Unmarshal parses a git-config file and stores it.
8290
func (c *Config) Unmarshal(b []byte) error {
8391
r := bytes.NewBuffer(b)
8492
d := format.NewDecoder(r)
@@ -89,6 +97,7 @@ func (c *Config) Unmarshal(b []byte) error {
8997
}
9098

9199
c.unmarshalCore()
100+
c.unmarshalSubmodules()
92101
return c.unmarshalRemotes()
93102
}
94103

@@ -97,6 +106,8 @@ func (c *Config) unmarshalCore() {
97106
if s.Options.Get(bareKey) == "true" {
98107
c.Core.IsBare = true
99108
}
109+
110+
c.Core.Worktree = s.Options.Get(worktreeKey)
100111
}
101112

102113
func (c *Config) unmarshalRemotes() error {
@@ -113,10 +124,21 @@ func (c *Config) unmarshalRemotes() error {
113124
return nil
114125
}
115126

116-
// Marshal returns Config encoded as a git-config file
127+
func (c *Config) unmarshalSubmodules() {
128+
s := c.raw.Section(submoduleSection)
129+
for _, sub := range s.Subsections {
130+
m := &Submodule{}
131+
m.unmarshal(sub)
132+
133+
c.Submodules[m.Name] = m
134+
}
135+
}
136+
137+
// Marshal returns Config encoded as a git-config file.
117138
func (c *Config) Marshal() ([]byte, error) {
118139
c.marshalCore()
119140
c.marshalRemotes()
141+
c.marshalSubmodules()
120142

121143
buf := bytes.NewBuffer(nil)
122144
if err := format.NewEncoder(buf).Encode(c.raw); err != nil {
@@ -129,6 +151,10 @@ func (c *Config) Marshal() ([]byte, error) {
129151
func (c *Config) marshalCore() {
130152
s := c.raw.Section(coreSection)
131153
s.SetOption(bareKey, fmt.Sprintf("%t", c.Core.IsBare))
154+
155+
if c.Core.Worktree != "" {
156+
s.SetOption(worktreeKey, c.Core.Worktree)
157+
}
132158
}
133159

134160
func (c *Config) marshalRemotes() {
@@ -142,7 +168,22 @@ func (c *Config) marshalRemotes() {
142168
}
143169
}
144170

145-
// RemoteConfig contains the configuration for a given remote repository
171+
func (c *Config) marshalSubmodules() {
172+
s := c.raw.Section(submoduleSection)
173+
s.Subsections = make(format.Subsections, len(c.Submodules))
174+
175+
var i int
176+
for _, r := range c.Submodules {
177+
section := r.marshal()
178+
// the submodule section at config is a subset of the .gitmodule file
179+
// we should remove the non-valid options for the config file.
180+
section.RemoveOption(pathKey)
181+
s.Subsections[i] = section
182+
i++
183+
}
184+
}
185+
186+
// RemoteConfig contains the configuration for a given remote repository.
146187
type RemoteConfig struct {
147188
// Name of the remote
148189
Name string
@@ -156,7 +197,7 @@ type RemoteConfig struct {
156197
raw *format.Subsection
157198
}
158199

159-
// Validate validates the fields and sets the default values
200+
// Validate validates the fields and sets the default values.
160201
func (c *RemoteConfig) Validate() error {
161202
if c.Name == "" {
162203
return ErrRemoteConfigEmptyName

config/config_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ var _ = Suite(&ConfigSuite{})
99
func (s *ConfigSuite) TestUnmarshall(c *C) {
1010
input := []byte(`[core]
1111
bare = true
12+
worktree = foo
1213
[remote "origin"]
1314
url = [email protected]:mcuadros/go-git.git
1415
fetch = +refs/heads/*:refs/remotes/origin/*
16+
[submodule "qux"]
17+
path = qux
18+
url = https://github.com/foo/qux.git
19+
branch = bar
1520
[branch "master"]
1621
remote = origin
1722
merge = refs/heads/master
@@ -22,15 +27,51 @@ func (s *ConfigSuite) TestUnmarshall(c *C) {
2227
c.Assert(err, IsNil)
2328

2429
c.Assert(cfg.Core.IsBare, Equals, true)
30+
c.Assert(cfg.Core.Worktree, Equals, "foo")
2531
c.Assert(cfg.Remotes, HasLen, 1)
2632
c.Assert(cfg.Remotes["origin"].Name, Equals, "origin")
2733
c.Assert(cfg.Remotes["origin"].URL, Equals, "[email protected]:mcuadros/go-git.git")
2834
c.Assert(cfg.Remotes["origin"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*"})
35+
c.Assert(cfg.Submodules, HasLen, 1)
36+
c.Assert(cfg.Submodules["qux"].Name, Equals, "qux")
37+
c.Assert(cfg.Submodules["qux"].URL, Equals, "https://github.com/foo/qux.git")
38+
c.Assert(cfg.Submodules["qux"].Branch, Equals, "bar")
39+
40+
}
41+
42+
func (s *ConfigSuite) TestMarshall(c *C) {
43+
output := []byte(`[core]
44+
bare = true
45+
worktree = bar
46+
[remote "origin"]
47+
url = [email protected]:mcuadros/go-git.git
48+
[submodule "qux"]
49+
url = https://github.com/foo/qux.git
50+
`)
51+
52+
cfg := NewConfig()
53+
cfg.Core.IsBare = true
54+
cfg.Core.Worktree = "bar"
55+
cfg.Remotes["origin"] = &RemoteConfig{
56+
Name: "origin",
57+
URL: "[email protected]:mcuadros/go-git.git",
58+
}
59+
60+
cfg.Submodules["qux"] = &Submodule{
61+
Name: "qux",
62+
URL: "https://github.com/foo/qux.git",
63+
}
64+
65+
b, err := cfg.Marshal()
66+
c.Assert(err, IsNil)
67+
68+
c.Assert(string(b), Equals, string(output))
2969
}
3070

3171
func (s *ConfigSuite) TestUnmarshallMarshall(c *C) {
3272
input := []byte(`[core]
3373
bare = true
74+
worktree = foo
3475
custom = ignored
3576
[remote "origin"]
3677
url = [email protected]:mcuadros/go-git.git

config/modules.go

+9-10
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var (
1515
// Modules defines the submodules properties, represents a .gitmodules file
1616
// https://www.kernel.org/pub/software/scm/git/docs/gitmodules.html
1717
type Modules struct {
18-
// Submodules is a map of submodules being the key the name of the submodule
18+
// Submodules is a map of submodules being the key the name of the submodule.
1919
Submodules map[string]*Submodule
2020

2121
raw *format.Config
@@ -30,12 +30,11 @@ func NewModules() *Modules {
3030
}
3131

3232
const (
33-
submoduleSection = "submodule"
34-
pathKey = "path"
35-
branchKey = "branch"
33+
pathKey = "path"
34+
branchKey = "branch"
3635
)
3736

38-
// Unmarshal parses a git-config file and stores it
37+
// Unmarshal parses a git-config file and stores it.
3938
func (m *Modules) Unmarshal(b []byte) error {
4039
r := bytes.NewBuffer(b)
4140
d := format.NewDecoder(r)
@@ -56,7 +55,7 @@ func (m *Modules) Unmarshal(b []byte) error {
5655
return nil
5756
}
5857

59-
// Marshal returns Modules encoded as a git-config file
58+
// Marshal returns Modules encoded as a git-config file.
6059
func (m *Modules) Marshal() ([]byte, error) {
6160
s := m.raw.Section(submoduleSection)
6261
s.Subsections = make(format.Subsections, len(m.Submodules))
@@ -75,12 +74,12 @@ func (m *Modules) Marshal() ([]byte, error) {
7574
return buf.Bytes(), nil
7675
}
7776

78-
// Submodule defines a submodule
77+
// Submodule defines a submodule.
7978
type Submodule struct {
8079
// Name module name
8180
Name string
8281
// Path defines the path, relative to the top-level directory of the Git
83-
// working tree,
82+
// working tree.
8483
Path string
8584
// URL defines a URL from which the submodule repository can be cloned.
8685
URL string
@@ -89,11 +88,11 @@ type Submodule struct {
8988
Branch string
9089

9190
// raw representation of the subsection, filled by marshal or unmarshal are
92-
// called
91+
// called.
9392
raw *format.Subsection
9493
}
9594

96-
// Validate validates the fields and sets the default values
95+
// Validate validates the fields and sets the default values.
9796
func (m *Submodule) Validate() error {
9897
if m.Path == "" {
9998
return ErrModuleEmptyPath

config/refspec.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func (s RefSpec) Validate() error {
4949
return ErrRefSpecMalformedWildcard
5050
}
5151

52-
// IsForceUpdate returns if update is allowed in non fast-forward merges
52+
// IsForceUpdate returns if update is allowed in non fast-forward merges.
5353
func (s RefSpec) IsForceUpdate() bool {
5454
if s[0] == refSpecForce[0] {
5555
return true
@@ -67,7 +67,7 @@ func (s RefSpec) IsDelete() bool {
6767
return false
6868
}
6969

70-
// Src return the src side
70+
// Src return the src side.
7171
func (s RefSpec) Src() string {
7272
spec := string(s)
7373
start := strings.Index(spec, refSpecForce) + 1
@@ -76,7 +76,7 @@ func (s RefSpec) Src() string {
7676
return spec[start:end]
7777
}
7878

79-
// Match match the given plumbing.ReferenceName against the source
79+
// Match match the given plumbing.ReferenceName against the source.
8080
func (s RefSpec) Match(n plumbing.ReferenceName) bool {
8181
if !s.IsWildcard() {
8282
return s.matchExact(n)
@@ -85,7 +85,7 @@ func (s RefSpec) Match(n plumbing.ReferenceName) bool {
8585
return s.matchGlob(n)
8686
}
8787

88-
// IsWildcard returns true if the RefSpec contains a wildcard
88+
// IsWildcard returns true if the RefSpec contains a wildcard.
8989
func (s RefSpec) IsWildcard() bool {
9090
return strings.Index(string(s), refSpecWildcard) != -1
9191
}
@@ -110,7 +110,7 @@ func (s RefSpec) matchGlob(n plumbing.ReferenceName) bool {
110110
strings.HasSuffix(name, suffix)
111111
}
112112

113-
// Dst returns the destination for the given remote reference
113+
// Dst returns the destination for the given remote reference.
114114
func (s RefSpec) Dst(n plumbing.ReferenceName) plumbing.ReferenceName {
115115
spec := string(s)
116116
start := strings.Index(spec, refSpecSeparator) + 1
@@ -133,7 +133,7 @@ func (s RefSpec) String() string {
133133
return string(s)
134134
}
135135

136-
// MatchAny returns true if any of the RefSpec match with the given ReferenceName
136+
// MatchAny returns true if any of the RefSpec match with the given ReferenceName.
137137
func MatchAny(l []RefSpec, n plumbing.ReferenceName) bool {
138138
for _, r := range l {
139139
if r.Match(n) {

0 commit comments

Comments
 (0)