|
- package config
-
- import (
- "bytes"
- "errors"
- "regexp"
-
- format "gopkg.in/src-d/go-git.v4/plumbing/format/config"
- )
-
- var (
- ErrModuleEmptyURL = errors.New("module config: empty URL")
- ErrModuleEmptyPath = errors.New("module config: empty path")
- ErrModuleBadPath = errors.New("submodule has an invalid path")
- )
-
- var (
- // Matches module paths with dotdot ".." components.
- dotdotPath = regexp.MustCompile(`(^|[/\\])\.\.([/\\]|$)`)
- )
-
- // Modules defines the submodules properties, represents a .gitmodules file
- // https://www.kernel.org/pub/software/scm/git/docs/gitmodules.html
- type Modules struct {
- // Submodules is a map of submodules being the key the name of the submodule.
- Submodules map[string]*Submodule
-
- raw *format.Config
- }
-
- // NewModules returns a new empty Modules
- func NewModules() *Modules {
- return &Modules{
- Submodules: make(map[string]*Submodule),
- raw: format.New(),
- }
- }
-
- const (
- pathKey = "path"
- branchKey = "branch"
- )
-
- // Unmarshal parses a git-config file and stores it.
- func (m *Modules) Unmarshal(b []byte) error {
- r := bytes.NewBuffer(b)
- d := format.NewDecoder(r)
-
- m.raw = format.New()
- if err := d.Decode(m.raw); err != nil {
- return err
- }
-
- unmarshalSubmodules(m.raw, m.Submodules)
- return nil
- }
-
- // Marshal returns Modules encoded as a git-config file.
- func (m *Modules) Marshal() ([]byte, error) {
- s := m.raw.Section(submoduleSection)
- s.Subsections = make(format.Subsections, len(m.Submodules))
-
- var i int
- for _, r := range m.Submodules {
- s.Subsections[i] = r.marshal()
- i++
- }
-
- buf := bytes.NewBuffer(nil)
- if err := format.NewEncoder(buf).Encode(m.raw); err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
- }
-
- // Submodule defines a submodule.
- type Submodule struct {
- // Name module name
- Name string
- // Path defines the path, relative to the top-level directory of the Git
- // working tree.
- Path string
- // URL defines a URL from which the submodule repository can be cloned.
- URL string
- // Branch is a remote branch name for tracking updates in the upstream
- // submodule. Optional value.
- Branch string
-
- // raw representation of the subsection, filled by marshal or unmarshal are
- // called.
- raw *format.Subsection
- }
-
- // Validate validates the fields and sets the default values.
- func (m *Submodule) Validate() error {
- if m.Path == "" {
- return ErrModuleEmptyPath
- }
-
- if m.URL == "" {
- return ErrModuleEmptyURL
- }
-
- if dotdotPath.MatchString(m.Path) {
- return ErrModuleBadPath
- }
-
- return nil
- }
-
- func (m *Submodule) unmarshal(s *format.Subsection) {
- m.raw = s
-
- m.Name = m.raw.Name
- m.Path = m.raw.Option(pathKey)
- m.URL = m.raw.Option(urlKey)
- m.Branch = m.raw.Option(branchKey)
- }
-
- func (m *Submodule) marshal() *format.Subsection {
- if m.raw == nil {
- m.raw = &format.Subsection{}
- }
-
- m.raw.Name = m.Name
- if m.raw.Name == "" {
- m.raw.Name = m.Path
- }
-
- m.raw.SetOption(pathKey, m.Path)
- m.raw.SetOption(urlKey, m.URL)
-
- if m.Branch != "" {
- m.raw.SetOption(branchKey, m.Branch)
- }
-
- return m.raw
- }
|