mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-14 18:24:14 +01:00
140 lines
2.9 KiB
Go
140 lines
2.9 KiB
Go
|
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
|
||
|
}
|