mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			140 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package config
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"errors"
 | 
						|
	"regexp"
 | 
						|
 | 
						|
	format "github.com/go-git/go-git/v5/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
 | 
						|
}
 |