You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							139 lines
						
					
					
						
							2.9 KiB
						
					
					
				
			
		
		
	
	
							139 lines
						
					
					
						
							2.9 KiB
						
					
					
				| 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
 | |
| }
 | |
| 
 |