repopool

package
v0.3.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2025 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package repopool periodically mirrors (bare clones) remote repositories locally. It supports multiple mirrored checked out worktrees on different references and it can also mirror multiple repositories.

Usages

please see examples below

Logging:

package takes slog reference for logging and prints logs up to 'trace' level

Example:

loggerLevel  = new(slog.LevelVar)
levelStrings = map[string]slog.Level{
	"trace": slog.Level(-8),
	"debug": slog.LevelDebug,
	"info":  slog.LevelInfo,
	"warn":  slog.LevelWarn,
	"error": slog.LevelError,
}

logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
	Level: loggerLevel,
}))
loggerLevel.Set(levelStrings["trace"])

repos, err := NewRepoPool(conf, logger.With("logger", "git-mirror"), nil)
if err != nil {
	panic(err)
}
Example (WithOutWorktree)
tmpRoot, err := os.MkdirTemp("", "git-mirror-without-worktree-example-*")
if err != nil {
	panic(err)
}
defer os.RemoveAll(tmpRoot)

config := `
defaults:
  root:
  interval: 30s
  mirror_timeout: 2m
  git_gc: always
repositories:
  - remote: https://github.com/utilitywarehouse/git-mirror.git
`
ctx := context.Background()

conf := repopool.Config{}
err = yaml.Unmarshal([]byte(config), &conf)
if err != nil {
	panic(err)
}
conf.Defaults.Root = tmpRoot

repos, err := repopool.New(ctx, conf, slog.Default(), "", nil)
if err != nil {
	panic(err)
}

// perform 1st mirror to ensure all repositories
// initial mirror might take longer
if err := repos.MirrorAll(ctx, 5*time.Minute); err != nil {
	panic(err)
}

// start mirror Loop
repos.StartLoop()

hash, err := repos.Hash(ctx, "https://github.com/utilitywarehouse/git-mirror.git", "main", "")
if err != nil {
	panic(err)
}
fmt.Println("last commit hash at main", "hash", hash)

msg, err := repos.Subject(ctx, "https://github.com/utilitywarehouse/git-mirror.git", "main")
if err != nil {
	panic(err)
}
fmt.Println("last commit msg at main", "msg", msg)
Example (Worktree)
tmpRoot, err := os.MkdirTemp("", "git-mirror-worktree-example-*")
if err != nil {
	panic(err)
}
defer os.RemoveAll(tmpRoot)

config := `
defaults:
  root: /tmp/git-mirror
  interval: 30s
  mirror_timeout: 2m
  git_gc: always
repositories:
  - remote: https://github.com/utilitywarehouse/git-mirror.git
    worktrees:
    - link: main
`
ctx := context.Background()

conf := repopool.Config{}
err = yaml.Unmarshal([]byte(config), &conf)
if err != nil {
	panic(err)
}

conf.Defaults.Root = tmpRoot

repos, err := repopool.New(ctx, conf, slog.Default(), "", nil)
if err != nil {
	panic(err)
}

// perform 1st mirror to ensure all repositories
// initial mirror might take longer
if err := repos.MirrorAll(ctx, 5*time.Minute); err != nil {
	panic(err)
}

// start mirror Loop
repos.StartLoop()

hash, err := repos.Hash(ctx, "https://github.com/utilitywarehouse/git-mirror.git", "main", "")
if err != nil {
	panic(err)
}
fmt.Println("last commit hash at main", "hash", hash)

msg, err := repos.Subject(ctx, "https://github.com/utilitywarehouse/git-mirror.git", "main")
if err != nil {
	panic(err)
}
fmt.Println("last commit msg at main", "msg", msg)

// make sure file exists in the tree
_, err = os.Stat(tmpRoot + "/main/repository/repository.go")
if err != nil {
	panic(err)
}

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrExist    = errors.New("repo already exist")
	ErrNotExist = errors.New("repo does not exist")
)

Functions

This section is empty.

Types

type Config

type Config struct {
	// default config for all the repositories if not set
	Defaults DefaultConfig `yaml:"defaults"`
	// List of mirrored repositories.
	Repositories []repository.Config `yaml:"repositories"`
}

Config is the configuration to create repoPool

func (*Config) ValidateAndApplyDefaults

func (conf *Config) ValidateAndApplyDefaults() error

ValidateAndApplyDefaults will validate link paths and default and apply defaults

type DefaultConfig

type DefaultConfig struct {
	// Root is the absolute path to the root dir where all repositories directories
	// will be created all repos worktree links will be created here if not
	// specified in repo config
	Root string `yaml:"root"`

	// LinkRoot is the absolute path to the dir which is the root for the worktree links
	// if link is a relative path it will be relative to this dir
	// if link is not specified it will be constructed from repo name and worktree ref
	// and it will be placed in this dir
	// if not specified it will be same as root
	LinkRoot string `yaml:"link_root"`

	// Interval is time duration for how long to wait between mirrors
	Interval time.Duration `yaml:"interval"`

	// MirrorTimeout represents the total time allowed for the complete mirror loop
	MirrorTimeout time.Duration `yaml:"mirror_timeout"`

	// GitGC garbage collection string. valid values are
	// 'auto', 'always', 'aggressive' or 'off'
	GitGC string `yaml:"git_gc"`

	// Auth config to fetch remote repos
	Auth repository.Auth `yaml:"auth"`
}

DefaultConfig is the default config for repositories if not set at repo level

type RepoPool

type RepoPool struct {
	Stopped chan bool
	// contains filtered or unexported fields
}

RepoPool represents the collection of mirrored repositories it provides simple wrapper around Repository methods. A RepoPool is safe for concurrent use by multiple goroutines.

func New

func New(ctx context.Context, conf Config, log *slog.Logger, gitExec string, commonENVs []string) (*RepoPool, error)

New will create repository pool based on given config. Remote repo will not be mirrored until either Mirror() or StartLoop() is called

func (*RepoPool) AddRepository

func (rp *RepoPool) AddRepository(repoConf repository.Config) error

AddRepository will add given repository to repoPool. Remote repo will not be mirrored until either Mirror() or StartLoop() is called

func (rp *RepoPool) AddWorktreeLink(remote string, wt repository.WorktreeConfig) error

AddWorktreeLink is wrapper around repositories AddWorktreeLink method

func (*RepoPool) BranchCommits

func (rp *RepoPool) BranchCommits(ctx context.Context, remote, branch string) ([]repository.CommitInfo, error)

BranchCommits is wrapper around repositories BranchCommits method

func (*RepoPool) ChangedFiles

func (rp *RepoPool) ChangedFiles(ctx context.Context, remote, hash string) ([]string, error)

ChangedFiles is wrapper around repositories ChangedFiles method

func (*RepoPool) Clone

func (rp *RepoPool) Clone(ctx context.Context, remote, dst, branch string, pathspecs []string, rmGitDir bool) (string, error)

Clone is wrapper around repositories Clone method

func (*RepoPool) Hash

func (rp *RepoPool) Hash(ctx context.Context, remote, ref, path string) (string, error)

Hash is wrapper around repositories hash method

func (*RepoPool) ListCommitsWithChangedFiles

func (rp *RepoPool) ListCommitsWithChangedFiles(ctx context.Context, remote, ref1, ref2 string) ([]repository.CommitInfo, error)

ListCommitsWithChangedFiles is wrapper around repositories ListCommitsWithChangedFiles method

func (*RepoPool) MergeCommits

func (rp *RepoPool) MergeCommits(ctx context.Context, remote, mergeCommitHash string) ([]repository.CommitInfo, error)

MergeCommits is wrapper around repositories MergeCommits method

func (*RepoPool) Mirror

func (rp *RepoPool) Mirror(ctx context.Context, remote string) error

Mirror is wrapper around repositories Mirror method

func (*RepoPool) MirrorAll

func (rp *RepoPool) MirrorAll(ctx context.Context, timeout time.Duration) error

MirrorAll will trigger mirror on every repo in foreground with given timeout. It will error out if any of the repository mirror errors. Ideally MirrorAll should be used for the first mirror cycle to ensure repositories are successfully mirrored

func (*RepoPool) ObjectExists

func (rp *RepoPool) ObjectExists(ctx context.Context, remote, obj string) error

ObjectExists is wrapper around repositories ObjectExists method

func (*RepoPool) QueueMirrorRun

func (rp *RepoPool) QueueMirrorRun(remote string) error

QueueMirrorRun is wrapper around repositories QueueMirrorRun method

func (*RepoPool) RemoveRepository

func (rp *RepoPool) RemoveRepository(remote string) error

RemoveRepository will remove given repository from the repoPool.

func (rp *RepoPool) RemoveWorktreeLink(remote string, wtLink string) error

RemoveWorktreeLink is wrapper around repositories RemoveWorktreeLink method

func (*RepoPool) RepositoriesDirPath

func (rp *RepoPool) RepositoriesDirPath() []string

RepositoriesDirPath returns local paths of all the mirrored repositories

func (*RepoPool) RepositoriesRemote

func (rp *RepoPool) RepositoriesRemote() []string

RepositoriesRemote returns remote URLs of all the repositories

func (*RepoPool) Repository

func (rp *RepoPool) Repository(remote string) (*repository.Repository, error)

Repository will return Repository object based on given remote URL

func (*RepoPool) StartLoop

func (rp *RepoPool) StartLoop()

StartLoop will start mirror loop on all repositories if its not already started

func (*RepoPool) Subject

func (rp *RepoPool) Subject(ctx context.Context, remote, hash string) (string, error)

Subject is wrapper around repositories Subject method

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL