git-module

git clone git://git.lin.moe/fork/git-module.git

  1package git
  2
  3import (
  4	"bufio"
  5	"bytes"
  6	"context"
  7	"strings"
  8)
  9
 10// Submodule contains information of a Git submodule.
 11type Submodule struct {
 12	// The name of the submodule.
 13	Name string
 14	// The URL of the submodule.
 15	URL string
 16	// The commit ID of the subproject.
 17	Commit string
 18}
 19
 20// Submodules contains information of submodules.
 21type Submodules = *objectCache
 22
 23// Submodules returns submodules found in this commit. Successful results are
 24// cached; failed attempts are not cached, allowing retries with a fresh context.
 25func (c *Commit) Submodules(ctx context.Context) (Submodules, error) {
 26	c.submodulesMu.Lock()
 27	defer c.submodulesMu.Unlock()
 28
 29	if c.submodulesSet {
 30		return c.submodules, nil
 31	}
 32
 33	e, err := c.TreeEntry(ctx, ".gitmodules")
 34	if err != nil {
 35		return nil, err
 36	}
 37
 38	p, err := e.Blob().Bytes(ctx)
 39	if err != nil {
 40		return nil, err
 41	}
 42
 43	scanner := bufio.NewScanner(bytes.NewReader(p))
 44	submodules := newObjectCache()
 45	var inSection bool
 46	var path string
 47	var url string
 48	for scanner.Scan() {
 49		if strings.HasPrefix(scanner.Text(), "[submodule") {
 50			inSection = true
 51			path = ""
 52			url = ""
 53			continue
 54		} else if !inSection {
 55			continue
 56		}
 57
 58		key, value, ok := strings.Cut(scanner.Text(), "=")
 59		if !ok {
 60			continue
 61		}
 62
 63		switch strings.TrimSpace(key) {
 64		case "path":
 65			path = strings.TrimSpace(value)
 66		case "url":
 67			url = strings.TrimSpace(value)
 68		}
 69
 70		if len(path) > 0 && len(url) > 0 {
 71			mod := &Submodule{
 72				Name: path,
 73				URL:  url,
 74			}
 75
 76			mod.Commit, err = c.repo.RevParse(ctx, c.id.String()+":"+mod.Name)
 77			if err != nil {
 78				return nil, err
 79			}
 80
 81			submodules.Set(path, mod)
 82			inSection = false
 83		}
 84	}
 85
 86	if err := scanner.Err(); err != nil {
 87		return nil, err
 88	}
 89
 90	c.submodules = submodules
 91	c.submodulesSet = true
 92	return c.submodules, nil
 93}
 94
 95// Submodule returns submodule by given name. It returns an ErrSubmoduleNotExist
 96// if the path does not exist as a submodule.
 97func (c *Commit) Submodule(ctx context.Context, path string) (*Submodule, error) {
 98	mods, err := c.Submodules(ctx)
 99	if err != nil {
100		return nil, err
101	}
102
103	m, has := mods.Get(path)
104	if has {
105		return m.(*Submodule), nil
106	}
107	return nil, ErrSubmoduleNotExist
108}